babylon.abstractMesh.ts 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434
  1. module BABYLON {
  2. export class AbstractMesh extends Node implements IDisposable, ICullable, IGetSetVerticesData {
  3. // Statics
  4. private static _BILLBOARDMODE_NONE = 0;
  5. private static _BILLBOARDMODE_X = 1;
  6. private static _BILLBOARDMODE_Y = 2;
  7. private static _BILLBOARDMODE_Z = 4;
  8. private static _BILLBOARDMODE_ALL = 7;
  9. public static OCCLUSION_TYPE_NONE = 0;
  10. public static OCCLUSION_TYPE_OPTIMISTIC = 1;
  11. public static OCCLUSION_TYPE_STRICT = 2;
  12. public static OCCLUSION_ALGORITHM_TYPE_ACCURATE = 0;
  13. public static OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE = 1;
  14. public static get BILLBOARDMODE_NONE(): number {
  15. return AbstractMesh._BILLBOARDMODE_NONE;
  16. }
  17. public static get BILLBOARDMODE_X(): number {
  18. return AbstractMesh._BILLBOARDMODE_X;
  19. }
  20. public static get BILLBOARDMODE_Y(): number {
  21. return AbstractMesh._BILLBOARDMODE_Y;
  22. }
  23. public static get BILLBOARDMODE_Z(): number {
  24. return AbstractMesh._BILLBOARDMODE_Z;
  25. }
  26. public static get BILLBOARDMODE_ALL(): number {
  27. return AbstractMesh._BILLBOARDMODE_ALL;
  28. }
  29. // facetData private properties
  30. private _facetPositions: Vector3[]; // facet local positions
  31. private _facetNormals: Vector3[]; // facet local normals
  32. private _facetPartitioning: number[][]; // partitioning array of facet index arrays
  33. private _facetNb: number = 0; // facet number
  34. private _partitioningSubdivisions: number = 10; // number of subdivisions per axis in the partioning space
  35. private _partitioningBBoxRatio: number = 1.01; // the partioning array space is by default 1% bigger than the bounding box
  36. private _facetDataEnabled: boolean = false; // is the facet data feature enabled on this mesh ?
  37. private _facetParameters: any = {}; // keep a reference to the object parameters to avoid memory re-allocation
  38. private _bbSize: Vector3 = Vector3.Zero(); // bbox size approximated for facet data
  39. private _subDiv = { // actual number of subdivisions per axis for ComputeNormals()
  40. max: 1,
  41. X: 1,
  42. Y: 1,
  43. Z: 1
  44. };
  45. /**
  46. * Read-only : the number of facets in the mesh
  47. */
  48. public get facetNb(): number {
  49. return this._facetNb;
  50. }
  51. /**
  52. * The number (integer) of subdivisions per axis in the partioning space
  53. */
  54. public get partitioningSubdivisions(): number {
  55. return this._partitioningSubdivisions;
  56. }
  57. public set partitioningSubdivisions(nb: number) {
  58. this._partitioningSubdivisions = nb;
  59. }
  60. /**
  61. * The ratio (float) to apply to the bouding box size to set to the partioning space.
  62. * Ex : 1.01 (default) the partioning space is 1% bigger than the bounding box.
  63. */
  64. public get partitioningBBoxRatio(): number {
  65. return this._partitioningBBoxRatio;
  66. }
  67. public set partitioningBBoxRatio(ratio: number) {
  68. this._partitioningBBoxRatio = ratio;
  69. }
  70. /**
  71. * Read-only boolean : is the feature facetData enabled ?
  72. */
  73. public get isFacetDataEnabled(): boolean {
  74. return this._facetDataEnabled;
  75. }
  76. // Events
  77. /**
  78. * An event triggered when this mesh collides with another one
  79. * @type {BABYLON.Observable}
  80. */
  81. public onCollideObservable = new Observable<AbstractMesh>();
  82. private _onCollideObserver: Nullable<Observer<AbstractMesh>>;
  83. public set onCollide(callback: () => void) {
  84. if (this._onCollideObserver) {
  85. this.onCollideObservable.remove(this._onCollideObserver);
  86. }
  87. this._onCollideObserver = this.onCollideObservable.add(callback);
  88. }
  89. /**
  90. * An event triggered when the collision's position changes
  91. * @type {BABYLON.Observable}
  92. */
  93. public onCollisionPositionChangeObservable = new Observable<Vector3>();
  94. private _onCollisionPositionChangeObserver: Nullable<Observer<Vector3>>;
  95. public set onCollisionPositionChange(callback: () => void) {
  96. if (this._onCollisionPositionChangeObserver) {
  97. this.onCollisionPositionChangeObservable.remove(this._onCollisionPositionChangeObserver);
  98. }
  99. this._onCollisionPositionChangeObserver = this.onCollisionPositionChangeObservable.add(callback);
  100. }
  101. /**
  102. * An event triggered after the world matrix is updated
  103. * @type {BABYLON.Observable}
  104. */
  105. public onAfterWorldMatrixUpdateObservable = new Observable<AbstractMesh>();
  106. /**
  107. * An event triggered when material is changed
  108. * @type {BABYLON.Observable}
  109. */
  110. public onMaterialChangedObservable = new Observable<AbstractMesh>();
  111. // Properties
  112. public definedFacingForward = true; // orientation for POV movement & rotation
  113. public position = Vector3.Zero();
  114. /**
  115. * This property determines the type of occlusion query algorithm to run in WebGl, you can use:
  116. * AbstractMesh.OCCLUSION_ALGORITHM_TYPE_ACCURATE which is mapped to GL_ANY_SAMPLES_PASSED.
  117. * or
  118. * AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE (Default Value) which is mapped to GL_ANY_SAMPLES_PASSED_CONSERVATIVE which is a false positive algorithm that is faster than GL_ANY_SAMPLES_PASSED but less accurate.
  119. * for more info check WebGl documentations
  120. */
  121. public occlusionQueryAlgorithmType = AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE;
  122. /**
  123. * This property is responsible for starting the occlusion query within the Mesh or not, this property is also used to determine what should happen when the occlusionRetryCount is reached. It has supports 3 values:
  124. * OCCLUSION_TYPE_NONE (Default Value): this option means no occlusion query whith the Mesh.
  125. * OCCLUSION_TYPE_OPTIMISTIC: this option is means use occlusion query and if occlusionRetryCount is reached and the query is broken show the mesh.
  126. * OCCLUSION_TYPE_STRICT: this option is means use occlusion query and if occlusionRetryCount is reached and the query is broken restore the last state of the mesh occlusion if the mesh was visible then show the mesh if was hidden then hide don't show.
  127. */
  128. public occlusionType = AbstractMesh.OCCLUSION_TYPE_NONE;
  129. /**
  130. * This number indicates the number of allowed retries before stop the occlusion query, this is useful if the occlusion query is taking long time before to the query result is retireved, the query result indicates if the object is visible within the scene or not and based on that Babylon.Js engine decideds to show or hide the object.
  131. * The default value is -1 which means don't break the query and wait till the result.
  132. */
  133. public occlusionRetryCount = -1;
  134. private _occlusionInternalRetryCounter = 0;
  135. protected _isOccluded = false;
  136. /**
  137. * Property isOccluded : Gets or sets whether the mesh is occluded or not, it is used also to set the intial state of the mesh to be occluded or not.
  138. */
  139. public get isOccluded(): boolean {
  140. return this._isOccluded;
  141. }
  142. public set isOccluded(value: boolean) {
  143. this._isOccluded = value;
  144. }
  145. private _isOcclusionQueryInProgress = false;
  146. /**
  147. * Flag to check the progress status of the query
  148. */
  149. public get isOcclusionQueryInProgress(): boolean {
  150. return this._isOcclusionQueryInProgress;
  151. }
  152. private _occlusionQuery: Nullable<WebGLQuery>;
  153. private _rotation = Vector3.Zero();
  154. private _rotationQuaternion: Nullable<Quaternion>;
  155. private _scaling = Vector3.One();
  156. public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
  157. public visibility = 1.0;
  158. public alphaIndex = Number.MAX_VALUE;
  159. public infiniteDistance = false;
  160. public isVisible = true;
  161. public isPickable = true;
  162. public showBoundingBox = false;
  163. public showSubMeshesBoundingBox = false;
  164. public isBlocker = false;
  165. public enablePointerMoveEvents = false;
  166. public renderingGroupId = 0;
  167. private _material: Material
  168. public get material(): Material {
  169. return this._material;
  170. }
  171. public set material(value: Material) {
  172. if (this._material === value) {
  173. return;
  174. }
  175. this._material = value;
  176. if (this.onMaterialChangedObservable.hasObservers) {
  177. this.onMaterialChangedObservable.notifyObservers(this);
  178. }
  179. if (!this.subMeshes) {
  180. return;
  181. }
  182. for (var subMesh of this.subMeshes) {
  183. subMesh.setEffect(null);
  184. }
  185. }
  186. private _receiveShadows = false;
  187. public get receiveShadows(): boolean {
  188. return this._receiveShadows;
  189. }
  190. public set receiveShadows(value: boolean) {
  191. if (this._receiveShadows === value) {
  192. return;
  193. }
  194. this._receiveShadows = value;
  195. this._markSubMeshesAsLightDirty();
  196. }
  197. public renderOutline = false;
  198. public outlineColor = Color3.Red();
  199. public outlineWidth = 0.02;
  200. public renderOverlay = false;
  201. public overlayColor = Color3.Red();
  202. public overlayAlpha = 0.5;
  203. private _hasVertexAlpha = false;
  204. public get hasVertexAlpha(): boolean {
  205. return this._hasVertexAlpha;
  206. }
  207. public set hasVertexAlpha(value: boolean) {
  208. if (this._hasVertexAlpha === value) {
  209. return;
  210. }
  211. this._hasVertexAlpha = value;
  212. this._markSubMeshesAsAttributesDirty();
  213. }
  214. private _useVertexColors = true;
  215. public get useVertexColors(): boolean {
  216. return this._useVertexColors;
  217. }
  218. public set useVertexColors(value: boolean) {
  219. if (this._useVertexColors === value) {
  220. return;
  221. }
  222. this._useVertexColors = value;
  223. this._markSubMeshesAsAttributesDirty();
  224. }
  225. private _computeBonesUsingShaders = true;
  226. public get computeBonesUsingShaders(): boolean {
  227. return this._computeBonesUsingShaders;
  228. }
  229. public set computeBonesUsingShaders(value: boolean) {
  230. if (this._computeBonesUsingShaders === value) {
  231. return;
  232. }
  233. this._computeBonesUsingShaders = value;
  234. this._markSubMeshesAsAttributesDirty();
  235. }
  236. private _numBoneInfluencers = 4;
  237. public get numBoneInfluencers(): number {
  238. return this._numBoneInfluencers;
  239. }
  240. public set numBoneInfluencers(value: number) {
  241. if (this._numBoneInfluencers === value) {
  242. return;
  243. }
  244. this._numBoneInfluencers = value;
  245. this._markSubMeshesAsAttributesDirty();
  246. }
  247. private _applyFog = true;
  248. public get applyFog(): boolean {
  249. return this._applyFog;
  250. }
  251. public set applyFog(value: boolean) {
  252. if (this._applyFog === value) {
  253. return;
  254. }
  255. this._applyFog = value;
  256. this._markSubMeshesAsMiscDirty();
  257. }
  258. public scalingDeterminant = 1;
  259. public useOctreeForRenderingSelection = true;
  260. public useOctreeForPicking = true;
  261. public useOctreeForCollisions = true;
  262. private _layerMask: number = 0x0FFFFFFF;
  263. public get layerMask(): number {
  264. return this._layerMask;
  265. }
  266. public set layerMask(value: number) {
  267. if (value === this._layerMask) {
  268. return;
  269. }
  270. this._layerMask = value;
  271. this._resyncLightSources();
  272. }
  273. /**
  274. * True if the mesh must be rendered in any case.
  275. */
  276. public alwaysSelectAsActiveMesh = false;
  277. /**
  278. * This scene's action manager
  279. * @type {BABYLON.ActionManager}
  280. */
  281. public actionManager: Nullable<ActionManager>;
  282. // Physics
  283. public physicsImpostor: Nullable<PhysicsImpostor>;
  284. // Collisions
  285. private _checkCollisions = false;
  286. private _collisionMask = -1;
  287. private _collisionGroup = -1;
  288. public ellipsoid = new Vector3(0.5, 1, 0.5);
  289. public ellipsoidOffset = new Vector3(0, 0, 0);
  290. private _collider: Collider;
  291. private _oldPositionForCollisions = new Vector3(0, 0, 0);
  292. private _diffPositionForCollisions = new Vector3(0, 0, 0);
  293. public get collisionMask(): number {
  294. return this._collisionMask;
  295. }
  296. public set collisionMask(mask: number) {
  297. this._collisionMask = !isNaN(mask) ? mask : -1;
  298. }
  299. public get collisionGroup(): number {
  300. return this._collisionGroup;
  301. }
  302. public set collisionGroup(mask: number) {
  303. this._collisionGroup = !isNaN(mask) ? mask : -1;
  304. }
  305. // Attach to bone
  306. private _meshToBoneReferal: Nullable<AbstractMesh>;
  307. // Edges
  308. public edgesWidth = 1;
  309. public edgesColor = new Color4(1, 0, 0, 1);
  310. public _edgesRenderer: Nullable<EdgesRenderer>;
  311. // Cache
  312. private _localWorld = Matrix.Zero();
  313. public _worldMatrix = Matrix.Zero();
  314. private _absolutePosition = Vector3.Zero();
  315. private _collisionsTransformMatrix = Matrix.Zero();
  316. private _collisionsScalingMatrix = Matrix.Zero();
  317. private _isDirty = false;
  318. public _masterMesh: AbstractMesh;
  319. public _boundingInfo: BoundingInfo;
  320. private _pivotMatrix = Matrix.Identity();
  321. private _pivotMatrixInverse: Matrix;
  322. private _postMultiplyPivotMatrix = false;
  323. public _isDisposed = false;
  324. public _renderId = 0;
  325. public subMeshes: SubMesh[];
  326. public _submeshesOctree: Octree<SubMesh>;
  327. public _intersectionsInProgress = new Array<AbstractMesh>();
  328. private _isWorldMatrixFrozen = false;
  329. public _unIndexed = false;
  330. public _poseMatrix: Matrix;
  331. public _lightSources = new Array<Light>();
  332. public get _positions(): Nullable<Vector3[]> {
  333. return null;
  334. }
  335. // Loading properties
  336. public _waitingActions: any;
  337. public _waitingFreezeWorldMatrix: Nullable<boolean>;
  338. // Skeleton
  339. private _skeleton: Nullable<Skeleton>;
  340. public _bonesTransformMatrices: Nullable<Float32Array>;
  341. public set skeleton(value: Nullable<Skeleton>) {
  342. if (this._skeleton && this._skeleton.needInitialSkinMatrix) {
  343. this._skeleton._unregisterMeshWithPoseMatrix(this);
  344. }
  345. if (value && value.needInitialSkinMatrix) {
  346. value._registerMeshWithPoseMatrix(this);
  347. }
  348. this._skeleton = value;
  349. if (!this._skeleton) {
  350. this._bonesTransformMatrices = null;
  351. }
  352. this._markSubMeshesAsAttributesDirty();
  353. }
  354. public get skeleton(): Nullable<Skeleton> {
  355. return this._skeleton;
  356. }
  357. // Constructor
  358. constructor(name: string, scene: Scene) {
  359. super(name, scene);
  360. this.getScene().addMesh(this);
  361. this._resyncLightSources();
  362. }
  363. /**
  364. * Boolean : true if the mesh has been disposed.
  365. */
  366. public isDisposed(): boolean {
  367. return this._isDisposed;
  368. }
  369. /**
  370. * Returns the string "AbstractMesh"
  371. */
  372. public getClassName(): string {
  373. return "AbstractMesh";
  374. }
  375. /**
  376. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  377. */
  378. public toString(fullDetails?: boolean): string {
  379. var ret = "Name: " + this.name + ", isInstance: " + (this instanceof InstancedMesh ? "YES" : "NO");
  380. ret += ", # of submeshes: " + (this.subMeshes ? this.subMeshes.length : 0);
  381. if (this._skeleton) {
  382. ret += ", skeleton: " + this._skeleton.name;
  383. }
  384. if (fullDetails) {
  385. ret += ", billboard mode: " + (["NONE", "X", "Y", null, "Z", null, null, "ALL"])[this.billboardMode];
  386. ret += ", freeze wrld mat: " + (this._isWorldMatrixFrozen || this._waitingFreezeWorldMatrix ? "YES" : "NO");
  387. }
  388. return ret;
  389. }
  390. public _rebuild(): void {
  391. if (this._occlusionQuery) {
  392. this._occlusionQuery = null;
  393. }
  394. if (this._edgesRenderer) {
  395. this._edgesRenderer._rebuild();
  396. }
  397. if (!this.subMeshes) {
  398. return;
  399. }
  400. for (var subMesh of this.subMeshes) {
  401. subMesh._rebuild();
  402. }
  403. }
  404. public _resyncLightSources(): void {
  405. this._lightSources.length = 0;
  406. for (var light of this.getScene().lights) {
  407. if (!light.isEnabled()) {
  408. continue;
  409. }
  410. if (light.canAffectMesh(this)) {
  411. this._lightSources.push(light);
  412. }
  413. }
  414. this._markSubMeshesAsLightDirty();
  415. }
  416. public _resyncLighSource(light: Light): void {
  417. var isIn = light.isEnabled() && light.canAffectMesh(this);
  418. var index = this._lightSources.indexOf(light);
  419. if (index === -1) {
  420. if (!isIn) {
  421. return;
  422. }
  423. this._lightSources.push(light);
  424. } else {
  425. if (isIn) {
  426. return;
  427. }
  428. this._lightSources.splice(index, 1);
  429. }
  430. this._markSubMeshesAsLightDirty();
  431. }
  432. public _removeLightSource(light: Light): void {
  433. var index = this._lightSources.indexOf(light);
  434. if (index === -1) {
  435. return;
  436. }
  437. this._lightSources.splice(index, 1);
  438. }
  439. private _markSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {
  440. if (!this.subMeshes) {
  441. return;
  442. }
  443. for (var subMesh of this.subMeshes) {
  444. if (subMesh._materialDefines) {
  445. func(subMesh._materialDefines);
  446. }
  447. }
  448. }
  449. public _markSubMeshesAsLightDirty() {
  450. this._markSubMeshesAsDirty(defines => defines.markAsLightDirty());
  451. }
  452. public _markSubMeshesAsAttributesDirty() {
  453. this._markSubMeshesAsDirty(defines => defines.markAsAttributesDirty());
  454. }
  455. public _markSubMeshesAsMiscDirty() {
  456. if (!this.subMeshes) {
  457. return;
  458. }
  459. for (var subMesh of this.subMeshes) {
  460. var material = subMesh.getMaterial();
  461. if (material) {
  462. material.markAsDirty(Material.MiscDirtyFlag);
  463. }
  464. }
  465. }
  466. /**
  467. * Rotation property : a Vector3 depicting the rotation value in radians around each local axis X, Y, Z.
  468. * If rotation quaternion is set, this Vector3 will (almost always) be the Zero vector!
  469. * Default : (0.0, 0.0, 0.0)
  470. */
  471. public get rotation(): Vector3 {
  472. return this._rotation;
  473. }
  474. public set rotation(newRotation: Vector3) {
  475. this._rotation = newRotation;
  476. }
  477. /**
  478. * Scaling property : a Vector3 depicting the mesh scaling along each local axis X, Y, Z.
  479. * Default : (1.0, 1.0, 1.0)
  480. */
  481. public get scaling(): Vector3 {
  482. return this._scaling;
  483. }
  484. public set scaling(newScaling: Vector3) {
  485. this._scaling = newScaling;
  486. if (this.physicsImpostor) {
  487. this.physicsImpostor.forceUpdate();
  488. }
  489. }
  490. /**
  491. * Rotation Quaternion property : this a Quaternion object depicting the mesh rotation by using a unit quaternion.
  492. * It's null by default.
  493. * If set, only the rotationQuaternion is then used to compute the mesh rotation and its property `.rotation\ is then ignored and set to (0.0, 0.0, 0.0)
  494. */
  495. public get rotationQuaternion(): Nullable<Quaternion> {
  496. return this._rotationQuaternion;
  497. }
  498. public set rotationQuaternion(quaternion: Nullable<Quaternion>) {
  499. this._rotationQuaternion = quaternion;
  500. //reset the rotation vector.
  501. if (quaternion && this.rotation.length()) {
  502. this.rotation.copyFromFloats(0.0, 0.0, 0.0);
  503. }
  504. }
  505. // Methods
  506. /**
  507. * Copies the paramater passed Matrix into the mesh Pose matrix.
  508. * Returns the AbstractMesh.
  509. */
  510. public updatePoseMatrix(matrix: Matrix): AbstractMesh {
  511. this._poseMatrix.copyFrom(matrix);
  512. return this;
  513. }
  514. /**
  515. * Returns the mesh Pose matrix.
  516. * Returned object : Matrix
  517. */
  518. public getPoseMatrix(): Matrix {
  519. return this._poseMatrix;
  520. }
  521. /**
  522. * Disables the mesh edger rendering mode.
  523. * Returns the AbstractMesh.
  524. */
  525. public disableEdgesRendering(): AbstractMesh {
  526. if (this._edgesRenderer) {
  527. this._edgesRenderer.dispose();
  528. this._edgesRenderer = null;
  529. }
  530. return this;
  531. }
  532. /**
  533. * Enables the edge rendering mode on the mesh.
  534. * This mode makes the mesh edges visible.
  535. * Returns the AbstractMesh.
  536. */
  537. public enableEdgesRendering(epsilon = 0.95, checkVerticesInsteadOfIndices = false): AbstractMesh {
  538. this.disableEdgesRendering();
  539. this._edgesRenderer = new EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
  540. return this;
  541. }
  542. /**
  543. * Returns true if the mesh is blocked. Used by the class Mesh.
  544. * Returns the boolean `false` by default.
  545. */
  546. public get isBlocked(): boolean {
  547. return false;
  548. }
  549. /**
  550. * Returns the mesh itself by default, used by the class Mesh.
  551. * Returned type : AbstractMesh
  552. */
  553. public getLOD(camera: Camera): AbstractMesh {
  554. return this;
  555. }
  556. /**
  557. * Returns 0 by default, used by the class Mesh.
  558. * Returns an integer.
  559. */
  560. public getTotalVertices(): number {
  561. return 0;
  562. }
  563. /**
  564. * Returns null by default, used by the class Mesh.
  565. * Returned type : integer array
  566. */
  567. public getIndices(): Nullable<IndicesArray> {
  568. return null;
  569. }
  570. /**
  571. * Returns the array of the requested vertex data kind. Used by the class Mesh. Returns null here.
  572. * Returned type : float array or Float32Array
  573. */
  574. public getVerticesData(kind: string): Nullable<number[] | Float32Array> {
  575. return null;
  576. }
  577. /**
  578. * Sets the vertex data of the mesh geometry for the requested `kind`.
  579. * If the mesh has no geometry, a new Geometry object is set to the mesh and then passed this vertex data.
  580. * The `data` are either a numeric array either a Float32Array.
  581. * The parameter `updatable` is passed as is to the underlying Geometry object constructor (if initianilly none) or updater.
  582. * The parameter `stride` is an optional positive integer, it is usually automatically deducted from the `kind` (3 for positions or normals, 2 for UV, etc).
  583. * Note that a new underlying VertexBuffer object is created each call.
  584. * If the `kind` is the `PositionKind`, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  585. *
  586. * Possible `kind` values :
  587. * - BABYLON.VertexBuffer.PositionKind
  588. * - BABYLON.VertexBuffer.UVKind
  589. * - BABYLON.VertexBuffer.UV2Kind
  590. * - BABYLON.VertexBuffer.UV3Kind
  591. * - BABYLON.VertexBuffer.UV4Kind
  592. * - BABYLON.VertexBuffer.UV5Kind
  593. * - BABYLON.VertexBuffer.UV6Kind
  594. * - BABYLON.VertexBuffer.ColorKind
  595. * - BABYLON.VertexBuffer.MatricesIndicesKind
  596. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  597. * - BABYLON.VertexBuffer.MatricesWeightsKind
  598. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  599. *
  600. * Returns the Mesh.
  601. */
  602. public setVerticesData(kind: string, data: number[] | Float32Array, updatable?: boolean, stride?: number): AbstractMesh {
  603. return this;
  604. }
  605. /**
  606. * Updates the existing vertex data of the mesh geometry for the requested `kind`.
  607. * If the mesh has no geometry, it is simply returned as it is.
  608. * The `data` are either a numeric array either a Float32Array.
  609. * No new underlying VertexBuffer object is created.
  610. * If the `kind` is the `PositionKind` and if `updateExtends` is true, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  611. * If the parameter `makeItUnique` is true, a new global geometry is created from this positions and is set to the mesh.
  612. *
  613. * Possible `kind` values :
  614. * - BABYLON.VertexBuffer.PositionKind
  615. * - BABYLON.VertexBuffer.UVKind
  616. * - BABYLON.VertexBuffer.UV2Kind
  617. * - BABYLON.VertexBuffer.UV3Kind
  618. * - BABYLON.VertexBuffer.UV4Kind
  619. * - BABYLON.VertexBuffer.UV5Kind
  620. * - BABYLON.VertexBuffer.UV6Kind
  621. * - BABYLON.VertexBuffer.ColorKind
  622. * - BABYLON.VertexBuffer.MatricesIndicesKind
  623. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  624. * - BABYLON.VertexBuffer.MatricesWeightsKind
  625. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  626. *
  627. * Returns the Mesh.
  628. */
  629. public updateVerticesData(kind: string, data: number[] | Float32Array, updateExtends?: boolean, makeItUnique?: boolean): AbstractMesh {
  630. return this;
  631. }
  632. /**
  633. * Sets the mesh indices.
  634. * Expects an array populated with integers or a typed array (Int32Array, Uint32Array, Uint16Array).
  635. * If the mesh has no geometry, a new Geometry object is created and set to the mesh.
  636. * This method creates a new index buffer each call.
  637. * Returns the Mesh.
  638. */
  639. public setIndices(indices: IndicesArray, totalVertices?: number): AbstractMesh {
  640. return this;
  641. }
  642. /** Returns false by default, used by the class Mesh.
  643. * Returns a boolean
  644. */
  645. public isVerticesDataPresent(kind: string): boolean {
  646. return false;
  647. }
  648. /**
  649. * Returns the mesh BoundingInfo object or creates a new one and returns it if undefined.
  650. * Returns a BoundingInfo
  651. */
  652. public getBoundingInfo(): BoundingInfo {
  653. if (this._masterMesh) {
  654. return this._masterMesh.getBoundingInfo();
  655. }
  656. if (!this._boundingInfo) {
  657. this._updateBoundingInfo();
  658. }
  659. return this._boundingInfo;
  660. }
  661. /**
  662. * Sets a mesh new object BoundingInfo.
  663. * Returns the AbstractMesh.
  664. */
  665. public setBoundingInfo(boundingInfo: BoundingInfo): AbstractMesh {
  666. this._boundingInfo = boundingInfo;
  667. return this;
  668. }
  669. public get useBones(): boolean {
  670. return (<boolean>(this.skeleton && this.getScene().skeletonsEnabled && this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind)));
  671. }
  672. public _preActivate(): void {
  673. }
  674. public _preActivateForIntermediateRendering(renderId: number): void {
  675. }
  676. public _activate(renderId: number): void {
  677. this._renderId = renderId;
  678. }
  679. /**
  680. * Returns the last update of the World matrix
  681. * Returns a Matrix.
  682. */
  683. public getWorldMatrix(): Matrix {
  684. if (this._masterMesh) {
  685. return this._masterMesh.getWorldMatrix();
  686. }
  687. if (this._currentRenderId !== this.getScene().getRenderId() || !this.isSynchronized()) {
  688. this.computeWorldMatrix();
  689. }
  690. return this._worldMatrix;
  691. }
  692. /**
  693. * Returns directly the last state of the mesh World matrix.
  694. * A Matrix is returned.
  695. */
  696. public get worldMatrixFromCache(): Matrix {
  697. return this._worldMatrix;
  698. }
  699. /**
  700. * Returns the current mesh absolute position.
  701. * Retuns a Vector3.
  702. */
  703. public get absolutePosition(): Vector3 {
  704. return this._absolutePosition;
  705. }
  706. /**
  707. * Prevents the World matrix to be computed any longer.
  708. * Returns the AbstractMesh.
  709. */
  710. public freezeWorldMatrix(): AbstractMesh {
  711. this._isWorldMatrixFrozen = false; // no guarantee world is not already frozen, switch off temporarily
  712. this.computeWorldMatrix(true);
  713. this._isWorldMatrixFrozen = true;
  714. return this;
  715. }
  716. /**
  717. * Allows back the World matrix computation.
  718. * Returns the AbstractMesh.
  719. */
  720. public unfreezeWorldMatrix() {
  721. this._isWorldMatrixFrozen = false;
  722. this.computeWorldMatrix(true);
  723. return this;
  724. }
  725. /**
  726. * True if the World matrix has been frozen.
  727. * Returns a boolean.
  728. */
  729. public get isWorldMatrixFrozen(): boolean {
  730. return this._isWorldMatrixFrozen;
  731. }
  732. private static _rotationAxisCache = new Quaternion();
  733. /**
  734. * Rotates the mesh around the axis vector for the passed angle (amount) expressed in radians, in the given space.
  735. * space (default LOCAL) can be either BABYLON.Space.LOCAL, either BABYLON.Space.WORLD.
  736. * Note that the property `rotationQuaternion` is then automatically updated and the property `rotation` is set to (0,0,0) and no longer used.
  737. * The passed axis is also normalized.
  738. * Returns the AbstractMesh.
  739. */
  740. public rotate(axis: Vector3, amount: number, space?: Space): AbstractMesh {
  741. axis.normalize();
  742. if (!this.rotationQuaternion) {
  743. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  744. this.rotation = Vector3.Zero();
  745. }
  746. var rotationQuaternion: Quaternion;
  747. if (!space || (space as any) === Space.LOCAL) {
  748. rotationQuaternion = Quaternion.RotationAxisToRef(axis, amount, AbstractMesh._rotationAxisCache);
  749. this.rotationQuaternion.multiplyToRef(rotationQuaternion, this.rotationQuaternion);
  750. }
  751. else {
  752. if (this.parent) {
  753. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  754. invertParentWorldMatrix.invert();
  755. axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
  756. }
  757. rotationQuaternion = Quaternion.RotationAxisToRef(axis, amount, AbstractMesh._rotationAxisCache);
  758. rotationQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
  759. }
  760. return this;
  761. }
  762. /**
  763. * Rotates the mesh around the axis vector for the passed angle (amount) expressed in radians, in world space.
  764. * Note that the property `rotationQuaternion` is then automatically updated and the property `rotation` is set to (0,0,0) and no longer used.
  765. * The passed axis is also normalized.
  766. * Returns the AbstractMesh.
  767. * Method is based on http://www.euclideanspace.com/maths/geometry/affine/aroundPoint/index.htm
  768. */
  769. public rotateAround(point: Vector3, axis: Vector3, amount: number): AbstractMesh {
  770. axis.normalize();
  771. if (!this.rotationQuaternion) {
  772. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  773. this.rotation.copyFromFloats(0, 0, 0);
  774. }
  775. point.subtractToRef(this.position, Tmp.Vector3[0]);
  776. Matrix.TranslationToRef(Tmp.Vector3[0].x, Tmp.Vector3[0].y, Tmp.Vector3[0].z, Tmp.Matrix[0]);
  777. Tmp.Matrix[0].invertToRef(Tmp.Matrix[2]);
  778. Matrix.RotationAxisToRef(axis, amount, Tmp.Matrix[1]);
  779. Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[2]);
  780. Tmp.Matrix[2].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[2]);
  781. Tmp.Matrix[2].decompose(Tmp.Vector3[0], Tmp.Quaternion[0], Tmp.Vector3[1]);
  782. this.position.addInPlace(Tmp.Vector3[1]);
  783. Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
  784. return this;
  785. }
  786. /**
  787. * Translates the mesh along the axis vector for the passed distance in the given space.
  788. * space (default LOCAL) can be either BABYLON.Space.LOCAL, either BABYLON.Space.WORLD.
  789. * Returns the AbstractMesh.
  790. */
  791. public translate(axis: Vector3, distance: number, space?: Space): AbstractMesh {
  792. var displacementVector = axis.scale(distance);
  793. if (!space || (space as any) === Space.LOCAL) {
  794. var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
  795. this.setPositionWithLocalVector(tempV3);
  796. }
  797. else {
  798. this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
  799. }
  800. return this;
  801. }
  802. /**
  803. * Adds a rotation step to the mesh current rotation.
  804. * x, y, z are Euler angles expressed in radians.
  805. * This methods updates the current mesh rotation, either mesh.rotation, either mesh.rotationQuaternion if it's set.
  806. * This means this rotation is made in the mesh local space only.
  807. * It's useful to set a custom rotation order different from the BJS standard one YXZ.
  808. * Example : this rotates the mesh first around its local X axis, then around its local Z axis, finally around its local Y axis.
  809. * ```javascript
  810. * mesh.addRotation(x1, 0, 0).addRotation(0, 0, z2).addRotation(0, 0, y3);
  811. * ```
  812. * Note that `addRotation()` accumulates the passed rotation values to the current ones and computes the .rotation or .rotationQuaternion updated values.
  813. * Under the hood, only quaternions are used. So it's a little faster is you use .rotationQuaternion because it doesn't need to translate them back to Euler angles.
  814. * Returns the AbstractMesh.
  815. */
  816. public addRotation(x: number, y: number, z: number): AbstractMesh {
  817. var rotationQuaternion;
  818. if (this.rotationQuaternion) {
  819. rotationQuaternion = this.rotationQuaternion;
  820. }
  821. else {
  822. rotationQuaternion = Tmp.Quaternion[1];
  823. Quaternion.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, rotationQuaternion);
  824. }
  825. var accumulation = BABYLON.Tmp.Quaternion[0];
  826. Quaternion.RotationYawPitchRollToRef(y, x, z, accumulation);
  827. rotationQuaternion.multiplyInPlace(accumulation);
  828. if (!this.rotationQuaternion) {
  829. rotationQuaternion.toEulerAnglesToRef(this.rotation);
  830. }
  831. return this;
  832. }
  833. /**
  834. * Retuns the mesh absolute position in the World.
  835. * Returns a Vector3.
  836. */
  837. public getAbsolutePosition(): Vector3 {
  838. this.computeWorldMatrix();
  839. return this._absolutePosition;
  840. }
  841. /**
  842. * Sets the mesh absolute position in the World from a Vector3 or an Array(3).
  843. * Returns the AbstractMesh.
  844. */
  845. public setAbsolutePosition(absolutePosition: Vector3): AbstractMesh {
  846. if (!absolutePosition) {
  847. return this;
  848. }
  849. var absolutePositionX;
  850. var absolutePositionY;
  851. var absolutePositionZ;
  852. if (absolutePosition.x === undefined) {
  853. if (arguments.length < 3) {
  854. return this;
  855. }
  856. absolutePositionX = arguments[0];
  857. absolutePositionY = arguments[1];
  858. absolutePositionZ = arguments[2];
  859. }
  860. else {
  861. absolutePositionX = absolutePosition.x;
  862. absolutePositionY = absolutePosition.y;
  863. absolutePositionZ = absolutePosition.z;
  864. }
  865. if (this.parent) {
  866. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  867. invertParentWorldMatrix.invert();
  868. var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
  869. this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
  870. } else {
  871. this.position.x = absolutePositionX;
  872. this.position.y = absolutePositionY;
  873. this.position.z = absolutePositionZ;
  874. }
  875. return this;
  876. }
  877. // ================================== Point of View Movement =================================
  878. /**
  879. * Perform relative position change from the point of view of behind the front of the mesh.
  880. * This is performed taking into account the meshes current rotation, so you do not have to care.
  881. * Supports definition of mesh facing forward or backward.
  882. * @param {number} amountRight
  883. * @param {number} amountUp
  884. * @param {number} amountForward
  885. *
  886. * Returns the AbstractMesh.
  887. */
  888. public movePOV(amountRight: number, amountUp: number, amountForward: number): AbstractMesh {
  889. this.position.addInPlace(this.calcMovePOV(amountRight, amountUp, amountForward));
  890. return this;
  891. }
  892. /**
  893. * Calculate relative position change from the point of view of behind the front of the mesh.
  894. * This is performed taking into account the meshes current rotation, so you do not have to care.
  895. * Supports definition of mesh facing forward or backward.
  896. * @param {number} amountRight
  897. * @param {number} amountUp
  898. * @param {number} amountForward
  899. *
  900. * Returns a new Vector3.
  901. */
  902. public calcMovePOV(amountRight: number, amountUp: number, amountForward: number): Vector3 {
  903. var rotMatrix = new Matrix();
  904. var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  905. rotQuaternion.toRotationMatrix(rotMatrix);
  906. var translationDelta = Vector3.Zero();
  907. var defForwardMult = this.definedFacingForward ? -1 : 1;
  908. Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
  909. return translationDelta;
  910. }
  911. // ================================== Point of View Rotation =================================
  912. /**
  913. * Perform relative rotation change from the point of view of behind the front of the mesh.
  914. * Supports definition of mesh facing forward or backward.
  915. * @param {number} flipBack
  916. * @param {number} twirlClockwise
  917. * @param {number} tiltRight
  918. *
  919. * Returns the AbstractMesh.
  920. */
  921. public rotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): AbstractMesh {
  922. this.rotation.addInPlace(this.calcRotatePOV(flipBack, twirlClockwise, tiltRight));
  923. return this;
  924. }
  925. /**
  926. * Calculate relative rotation change from the point of view of behind the front of the mesh.
  927. * Supports definition of mesh facing forward or backward.
  928. * @param {number} flipBack
  929. * @param {number} twirlClockwise
  930. * @param {number} tiltRight
  931. *
  932. * Returns a new Vector3.
  933. */
  934. public calcRotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): Vector3 {
  935. var defForwardMult = this.definedFacingForward ? 1 : -1;
  936. return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
  937. }
  938. /**
  939. * Sets a new pivot matrix to the mesh.
  940. * Returns the AbstractMesh.
  941. */
  942. public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = false): AbstractMesh {
  943. this._pivotMatrix = matrix.clone();
  944. this._cache.pivotMatrixUpdated = true;
  945. this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
  946. if (this._postMultiplyPivotMatrix) {
  947. this._pivotMatrixInverse = Matrix.Invert(matrix);
  948. }
  949. return this;
  950. }
  951. /**
  952. * Returns the mesh pivot matrix.
  953. * Default : Identity.
  954. * A Matrix is returned.
  955. */
  956. public getPivotMatrix(): Matrix {
  957. return this._pivotMatrix;
  958. }
  959. public _isSynchronized(): boolean {
  960. if (this._isDirty) {
  961. return false;
  962. }
  963. if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE)
  964. return false;
  965. if (this._cache.pivotMatrixUpdated) {
  966. return false;
  967. }
  968. if (this.infiniteDistance) {
  969. return false;
  970. }
  971. if (!this._cache.position.equals(this.position))
  972. return false;
  973. if (this.rotationQuaternion) {
  974. if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
  975. return false;
  976. }
  977. if (!this._cache.rotation.equals(this.rotation))
  978. return false;
  979. if (!this._cache.scaling.equals(this.scaling))
  980. return false;
  981. return true;
  982. }
  983. public _initCache() {
  984. super._initCache();
  985. this._cache.localMatrixUpdated = false;
  986. this._cache.position = Vector3.Zero();
  987. this._cache.scaling = Vector3.Zero();
  988. this._cache.rotation = Vector3.Zero();
  989. this._cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
  990. this._cache.billboardMode = -1;
  991. }
  992. public markAsDirty(property: string): AbstractMesh {
  993. if (property === "rotation") {
  994. this.rotationQuaternion = null;
  995. }
  996. this._currentRenderId = Number.MAX_VALUE;
  997. this._isDirty = true;
  998. return this;
  999. }
  1000. /**
  1001. * Return the minimum and maximum world vectors of the entire hierarchy under current mesh
  1002. */
  1003. public getHierarchyBoundingVectors(): { min: Vector3, max: Vector3 }{
  1004. this.computeWorldMatrix(true);
  1005. let min: Vector3;
  1006. let max: Vector3;
  1007. if (!this.subMeshes) {
  1008. min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  1009. max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  1010. } else {
  1011. min = this.getBoundingInfo().boundingBox.minimumWorld;
  1012. max = this.getBoundingInfo().boundingBox.maximumWorld;
  1013. }
  1014. let descendants = this.getDescendants(false);
  1015. for (var descendant of descendants) {
  1016. let childMesh = <AbstractMesh>descendant;
  1017. childMesh.computeWorldMatrix(true);
  1018. if (childMesh.getTotalVertices() === 0) {
  1019. continue;
  1020. }
  1021. let boundingBox = childMesh.getBoundingInfo().boundingBox;
  1022. var minBox = boundingBox.minimumWorld;
  1023. var maxBox = boundingBox.maximumWorld;
  1024. Tools.CheckExtends(minBox, min, max);
  1025. Tools.CheckExtends(maxBox, min, max);
  1026. }
  1027. return {
  1028. min: min,
  1029. max: max
  1030. }
  1031. }
  1032. /**
  1033. * Updates the mesh BoundingInfo object and all its children BoundingInfo objects also.
  1034. * Returns the AbstractMesh.
  1035. */
  1036. public _updateBoundingInfo(): AbstractMesh {
  1037. this._boundingInfo = this._boundingInfo || new BoundingInfo(this.absolutePosition, this.absolutePosition);
  1038. this._boundingInfo.update(this.worldMatrixFromCache);
  1039. this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
  1040. return this;
  1041. }
  1042. /**
  1043. * Update a mesh's children BoundingInfo objects only.
  1044. * Returns the AbstractMesh.
  1045. */
  1046. public _updateSubMeshesBoundingInfo(matrix: Matrix): AbstractMesh {
  1047. if (!this.subMeshes) {
  1048. return this;
  1049. }
  1050. for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
  1051. var subMesh = this.subMeshes[subIndex];
  1052. if (!subMesh.IsGlobal) {
  1053. subMesh.updateBoundingInfo(matrix);
  1054. }
  1055. }
  1056. return this;
  1057. }
  1058. /**
  1059. * Computes the mesh World matrix and returns it.
  1060. * If the mesh world matrix is frozen, this computation does nothing more than returning the last frozen values.
  1061. * If the parameter `force` is let to `false` (default), the current cached World matrix is returned.
  1062. * If the parameter `force`is set to `true`, the actual computation is done.
  1063. * Returns the mesh World Matrix.
  1064. */
  1065. public computeWorldMatrix(force?: boolean): Matrix {
  1066. if (this._isWorldMatrixFrozen) {
  1067. return this._worldMatrix;
  1068. }
  1069. if (!force && this.isSynchronized(true)) {
  1070. this._currentRenderId = this.getScene().getRenderId();
  1071. return this._worldMatrix;
  1072. }
  1073. this._cache.position.copyFrom(this.position);
  1074. this._cache.scaling.copyFrom(this.scaling);
  1075. this._cache.pivotMatrixUpdated = false;
  1076. this._cache.billboardMode = this.billboardMode;
  1077. this._currentRenderId = this.getScene().getRenderId();
  1078. this._isDirty = false;
  1079. // Scaling
  1080. Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
  1081. // Rotation
  1082. //rotate, if quaternion is set and rotation was used
  1083. if (this.rotationQuaternion) {
  1084. var len = this.rotation.length();
  1085. if (len) {
  1086. this.rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z))
  1087. this.rotation.copyFromFloats(0, 0, 0);
  1088. }
  1089. }
  1090. if (this.rotationQuaternion) {
  1091. this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
  1092. this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
  1093. } else {
  1094. Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
  1095. this._cache.rotation.copyFrom(this.rotation);
  1096. }
  1097. // Translation
  1098. let camera = (<Camera>this.getScene().activeCamera);
  1099. if (this.infiniteDistance && !this.parent && camera) {
  1100. var cameraWorldMatrix = camera.getWorldMatrix();
  1101. var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
  1102. Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
  1103. this.position.z + cameraGlobalPosition.z, Tmp.Matrix[2]);
  1104. } else {
  1105. Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, Tmp.Matrix[2]);
  1106. }
  1107. // Composing transformations
  1108. this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
  1109. Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
  1110. // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
  1111. if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && camera) {
  1112. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
  1113. // Need to decompose each rotation here
  1114. var currentPosition = Tmp.Vector3[3];
  1115. if (this.parent && this.parent.getWorldMatrix) {
  1116. if (this._meshToBoneReferal) {
  1117. this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
  1118. Vector3.TransformCoordinatesToRef(this.position, Tmp.Matrix[6], currentPosition);
  1119. } else {
  1120. Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), currentPosition);
  1121. }
  1122. } else {
  1123. currentPosition.copyFrom(this.position);
  1124. }
  1125. currentPosition.subtractInPlace(camera.globalPosition);
  1126. var finalEuler = Tmp.Vector3[4].copyFromFloats(0, 0, 0);
  1127. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_X) === AbstractMesh.BILLBOARDMODE_X) {
  1128. finalEuler.x = Math.atan2(-currentPosition.y, currentPosition.z);
  1129. }
  1130. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Y) === AbstractMesh.BILLBOARDMODE_Y) {
  1131. finalEuler.y = Math.atan2(currentPosition.x, currentPosition.z);
  1132. }
  1133. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Z) === AbstractMesh.BILLBOARDMODE_Z) {
  1134. finalEuler.z = Math.atan2(currentPosition.y, currentPosition.x);
  1135. }
  1136. Matrix.RotationYawPitchRollToRef(finalEuler.y, finalEuler.x, finalEuler.z, Tmp.Matrix[0]);
  1137. } else {
  1138. Tmp.Matrix[1].copyFrom(camera.getViewMatrix());
  1139. Tmp.Matrix[1].setTranslationFromFloats(0, 0, 0);
  1140. Tmp.Matrix[1].invertToRef(Tmp.Matrix[0]);
  1141. }
  1142. Tmp.Matrix[1].copyFrom(Tmp.Matrix[5]);
  1143. Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
  1144. }
  1145. // Local world
  1146. Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localWorld);
  1147. // Parent
  1148. if (this.parent && this.parent.getWorldMatrix) {
  1149. if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
  1150. if (this._meshToBoneReferal) {
  1151. this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
  1152. Tmp.Matrix[5].copyFrom(Tmp.Matrix[6]);
  1153. } else {
  1154. Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
  1155. }
  1156. this._localWorld.getTranslationToRef(Tmp.Vector3[5]);
  1157. Vector3.TransformCoordinatesToRef(Tmp.Vector3[5], Tmp.Matrix[5], Tmp.Vector3[5]);
  1158. this._worldMatrix.copyFrom(this._localWorld);
  1159. this._worldMatrix.setTranslation(Tmp.Vector3[5]);
  1160. } else {
  1161. if (this._meshToBoneReferal) {
  1162. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
  1163. Tmp.Matrix[6].multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), this._worldMatrix);
  1164. } else {
  1165. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
  1166. }
  1167. }
  1168. this._markSyncedWithParent();
  1169. } else {
  1170. this._worldMatrix.copyFrom(this._localWorld);
  1171. }
  1172. // Post multiply inverse of pivotMatrix
  1173. if (this._postMultiplyPivotMatrix) {
  1174. this._worldMatrix.multiplyToRef(this._pivotMatrixInverse, this._worldMatrix);
  1175. }
  1176. // Bounding info
  1177. this._updateBoundingInfo();
  1178. // Absolute position
  1179. this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
  1180. // Callbacks
  1181. this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
  1182. if (!this._poseMatrix) {
  1183. this._poseMatrix = Matrix.Invert(this._worldMatrix);
  1184. }
  1185. return this._worldMatrix;
  1186. }
  1187. /**
  1188. * If you'd like to be called back after the mesh position, rotation or scaling has been updated.
  1189. * @param func: callback function to add
  1190. *
  1191. * Returns the AbstractMesh.
  1192. */
  1193. public registerAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): AbstractMesh {
  1194. this.onAfterWorldMatrixUpdateObservable.add(func);
  1195. return this;
  1196. }
  1197. /**
  1198. * Removes a registered callback function.
  1199. * Returns the AbstractMesh.
  1200. */
  1201. public unregisterAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): AbstractMesh {
  1202. this.onAfterWorldMatrixUpdateObservable.removeCallback(func);
  1203. return this;
  1204. }
  1205. /**
  1206. * Sets the mesh position in its local space.
  1207. * Returns the AbstractMesh.
  1208. */
  1209. public setPositionWithLocalVector(vector3: Vector3): AbstractMesh {
  1210. this.computeWorldMatrix();
  1211. this.position = Vector3.TransformNormal(vector3, this._localWorld);
  1212. return this;
  1213. }
  1214. /**
  1215. * Returns the mesh position in the local space from the current World matrix values.
  1216. * Returns a new Vector3.
  1217. */
  1218. public getPositionExpressedInLocalSpace(): Vector3 {
  1219. this.computeWorldMatrix();
  1220. var invLocalWorldMatrix = this._localWorld.clone();
  1221. invLocalWorldMatrix.invert();
  1222. return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
  1223. }
  1224. /**
  1225. * Translates the mesh along the passed Vector3 in its local space.
  1226. * Returns the AbstractMesh.
  1227. */
  1228. public locallyTranslate(vector3: Vector3): AbstractMesh {
  1229. this.computeWorldMatrix(true);
  1230. this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
  1231. return this;
  1232. }
  1233. private static _lookAtVectorCache = new Vector3(0, 0, 0);
  1234. public lookAt(targetPoint: Vector3, yawCor: number = 0, pitchCor: number = 0, rollCor: number = 0, space: Space = Space.LOCAL): AbstractMesh {
  1235. /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
  1236. /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
  1237. /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
  1238. /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
  1239. /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
  1240. /// <returns>Mesh oriented towards targetMesh</returns>
  1241. var dv = AbstractMesh._lookAtVectorCache;
  1242. var pos = space === Space.LOCAL ? this.position : this.getAbsolutePosition();
  1243. targetPoint.subtractToRef(pos, dv);
  1244. var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
  1245. var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
  1246. var pitch = Math.atan2(dv.y, len);
  1247. this.rotationQuaternion = this.rotationQuaternion || new Quaternion();
  1248. Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
  1249. return this;
  1250. }
  1251. public attachToBone(bone: Bone, affectedMesh: AbstractMesh): AbstractMesh {
  1252. this._meshToBoneReferal = affectedMesh;
  1253. this.parent = bone;
  1254. if (bone.getWorldMatrix().determinant() < 0) {
  1255. this.scalingDeterminant *= -1;
  1256. }
  1257. return this;
  1258. }
  1259. public detachFromBone(): AbstractMesh {
  1260. if (!this.parent) {
  1261. return this;
  1262. }
  1263. if (this.parent.getWorldMatrix().determinant() < 0) {
  1264. this.scalingDeterminant *= -1;
  1265. }
  1266. this._meshToBoneReferal = null;
  1267. this.parent = null;
  1268. return this;
  1269. }
  1270. /**
  1271. * Returns `true` if the mesh is within the frustum defined by the passed array of planes.
  1272. * A mesh is in the frustum if its bounding box intersects the frustum.
  1273. * Boolean returned.
  1274. */
  1275. public isInFrustum(frustumPlanes: Plane[]): boolean {
  1276. return this._boundingInfo.isInFrustum(frustumPlanes);
  1277. }
  1278. /**
  1279. * Returns `true` if the mesh is completely in the frustum defined be the passed array of planes.
  1280. * A mesh is completely in the frustum if its bounding box it completely inside the frustum.
  1281. * Boolean returned.
  1282. */
  1283. public isCompletelyInFrustum(frustumPlanes: Plane[]): boolean {
  1284. return this._boundingInfo.isCompletelyInFrustum(frustumPlanes);;
  1285. }
  1286. /**
  1287. * True if the mesh intersects another mesh or a SolidParticle object.
  1288. * 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)
  1289. * includeDescendants can be set to true to test if the mesh defined in parameters intersects with the current mesh or any child meshes
  1290. * Returns a boolean.
  1291. */
  1292. public intersectsMesh(mesh: AbstractMesh | SolidParticle, precise: boolean = false, includeDescendants?: boolean): boolean {
  1293. if (!this._boundingInfo || !mesh._boundingInfo) {
  1294. return false;
  1295. }
  1296. if (this._boundingInfo.intersects(mesh._boundingInfo, precise)) {
  1297. return true;
  1298. }
  1299. if (includeDescendants) {
  1300. for (var child of this.getChildMeshes()) {
  1301. if (child.intersectsMesh(mesh, precise, true)) {
  1302. return true;
  1303. }
  1304. }
  1305. }
  1306. return false;
  1307. }
  1308. /**
  1309. * Returns true if the passed point (Vector3) is inside the mesh bounding box.
  1310. * Returns a boolean.
  1311. */
  1312. public intersectsPoint(point: Vector3): boolean {
  1313. if (!this._boundingInfo) {
  1314. return false;
  1315. }
  1316. return this._boundingInfo.intersectsPoint(point);
  1317. }
  1318. public getPhysicsImpostor(): Nullable<PhysicsImpostor> {
  1319. return this.physicsImpostor;
  1320. }
  1321. public getPositionInCameraSpace(camera: Nullable<Camera> = null): Vector3 {
  1322. if (!camera) {
  1323. camera = (<Camera>this.getScene().activeCamera);
  1324. }
  1325. return Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
  1326. }
  1327. /**
  1328. * Returns the distance from the mesh to the active camera.
  1329. * Returns a float.
  1330. */
  1331. public getDistanceToCamera(camera: Nullable<Camera> = null): number {
  1332. if (!camera) {
  1333. camera = (<Camera>this.getScene().activeCamera);
  1334. }
  1335. return this.absolutePosition.subtract(camera.position).length();
  1336. }
  1337. public applyImpulse(force: Vector3, contactPoint: Vector3): AbstractMesh {
  1338. if (!this.physicsImpostor) {
  1339. return this;
  1340. }
  1341. this.physicsImpostor.applyImpulse(force, contactPoint);
  1342. return this;
  1343. }
  1344. public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): AbstractMesh {
  1345. if (!this.physicsImpostor || !otherMesh.physicsImpostor) {
  1346. return this;
  1347. }
  1348. this.physicsImpostor.createJoint(otherMesh.physicsImpostor, PhysicsJoint.HingeJoint, {
  1349. mainPivot: pivot1,
  1350. connectedPivot: pivot2,
  1351. nativeParams: options
  1352. });
  1353. return this;
  1354. }
  1355. // Collisions
  1356. /**
  1357. * Property checkCollisions : Boolean, whether the camera should check the collisions against the mesh.
  1358. * Default `false`.
  1359. */
  1360. public get checkCollisions(): boolean {
  1361. return this._checkCollisions;
  1362. }
  1363. public set checkCollisions(collisionEnabled: boolean) {
  1364. this._checkCollisions = collisionEnabled;
  1365. if (this.getScene().workerCollisions) {
  1366. this.getScene().collisionCoordinator.onMeshUpdated(this);
  1367. }
  1368. }
  1369. public moveWithCollisions(displacement: Vector3): AbstractMesh {
  1370. var globalPosition = this.getAbsolutePosition();
  1371. globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
  1372. this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
  1373. if (!this._collider) {
  1374. this._collider = new Collider();
  1375. }
  1376. this._collider.radius = this.ellipsoid;
  1377. this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, displacement, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
  1378. return this;
  1379. }
  1380. private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
  1381. //TODO move this to the collision coordinator!
  1382. if (this.getScene().workerCollisions)
  1383. newPosition.multiplyInPlace(this._collider.radius);
  1384. newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
  1385. if (this._diffPositionForCollisions.length() > Engine.CollisionsEpsilon) {
  1386. this.position.addInPlace(this._diffPositionForCollisions);
  1387. }
  1388. if (collidedMesh) {
  1389. this.onCollideObservable.notifyObservers(collidedMesh);
  1390. }
  1391. this.onCollisionPositionChangeObservable.notifyObservers(this.position);
  1392. }
  1393. // Submeshes octree
  1394. /**
  1395. * This function will create an octree to help to select the right submeshes for rendering, picking and collision computations.
  1396. * Please note that you must have a decent number of submeshes to get performance improvements when using an octree.
  1397. * Returns an Octree of submeshes.
  1398. */
  1399. public createOrUpdateSubmeshesOctree(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
  1400. if (!this._submeshesOctree) {
  1401. this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
  1402. }
  1403. this.computeWorldMatrix(true);
  1404. // Update octree
  1405. var bbox = this.getBoundingInfo().boundingBox;
  1406. this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
  1407. return this._submeshesOctree;
  1408. }
  1409. // Collisions
  1410. public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): AbstractMesh {
  1411. this._generatePointsArray();
  1412. if (!this._positions) {
  1413. return this;
  1414. }
  1415. // Transformation
  1416. if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
  1417. subMesh._lastColliderTransformMatrix = transformMatrix.clone();
  1418. subMesh._lastColliderWorldVertices = [];
  1419. subMesh._trianglePlanes = [];
  1420. var start = subMesh.verticesStart;
  1421. var end = (subMesh.verticesStart + subMesh.verticesCount);
  1422. for (var i = start; i < end; i++) {
  1423. subMesh._lastColliderWorldVertices.push(Vector3.TransformCoordinates(this._positions[i], transformMatrix));
  1424. }
  1425. }
  1426. // Collide
  1427. collider._collide(subMesh._trianglePlanes, subMesh._lastColliderWorldVertices, (<IndicesArray>this.getIndices()), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, !!subMesh.getMaterial());
  1428. if (collider.collisionFound) {
  1429. collider.collidedMesh = this;
  1430. }
  1431. return this;
  1432. }
  1433. public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): AbstractMesh {
  1434. var subMeshes: SubMesh[];
  1435. var len: number;
  1436. // Octrees
  1437. if (this._submeshesOctree && this.useOctreeForCollisions) {
  1438. var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
  1439. var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
  1440. len = intersections.length;
  1441. subMeshes = intersections.data;
  1442. } else {
  1443. subMeshes = this.subMeshes;
  1444. len = subMeshes.length;
  1445. }
  1446. for (var index = 0; index < len; index++) {
  1447. var subMesh = subMeshes[index];
  1448. // Bounding test
  1449. if (len > 1 && !subMesh._checkCollision(collider))
  1450. continue;
  1451. this._collideForSubMesh(subMesh, transformMatrix, collider);
  1452. }
  1453. return this;
  1454. }
  1455. public _checkCollision(collider: Collider): AbstractMesh {
  1456. // Bounding box test
  1457. if (!this._boundingInfo._checkCollision(collider))
  1458. return this;
  1459. // Transformation matrix
  1460. Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
  1461. this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
  1462. this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
  1463. return this;
  1464. }
  1465. // Picking
  1466. public _generatePointsArray(): boolean {
  1467. return false;
  1468. }
  1469. /**
  1470. * Checks if the passed Ray intersects with the mesh.
  1471. * Returns an object PickingInfo.
  1472. */
  1473. public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
  1474. var pickingInfo = new PickingInfo();
  1475. if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
  1476. return pickingInfo;
  1477. }
  1478. if (!this._generatePointsArray()) {
  1479. return pickingInfo;
  1480. }
  1481. var intersectInfo: Nullable<IntersectionInfo> = null;
  1482. // Octrees
  1483. var subMeshes: SubMesh[];
  1484. var len: number;
  1485. if (this._submeshesOctree && this.useOctreeForPicking) {
  1486. var worldRay = Ray.Transform(ray, this.getWorldMatrix());
  1487. var intersections = this._submeshesOctree.intersectsRay(worldRay);
  1488. len = intersections.length;
  1489. subMeshes = intersections.data;
  1490. } else {
  1491. subMeshes = this.subMeshes;
  1492. len = subMeshes.length;
  1493. }
  1494. for (var index = 0; index < len; index++) {
  1495. var subMesh = subMeshes[index];
  1496. // Bounding test
  1497. if (len > 1 && !subMesh.canIntersects(ray))
  1498. continue;
  1499. var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions), (<IndicesArray>this.getIndices()), fastCheck);
  1500. if (currentIntersectInfo) {
  1501. if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
  1502. intersectInfo = currentIntersectInfo;
  1503. intersectInfo.subMeshId = index;
  1504. if (fastCheck) {
  1505. break;
  1506. }
  1507. }
  1508. }
  1509. }
  1510. if (intersectInfo) {
  1511. // Get picked point
  1512. var world = this.getWorldMatrix();
  1513. var worldOrigin = Vector3.TransformCoordinates(ray.origin, world);
  1514. var direction = ray.direction.clone();
  1515. direction = direction.scale(intersectInfo.distance);
  1516. var worldDirection = Vector3.TransformNormal(direction, world);
  1517. var pickedPoint = worldOrigin.add(worldDirection);
  1518. // Return result
  1519. pickingInfo.hit = true;
  1520. pickingInfo.distance = Vector3.Distance(worldOrigin, pickedPoint);
  1521. pickingInfo.pickedPoint = pickedPoint;
  1522. pickingInfo.pickedMesh = this;
  1523. pickingInfo.bu = intersectInfo.bu || 0;
  1524. pickingInfo.bv = intersectInfo.bv || 0;
  1525. pickingInfo.faceId = intersectInfo.faceId;
  1526. pickingInfo.subMeshId = intersectInfo.subMeshId;
  1527. return pickingInfo;
  1528. }
  1529. return pickingInfo;
  1530. }
  1531. /**
  1532. * Clones the mesh, used by the class Mesh.
  1533. * Just returns `null` for an AbstractMesh.
  1534. */
  1535. public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): Nullable<AbstractMesh> {
  1536. return null;
  1537. }
  1538. /**
  1539. * Disposes all the mesh submeshes.
  1540. * Returns the AbstractMesh.
  1541. */
  1542. public releaseSubMeshes(): AbstractMesh {
  1543. if (this.subMeshes) {
  1544. while (this.subMeshes.length) {
  1545. this.subMeshes[0].dispose();
  1546. }
  1547. } else {
  1548. this.subMeshes = new Array<SubMesh>();
  1549. }
  1550. return this;
  1551. }
  1552. /**
  1553. * Disposes the AbstractMesh.
  1554. * Some internal references are kept for further use.
  1555. * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.
  1556. * Returns nothing.
  1557. */
  1558. public dispose(doNotRecurse?: boolean): void {
  1559. var index: number;
  1560. // Action manager
  1561. if (this.actionManager) {
  1562. this.actionManager.dispose();
  1563. this.actionManager = null;
  1564. }
  1565. // Skeleton
  1566. this.skeleton = null;
  1567. // Animations
  1568. this.getScene().stopAnimation(this);
  1569. // Physics
  1570. if (this.physicsImpostor) {
  1571. this.physicsImpostor.dispose(/*!doNotRecurse*/);
  1572. }
  1573. // Intersections in progress
  1574. for (index = 0; index < this._intersectionsInProgress.length; index++) {
  1575. var other = this._intersectionsInProgress[index];
  1576. var pos = other._intersectionsInProgress.indexOf(this);
  1577. other._intersectionsInProgress.splice(pos, 1);
  1578. }
  1579. this._intersectionsInProgress = [];
  1580. // Lights
  1581. var lights = this.getScene().lights;
  1582. lights.forEach((light: Light) => {
  1583. var meshIndex = light.includedOnlyMeshes.indexOf(this);
  1584. if (meshIndex !== -1) {
  1585. light.includedOnlyMeshes.splice(meshIndex, 1);
  1586. }
  1587. meshIndex = light.excludedMeshes.indexOf(this);
  1588. if (meshIndex !== -1) {
  1589. light.excludedMeshes.splice(meshIndex, 1);
  1590. }
  1591. // Shadow generators
  1592. var generator = light.getShadowGenerator();
  1593. if (generator) {
  1594. var shadowMap = generator.getShadowMap();
  1595. if (shadowMap && shadowMap.renderList) {
  1596. meshIndex = shadowMap.renderList.indexOf(this);
  1597. if (meshIndex !== -1) {
  1598. shadowMap.renderList.splice(meshIndex, 1);
  1599. }
  1600. }
  1601. }
  1602. });
  1603. // Edges
  1604. if (this._edgesRenderer) {
  1605. this._edgesRenderer.dispose();
  1606. this._edgesRenderer = null;
  1607. }
  1608. // SubMeshes
  1609. if (this.getClassName() !== "InstancedMesh") {
  1610. this.releaseSubMeshes();
  1611. }
  1612. // Octree
  1613. var sceneOctree = this.getScene().selectionOctree;
  1614. if (sceneOctree) {
  1615. var index = sceneOctree.dynamicContent.indexOf(this);
  1616. if (index !== -1) {
  1617. sceneOctree.dynamicContent.splice(index, 1);
  1618. }
  1619. }
  1620. // Query
  1621. let engine = this.getScene().getEngine();
  1622. if (this._occlusionQuery) {
  1623. this._isOcclusionQueryInProgress = false;
  1624. engine.deleteQuery(this._occlusionQuery);
  1625. this._occlusionQuery = null;
  1626. }
  1627. // Engine
  1628. engine.wipeCaches();
  1629. // Remove from scene
  1630. this.getScene().removeMesh(this);
  1631. if (!doNotRecurse) {
  1632. // Particles
  1633. for (index = 0; index < this.getScene().particleSystems.length; index++) {
  1634. if (this.getScene().particleSystems[index].emitter === this) {
  1635. this.getScene().particleSystems[index].dispose();
  1636. index--;
  1637. }
  1638. }
  1639. // Children
  1640. var objects = this.getDescendants(true);
  1641. for (index = 0; index < objects.length; index++) {
  1642. objects[index].dispose();
  1643. }
  1644. } else {
  1645. var childMeshes = this.getChildMeshes(true);
  1646. for (index = 0; index < childMeshes.length; index++) {
  1647. var child = childMeshes[index];
  1648. child.parent = null;
  1649. child.computeWorldMatrix(true);
  1650. }
  1651. }
  1652. // facet data
  1653. if (this._facetDataEnabled) {
  1654. this.disableFacetData();
  1655. }
  1656. this.onAfterWorldMatrixUpdateObservable.clear();
  1657. this.onCollideObservable.clear();
  1658. this.onCollisionPositionChangeObservable.clear();
  1659. this._isDisposed = true;
  1660. super.dispose();
  1661. }
  1662. /**
  1663. * Returns a new Vector3 what is the localAxis, expressed in the mesh local space, rotated like the mesh.
  1664. * This Vector3 is expressed in the World space.
  1665. */
  1666. public getDirection(localAxis: Vector3): Vector3 {
  1667. var result = Vector3.Zero();
  1668. this.getDirectionToRef(localAxis, result);
  1669. return result;
  1670. }
  1671. /**
  1672. * Sets the Vector3 "result" as the rotated Vector3 "localAxis" in the same rotation than the mesh.
  1673. * localAxis is expressed in the mesh local space.
  1674. * result is computed in the Wordl space from the mesh World matrix.
  1675. * Returns the AbstractMesh.
  1676. */
  1677. public getDirectionToRef(localAxis: Vector3, result: Vector3): AbstractMesh {
  1678. Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
  1679. return this;
  1680. }
  1681. public setPivotPoint(point: Vector3, space: Space = Space.LOCAL): AbstractMesh {
  1682. if (this.getScene().getRenderId() == 0) {
  1683. this.computeWorldMatrix(true);
  1684. }
  1685. var wm = this.getWorldMatrix();
  1686. if (space == Space.WORLD) {
  1687. var tmat = Tmp.Matrix[0];
  1688. wm.invertToRef(tmat);
  1689. point = Vector3.TransformCoordinates(point, tmat);
  1690. }
  1691. Vector3.TransformCoordinatesToRef(point, wm, this.position);
  1692. this._pivotMatrix.m[12] = -point.x;
  1693. this._pivotMatrix.m[13] = -point.y;
  1694. this._pivotMatrix.m[14] = -point.z;
  1695. this._cache.pivotMatrixUpdated = true;
  1696. return this;
  1697. }
  1698. /**
  1699. * Returns a new Vector3 set with the mesh pivot point coordinates in the local space.
  1700. */
  1701. public getPivotPoint(): Vector3 {
  1702. var point = Vector3.Zero();
  1703. this.getPivotPointToRef(point);
  1704. return point;
  1705. }
  1706. /**
  1707. * Sets the passed Vector3 "result" with the coordinates of the mesh pivot point in the local space.
  1708. * Returns the AbstractMesh.
  1709. */
  1710. public getPivotPointToRef(result: Vector3): AbstractMesh {
  1711. result.x = -this._pivotMatrix.m[12];
  1712. result.y = -this._pivotMatrix.m[13];
  1713. result.z = -this._pivotMatrix.m[14];
  1714. return this;
  1715. }
  1716. /**
  1717. * Returns a new Vector3 set with the mesh pivot point World coordinates.
  1718. */
  1719. public getAbsolutePivotPoint(): Vector3 {
  1720. var point = Vector3.Zero();
  1721. this.getAbsolutePivotPointToRef(point);
  1722. return point;
  1723. }
  1724. /**
  1725. * Defines the passed mesh as the parent of the current mesh.
  1726. * Returns the AbstractMesh.
  1727. */
  1728. public setParent(mesh: Nullable<AbstractMesh>): AbstractMesh {
  1729. var child = this;
  1730. var parent = (<AbstractMesh>mesh);
  1731. if (mesh == null) {
  1732. var rotation = Tmp.Quaternion[0];
  1733. var position = Tmp.Vector3[0];
  1734. var scale = Tmp.Vector3[1];
  1735. child.getWorldMatrix().decompose(scale, rotation, position);
  1736. if (child.rotationQuaternion) {
  1737. child.rotationQuaternion.copyFrom(rotation);
  1738. } else {
  1739. rotation.toEulerAnglesToRef(child.rotation);
  1740. }
  1741. child.position.x = position.x;
  1742. child.position.y = position.y;
  1743. child.position.z = position.z;
  1744. } else {
  1745. var position = Tmp.Vector3[0];
  1746. var m1 = Tmp.Matrix[0];
  1747. parent.getWorldMatrix().invertToRef(m1);
  1748. Vector3.TransformCoordinatesToRef(child.position, m1, position);
  1749. child.position.copyFrom(position);
  1750. }
  1751. child.parent = parent;
  1752. return this;
  1753. }
  1754. /**
  1755. * Adds the passed mesh as a child to the current mesh.
  1756. * Returns the AbstractMesh.
  1757. */
  1758. public addChild(mesh: AbstractMesh): AbstractMesh {
  1759. mesh.setParent(this);
  1760. return this;
  1761. }
  1762. /**
  1763. * Removes the passed mesh from the current mesh children list.
  1764. * Returns the AbstractMesh.
  1765. */
  1766. public removeChild(mesh: AbstractMesh): AbstractMesh {
  1767. mesh.setParent(null);
  1768. return this;
  1769. }
  1770. /**
  1771. * Sets the Vector3 "result" coordinates with the mesh pivot point World coordinates.
  1772. * Returns the AbstractMesh.
  1773. */
  1774. public getAbsolutePivotPointToRef(result: Vector3): AbstractMesh {
  1775. result.x = this._pivotMatrix.m[12];
  1776. result.y = this._pivotMatrix.m[13];
  1777. result.z = this._pivotMatrix.m[14];
  1778. this.getPivotPointToRef(result);
  1779. Vector3.TransformCoordinatesToRef(result, this.getWorldMatrix(), result);
  1780. return this;
  1781. }
  1782. // Facet data
  1783. /**
  1784. * Initialize the facet data arrays : facetNormals, facetPositions and facetPartitioning.
  1785. * Returns the AbstractMesh.
  1786. */
  1787. private _initFacetData(): AbstractMesh {
  1788. if (!this._facetNormals) {
  1789. this._facetNormals = new Array<Vector3>();
  1790. }
  1791. if (!this._facetPositions) {
  1792. this._facetPositions = new Array<Vector3>();
  1793. }
  1794. if (!this._facetPartitioning) {
  1795. this._facetPartitioning = new Array<number[]>();
  1796. }
  1797. this._facetNb = (<IndicesArray>this.getIndices()).length / 3;
  1798. this._partitioningSubdivisions = (this._partitioningSubdivisions) ? this._partitioningSubdivisions : 10; // default nb of partitioning subdivisions = 10
  1799. this._partitioningBBoxRatio = (this._partitioningBBoxRatio) ? this._partitioningBBoxRatio : 1.01; // default ratio 1.01 = the partitioning is 1% bigger than the bounding box
  1800. for (var f = 0; f < this._facetNb; f++) {
  1801. this._facetNormals[f] = Vector3.Zero();
  1802. this._facetPositions[f] = Vector3.Zero();
  1803. }
  1804. this._facetDataEnabled = true;
  1805. return this;
  1806. }
  1807. /**
  1808. * Updates the mesh facetData arrays and the internal partitioning when the mesh is morphed or updated.
  1809. * This method can be called within the render loop.
  1810. * 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.
  1811. * Returns the AbstractMesh.
  1812. */
  1813. public updateFacetData(): AbstractMesh {
  1814. if (!this._facetDataEnabled) {
  1815. this._initFacetData();
  1816. }
  1817. var positions = this.getVerticesData(VertexBuffer.PositionKind);
  1818. var indices = this.getIndices();
  1819. var normals = this.getVerticesData(VertexBuffer.NormalKind);
  1820. var bInfo = this.getBoundingInfo();
  1821. this._bbSize.x = (bInfo.maximum.x - bInfo.minimum.x > Epsilon) ? bInfo.maximum.x - bInfo.minimum.x : Epsilon;
  1822. this._bbSize.y = (bInfo.maximum.y - bInfo.minimum.y > Epsilon) ? bInfo.maximum.y - bInfo.minimum.y : Epsilon;
  1823. this._bbSize.z = (bInfo.maximum.z - bInfo.minimum.z > Epsilon) ? bInfo.maximum.z - bInfo.minimum.z : Epsilon;
  1824. var bbSizeMax = (this._bbSize.x > this._bbSize.y) ? this._bbSize.x : this._bbSize.y;
  1825. bbSizeMax = (bbSizeMax > this._bbSize.z) ? bbSizeMax : this._bbSize.z;
  1826. this._subDiv.max = this._partitioningSubdivisions;
  1827. this._subDiv.X = Math.floor(this._subDiv.max * this._bbSize.x / bbSizeMax); // adjust the number of subdivisions per axis
  1828. this._subDiv.Y = Math.floor(this._subDiv.max * this._bbSize.y / bbSizeMax); // according to each bbox size per axis
  1829. this._subDiv.Z = Math.floor(this._subDiv.max * this._bbSize.z / bbSizeMax);
  1830. this._subDiv.X = this._subDiv.X < 1 ? 1 : this._subDiv.X; // at least one subdivision
  1831. this._subDiv.Y = this._subDiv.Y < 1 ? 1 : this._subDiv.Y;
  1832. this._subDiv.Z = this._subDiv.Z < 1 ? 1 : this._subDiv.Z;
  1833. // set the parameters for ComputeNormals()
  1834. this._facetParameters.facetNormals = this.getFacetLocalNormals();
  1835. this._facetParameters.facetPositions = this.getFacetLocalPositions();
  1836. this._facetParameters.facetPartitioning = this.getFacetLocalPartitioning();
  1837. this._facetParameters.bInfo = bInfo;
  1838. this._facetParameters.bbSize = this._bbSize;
  1839. this._facetParameters.subDiv = this._subDiv;
  1840. this._facetParameters.ratio = this.partitioningBBoxRatio;
  1841. VertexData.ComputeNormals(positions, indices, normals, this._facetParameters);
  1842. return this;
  1843. }
  1844. /**
  1845. * Returns the facetLocalNormals array.
  1846. * The normals are expressed in the mesh local space.
  1847. */
  1848. public getFacetLocalNormals(): Vector3[] {
  1849. if (!this._facetNormals) {
  1850. this.updateFacetData();
  1851. }
  1852. return this._facetNormals;
  1853. }
  1854. /**
  1855. * Returns the facetLocalPositions array.
  1856. * The facet positions are expressed in the mesh local space.
  1857. */
  1858. public getFacetLocalPositions(): Vector3[] {
  1859. if (!this._facetPositions) {
  1860. this.updateFacetData();
  1861. }
  1862. return this._facetPositions;
  1863. }
  1864. /**
  1865. * Returns the facetLocalPartioning array.
  1866. */
  1867. public getFacetLocalPartitioning(): number[][] {
  1868. if (!this._facetPartitioning) {
  1869. this.updateFacetData();
  1870. }
  1871. return this._facetPartitioning;
  1872. }
  1873. /**
  1874. * Returns the i-th facet position in the world system.
  1875. * This method allocates a new Vector3 per call.
  1876. */
  1877. public getFacetPosition(i: number): Vector3 {
  1878. var pos = Vector3.Zero();
  1879. this.getFacetPositionToRef(i, pos);
  1880. return pos;
  1881. }
  1882. /**
  1883. * Sets the reference Vector3 with the i-th facet position in the world system.
  1884. * Returns the AbstractMesh.
  1885. */
  1886. public getFacetPositionToRef(i: number, ref: Vector3): AbstractMesh {
  1887. var localPos = (this.getFacetLocalPositions())[i];
  1888. var world = this.getWorldMatrix();
  1889. Vector3.TransformCoordinatesToRef(localPos, world, ref);
  1890. return this;
  1891. }
  1892. /**
  1893. * Returns the i-th facet normal in the world system.
  1894. * This method allocates a new Vector3 per call.
  1895. */
  1896. public getFacetNormal(i: number): Vector3 {
  1897. var norm = Vector3.Zero();
  1898. this.getFacetNormalToRef(i, norm);
  1899. return norm;
  1900. }
  1901. /**
  1902. * Sets the reference Vector3 with the i-th facet normal in the world system.
  1903. * Returns the AbstractMesh.
  1904. */
  1905. public getFacetNormalToRef(i: number, ref: Vector3) {
  1906. var localNorm = (this.getFacetLocalNormals())[i];
  1907. Vector3.TransformNormalToRef(localNorm, this.getWorldMatrix(), ref);
  1908. return this;
  1909. }
  1910. /**
  1911. * 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).
  1912. */
  1913. public getFacetsAtLocalCoordinates(x: number, y: number, z: number): Nullable<number[]> {
  1914. var bInfo = this.getBoundingInfo();
  1915. var ox = Math.floor((x - bInfo.minimum.x * this._partitioningBBoxRatio) * this._subDiv.X * this._partitioningBBoxRatio / this._bbSize.x);
  1916. var oy = Math.floor((y - bInfo.minimum.y * this._partitioningBBoxRatio) * this._subDiv.Y * this._partitioningBBoxRatio / this._bbSize.y);
  1917. var oz = Math.floor((z - bInfo.minimum.z * this._partitioningBBoxRatio) * this._subDiv.Z * this._partitioningBBoxRatio / this._bbSize.z);
  1918. if (ox < 0 || ox > this._subDiv.max || oy < 0 || oy > this._subDiv.max || oz < 0 || oz > this._subDiv.max) {
  1919. return null;
  1920. }
  1921. return this._facetPartitioning[ox + this._subDiv.max * oy + this._subDiv.max * this._subDiv.max * oz];
  1922. }
  1923. /**
  1924. * Returns the closest mesh facet index at (x,y,z) World coordinates, null if not found.
  1925. * If the parameter projected (vector3) is passed, it is set as the (x,y,z) World projection on the facet.
  1926. * If checkFace is 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.
  1927. * If facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position.
  1928. * 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.
  1929. */
  1930. public getClosestFacetAtCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true): Nullable<number> {
  1931. var world = this.getWorldMatrix();
  1932. var invMat = Tmp.Matrix[5];
  1933. world.invertToRef(invMat);
  1934. var invVect = Tmp.Vector3[8];
  1935. Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, invMat, invVect); // transform (x,y,z) to coordinates in the mesh local space
  1936. var closest = this.getClosestFacetAtLocalCoordinates(invVect.x, invVect.y, invVect.z, projected, checkFace, facing);
  1937. if (projected) {
  1938. // tranform the local computed projected vector to world coordinates
  1939. Vector3.TransformCoordinatesFromFloatsToRef(projected.x, projected.y, projected.z, world, projected);
  1940. }
  1941. return closest;
  1942. }
  1943. /**
  1944. * Returns the closest mesh facet index at (x,y,z) local coordinates, null if not found.
  1945. * If the parameter projected (vector3) is passed, it is set as the (x,y,z) local projection on the facet.
  1946. * If checkFace is 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.
  1947. * If facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position.
  1948. * 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.
  1949. */
  1950. public getClosestFacetAtLocalCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true): Nullable<number> {
  1951. var closest = null;
  1952. var tmpx = 0.0;
  1953. var tmpy = 0.0;
  1954. var tmpz = 0.0;
  1955. var d = 0.0; // tmp dot facet normal * facet position
  1956. var t0 = 0.0;
  1957. var projx = 0.0;
  1958. var projy = 0.0;
  1959. var projz = 0.0;
  1960. // Get all the facets in the same partitioning block than (x, y, z)
  1961. var facetPositions = this.getFacetLocalPositions();
  1962. var facetNormals = this.getFacetLocalNormals();
  1963. var facetsInBlock = this.getFacetsAtLocalCoordinates(x, y, z);
  1964. if (!facetsInBlock) {
  1965. return null;
  1966. }
  1967. // Get the closest facet to (x, y, z)
  1968. var shortest = Number.MAX_VALUE; // init distance vars
  1969. var tmpDistance = shortest;
  1970. var fib; // current facet in the block
  1971. var norm; // current facet normal
  1972. var p0; // current facet barycenter position
  1973. // loop on all the facets in the current partitioning block
  1974. for (var idx = 0; idx < facetsInBlock.length; idx++) {
  1975. fib = facetsInBlock[idx];
  1976. norm = facetNormals[fib];
  1977. p0 = facetPositions[fib];
  1978. d = (x - p0.x) * norm.x + (y - p0.y) * norm.y + (z - p0.z) * norm.z;
  1979. if (!checkFace || (checkFace && facing && d >= 0.0) || (checkFace && !facing && d <= 0.0)) {
  1980. // compute (x,y,z) projection on the facet = (projx, projy, projz)
  1981. d = norm.x * p0.x + norm.y * p0.y + norm.z * p0.z;
  1982. t0 = -(norm.x * x + norm.y * y + norm.z * z - d) / (norm.x * norm.x + norm.y * norm.y + norm.z * norm.z);
  1983. projx = x + norm.x * t0;
  1984. projy = y + norm.y * t0;
  1985. projz = z + norm.z * t0;
  1986. tmpx = projx - x;
  1987. tmpy = projy - y;
  1988. tmpz = projz - z;
  1989. tmpDistance = tmpx * tmpx + tmpy * tmpy + tmpz * tmpz; // compute length between (x, y, z) and its projection on the facet
  1990. if (tmpDistance < shortest) { // just keep the closest facet to (x, y, z)
  1991. shortest = tmpDistance;
  1992. closest = fib;
  1993. if (projected) {
  1994. projected.x = projx;
  1995. projected.y = projy;
  1996. projected.z = projz;
  1997. }
  1998. }
  1999. }
  2000. }
  2001. return closest;
  2002. }
  2003. /**
  2004. * Returns the object "parameter" set with all the expected parameters for facetData computation by ComputeNormals()
  2005. */
  2006. public getFacetDataParameters(): any {
  2007. return this._facetParameters;
  2008. }
  2009. /**
  2010. * Disables the feature FacetData and frees the related memory.
  2011. * Returns the AbstractMesh.
  2012. */
  2013. public disableFacetData(): AbstractMesh {
  2014. if (this._facetDataEnabled) {
  2015. this._facetDataEnabled = false;
  2016. this._facetPositions = new Array<Vector3>();;
  2017. this._facetNormals = new Array<Vector3>();;
  2018. this._facetPartitioning = new Array<number[]>();;
  2019. this._facetParameters = null;
  2020. }
  2021. return this;
  2022. }
  2023. /**
  2024. * Creates new normals data for the mesh.
  2025. * @param updatable.
  2026. */
  2027. public createNormals(updatable: boolean) {
  2028. var positions = this.getVerticesData(VertexBuffer.PositionKind);
  2029. var indices = this.getIndices();
  2030. var normals: number[] | Float32Array;
  2031. if (this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
  2032. normals = (<number[] | Float32Array>this.getVerticesData(VertexBuffer.NormalKind));
  2033. } else {
  2034. normals = [];
  2035. }
  2036. VertexData.ComputeNormals(positions, indices, normals, { useRightHandedSystem: this.getScene().useRightHandedSystem });
  2037. this.setVerticesData(VertexBuffer.NormalKind, normals, updatable);
  2038. }
  2039. protected checkOcclusionQuery() {
  2040. var engine = this.getEngine();
  2041. if (engine.webGLVersion < 2 || this.occlusionType === AbstractMesh.OCCLUSION_TYPE_NONE) {
  2042. this._isOccluded = false;
  2043. return;
  2044. }
  2045. if (this.isOcclusionQueryInProgress && this._occlusionQuery) {
  2046. var isOcclusionQueryAvailable = engine.isQueryResultAvailable(this._occlusionQuery);
  2047. if (isOcclusionQueryAvailable) {
  2048. var occlusionQueryResult = engine.getQueryResult(this._occlusionQuery);
  2049. this._isOcclusionQueryInProgress = false;
  2050. this._occlusionInternalRetryCounter = 0;
  2051. this._isOccluded = occlusionQueryResult === 1 ? false : true;
  2052. }
  2053. else {
  2054. this._occlusionInternalRetryCounter++;
  2055. if (this.occlusionRetryCount !== -1 && this._occlusionInternalRetryCounter > this.occlusionRetryCount) {
  2056. this._isOcclusionQueryInProgress = false;
  2057. this._occlusionInternalRetryCounter = 0;
  2058. // if optimistic set isOccluded to false regardless of the status of isOccluded. (Render in the current render loop)
  2059. // if strict continue the last state of the object.
  2060. this._isOccluded = this.occlusionType === AbstractMesh.OCCLUSION_TYPE_OPTIMISTIC ? false : this._isOccluded;
  2061. }
  2062. else {
  2063. return;
  2064. }
  2065. }
  2066. }
  2067. var scene = this.getScene();
  2068. var occlusionBoundingBoxRenderer = scene.getBoundingBoxRenderer();
  2069. if (!this._occlusionQuery) {
  2070. this._occlusionQuery = engine.createQuery();
  2071. }
  2072. engine.beginQuery(this.occlusionQueryAlgorithmType, this._occlusionQuery);
  2073. occlusionBoundingBoxRenderer.renderOcclusionBoundingBox(this);
  2074. engine.endQuery(this.occlusionQueryAlgorithmType);
  2075. this._isOcclusionQueryInProgress = true;
  2076. }
  2077. }
  2078. }