abstractMesh.js 98 KB

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