babylon.abstractMesh.ts 89 KB

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