abstractMesh.ts 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188
  1. import { Tools } from "../Misc/tools";
  2. import { Observable } from "../Misc/observable";
  3. import { Nullable, FloatArray, IndicesArray, DeepImmutable } from "../types";
  4. import { Camera } from "../Cameras/camera";
  5. import { Scene, IDisposable } from "../scene";
  6. import { Quaternion, Matrix, Vector3, TmpVectors, Vector2 } from "../Maths/math.vector";
  7. import { Engine } from "../Engines/engine";
  8. import { Node } from "../node";
  9. import { VertexBuffer } from "../Meshes/buffer";
  10. import { VertexData, IGetSetVerticesData } from "../Meshes/mesh.vertexData";
  11. import { TransformNode } from "../Meshes/transformNode";
  12. import { SubMesh } from "../Meshes/subMesh";
  13. import { PickingInfo } from "../Collisions/pickingInfo";
  14. import { IntersectionInfo } from "../Collisions/intersectionInfo";
  15. import { ICullable, BoundingInfo } from "../Culling/boundingInfo";
  16. import { Material } from "../Materials/material";
  17. import { MaterialDefines } from "../Materials/materialDefines";
  18. import { Light } from "../Lights/light";
  19. import { Skeleton } from "../Bones/skeleton";
  20. import { IEdgesRenderer } from "../Rendering/edgesRenderer";
  21. import { SolidParticle } from "../Particles/solidParticle";
  22. import { Constants } from "../Engines/constants";
  23. import { AbstractActionManager } from '../Actions/abstractActionManager';
  24. import { _MeshCollisionData } from '../Collisions/meshCollisionData';
  25. import { _DevTools } from '../Misc/devTools';
  26. import { RawTexture } from '../Materials/Textures/rawTexture';
  27. import { extractMinAndMax } from '../Maths/math.functions';
  28. import { Color3, Color4 } from '../Maths/math.color';
  29. import { Epsilon } from '../Maths/math.constants';
  30. import { Plane } from '../Maths/math.plane';
  31. import { Axis } from '../Maths/math.axis';
  32. import { IParticleSystem } from '../Particles/IParticleSystem';
  33. declare type Ray = import("../Culling/ray").Ray;
  34. declare type Collider = import("../Collisions/collider").Collider;
  35. declare type TrianglePickingPredicate = import("../Culling/ray").TrianglePickingPredicate;
  36. declare type RenderingGroup = import("../Rendering/renderingGroup").RenderingGroup;
  37. /** @hidden */
  38. class _FacetDataStorage {
  39. // facetData private properties
  40. public facetPositions: Vector3[]; // facet local positions
  41. public facetNormals: Vector3[]; // facet local normals
  42. public facetPartitioning: number[][]; // partitioning array of facet index arrays
  43. public facetNb: number = 0; // facet number
  44. public partitioningSubdivisions: number = 10; // number of subdivisions per axis in the partioning space
  45. public partitioningBBoxRatio: number = 1.01; // the partioning array space is by default 1% bigger than the bounding box
  46. public facetDataEnabled: boolean = false; // is the facet data feature enabled on this mesh ?
  47. public facetParameters: any = {}; // keep a reference to the object parameters to avoid memory re-allocation
  48. public bbSize: Vector3 = Vector3.Zero(); // bbox size approximated for facet data
  49. public subDiv = { // actual number of subdivisions per axis for ComputeNormals()
  50. max: 1,
  51. X: 1,
  52. Y: 1,
  53. Z: 1
  54. };
  55. public facetDepthSort: boolean = false; // is the facet depth sort to be computed
  56. public facetDepthSortEnabled: boolean = false; // is the facet depth sort initialized
  57. public depthSortedIndices: IndicesArray; // copy of the indices array to store them once sorted
  58. public depthSortedFacets: { ind: number, sqDistance: number }[]; // array of depth sorted facets
  59. public facetDepthSortFunction: (f1: { ind: number, sqDistance: number }, f2: { ind: number, sqDistance: number }) => number; // facet depth sort function
  60. public facetDepthSortFrom: Vector3; // location where to depth sort from
  61. public facetDepthSortOrigin: Vector3; // same as facetDepthSortFrom but expressed in the mesh local space
  62. public invertedMatrix: Matrix; // Inverted world matrix.
  63. }
  64. /**
  65. * @hidden
  66. **/
  67. class _InternalAbstractMeshDataInfo {
  68. public _hasVertexAlpha = false;
  69. public _useVertexColors = true;
  70. public _numBoneInfluencers = 4;
  71. public _applyFog = true;
  72. public _receiveShadows = false;
  73. public _facetData = new _FacetDataStorage();
  74. public _visibility = 1.0;
  75. public _skeleton: Nullable<Skeleton> = null;
  76. public _layerMask: number = 0x0FFFFFFF;
  77. public _computeBonesUsingShaders = true;
  78. public _isActive = false;
  79. public _onlyForInstances = false;
  80. public _isActiveIntermediate = false;
  81. public _onlyForInstancesIntermediate = false;
  82. public _actAsRegularMesh = false;
  83. }
  84. /**
  85. * Class used to store all common mesh properties
  86. */
  87. export class AbstractMesh extends TransformNode implements IDisposable, ICullable, IGetSetVerticesData {
  88. /** No occlusion */
  89. public static OCCLUSION_TYPE_NONE = 0;
  90. /** Occlusion set to optimisitic */
  91. public static OCCLUSION_TYPE_OPTIMISTIC = 1;
  92. /** Occlusion set to strict */
  93. public static OCCLUSION_TYPE_STRICT = 2;
  94. /** Use an accurante occlusion algorithm */
  95. public static OCCLUSION_ALGORITHM_TYPE_ACCURATE = 0;
  96. /** Use a conservative occlusion algorithm */
  97. public static OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE = 1;
  98. /** Default culling strategy : this is an exclusion test and it's the more accurate.
  99. * Test order :
  100. * Is the bounding sphere outside the frustum ?
  101. * If not, are the bounding box vertices outside the frustum ?
  102. * It not, then the cullable object is in the frustum.
  103. */
  104. public static readonly CULLINGSTRATEGY_STANDARD = Constants.MESHES_CULLINGSTRATEGY_STANDARD;
  105. /** Culling strategy : Bounding Sphere Only.
  106. * This is an exclusion test. It's faster than the standard strategy because the bounding box is not tested.
  107. * It's also less accurate than the standard because some not visible objects can still be selected.
  108. * Test : is the bounding sphere outside the frustum ?
  109. * If not, then the cullable object is in the frustum.
  110. */
  111. public static readonly CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY = Constants.MESHES_CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY;
  112. /** Culling strategy : Optimistic Inclusion.
  113. * This in an inclusion test first, then the standard exclusion test.
  114. * This can be faster when a cullable object is expected to be almost always in the camera frustum.
  115. * This could also be a little slower than the standard test when the tested object center is not the frustum but one of its bounding box vertex is still inside.
  116. * Anyway, it's as accurate as the standard strategy.
  117. * Test :
  118. * Is the cullable object bounding sphere center in the frustum ?
  119. * If not, apply the default culling strategy.
  120. */
  121. public static readonly CULLINGSTRATEGY_OPTIMISTIC_INCLUSION = Constants.MESHES_CULLINGSTRATEGY_OPTIMISTIC_INCLUSION;
  122. /** Culling strategy : Optimistic Inclusion then Bounding Sphere Only.
  123. * This in an inclusion test first, then the bounding sphere only exclusion test.
  124. * This can be the fastest test when a cullable object is expected to be almost always in the camera frustum.
  125. * This could also be a little slower than the BoundingSphereOnly strategy when the tested object center is not in the frustum but its bounding sphere still intersects it.
  126. * It's less accurate than the standard strategy and as accurate as the BoundingSphereOnly strategy.
  127. * Test :
  128. * Is the cullable object bounding sphere center in the frustum ?
  129. * If not, apply the Bounding Sphere Only strategy. No Bounding Box is tested here.
  130. */
  131. public static readonly CULLINGSTRATEGY_OPTIMISTIC_INCLUSION_THEN_BSPHERE_ONLY = Constants.MESHES_CULLINGSTRATEGY_OPTIMISTIC_INCLUSION_THEN_BSPHERE_ONLY;
  132. /**
  133. * No billboard
  134. */
  135. public static get BILLBOARDMODE_NONE(): number {
  136. return TransformNode.BILLBOARDMODE_NONE;
  137. }
  138. /** Billboard on X axis */
  139. public static get BILLBOARDMODE_X(): number {
  140. return TransformNode.BILLBOARDMODE_X;
  141. }
  142. /** Billboard on Y axis */
  143. public static get BILLBOARDMODE_Y(): number {
  144. return TransformNode.BILLBOARDMODE_Y;
  145. }
  146. /** Billboard on Z axis */
  147. public static get BILLBOARDMODE_Z(): number {
  148. return TransformNode.BILLBOARDMODE_Z;
  149. }
  150. /** Billboard on all axes */
  151. public static get BILLBOARDMODE_ALL(): number {
  152. return TransformNode.BILLBOARDMODE_ALL;
  153. }
  154. /** Billboard on using position instead of orientation */
  155. public static get BILLBOARDMODE_USE_POSITION(): number {
  156. return TransformNode.BILLBOARDMODE_USE_POSITION;
  157. }
  158. // Internal data
  159. /** @hidden */
  160. public _internalAbstractMeshDataInfo = new _InternalAbstractMeshDataInfo();
  161. /**
  162. * The culling strategy to use to check whether the mesh must be rendered or not.
  163. * This value can be changed at any time and will be used on the next render mesh selection.
  164. * The possible values are :
  165. * - AbstractMesh.CULLINGSTRATEGY_STANDARD
  166. * - AbstractMesh.CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY
  167. * - AbstractMesh.CULLINGSTRATEGY_OPTIMISTIC_INCLUSION
  168. * - AbstractMesh.CULLINGSTRATEGY_OPTIMISTIC_INCLUSION_THEN_BSPHERE_ONLY
  169. * Please read each static variable documentation to get details about the culling process.
  170. * */
  171. public cullingStrategy = AbstractMesh.CULLINGSTRATEGY_BOUNDINGSPHERE_ONLY;
  172. /**
  173. * Gets the number of facets in the mesh
  174. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#what-is-a-mesh-facet
  175. */
  176. public get facetNb(): number {
  177. return this._internalAbstractMeshDataInfo._facetData.facetNb;
  178. }
  179. /**
  180. * Gets or set the number (integer) of subdivisions per axis in the partioning space
  181. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#tweaking-the-partitioning
  182. */
  183. public get partitioningSubdivisions(): number {
  184. return this._internalAbstractMeshDataInfo._facetData.partitioningSubdivisions;
  185. }
  186. public set partitioningSubdivisions(nb: number) {
  187. this._internalAbstractMeshDataInfo._facetData.partitioningSubdivisions = nb;
  188. }
  189. /**
  190. * The ratio (float) to apply to the bouding box size to set to the partioning space.
  191. * Ex : 1.01 (default) the partioning space is 1% bigger than the bounding box
  192. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#tweaking-the-partitioning
  193. */
  194. public get partitioningBBoxRatio(): number {
  195. return this._internalAbstractMeshDataInfo._facetData.partitioningBBoxRatio;
  196. }
  197. public set partitioningBBoxRatio(ratio: number) {
  198. this._internalAbstractMeshDataInfo._facetData.partitioningBBoxRatio = ratio;
  199. }
  200. /**
  201. * Gets or sets a boolean indicating that the facets must be depth sorted on next call to `updateFacetData()`.
  202. * Works only for updatable meshes.
  203. * Doesn't work with multi-materials
  204. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#facet-depth-sort
  205. */
  206. public get mustDepthSortFacets(): boolean {
  207. return this._internalAbstractMeshDataInfo._facetData.facetDepthSort;
  208. }
  209. public set mustDepthSortFacets(sort: boolean) {
  210. this._internalAbstractMeshDataInfo._facetData.facetDepthSort = sort;
  211. }
  212. /**
  213. * The location (Vector3) where the facet depth sort must be computed from.
  214. * By default, the active camera position.
  215. * Used only when facet depth sort is enabled
  216. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#facet-depth-sort
  217. */
  218. public get facetDepthSortFrom(): Vector3 {
  219. return this._internalAbstractMeshDataInfo._facetData.facetDepthSortFrom;
  220. }
  221. public set facetDepthSortFrom(location: Vector3) {
  222. this._internalAbstractMeshDataInfo._facetData.facetDepthSortFrom = location;
  223. }
  224. /**
  225. * gets a boolean indicating if facetData is enabled
  226. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata#what-is-a-mesh-facet
  227. */
  228. public get isFacetDataEnabled(): boolean {
  229. return this._internalAbstractMeshDataInfo._facetData.facetDataEnabled;
  230. }
  231. /** @hidden */
  232. public _updateNonUniformScalingState(value: boolean): boolean {
  233. if (!super._updateNonUniformScalingState(value)) {
  234. return false;
  235. }
  236. this._markSubMeshesAsMiscDirty();
  237. return true;
  238. }
  239. // Events
  240. /**
  241. * An event triggered when this mesh collides with another one
  242. */
  243. public onCollideObservable = new Observable<AbstractMesh>();
  244. /** Set a function to call when this mesh collides with another one */
  245. public set onCollide(callback: () => void) {
  246. if (this._meshCollisionData._onCollideObserver) {
  247. this.onCollideObservable.remove(this._meshCollisionData._onCollideObserver);
  248. }
  249. this._meshCollisionData._onCollideObserver = this.onCollideObservable.add(callback);
  250. }
  251. /**
  252. * An event triggered when the collision's position changes
  253. */
  254. public onCollisionPositionChangeObservable = new Observable<Vector3>();
  255. /** Set a function to call when the collision's position changes */
  256. public set onCollisionPositionChange(callback: () => void) {
  257. if (this._meshCollisionData._onCollisionPositionChangeObserver) {
  258. this.onCollisionPositionChangeObservable.remove(this._meshCollisionData._onCollisionPositionChangeObserver);
  259. }
  260. this._meshCollisionData._onCollisionPositionChangeObserver = this.onCollisionPositionChangeObservable.add(callback);
  261. }
  262. /**
  263. * An event triggered when material is changed
  264. */
  265. public onMaterialChangedObservable = new Observable<AbstractMesh>();
  266. // Properties
  267. /**
  268. * Gets or sets the orientation for POV movement & rotation
  269. */
  270. public definedFacingForward = true;
  271. /** @hidden */
  272. public _occlusionQuery: Nullable<WebGLQuery> = null;
  273. /** @hidden */
  274. public _renderingGroup: Nullable<RenderingGroup> = null;
  275. /**
  276. * Gets or sets mesh visibility between 0 and 1 (default is 1)
  277. */
  278. public get visibility(): number {
  279. return this._internalAbstractMeshDataInfo._visibility;
  280. }
  281. /**
  282. * Gets or sets mesh visibility between 0 and 1 (default is 1)
  283. */
  284. public set visibility(value: number) {
  285. if (this._internalAbstractMeshDataInfo._visibility === value) {
  286. return;
  287. }
  288. this._internalAbstractMeshDataInfo._visibility = value;
  289. this._markSubMeshesAsMiscDirty();
  290. }
  291. /** Gets or sets the alpha index used to sort transparent meshes
  292. * @see https://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered#alpha-index
  293. */
  294. public alphaIndex = Number.MAX_VALUE;
  295. /**
  296. * Gets or sets a boolean indicating if the mesh is visible (renderable). Default is true
  297. */
  298. public isVisible = true;
  299. /**
  300. * Gets or sets a boolean indicating if the mesh can be picked (by scene.pick for instance or through actions). Default is true
  301. */
  302. public isPickable = true;
  303. /** Gets or sets a boolean indicating that bounding boxes of subMeshes must be rendered as well (false by default) */
  304. public showSubMeshesBoundingBox = false;
  305. /** Gets or sets a boolean indicating if the mesh must be considered as a ray blocker for lens flares (false by default)
  306. * @see https://doc.babylonjs.com/how_to/how_to_use_lens_flares
  307. */
  308. public isBlocker = false;
  309. /**
  310. * Gets or sets a boolean indicating that pointer move events must be supported on this mesh (false by default)
  311. */
  312. public enablePointerMoveEvents = false;
  313. /**
  314. * Specifies the rendering group id for this mesh (0 by default)
  315. * @see https://doc.babylonjs.com/resources/transparency_and_how_meshes_are_rendered#rendering-groups
  316. */
  317. public renderingGroupId = 0;
  318. private _material: Nullable<Material> = null;
  319. /** Gets or sets current material */
  320. public get material(): Nullable<Material> {
  321. return this._material;
  322. }
  323. public set material(value: Nullable<Material>) {
  324. if (this._material === value) {
  325. return;
  326. }
  327. // remove from material mesh map id needed
  328. if (this._material && this._material.meshMap) {
  329. this._material.meshMap[this.uniqueId] = undefined;
  330. }
  331. this._material = value;
  332. if (value && value.meshMap) {
  333. value.meshMap[this.uniqueId] = this;
  334. }
  335. if (this.onMaterialChangedObservable.hasObservers()) {
  336. this.onMaterialChangedObservable.notifyObservers(this);
  337. }
  338. if (!this.subMeshes) {
  339. return;
  340. }
  341. this._unBindEffect();
  342. }
  343. /**
  344. * Gets or sets a boolean indicating that this mesh can receive realtime shadows
  345. * @see https://doc.babylonjs.com/babylon101/shadows
  346. */
  347. public get receiveShadows(): boolean {
  348. return this._internalAbstractMeshDataInfo._receiveShadows;
  349. }
  350. public set receiveShadows(value: boolean) {
  351. if (this._internalAbstractMeshDataInfo._receiveShadows === value) {
  352. return;
  353. }
  354. this._internalAbstractMeshDataInfo._receiveShadows = value;
  355. this._markSubMeshesAsLightDirty();
  356. }
  357. /** Defines color to use when rendering outline */
  358. public outlineColor = Color3.Red();
  359. /** Define width to use when rendering outline */
  360. public outlineWidth = 0.02;
  361. /** Defines color to use when rendering overlay */
  362. public overlayColor = Color3.Red();
  363. /** Defines alpha to use when rendering overlay */
  364. public overlayAlpha = 0.5;
  365. /** Gets or sets a boolean indicating that this mesh contains vertex color data with alpha values */
  366. public get hasVertexAlpha(): boolean {
  367. return this._internalAbstractMeshDataInfo._hasVertexAlpha;
  368. }
  369. public set hasVertexAlpha(value: boolean) {
  370. if (this._internalAbstractMeshDataInfo._hasVertexAlpha === value) {
  371. return;
  372. }
  373. this._internalAbstractMeshDataInfo._hasVertexAlpha = value;
  374. this._markSubMeshesAsAttributesDirty();
  375. this._markSubMeshesAsMiscDirty();
  376. }
  377. /** Gets or sets a boolean indicating that this mesh needs to use vertex color data to render (if this kind of vertex data is available in the geometry) */
  378. public get useVertexColors(): boolean {
  379. return this._internalAbstractMeshDataInfo._useVertexColors;
  380. }
  381. public set useVertexColors(value: boolean) {
  382. if (this._internalAbstractMeshDataInfo._useVertexColors === value) {
  383. return;
  384. }
  385. this._internalAbstractMeshDataInfo._useVertexColors = value;
  386. this._markSubMeshesAsAttributesDirty();
  387. }
  388. /**
  389. * Gets or sets a boolean indicating that bone animations must be computed by the CPU (false by default)
  390. */
  391. public get computeBonesUsingShaders(): boolean {
  392. return this._internalAbstractMeshDataInfo._computeBonesUsingShaders;
  393. }
  394. public set computeBonesUsingShaders(value: boolean) {
  395. if (this._internalAbstractMeshDataInfo._computeBonesUsingShaders === value) {
  396. return;
  397. }
  398. this._internalAbstractMeshDataInfo._computeBonesUsingShaders = value;
  399. this._markSubMeshesAsAttributesDirty();
  400. }
  401. /** Gets or sets the number of allowed bone influences per vertex (4 by default) */
  402. public get numBoneInfluencers(): number {
  403. return this._internalAbstractMeshDataInfo._numBoneInfluencers;
  404. }
  405. public set numBoneInfluencers(value: number) {
  406. if (this._internalAbstractMeshDataInfo._numBoneInfluencers === value) {
  407. return;
  408. }
  409. this._internalAbstractMeshDataInfo._numBoneInfluencers = value;
  410. this._markSubMeshesAsAttributesDirty();
  411. }
  412. /** Gets or sets a boolean indicating that this mesh will allow fog to be rendered on it (true by default) */
  413. public get applyFog(): boolean {
  414. return this._internalAbstractMeshDataInfo._applyFog;
  415. }
  416. public set applyFog(value: boolean) {
  417. if (this._internalAbstractMeshDataInfo._applyFog === value) {
  418. return;
  419. }
  420. this._internalAbstractMeshDataInfo._applyFog = value;
  421. this._markSubMeshesAsMiscDirty();
  422. }
  423. /** Gets or sets a boolean indicating that internal octree (if available) can be used to boost submeshes selection (true by default) */
  424. public useOctreeForRenderingSelection = true;
  425. /** Gets or sets a boolean indicating that internal octree (if available) can be used to boost submeshes picking (true by default) */
  426. public useOctreeForPicking = true;
  427. /** Gets or sets a boolean indicating that internal octree (if available) can be used to boost submeshes collision (true by default) */
  428. public useOctreeForCollisions = true;
  429. /**
  430. * Gets or sets the current layer mask (default is 0x0FFFFFFF)
  431. * @see https://doc.babylonjs.com/how_to/layermasks_and_multi-cam_textures
  432. */
  433. public get layerMask(): number {
  434. return this._internalAbstractMeshDataInfo._layerMask;
  435. }
  436. public set layerMask(value: number) {
  437. if (value === this._internalAbstractMeshDataInfo._layerMask) {
  438. return;
  439. }
  440. this._internalAbstractMeshDataInfo._layerMask = value;
  441. this._resyncLightSources();
  442. }
  443. /**
  444. * True if the mesh must be rendered in any case (this will shortcut the frustum clipping phase)
  445. */
  446. public alwaysSelectAsActiveMesh = false;
  447. /**
  448. * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
  449. */
  450. public doNotSyncBoundingInfo = false;
  451. /**
  452. * Gets or sets the current action manager
  453. * @see https://doc.babylonjs.com/how_to/how_to_use_actions
  454. */
  455. public actionManager: Nullable<AbstractActionManager> = null;
  456. // Collisions
  457. private _meshCollisionData = new _MeshCollisionData();
  458. /**
  459. * Gets or sets the ellipsoid used to impersonate this mesh when using collision engine (default is (0.5, 1, 0.5))
  460. * @see https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity
  461. */
  462. public ellipsoid = new Vector3(0.5, 1, 0.5);
  463. /**
  464. * Gets or sets the ellipsoid offset used to impersonate this mesh when using collision engine (default is (0, 0, 0))
  465. * @see https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity
  466. */
  467. public ellipsoidOffset = new Vector3(0, 0, 0);
  468. /**
  469. * Gets or sets a collision mask used to mask collisions (default is -1).
  470. * A collision between A and B will happen if A.collisionGroup & b.collisionMask !== 0
  471. */
  472. public get collisionMask(): number {
  473. return this._meshCollisionData._collisionMask;
  474. }
  475. public set collisionMask(mask: number) {
  476. this._meshCollisionData._collisionMask = !isNaN(mask) ? mask : -1;
  477. }
  478. /**
  479. * Gets or sets the current collision group mask (-1 by default).
  480. * A collision between A and B will happen if A.collisionGroup & b.collisionMask !== 0
  481. */
  482. public get collisionGroup(): number {
  483. return this._meshCollisionData._collisionGroup;
  484. }
  485. public set collisionGroup(mask: number) {
  486. this._meshCollisionData._collisionGroup = !isNaN(mask) ? mask : -1;
  487. }
  488. /**
  489. * Gets or sets current surrounding meshes (null by default).
  490. *
  491. * By default collision detection is tested against every mesh in the scene.
  492. * It is possible to set surroundingMeshes to a defined list of meshes and then only these specified
  493. * meshes will be tested for the collision.
  494. *
  495. * Note: if set to an empty array no collision will happen when this mesh is moved.
  496. */
  497. public get surroundingMeshes(): Nullable<AbstractMesh[]> {
  498. return this._meshCollisionData._surroundingMeshes;
  499. }
  500. public set surroundingMeshes(meshes: Nullable<AbstractMesh[]>) {
  501. this._meshCollisionData._surroundingMeshes = meshes;
  502. }
  503. // Edges
  504. /**
  505. * Defines edge width used when edgesRenderer is enabled
  506. * @see https://www.babylonjs-playground.com/#10OJSG#13
  507. */
  508. public edgesWidth = 1;
  509. /**
  510. * Defines edge color used when edgesRenderer is enabled
  511. * @see https://www.babylonjs-playground.com/#10OJSG#13
  512. */
  513. public edgesColor = new Color4(1, 0, 0, 1);
  514. /** @hidden */
  515. public _edgesRenderer: Nullable<IEdgesRenderer> = null;
  516. /** @hidden */
  517. public _masterMesh: Nullable<AbstractMesh> = null;
  518. /** @hidden */
  519. public _boundingInfo: Nullable<BoundingInfo> = null;
  520. /** @hidden */
  521. public _renderId = 0;
  522. /**
  523. * Gets or sets the list of subMeshes
  524. * @see https://doc.babylonjs.com/how_to/multi_materials
  525. */
  526. public subMeshes: SubMesh[];
  527. /** @hidden */
  528. public _intersectionsInProgress = new Array<AbstractMesh>();
  529. /** @hidden */
  530. public _unIndexed = false;
  531. /** @hidden */
  532. public _lightSources = new Array<Light>();
  533. /** Gets the list of lights affecting that mesh */
  534. public get lightSources(): Light[] {
  535. return this._lightSources;
  536. }
  537. /** @hidden */
  538. public get _positions(): Nullable<Vector3[]> {
  539. return null;
  540. }
  541. // Loading properties
  542. /** @hidden */
  543. public _waitingData: {
  544. lods: Nullable<any>,
  545. actions: Nullable<any>
  546. freezeWorldMatrix: Nullable<boolean>
  547. } = {
  548. lods: null,
  549. actions: null,
  550. freezeWorldMatrix: null
  551. };
  552. /** @hidden */
  553. public _bonesTransformMatrices: Nullable<Float32Array> = null;
  554. /** @hidden */
  555. public _transformMatrixTexture: Nullable<RawTexture> = null;
  556. /**
  557. * Gets or sets a skeleton to apply skining transformations
  558. * @see https://doc.babylonjs.com/how_to/how_to_use_bones_and_skeletons
  559. */
  560. public set skeleton(value: Nullable<Skeleton>) {
  561. let skeleton = this._internalAbstractMeshDataInfo._skeleton;
  562. if (skeleton && skeleton.needInitialSkinMatrix) {
  563. skeleton._unregisterMeshWithPoseMatrix(this);
  564. }
  565. if (value && value.needInitialSkinMatrix) {
  566. value._registerMeshWithPoseMatrix(this);
  567. }
  568. this._internalAbstractMeshDataInfo._skeleton = value;
  569. if (!this._internalAbstractMeshDataInfo._skeleton) {
  570. this._bonesTransformMatrices = null;
  571. }
  572. this._markSubMeshesAsAttributesDirty();
  573. }
  574. public get skeleton(): Nullable<Skeleton> {
  575. return this._internalAbstractMeshDataInfo._skeleton;
  576. }
  577. /**
  578. * An event triggered when the mesh is rebuilt.
  579. */
  580. public onRebuildObservable = new Observable<AbstractMesh>();
  581. // Constructor
  582. /**
  583. * Creates a new AbstractMesh
  584. * @param name defines the name of the mesh
  585. * @param scene defines the hosting scene
  586. */
  587. constructor(name: string, scene: Nullable<Scene> = null) {
  588. super(name, scene, false);
  589. this.getScene().addMesh(this);
  590. this._resyncLightSources();
  591. }
  592. /**
  593. * Returns the string "AbstractMesh"
  594. * @returns "AbstractMesh"
  595. */
  596. public getClassName(): string {
  597. return "AbstractMesh";
  598. }
  599. /**
  600. * Gets a string representation of the current mesh
  601. * @param fullDetails defines a boolean indicating if full details must be included
  602. * @returns a string representation of the current mesh
  603. */
  604. public toString(fullDetails?: boolean): string {
  605. var ret = "Name: " + this.name + ", isInstance: " + (this.getClassName() !== "InstancedMesh" ? "YES" : "NO");
  606. ret += ", # of submeshes: " + (this.subMeshes ? this.subMeshes.length : 0);
  607. let skeleton = this._internalAbstractMeshDataInfo._skeleton;
  608. if (skeleton) {
  609. ret += ", skeleton: " + skeleton.name;
  610. }
  611. if (fullDetails) {
  612. ret += ", billboard mode: " + (["NONE", "X", "Y", null, "Z", null, null, "ALL"])[this.billboardMode];
  613. ret += ", freeze wrld mat: " + (this._isWorldMatrixFrozen || this._waitingData.freezeWorldMatrix ? "YES" : "NO");
  614. }
  615. return ret;
  616. }
  617. /**
  618. * @hidden
  619. */
  620. protected _getEffectiveParent(): Nullable<Node> {
  621. if (this._masterMesh && this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
  622. return this._masterMesh;
  623. }
  624. return super._getEffectiveParent();
  625. }
  626. /** @hidden */
  627. public _getActionManagerForTrigger(trigger?: number, initialCall = true): Nullable<AbstractActionManager> {
  628. if (this.actionManager && (initialCall || this.actionManager.isRecursive)) {
  629. if (trigger) {
  630. if (this.actionManager.hasSpecificTrigger(trigger)) {
  631. return this.actionManager;
  632. }
  633. }
  634. else {
  635. return this.actionManager;
  636. }
  637. }
  638. if (!this.parent) {
  639. return null;
  640. }
  641. return this.parent._getActionManagerForTrigger(trigger, false);
  642. }
  643. /** @hidden */
  644. public _rebuild(): void {
  645. this.onRebuildObservable.notifyObservers(this);
  646. if (this._occlusionQuery) {
  647. this._occlusionQuery = null;
  648. }
  649. if (!this.subMeshes) {
  650. return;
  651. }
  652. for (var subMesh of this.subMeshes) {
  653. subMesh._rebuild();
  654. }
  655. }
  656. /** @hidden */
  657. public _resyncLightSources(): void {
  658. this._lightSources.length = 0;
  659. for (var light of this.getScene().lights) {
  660. if (!light.isEnabled()) {
  661. continue;
  662. }
  663. if (light.canAffectMesh(this)) {
  664. this._lightSources.push(light);
  665. }
  666. }
  667. this._markSubMeshesAsLightDirty();
  668. }
  669. /** @hidden */
  670. public _resyncLightSource(light: Light): void {
  671. var isIn = light.isEnabled() && light.canAffectMesh(this);
  672. var index = this._lightSources.indexOf(light);
  673. var removed = false;
  674. if (index === -1) {
  675. if (!isIn) {
  676. return;
  677. }
  678. this._lightSources.push(light);
  679. } else {
  680. if (isIn) {
  681. return;
  682. }
  683. removed = true;
  684. this._lightSources.splice(index, 1);
  685. }
  686. this._markSubMeshesAsLightDirty(removed);
  687. }
  688. /** @hidden */
  689. public _unBindEffect() {
  690. for (var subMesh of this.subMeshes) {
  691. subMesh.setEffect(null);
  692. }
  693. }
  694. /** @hidden */
  695. public _removeLightSource(light: Light, dispose: boolean): void {
  696. var index = this._lightSources.indexOf(light);
  697. if (index === -1) {
  698. return;
  699. }
  700. this._lightSources.splice(index, 1);
  701. this._markSubMeshesAsLightDirty(dispose);
  702. }
  703. private _markSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
  704. if (!this.subMeshes) {
  705. return;
  706. }
  707. for (var subMesh of this.subMeshes) {
  708. if (subMesh._materialDefines) {
  709. func(subMesh._materialDefines);
  710. }
  711. }
  712. }
  713. /** @hidden */
  714. public _markSubMeshesAsLightDirty(dispose: boolean = false) {
  715. this._markSubMeshesAsDirty((defines) => defines.markAsLightDirty(dispose));
  716. }
  717. /** @hidden */
  718. public _markSubMeshesAsAttributesDirty() {
  719. this._markSubMeshesAsDirty((defines) => defines.markAsAttributesDirty());
  720. }
  721. /** @hidden */
  722. public _markSubMeshesAsMiscDirty() {
  723. this._markSubMeshesAsDirty((defines) => defines.markAsMiscDirty());
  724. }
  725. /**
  726. * Gets or sets a Vector3 depicting the mesh scaling along each local axis X, Y, Z. Default is (1.0, 1.0, 1.0)
  727. */
  728. public get scaling(): Vector3 {
  729. return this._scaling;
  730. }
  731. public set scaling(newScaling: Vector3) {
  732. this._scaling = newScaling;
  733. }
  734. // Methods
  735. /**
  736. * Returns true if the mesh is blocked. Implemented by child classes
  737. */
  738. public get isBlocked(): boolean {
  739. return false;
  740. }
  741. /**
  742. * Returns the mesh itself by default. Implemented by child classes
  743. * @param camera defines the camera to use to pick the right LOD level
  744. * @returns the currentAbstractMesh
  745. */
  746. public getLOD(camera: Camera): Nullable<AbstractMesh> {
  747. return this;
  748. }
  749. /**
  750. * Returns 0 by default. Implemented by child classes
  751. * @returns an integer
  752. */
  753. public getTotalVertices(): number {
  754. return 0;
  755. }
  756. /**
  757. * Returns a positive integer : the total number of indices in this mesh geometry.
  758. * @returns the numner of indices or zero if the mesh has no geometry.
  759. */
  760. public getTotalIndices(): number {
  761. return 0;
  762. }
  763. /**
  764. * Returns null by default. Implemented by child classes
  765. * @returns null
  766. */
  767. public getIndices(): Nullable<IndicesArray> {
  768. return null;
  769. }
  770. /**
  771. * Returns the array of the requested vertex data kind. Implemented by child classes
  772. * @param kind defines the vertex data kind to use
  773. * @returns null
  774. */
  775. public getVerticesData(kind: string): Nullable<FloatArray> {
  776. return null;
  777. }
  778. /**
  779. * Sets the vertex data of the mesh geometry for the requested `kind`.
  780. * If the mesh has no geometry, a new Geometry object is set to the mesh and then passed this vertex data.
  781. * Note that a new underlying VertexBuffer object is created each call.
  782. * If the `kind` is the `PositionKind`, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  783. * @param kind defines vertex data kind:
  784. * * VertexBuffer.PositionKind
  785. * * VertexBuffer.UVKind
  786. * * VertexBuffer.UV2Kind
  787. * * VertexBuffer.UV3Kind
  788. * * VertexBuffer.UV4Kind
  789. * * VertexBuffer.UV5Kind
  790. * * VertexBuffer.UV6Kind
  791. * * VertexBuffer.ColorKind
  792. * * VertexBuffer.MatricesIndicesKind
  793. * * VertexBuffer.MatricesIndicesExtraKind
  794. * * VertexBuffer.MatricesWeightsKind
  795. * * VertexBuffer.MatricesWeightsExtraKind
  796. * @param data defines the data source
  797. * @param updatable defines if the data must be flagged as updatable (or static)
  798. * @param stride defines the vertex stride (size of an entire vertex). Can be null and in this case will be deduced from vertex data kind
  799. * @returns the current mesh
  800. */
  801. public setVerticesData(kind: string, data: FloatArray, updatable?: boolean, stride?: number): AbstractMesh {
  802. return this;
  803. }
  804. /**
  805. * Updates the existing vertex data of the mesh geometry for the requested `kind`.
  806. * If the mesh has no geometry, it is simply returned as it is.
  807. * @param kind defines vertex data kind:
  808. * * VertexBuffer.PositionKind
  809. * * VertexBuffer.UVKind
  810. * * VertexBuffer.UV2Kind
  811. * * VertexBuffer.UV3Kind
  812. * * VertexBuffer.UV4Kind
  813. * * VertexBuffer.UV5Kind
  814. * * VertexBuffer.UV6Kind
  815. * * VertexBuffer.ColorKind
  816. * * VertexBuffer.MatricesIndicesKind
  817. * * VertexBuffer.MatricesIndicesExtraKind
  818. * * VertexBuffer.MatricesWeightsKind
  819. * * VertexBuffer.MatricesWeightsExtraKind
  820. * @param data defines the data source
  821. * @param updateExtends If `kind` is `PositionKind` and if `updateExtends` is true, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed
  822. * @param makeItUnique If true, a new global geometry is created from this data and is set to the mesh
  823. * @returns the current mesh
  824. */
  825. public updateVerticesData(kind: string, data: FloatArray, updateExtends?: boolean, makeItUnique?: boolean): AbstractMesh {
  826. return this;
  827. }
  828. /**
  829. * Sets the mesh indices,
  830. * If the mesh has no geometry, a new Geometry object is created and set to the mesh.
  831. * @param indices Expects an array populated with integers or a typed array (Int32Array, Uint32Array, Uint16Array)
  832. * @param totalVertices Defines the total number of vertices
  833. * @returns the current mesh
  834. */
  835. public setIndices(indices: IndicesArray, totalVertices: Nullable<number>): AbstractMesh {
  836. return this;
  837. }
  838. /**
  839. * Gets a boolean indicating if specific vertex data is present
  840. * @param kind defines the vertex data kind to use
  841. * @returns true is data kind is present
  842. */
  843. public isVerticesDataPresent(kind: string): boolean {
  844. return false;
  845. }
  846. /**
  847. * Returns the mesh BoundingInfo object or creates a new one and returns if it was undefined.
  848. * Note that it returns a shallow bounding of the mesh (i.e. it does not include children).
  849. * To get the full bounding of all children, call `getHierarchyBoundingVectors` instead.
  850. * @returns a BoundingInfo
  851. */
  852. public getBoundingInfo(): BoundingInfo {
  853. if (this._masterMesh) {
  854. return this._masterMesh.getBoundingInfo();
  855. }
  856. if (!this._boundingInfo) {
  857. // this._boundingInfo is being created here
  858. this._updateBoundingInfo();
  859. }
  860. // cannot be null.
  861. return this._boundingInfo!;
  862. }
  863. /**
  864. * Uniformly scales the mesh to fit inside of a unit cube (1 X 1 X 1 units)
  865. * @param includeDescendants Use the hierarchy's bounding box instead of the mesh's bounding box. Default is false
  866. * @param ignoreRotation ignore rotation when computing the scale (ie. object will be axis aligned). Default is false
  867. * @param predicate predicate that is passed in to getHierarchyBoundingVectors when selecting which object should be included when scaling
  868. * @returns the current mesh
  869. */
  870. public normalizeToUnitCube(includeDescendants = true, ignoreRotation = false, predicate?: Nullable<(node: AbstractMesh) => boolean>): AbstractMesh {
  871. return <AbstractMesh>super.normalizeToUnitCube(includeDescendants, ignoreRotation, predicate);
  872. }
  873. /**
  874. * Overwrite the current bounding info
  875. * @param boundingInfo defines the new bounding info
  876. * @returns the current mesh
  877. */
  878. public setBoundingInfo(boundingInfo: BoundingInfo): AbstractMesh {
  879. this._boundingInfo = boundingInfo;
  880. return this;
  881. }
  882. /** Gets a boolean indicating if this mesh has skinning data and an attached skeleton */
  883. public get useBones(): boolean {
  884. return (<boolean>(this.skeleton && this.getScene().skeletonsEnabled && this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)));
  885. }
  886. /** @hidden */
  887. public _preActivate(): void {
  888. }
  889. /** @hidden */
  890. public _preActivateForIntermediateRendering(renderId: number): void {
  891. }
  892. /** @hidden */
  893. public _activate(renderId: number, intermediateRendering: boolean): boolean {
  894. this._renderId = renderId;
  895. return true;
  896. }
  897. /** @hidden */
  898. public _postActivate(): void {
  899. // Do nothing
  900. }
  901. /** @hidden */
  902. public _freeze() {
  903. // Do nothing
  904. }
  905. /** @hidden */
  906. public _unFreeze() {
  907. // Do nothing
  908. }
  909. /**
  910. * Gets the current world matrix
  911. * @returns a Matrix
  912. */
  913. public getWorldMatrix(): Matrix {
  914. if (this._masterMesh && this.billboardMode === TransformNode.BILLBOARDMODE_NONE) {
  915. return this._masterMesh.getWorldMatrix();
  916. }
  917. return super.getWorldMatrix();
  918. }
  919. /** @hidden */
  920. public _getWorldMatrixDeterminant(): number {
  921. if (this._masterMesh) {
  922. return this._masterMesh._getWorldMatrixDeterminant();
  923. }
  924. return super._getWorldMatrixDeterminant();
  925. }
  926. /**
  927. * Gets a boolean indicating if this mesh is an instance or a regular mesh
  928. */
  929. public get isAnInstance(): boolean {
  930. return false;
  931. }
  932. /**
  933. * Gets a boolean indicating if this mesh has instances
  934. */
  935. public get hasInstances(): boolean {
  936. return false;
  937. }
  938. /**
  939. * Gets a boolean indicating if this mesh has thin instances
  940. */
  941. public get hasThinInstances(): boolean {
  942. return false;
  943. }
  944. // ================================== Point of View Movement =================================
  945. /**
  946. * Perform relative position change from the point of view of behind the front of the mesh.
  947. * This is performed taking into account the meshes current rotation, so you do not have to care.
  948. * Supports definition of mesh facing forward or backward
  949. * @param amountRight defines the distance on the right axis
  950. * @param amountUp defines the distance on the up axis
  951. * @param amountForward defines the distance on the forward axis
  952. * @returns the current mesh
  953. */
  954. public movePOV(amountRight: number, amountUp: number, amountForward: number): AbstractMesh {
  955. this.position.addInPlace(this.calcMovePOV(amountRight, amountUp, amountForward));
  956. return this;
  957. }
  958. /**
  959. * Calculate relative position change from the point of view of behind the front of the mesh.
  960. * This is performed taking into account the meshes current rotation, so you do not have to care.
  961. * Supports definition of mesh facing forward or backward
  962. * @param amountRight defines the distance on the right axis
  963. * @param amountUp defines the distance on the up axis
  964. * @param amountForward defines the distance on the forward axis
  965. * @returns the new displacement vector
  966. */
  967. public calcMovePOV(amountRight: number, amountUp: number, amountForward: number): Vector3 {
  968. var rotMatrix = new Matrix();
  969. var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  970. rotQuaternion.toRotationMatrix(rotMatrix);
  971. var translationDelta = Vector3.Zero();
  972. var defForwardMult = this.definedFacingForward ? -1 : 1;
  973. Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
  974. return translationDelta;
  975. }
  976. // ================================== Point of View Rotation =================================
  977. /**
  978. * Perform relative rotation change from the point of view of behind the front of the mesh.
  979. * Supports definition of mesh facing forward or backward
  980. * @param flipBack defines the flip
  981. * @param twirlClockwise defines the twirl
  982. * @param tiltRight defines the tilt
  983. * @returns the current mesh
  984. */
  985. public rotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): AbstractMesh {
  986. this.rotation.addInPlace(this.calcRotatePOV(flipBack, twirlClockwise, tiltRight));
  987. return this;
  988. }
  989. /**
  990. * Calculate relative rotation change from the point of view of behind the front of the mesh.
  991. * Supports definition of mesh facing forward or backward.
  992. * @param flipBack defines the flip
  993. * @param twirlClockwise defines the twirl
  994. * @param tiltRight defines the tilt
  995. * @returns the new rotation vector
  996. */
  997. public calcRotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): Vector3 {
  998. var defForwardMult = this.definedFacingForward ? 1 : -1;
  999. return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
  1000. }
  1001. /**
  1002. * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
  1003. * This means the mesh underlying bounding box and sphere are recomputed.
  1004. * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
  1005. * @returns the current mesh
  1006. */
  1007. public refreshBoundingInfo(applySkeleton: boolean = false): AbstractMesh {
  1008. if (this._boundingInfo && this._boundingInfo.isLocked) {
  1009. return this;
  1010. }
  1011. this._refreshBoundingInfo(this._getPositionData(applySkeleton), null);
  1012. return this;
  1013. }
  1014. /** @hidden */
  1015. public _refreshBoundingInfo(data: Nullable<FloatArray>, bias: Nullable<Vector2>): void {
  1016. if (data) {
  1017. var extend = extractMinAndMax(data, 0, this.getTotalVertices(), bias);
  1018. if (this._boundingInfo) {
  1019. this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
  1020. }
  1021. else {
  1022. this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
  1023. }
  1024. }
  1025. if (this.subMeshes) {
  1026. for (var index = 0; index < this.subMeshes.length; index++) {
  1027. this.subMeshes[index].refreshBoundingInfo(data);
  1028. }
  1029. }
  1030. this._updateBoundingInfo();
  1031. }
  1032. /** @hidden */
  1033. public _getPositionData(applySkeleton: boolean): Nullable<FloatArray> {
  1034. var data = this.getVerticesData(VertexBuffer.PositionKind);
  1035. if (data && applySkeleton && this.skeleton) {
  1036. data = Tools.Slice(data);
  1037. this._generatePointsArray();
  1038. var matricesIndicesData = this.getVerticesData(VertexBuffer.MatricesIndicesKind);
  1039. var matricesWeightsData = this.getVerticesData(VertexBuffer.MatricesWeightsKind);
  1040. if (matricesWeightsData && matricesIndicesData) {
  1041. var needExtras = this.numBoneInfluencers > 4;
  1042. var matricesIndicesExtraData = needExtras ? this.getVerticesData(VertexBuffer.MatricesIndicesExtraKind) : null;
  1043. var matricesWeightsExtraData = needExtras ? this.getVerticesData(VertexBuffer.MatricesWeightsExtraKind) : null;
  1044. this.skeleton.prepare();
  1045. var skeletonMatrices = this.skeleton.getTransformMatrices(this);
  1046. var tempVector = TmpVectors.Vector3[0];
  1047. var finalMatrix = TmpVectors.Matrix[0];
  1048. var tempMatrix = TmpVectors.Matrix[1];
  1049. var matWeightIdx = 0;
  1050. for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
  1051. finalMatrix.reset();
  1052. var inf: number;
  1053. var weight: number;
  1054. for (inf = 0; inf < 4; inf++) {
  1055. weight = matricesWeightsData[matWeightIdx + inf];
  1056. if (weight > 0) {
  1057. Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
  1058. finalMatrix.addToSelf(tempMatrix);
  1059. }
  1060. }
  1061. if (needExtras) {
  1062. for (inf = 0; inf < 4; inf++) {
  1063. weight = matricesWeightsExtraData![matWeightIdx + inf];
  1064. if (weight > 0) {
  1065. Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData![matWeightIdx + inf] * 16), weight, tempMatrix);
  1066. finalMatrix.addToSelf(tempMatrix);
  1067. }
  1068. }
  1069. }
  1070. Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
  1071. tempVector.toArray(data, index);
  1072. if (this._positions) {
  1073. this._positions[index / 3].copyFrom(tempVector);
  1074. }
  1075. }
  1076. }
  1077. }
  1078. return data;
  1079. }
  1080. /** @hidden */
  1081. public _updateBoundingInfo(): AbstractMesh {
  1082. const effectiveMesh = this._effectiveMesh;
  1083. if (this._boundingInfo) {
  1084. this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
  1085. }
  1086. else {
  1087. this._boundingInfo = new BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
  1088. }
  1089. this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
  1090. return this;
  1091. }
  1092. /** @hidden */
  1093. public _updateSubMeshesBoundingInfo(matrix: DeepImmutable<Matrix>): AbstractMesh {
  1094. if (!this.subMeshes) {
  1095. return this;
  1096. }
  1097. let count = this.subMeshes.length;
  1098. for (var subIndex = 0; subIndex < count; subIndex++) {
  1099. var subMesh = this.subMeshes[subIndex];
  1100. if (count > 1 || !subMesh.IsGlobal) {
  1101. subMesh.updateBoundingInfo(matrix);
  1102. }
  1103. }
  1104. return this;
  1105. }
  1106. /** @hidden */
  1107. protected _afterComputeWorldMatrix(): void {
  1108. if (this.doNotSyncBoundingInfo) {
  1109. return;
  1110. }
  1111. // Bounding info
  1112. this._updateBoundingInfo();
  1113. }
  1114. /** @hidden */
  1115. public get _effectiveMesh(): AbstractMesh {
  1116. return (this.skeleton && this.skeleton.overrideMesh) || this;
  1117. }
  1118. /**
  1119. * Returns `true` if the mesh is within the frustum defined by the passed array of planes.
  1120. * A mesh is in the frustum if its bounding box intersects the frustum
  1121. * @param frustumPlanes defines the frustum to test
  1122. * @returns true if the mesh is in the frustum planes
  1123. */
  1124. public isInFrustum(frustumPlanes: Plane[]): boolean {
  1125. return this._boundingInfo !== null && this._boundingInfo.isInFrustum(frustumPlanes, this.cullingStrategy);
  1126. }
  1127. /**
  1128. * Returns `true` if the mesh is completely in the frustum defined be the passed array of planes.
  1129. * A mesh is completely in the frustum if its bounding box it completely inside the frustum.
  1130. * @param frustumPlanes defines the frustum to test
  1131. * @returns true if the mesh is completely in the frustum planes
  1132. */
  1133. public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
  1134. return this._boundingInfo !== null && this._boundingInfo.isCompletelyInFrustum(frustumPlanes);
  1135. }
  1136. /**
  1137. * True if the mesh intersects another mesh or a SolidParticle object
  1138. * @param mesh defines a target mesh or SolidParticle to test
  1139. * @param precise Unless the parameter `precise` is set to `true` the intersection is computed according to Axis Aligned Bounding Boxes (AABB), else according to OBB (Oriented BBoxes)
  1140. * @param includeDescendants Can be set to true to test if the mesh defined in parameters intersects with the current mesh or any child meshes
  1141. * @returns true if there is an intersection
  1142. */
  1143. public intersectsMesh(mesh: AbstractMesh | SolidParticle, precise: boolean = false, includeDescendants?: boolean): boolean {
  1144. if (!this._boundingInfo || !mesh._boundingInfo) {
  1145. return false;
  1146. }
  1147. if (this._boundingInfo.intersects(mesh._boundingInfo, precise)) {
  1148. return true;
  1149. }
  1150. if (includeDescendants) {
  1151. for (var child of this.getChildMeshes()) {
  1152. if (child.intersectsMesh(mesh, precise, true)) {
  1153. return true;
  1154. }
  1155. }
  1156. }
  1157. return false;
  1158. }
  1159. /**
  1160. * Returns true if the passed point (Vector3) is inside the mesh bounding box
  1161. * @param point defines the point to test
  1162. * @returns true if there is an intersection
  1163. */
  1164. public intersectsPoint(point: Vector3): boolean {
  1165. if (!this._boundingInfo) {
  1166. return false;
  1167. }
  1168. return this._boundingInfo.intersectsPoint(point);
  1169. }
  1170. // Collisions
  1171. /**
  1172. * Gets or sets a boolean indicating that this mesh can be used in the collision engine
  1173. * @see https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity
  1174. */
  1175. public get checkCollisions(): boolean {
  1176. return this._meshCollisionData._checkCollisions;
  1177. }
  1178. public set checkCollisions(collisionEnabled: boolean) {
  1179. this._meshCollisionData._checkCollisions = collisionEnabled;
  1180. }
  1181. /**
  1182. * Gets Collider object used to compute collisions (not physics)
  1183. * @see https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity
  1184. */
  1185. public get collider(): Nullable<Collider> {
  1186. return this._meshCollisionData._collider;
  1187. }
  1188. /**
  1189. * Move the mesh using collision engine
  1190. * @see https://doc.babylonjs.com/babylon101/cameras,_mesh_collisions_and_gravity
  1191. * @param displacement defines the requested displacement vector
  1192. * @returns the current mesh
  1193. */
  1194. public moveWithCollisions(displacement: Vector3): AbstractMesh {
  1195. var globalPosition = this.getAbsolutePosition();
  1196. globalPosition.addToRef(this.ellipsoidOffset, this._meshCollisionData._oldPositionForCollisions);
  1197. let coordinator = this.getScene().collisionCoordinator;
  1198. if (!this._meshCollisionData._collider) {
  1199. this._meshCollisionData._collider = coordinator.createCollider();
  1200. }
  1201. this._meshCollisionData._collider._radius = this.ellipsoid;
  1202. coordinator.getNewPosition(this._meshCollisionData._oldPositionForCollisions, displacement, this._meshCollisionData._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
  1203. return this;
  1204. }
  1205. private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
  1206. newPosition.subtractToRef(this._meshCollisionData._oldPositionForCollisions, this._meshCollisionData._diffPositionForCollisions);
  1207. if (this._meshCollisionData._diffPositionForCollisions.length() > Engine.CollisionsEpsilon) {
  1208. this.position.addInPlace(this._meshCollisionData._diffPositionForCollisions);
  1209. }
  1210. if (collidedMesh) {
  1211. this.onCollideObservable.notifyObservers(collidedMesh);
  1212. }
  1213. this.onCollisionPositionChangeObservable.notifyObservers(this.position);
  1214. }
  1215. // Collisions
  1216. /** @hidden */
  1217. public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): AbstractMesh {
  1218. this._generatePointsArray();
  1219. if (!this._positions) {
  1220. return this;
  1221. }
  1222. // Transformation
  1223. if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix!.equals(transformMatrix)) {
  1224. subMesh._lastColliderTransformMatrix = transformMatrix.clone();
  1225. subMesh._lastColliderWorldVertices = [];
  1226. subMesh._trianglePlanes = [];
  1227. var start = subMesh.verticesStart;
  1228. var end = (subMesh.verticesStart + subMesh.verticesCount);
  1229. for (var i = start; i < end; i++) {
  1230. subMesh._lastColliderWorldVertices.push(Vector3.TransformCoordinates(this._positions[i], transformMatrix));
  1231. }
  1232. }
  1233. // Collide
  1234. collider._collide(subMesh._trianglePlanes, subMesh._lastColliderWorldVertices, (<IndicesArray>this.getIndices()), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, !!subMesh.getMaterial(), this);
  1235. return this;
  1236. }
  1237. /** @hidden */
  1238. public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): AbstractMesh {
  1239. const subMeshes = this._scene.getCollidingSubMeshCandidates(this, collider);
  1240. const len = subMeshes.length;
  1241. for (var index = 0; index < len; index++) {
  1242. var subMesh = subMeshes.data[index];
  1243. // Bounding test
  1244. if (len > 1 && !subMesh._checkCollision(collider)) {
  1245. continue;
  1246. }
  1247. this._collideForSubMesh(subMesh, transformMatrix, collider);
  1248. }
  1249. return this;
  1250. }
  1251. /** @hidden */
  1252. public _checkCollision(collider: Collider): AbstractMesh {
  1253. // Bounding box test
  1254. if (!this._boundingInfo || !this._boundingInfo._checkCollision(collider)) {
  1255. return this;
  1256. }
  1257. // Transformation matrix
  1258. const collisionsScalingMatrix = TmpVectors.Matrix[0];
  1259. const collisionsTransformMatrix = TmpVectors.Matrix[1];
  1260. Matrix.ScalingToRef(1.0 / collider._radius.x, 1.0 / collider._radius.y, 1.0 / collider._radius.z, collisionsScalingMatrix);
  1261. this.worldMatrixFromCache.multiplyToRef(collisionsScalingMatrix, collisionsTransformMatrix);
  1262. this._processCollisionsForSubMeshes(collider, collisionsTransformMatrix);
  1263. return this;
  1264. }
  1265. // Picking
  1266. /** @hidden */
  1267. public _generatePointsArray(): boolean {
  1268. return false;
  1269. }
  1270. /**
  1271. * Checks if the passed Ray intersects with the mesh
  1272. * @param ray defines the ray to use
  1273. * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
  1274. * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
  1275. * @param onlyBoundingInfo defines a boolean indicating if picking should only happen using bounding info (false by default)
  1276. * @returns the picking info
  1277. * @see https://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
  1278. */
  1279. public intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate, onlyBoundingInfo = false): PickingInfo {
  1280. var pickingInfo = new PickingInfo();
  1281. const intersectionThreshold = this.getClassName() === "InstancedLinesMesh" || this.getClassName() === "LinesMesh" ? (this as any).intersectionThreshold : 0;
  1282. const boundingInfo = this._boundingInfo;
  1283. if (!this.subMeshes || !boundingInfo || !ray.intersectsSphere(boundingInfo.boundingSphere, intersectionThreshold) || !ray.intersectsBox(boundingInfo.boundingBox, intersectionThreshold)) {
  1284. return pickingInfo;
  1285. }
  1286. if (onlyBoundingInfo) {
  1287. pickingInfo.hit = true;
  1288. pickingInfo.pickedMesh = this;
  1289. pickingInfo.distance = Vector3.Distance(ray.origin, boundingInfo.boundingSphere.center);
  1290. pickingInfo.subMeshId = 0;
  1291. return pickingInfo;
  1292. }
  1293. if (!this._generatePointsArray()) {
  1294. return pickingInfo;
  1295. }
  1296. var intersectInfo: Nullable<IntersectionInfo> = null;
  1297. var subMeshes = this._scene.getIntersectingSubMeshCandidates(this, ray);
  1298. var len: number = subMeshes.length;
  1299. for (var index = 0; index < len; index++) {
  1300. var subMesh = subMeshes.data[index];
  1301. // Bounding test
  1302. if (len > 1 && !subMesh.canIntersects(ray)) {
  1303. continue;
  1304. }
  1305. var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions),
  1306. (<IndicesArray>this.getIndices()), fastCheck,
  1307. trianglePredicate);
  1308. if (currentIntersectInfo) {
  1309. if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
  1310. intersectInfo = currentIntersectInfo;
  1311. intersectInfo.subMeshId = index;
  1312. if (fastCheck) {
  1313. break;
  1314. }
  1315. }
  1316. }
  1317. }
  1318. if (intersectInfo) {
  1319. // Get picked point
  1320. const world = this.skeleton && this.skeleton.overrideMesh ? this.skeleton.overrideMesh.getWorldMatrix() : this.getWorldMatrix();
  1321. const worldOrigin = TmpVectors.Vector3[0];
  1322. const direction = TmpVectors.Vector3[1];
  1323. Vector3.TransformCoordinatesToRef(ray.origin, world, worldOrigin);
  1324. ray.direction.scaleToRef(intersectInfo.distance, direction);
  1325. const worldDirection = Vector3.TransformNormal(direction, world);
  1326. const pickedPoint = worldDirection.addInPlace(worldOrigin);
  1327. // Return result
  1328. pickingInfo.hit = true;
  1329. pickingInfo.distance = Vector3.Distance(worldOrigin, pickedPoint);
  1330. pickingInfo.pickedPoint = pickedPoint;
  1331. pickingInfo.pickedMesh = this;
  1332. pickingInfo.bu = intersectInfo.bu || 0;
  1333. pickingInfo.bv = intersectInfo.bv || 0;
  1334. pickingInfo.subMeshFaceId = intersectInfo.faceId;
  1335. pickingInfo.faceId = intersectInfo.faceId + subMeshes.data[intersectInfo.subMeshId].indexStart / (this.getClassName().indexOf("LinesMesh") !== -1 ? 2 : 3);
  1336. pickingInfo.subMeshId = intersectInfo.subMeshId;
  1337. return pickingInfo;
  1338. }
  1339. return pickingInfo;
  1340. }
  1341. /**
  1342. * Clones the current mesh
  1343. * @param name defines the mesh name
  1344. * @param newParent defines the new mesh parent
  1345. * @param doNotCloneChildren defines a boolean indicating that children must not be cloned (false by default)
  1346. * @returns the new mesh
  1347. */
  1348. public clone(name: string, newParent: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh> {
  1349. return null;
  1350. }
  1351. /**
  1352. * Disposes all the submeshes of the current meshnp
  1353. * @returns the current mesh
  1354. */
  1355. public releaseSubMeshes(): AbstractMesh {
  1356. if (this.subMeshes) {
  1357. while (this.subMeshes.length) {
  1358. this.subMeshes[0].dispose();
  1359. }
  1360. } else {
  1361. this.subMeshes = new Array<SubMesh>();
  1362. }
  1363. return this;
  1364. }
  1365. /**
  1366. * Releases resources associated with this abstract mesh.
  1367. * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
  1368. * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
  1369. */
  1370. public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
  1371. var index: number;
  1372. // mesh map release.
  1373. if (this._scene.useMaterialMeshMap) {
  1374. // remove from material mesh map id needed
  1375. if (this._material && this._material.meshMap) {
  1376. this._material.meshMap[this.uniqueId] = undefined;
  1377. }
  1378. }
  1379. // Smart Array Retainers.
  1380. this.getScene().freeActiveMeshes();
  1381. this.getScene().freeRenderingGroups();
  1382. // Action manager
  1383. if (this.actionManager !== undefined && this.actionManager !== null) {
  1384. this.actionManager.dispose();
  1385. this.actionManager = null;
  1386. }
  1387. // Skeleton
  1388. this._internalAbstractMeshDataInfo._skeleton = null;
  1389. if (this._transformMatrixTexture) {
  1390. this._transformMatrixTexture.dispose();
  1391. this._transformMatrixTexture = null;
  1392. }
  1393. // Intersections in progress
  1394. for (index = 0; index < this._intersectionsInProgress.length; index++) {
  1395. var other = this._intersectionsInProgress[index];
  1396. var pos = other._intersectionsInProgress.indexOf(this);
  1397. other._intersectionsInProgress.splice(pos, 1);
  1398. }
  1399. this._intersectionsInProgress = [];
  1400. // Lights
  1401. var lights = this.getScene().lights;
  1402. lights.forEach((light: Light) => {
  1403. var meshIndex = light.includedOnlyMeshes.indexOf(this);
  1404. if (meshIndex !== -1) {
  1405. light.includedOnlyMeshes.splice(meshIndex, 1);
  1406. }
  1407. meshIndex = light.excludedMeshes.indexOf(this);
  1408. if (meshIndex !== -1) {
  1409. light.excludedMeshes.splice(meshIndex, 1);
  1410. }
  1411. // Shadow generators
  1412. var generator = light.getShadowGenerator();
  1413. if (generator) {
  1414. var shadowMap = generator.getShadowMap();
  1415. if (shadowMap && shadowMap.renderList) {
  1416. meshIndex = shadowMap.renderList.indexOf(this);
  1417. if (meshIndex !== -1) {
  1418. shadowMap.renderList.splice(meshIndex, 1);
  1419. }
  1420. }
  1421. }
  1422. });
  1423. // SubMeshes
  1424. if (this.getClassName() !== "InstancedMesh" || this.getClassName() !== "InstancedLinesMesh") {
  1425. this.releaseSubMeshes();
  1426. }
  1427. // Query
  1428. let engine = this.getScene().getEngine();
  1429. if (this._occlusionQuery) {
  1430. this.isOcclusionQueryInProgress = false;
  1431. engine.deleteQuery(this._occlusionQuery);
  1432. this._occlusionQuery = null;
  1433. }
  1434. // Engine
  1435. engine.wipeCaches();
  1436. // Remove from scene
  1437. this.getScene().removeMesh(this);
  1438. if (disposeMaterialAndTextures) {
  1439. if (this.material) {
  1440. if (this.material.getClassName() === "MultiMaterial") {
  1441. this.material.dispose(false, true, true);
  1442. } else {
  1443. this.material.dispose(false, true);
  1444. }
  1445. }
  1446. }
  1447. if (!doNotRecurse) {
  1448. // Particles
  1449. for (index = 0; index < this.getScene().particleSystems.length; index++) {
  1450. if (this.getScene().particleSystems[index].emitter === this) {
  1451. this.getScene().particleSystems[index].dispose();
  1452. index--;
  1453. }
  1454. }
  1455. }
  1456. // facet data
  1457. if (this._internalAbstractMeshDataInfo._facetData.facetDataEnabled) {
  1458. this.disableFacetData();
  1459. }
  1460. this.onAfterWorldMatrixUpdateObservable.clear();
  1461. this.onCollideObservable.clear();
  1462. this.onCollisionPositionChangeObservable.clear();
  1463. this.onRebuildObservable.clear();
  1464. super.dispose(doNotRecurse, disposeMaterialAndTextures);
  1465. }
  1466. /**
  1467. * Adds the passed mesh as a child to the current mesh
  1468. * @param mesh defines the child mesh
  1469. * @returns the current mesh
  1470. */
  1471. public addChild(mesh: AbstractMesh): AbstractMesh {
  1472. mesh.setParent(this);
  1473. return this;
  1474. }
  1475. /**
  1476. * Removes the passed mesh from the current mesh children list
  1477. * @param mesh defines the child mesh
  1478. * @returns the current mesh
  1479. */
  1480. public removeChild(mesh: AbstractMesh): AbstractMesh {
  1481. mesh.setParent(null);
  1482. return this;
  1483. }
  1484. // Facet data
  1485. /** @hidden */
  1486. private _initFacetData(): AbstractMesh {
  1487. const data = this._internalAbstractMeshDataInfo._facetData;
  1488. if (!data.facetNormals) {
  1489. data.facetNormals = new Array<Vector3>();
  1490. }
  1491. if (!data.facetPositions) {
  1492. data.facetPositions = new Array<Vector3>();
  1493. }
  1494. if (!data.facetPartitioning) {
  1495. data.facetPartitioning = new Array<number[]>();
  1496. }
  1497. data.facetNb = ((<IndicesArray>this.getIndices()).length / 3) | 0;
  1498. data.partitioningSubdivisions = (data.partitioningSubdivisions) ? data.partitioningSubdivisions : 10; // default nb of partitioning subdivisions = 10
  1499. data.partitioningBBoxRatio = (data.partitioningBBoxRatio) ? data.partitioningBBoxRatio : 1.01; // default ratio 1.01 = the partitioning is 1% bigger than the bounding box
  1500. for (var f = 0; f < data.facetNb; f++) {
  1501. data.facetNormals[f] = Vector3.Zero();
  1502. data.facetPositions[f] = Vector3.Zero();
  1503. }
  1504. data.facetDataEnabled = true;
  1505. return this;
  1506. }
  1507. /**
  1508. * Updates the mesh facetData arrays and the internal partitioning when the mesh is morphed or updated.
  1509. * This method can be called within the render loop.
  1510. * You don't need to call this method by yourself in the render loop when you update/morph a mesh with the methods CreateXXX() as they automatically manage this computation
  1511. * @returns the current mesh
  1512. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1513. */
  1514. public updateFacetData(): AbstractMesh {
  1515. const data = this._internalAbstractMeshDataInfo._facetData;
  1516. if (!data.facetDataEnabled) {
  1517. this._initFacetData();
  1518. }
  1519. var positions = this.getVerticesData(VertexBuffer.PositionKind);
  1520. var indices = this.getIndices();
  1521. var normals = this.getVerticesData(VertexBuffer.NormalKind);
  1522. var bInfo = this.getBoundingInfo();
  1523. if (data.facetDepthSort && !data.facetDepthSortEnabled) {
  1524. // init arrays, matrix and sort function on first call
  1525. data.facetDepthSortEnabled = true;
  1526. if (indices instanceof Uint16Array) {
  1527. data.depthSortedIndices = new Uint16Array(indices!);
  1528. }
  1529. else if (indices instanceof Uint32Array) {
  1530. data.depthSortedIndices = new Uint32Array(indices!);
  1531. }
  1532. else {
  1533. var needs32bits = false;
  1534. for (var i = 0; i < indices!.length; i++) {
  1535. if (indices![i] > 65535) {
  1536. needs32bits = true;
  1537. break;
  1538. }
  1539. }
  1540. if (needs32bits) {
  1541. data.depthSortedIndices = new Uint32Array(indices!);
  1542. }
  1543. else {
  1544. data.depthSortedIndices = new Uint16Array(indices!);
  1545. }
  1546. }
  1547. data.facetDepthSortFunction = function(f1, f2) {
  1548. return (f2.sqDistance - f1.sqDistance);
  1549. };
  1550. if (!data.facetDepthSortFrom) {
  1551. var camera = this.getScene().activeCamera;
  1552. data.facetDepthSortFrom = (camera) ? camera.position : Vector3.Zero();
  1553. }
  1554. data.depthSortedFacets = [];
  1555. for (var f = 0; f < data.facetNb; f++) {
  1556. var depthSortedFacet = { ind: f * 3, sqDistance: 0.0 };
  1557. data.depthSortedFacets.push(depthSortedFacet);
  1558. }
  1559. data.invertedMatrix = Matrix.Identity();
  1560. data.facetDepthSortOrigin = Vector3.Zero();
  1561. }
  1562. data.bbSize.x = (bInfo.maximum.x - bInfo.minimum.x > Epsilon) ? bInfo.maximum.x - bInfo.minimum.x : Epsilon;
  1563. data.bbSize.y = (bInfo.maximum.y - bInfo.minimum.y > Epsilon) ? bInfo.maximum.y - bInfo.minimum.y : Epsilon;
  1564. data.bbSize.z = (bInfo.maximum.z - bInfo.minimum.z > Epsilon) ? bInfo.maximum.z - bInfo.minimum.z : Epsilon;
  1565. var bbSizeMax = (data.bbSize.x > data.bbSize.y) ? data.bbSize.x : data.bbSize.y;
  1566. bbSizeMax = (bbSizeMax > data.bbSize.z) ? bbSizeMax : data.bbSize.z;
  1567. data.subDiv.max = data.partitioningSubdivisions;
  1568. data.subDiv.X = Math.floor(data.subDiv.max * data.bbSize.x / bbSizeMax); // adjust the number of subdivisions per axis
  1569. data.subDiv.Y = Math.floor(data.subDiv.max * data.bbSize.y / bbSizeMax); // according to each bbox size per axis
  1570. data.subDiv.Z = Math.floor(data.subDiv.max * data.bbSize.z / bbSizeMax);
  1571. data.subDiv.X = data.subDiv.X < 1 ? 1 : data.subDiv.X; // at least one subdivision
  1572. data.subDiv.Y = data.subDiv.Y < 1 ? 1 : data.subDiv.Y;
  1573. data.subDiv.Z = data.subDiv.Z < 1 ? 1 : data.subDiv.Z;
  1574. // set the parameters for ComputeNormals()
  1575. data.facetParameters.facetNormals = this.getFacetLocalNormals();
  1576. data.facetParameters.facetPositions = this.getFacetLocalPositions();
  1577. data.facetParameters.facetPartitioning = this.getFacetLocalPartitioning();
  1578. data.facetParameters.bInfo = bInfo;
  1579. data.facetParameters.bbSize = data.bbSize;
  1580. data.facetParameters.subDiv = data.subDiv;
  1581. data.facetParameters.ratio = this.partitioningBBoxRatio;
  1582. data.facetParameters.depthSort = data.facetDepthSort;
  1583. if (data.facetDepthSort && data.facetDepthSortEnabled) {
  1584. this.computeWorldMatrix(true);
  1585. this._worldMatrix.invertToRef(data.invertedMatrix);
  1586. Vector3.TransformCoordinatesToRef(data.facetDepthSortFrom, data.invertedMatrix, data.facetDepthSortOrigin);
  1587. data.facetParameters.distanceTo = data.facetDepthSortOrigin;
  1588. }
  1589. data.facetParameters.depthSortedFacets = data.depthSortedFacets;
  1590. VertexData.ComputeNormals(positions, indices, normals, data.facetParameters);
  1591. if (data.facetDepthSort && data.facetDepthSortEnabled) {
  1592. data.depthSortedFacets.sort(data.facetDepthSortFunction);
  1593. var l = (data.depthSortedIndices.length / 3) | 0;
  1594. for (var f = 0; f < l; f++) {
  1595. var sind = data.depthSortedFacets[f].ind;
  1596. data.depthSortedIndices[f * 3] = indices![sind];
  1597. data.depthSortedIndices[f * 3 + 1] = indices![sind + 1];
  1598. data.depthSortedIndices[f * 3 + 2] = indices![sind + 2];
  1599. }
  1600. this.updateIndices(data.depthSortedIndices, undefined, true);
  1601. }
  1602. return this;
  1603. }
  1604. /**
  1605. * Returns the facetLocalNormals array.
  1606. * The normals are expressed in the mesh local spac
  1607. * @returns an array of Vector3
  1608. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1609. */
  1610. public getFacetLocalNormals(): Vector3[] {
  1611. let facetData = this._internalAbstractMeshDataInfo._facetData;
  1612. if (!facetData.facetNormals) {
  1613. this.updateFacetData();
  1614. }
  1615. return facetData.facetNormals;
  1616. }
  1617. /**
  1618. * Returns the facetLocalPositions array.
  1619. * The facet positions are expressed in the mesh local space
  1620. * @returns an array of Vector3
  1621. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1622. */
  1623. public getFacetLocalPositions(): Vector3[] {
  1624. let facetData = this._internalAbstractMeshDataInfo._facetData;
  1625. if (!facetData.facetPositions) {
  1626. this.updateFacetData();
  1627. }
  1628. return facetData.facetPositions;
  1629. }
  1630. /**
  1631. * Returns the facetLocalPartioning array
  1632. * @returns an array of array of numbers
  1633. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1634. */
  1635. public getFacetLocalPartitioning(): number[][] {
  1636. let facetData = this._internalAbstractMeshDataInfo._facetData;
  1637. if (!facetData.facetPartitioning) {
  1638. this.updateFacetData();
  1639. }
  1640. return facetData.facetPartitioning;
  1641. }
  1642. /**
  1643. * Returns the i-th facet position in the world system.
  1644. * This method allocates a new Vector3 per call
  1645. * @param i defines the facet index
  1646. * @returns a new Vector3
  1647. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1648. */
  1649. public getFacetPosition(i: number): Vector3 {
  1650. var pos = Vector3.Zero();
  1651. this.getFacetPositionToRef(i, pos);
  1652. return pos;
  1653. }
  1654. /**
  1655. * Sets the reference Vector3 with the i-th facet position in the world system
  1656. * @param i defines the facet index
  1657. * @param ref defines the target vector
  1658. * @returns the current mesh
  1659. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1660. */
  1661. public getFacetPositionToRef(i: number, ref: Vector3): AbstractMesh {
  1662. var localPos = (this.getFacetLocalPositions())[i];
  1663. var world = this.getWorldMatrix();
  1664. Vector3.TransformCoordinatesToRef(localPos, world, ref);
  1665. return this;
  1666. }
  1667. /**
  1668. * Returns the i-th facet normal in the world system.
  1669. * This method allocates a new Vector3 per call
  1670. * @param i defines the facet index
  1671. * @returns a new Vector3
  1672. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1673. */
  1674. public getFacetNormal(i: number): Vector3 {
  1675. var norm = Vector3.Zero();
  1676. this.getFacetNormalToRef(i, norm);
  1677. return norm;
  1678. }
  1679. /**
  1680. * Sets the reference Vector3 with the i-th facet normal in the world system
  1681. * @param i defines the facet index
  1682. * @param ref defines the target vector
  1683. * @returns the current mesh
  1684. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1685. */
  1686. public getFacetNormalToRef(i: number, ref: Vector3) {
  1687. var localNorm = (this.getFacetLocalNormals())[i];
  1688. Vector3.TransformNormalToRef(localNorm, this.getWorldMatrix(), ref);
  1689. return this;
  1690. }
  1691. /**
  1692. * Returns the facets (in an array) in the same partitioning block than the one the passed coordinates are located (expressed in the mesh local system)
  1693. * @param x defines x coordinate
  1694. * @param y defines y coordinate
  1695. * @param z defines z coordinate
  1696. * @returns the array of facet indexes
  1697. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1698. */
  1699. public getFacetsAtLocalCoordinates(x: number, y: number, z: number): Nullable<number[]> {
  1700. var bInfo = this.getBoundingInfo();
  1701. const data = this._internalAbstractMeshDataInfo._facetData;
  1702. var ox = Math.floor((x - bInfo.minimum.x * data.partitioningBBoxRatio) * data.subDiv.X * data.partitioningBBoxRatio / data.bbSize.x);
  1703. var oy = Math.floor((y - bInfo.minimum.y * data.partitioningBBoxRatio) * data.subDiv.Y * data.partitioningBBoxRatio / data.bbSize.y);
  1704. var oz = Math.floor((z - bInfo.minimum.z * data.partitioningBBoxRatio) * data.subDiv.Z * data.partitioningBBoxRatio / data.bbSize.z);
  1705. if (ox < 0 || ox > data.subDiv.max || oy < 0 || oy > data.subDiv.max || oz < 0 || oz > data.subDiv.max) {
  1706. return null;
  1707. }
  1708. return data.facetPartitioning[ox + data.subDiv.max * oy + data.subDiv.max * data.subDiv.max * oz];
  1709. }
  1710. /**
  1711. * Returns the closest mesh facet index at (x,y,z) World coordinates, null if not found
  1712. * @param projected sets as the (x,y,z) world projection on the facet
  1713. * @param checkFace if true (default false), only the facet "facing" to (x,y,z) or only the ones "turning their backs", according to the parameter "facing" are returned
  1714. * @param facing if facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position. If facing si false and checkFace is true, only the facet "turning their backs" to (x, y, z) are returned : negative dot (x, y, z) * facet position
  1715. * @param x defines x coordinate
  1716. * @param y defines y coordinate
  1717. * @param z defines z coordinate
  1718. * @returns the face index if found (or null instead)
  1719. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1720. */
  1721. public getClosestFacetAtCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true): Nullable<number> {
  1722. var world = this.getWorldMatrix();
  1723. var invMat = TmpVectors.Matrix[5];
  1724. world.invertToRef(invMat);
  1725. var invVect = TmpVectors.Vector3[8];
  1726. Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, invMat, invVect); // transform (x,y,z) to coordinates in the mesh local space
  1727. var closest = this.getClosestFacetAtLocalCoordinates(invVect.x, invVect.y, invVect.z, projected, checkFace, facing);
  1728. if (projected) {
  1729. // tranform the local computed projected vector to world coordinates
  1730. Vector3.TransformCoordinatesFromFloatsToRef(projected.x, projected.y, projected.z, world, projected);
  1731. }
  1732. return closest;
  1733. }
  1734. /**
  1735. * Returns the closest mesh facet index at (x,y,z) local coordinates, null if not found
  1736. * @param projected sets as the (x,y,z) local projection on the facet
  1737. * @param checkFace if true (default false), only the facet "facing" to (x,y,z) or only the ones "turning their backs", according to the parameter "facing" are returned
  1738. * @param facing if facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position. If facing si false and checkFace is true, only the facet "turning their backs" to (x, y, z) are returned : negative dot (x, y, z) * facet position
  1739. * @param x defines x coordinate
  1740. * @param y defines y coordinate
  1741. * @param z defines z coordinate
  1742. * @returns the face index if found (or null instead)
  1743. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1744. */
  1745. public getClosestFacetAtLocalCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true): Nullable<number> {
  1746. var closest = null;
  1747. var tmpx = 0.0;
  1748. var tmpy = 0.0;
  1749. var tmpz = 0.0;
  1750. var d = 0.0; // tmp dot facet normal * facet position
  1751. var t0 = 0.0;
  1752. var projx = 0.0;
  1753. var projy = 0.0;
  1754. var projz = 0.0;
  1755. // Get all the facets in the same partitioning block than (x, y, z)
  1756. var facetPositions = this.getFacetLocalPositions();
  1757. var facetNormals = this.getFacetLocalNormals();
  1758. var facetsInBlock = this.getFacetsAtLocalCoordinates(x, y, z);
  1759. if (!facetsInBlock) {
  1760. return null;
  1761. }
  1762. // Get the closest facet to (x, y, z)
  1763. var shortest = Number.MAX_VALUE; // init distance vars
  1764. var tmpDistance = shortest;
  1765. var fib; // current facet in the block
  1766. var norm; // current facet normal
  1767. var p0; // current facet barycenter position
  1768. // loop on all the facets in the current partitioning block
  1769. for (var idx = 0; idx < facetsInBlock.length; idx++) {
  1770. fib = facetsInBlock[idx];
  1771. norm = facetNormals[fib];
  1772. p0 = facetPositions[fib];
  1773. d = (x - p0.x) * norm.x + (y - p0.y) * norm.y + (z - p0.z) * norm.z;
  1774. if (!checkFace || (checkFace && facing && d >= 0.0) || (checkFace && !facing && d <= 0.0)) {
  1775. // compute (x,y,z) projection on the facet = (projx, projy, projz)
  1776. d = norm.x * p0.x + norm.y * p0.y + norm.z * p0.z;
  1777. t0 = -(norm.x * x + norm.y * y + norm.z * z - d) / (norm.x * norm.x + norm.y * norm.y + norm.z * norm.z);
  1778. projx = x + norm.x * t0;
  1779. projy = y + norm.y * t0;
  1780. projz = z + norm.z * t0;
  1781. tmpx = projx - x;
  1782. tmpy = projy - y;
  1783. tmpz = projz - z;
  1784. tmpDistance = tmpx * tmpx + tmpy * tmpy + tmpz * tmpz; // compute length between (x, y, z) and its projection on the facet
  1785. if (tmpDistance < shortest) { // just keep the closest facet to (x, y, z)
  1786. shortest = tmpDistance;
  1787. closest = fib;
  1788. if (projected) {
  1789. projected.x = projx;
  1790. projected.y = projy;
  1791. projected.z = projz;
  1792. }
  1793. }
  1794. }
  1795. }
  1796. return closest;
  1797. }
  1798. /**
  1799. * Returns the object "parameter" set with all the expected parameters for facetData computation by ComputeNormals()
  1800. * @returns the parameters
  1801. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1802. */
  1803. public getFacetDataParameters(): any {
  1804. return this._internalAbstractMeshDataInfo._facetData.facetParameters;
  1805. }
  1806. /**
  1807. * Disables the feature FacetData and frees the related memory
  1808. * @returns the current mesh
  1809. * @see https://doc.babylonjs.com/how_to/how_to_use_facetdata
  1810. */
  1811. public disableFacetData(): AbstractMesh {
  1812. let facetData = this._internalAbstractMeshDataInfo._facetData;
  1813. if (facetData.facetDataEnabled) {
  1814. facetData.facetDataEnabled = false;
  1815. facetData.facetPositions = new Array<Vector3>();
  1816. facetData.facetNormals = new Array<Vector3>();
  1817. facetData.facetPartitioning = new Array<number[]>();
  1818. facetData.facetParameters = null;
  1819. facetData.depthSortedIndices = new Uint32Array(0);
  1820. }
  1821. return this;
  1822. }
  1823. /**
  1824. * Updates the AbstractMesh indices array
  1825. * @param indices defines the data source
  1826. * @param offset defines the offset in the index buffer where to store the new data (can be null)
  1827. * @param gpuMemoryOnly defines a boolean indicating that only the GPU memory must be updated leaving the CPU version of the indices unchanged (false by default)
  1828. * @returns the current mesh
  1829. */
  1830. public updateIndices(indices: IndicesArray, offset?: number, gpuMemoryOnly = false): AbstractMesh {
  1831. return this;
  1832. }
  1833. /**
  1834. * Creates new normals data for the mesh
  1835. * @param updatable defines if the normal vertex buffer must be flagged as updatable
  1836. * @returns the current mesh
  1837. */
  1838. public createNormals(updatable: boolean): AbstractMesh {
  1839. var positions = this.getVerticesData(VertexBuffer.PositionKind);
  1840. var indices = this.getIndices();
  1841. var normals: FloatArray;
  1842. if (this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
  1843. normals = (<FloatArray>this.getVerticesData(VertexBuffer.NormalKind));
  1844. } else {
  1845. normals = [];
  1846. }
  1847. VertexData.ComputeNormals(positions, indices, normals, { useRightHandedSystem: this.getScene().useRightHandedSystem });
  1848. this.setVerticesData(VertexBuffer.NormalKind, normals, updatable);
  1849. return this;
  1850. }
  1851. /**
  1852. * Align the mesh with a normal
  1853. * @param normal defines the normal to use
  1854. * @param upDirection can be used to redefined the up vector to use (will use the (0, 1, 0) by default)
  1855. * @returns the current mesh
  1856. */
  1857. public alignWithNormal(normal: Vector3, upDirection?: Vector3): AbstractMesh {
  1858. if (!upDirection) {
  1859. upDirection = Axis.Y;
  1860. }
  1861. var axisX = TmpVectors.Vector3[0];
  1862. var axisZ = TmpVectors.Vector3[1];
  1863. Vector3.CrossToRef(upDirection, normal, axisZ);
  1864. Vector3.CrossToRef(normal, axisZ, axisX);
  1865. if (this.rotationQuaternion) {
  1866. Quaternion.RotationQuaternionFromAxisToRef(axisX, normal, axisZ, this.rotationQuaternion);
  1867. } else {
  1868. Vector3.RotationFromAxisToRef(axisX, normal, axisZ, this.rotation);
  1869. }
  1870. return this;
  1871. }
  1872. /** @hidden */
  1873. public _checkOcclusionQuery(): boolean { // Will be replaced by correct code if Occlusion queries are referenced
  1874. return false;
  1875. }
  1876. /**
  1877. * Disables the mesh edge rendering mode
  1878. * @returns the currentAbstractMesh
  1879. */
  1880. disableEdgesRendering(): AbstractMesh {
  1881. throw _DevTools.WarnImport("EdgesRenderer");
  1882. }
  1883. /**
  1884. * Enables the edge rendering mode on the mesh.
  1885. * This mode makes the mesh edges visible
  1886. * @param epsilon defines the maximal distance between two angles to detect a face
  1887. * @param checkVerticesInsteadOfIndices indicates that we should check vertex list directly instead of faces
  1888. * @returns the currentAbstractMesh
  1889. * @see https://www.babylonjs-playground.com/#19O9TU#0
  1890. */
  1891. enableEdgesRendering(epsilon?: number, checkVerticesInsteadOfIndices?: boolean): AbstractMesh {
  1892. throw _DevTools.WarnImport("EdgesRenderer");
  1893. }
  1894. /**
  1895. * This function returns all of the particle systems in the scene that use the mesh as an emitter.
  1896. * @returns an array of particle systems in the scene that use the mesh as an emitter
  1897. */
  1898. public getConnectedParticleSystems(): IParticleSystem[] {
  1899. return this._scene.particleSystems.filter((particleSystem) => particleSystem.emitter === this);
  1900. }
  1901. }