octreeSceneComponent.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import { Scene } from "../../scene.js";
  2. import { Vector3 } from "../../Maths/math.vector.js";
  3. import { AbstractMesh } from "../../Meshes/abstractMesh.js";
  4. import { Ray } from "../../Culling/ray.js";
  5. import { SceneComponentConstants } from "../../sceneComponent.js";
  6. import { Octree } from "./octree.js";
  7. import { EngineStore } from "../../Engines/engineStore.js";
  8. Scene.prototype.createOrUpdateSelectionOctree = function (maxCapacity = 64, maxDepth = 2) {
  9. let component = this._getComponent(SceneComponentConstants.NAME_OCTREE);
  10. if (!component) {
  11. component = new OctreeSceneComponent(this);
  12. this._addComponent(component);
  13. }
  14. if (!this._selectionOctree) {
  15. this._selectionOctree = new Octree(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
  16. }
  17. const worldExtends = this.getWorldExtends();
  18. // Update octree
  19. this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes);
  20. return this._selectionOctree;
  21. };
  22. Object.defineProperty(Scene.prototype, "selectionOctree", {
  23. get: function () {
  24. return this._selectionOctree;
  25. },
  26. enumerable: true,
  27. configurable: true,
  28. });
  29. /**
  30. * This function will create an octree to help to select the right submeshes for rendering, picking and collision computations.
  31. * Please note that you must have a decent number of submeshes to get performance improvements when using an octree
  32. * @param maxCapacity defines the maximum size of each block (64 by default)
  33. * @param maxDepth defines the maximum depth to use (no more than 2 levels by default)
  34. * @returns the new octree
  35. * @see https://www.babylonjs-playground.com/#NA4OQ#12
  36. * @see https://doc.babylonjs.com/features/featuresDeepDive/scene/optimizeOctrees
  37. */
  38. AbstractMesh.prototype.createOrUpdateSubmeshesOctree = function (maxCapacity = 64, maxDepth = 2) {
  39. const scene = this.getScene();
  40. let component = scene._getComponent(SceneComponentConstants.NAME_OCTREE);
  41. if (!component) {
  42. component = new OctreeSceneComponent(scene);
  43. scene._addComponent(component);
  44. }
  45. if (!this._submeshesOctree) {
  46. this._submeshesOctree = new Octree(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
  47. }
  48. this.computeWorldMatrix(true);
  49. const boundingInfo = this.getBoundingInfo();
  50. // Update octree
  51. const bbox = boundingInfo.boundingBox;
  52. this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
  53. return this._submeshesOctree;
  54. };
  55. /**
  56. * Defines the octree scene component responsible to manage any octrees
  57. * in a given scene.
  58. */
  59. export class OctreeSceneComponent {
  60. /**
  61. * Creates a new instance of the component for the given scene
  62. * @param scene Defines the scene to register the component in
  63. */
  64. constructor(scene) {
  65. /**
  66. * The component name help to identify the component in the list of scene components.
  67. */
  68. this.name = SceneComponentConstants.NAME_OCTREE;
  69. /**
  70. * Indicates if the meshes have been checked to make sure they are isEnabled()
  71. */
  72. this.checksIsEnabled = true;
  73. this._tempRay = new Ray(Vector3.Zero(), new Vector3(1, 1, 1));
  74. scene = scene || EngineStore.LastCreatedScene;
  75. if (!scene) {
  76. return;
  77. }
  78. this.scene = scene;
  79. this.scene.getActiveMeshCandidates = () => this.getActiveMeshCandidates();
  80. this.scene.getActiveSubMeshCandidates = (mesh) => this.getActiveSubMeshCandidates(mesh);
  81. this.scene.getCollidingSubMeshCandidates = (mesh, collider) => this.getCollidingSubMeshCandidates(mesh, collider);
  82. this.scene.getIntersectingSubMeshCandidates = (mesh, localRay) => this.getIntersectingSubMeshCandidates(mesh, localRay);
  83. }
  84. /**
  85. * Registers the component in a given scene
  86. */
  87. register() {
  88. this.scene.onMeshRemovedObservable.add((mesh) => {
  89. const sceneOctree = this.scene.selectionOctree;
  90. if (sceneOctree !== undefined && sceneOctree !== null) {
  91. const index = sceneOctree.dynamicContent.indexOf(mesh);
  92. if (index !== -1) {
  93. sceneOctree.dynamicContent.splice(index, 1);
  94. }
  95. }
  96. });
  97. this.scene.onMeshImportedObservable.add((mesh) => {
  98. const sceneOctree = this.scene.selectionOctree;
  99. if (sceneOctree !== undefined && sceneOctree !== null) {
  100. sceneOctree.addMesh(mesh);
  101. }
  102. });
  103. }
  104. /**
  105. * Return the list of active meshes
  106. * @returns the list of active meshes
  107. */
  108. getActiveMeshCandidates() {
  109. return this.scene._selectionOctree?.select(this.scene.frustumPlanes) || this.scene._getDefaultMeshCandidates();
  110. }
  111. /**
  112. * Return the list of active sub meshes
  113. * @param mesh The mesh to get the candidates sub meshes from
  114. * @returns the list of active sub meshes
  115. */
  116. getActiveSubMeshCandidates(mesh) {
  117. if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
  118. const intersections = mesh._submeshesOctree.select(this.scene.frustumPlanes);
  119. return intersections;
  120. }
  121. return this.scene._getDefaultSubMeshCandidates(mesh);
  122. }
  123. /**
  124. * Return the list of sub meshes intersecting with a given local ray
  125. * @param mesh defines the mesh to find the submesh for
  126. * @param localRay defines the ray in local space
  127. * @returns the list of intersecting sub meshes
  128. */
  129. getIntersectingSubMeshCandidates(mesh, localRay) {
  130. if (mesh._submeshesOctree && mesh.useOctreeForPicking) {
  131. Ray.TransformToRef(localRay, mesh.getWorldMatrix(), this._tempRay);
  132. const intersections = mesh._submeshesOctree.intersectsRay(this._tempRay);
  133. return intersections;
  134. }
  135. return this.scene._getDefaultSubMeshCandidates(mesh);
  136. }
  137. /**
  138. * Return the list of sub meshes colliding with a collider
  139. * @param mesh defines the mesh to find the submesh for
  140. * @param collider defines the collider to evaluate the collision against
  141. * @returns the list of colliding sub meshes
  142. */
  143. getCollidingSubMeshCandidates(mesh, collider) {
  144. if (mesh._submeshesOctree && mesh.useOctreeForCollisions) {
  145. const radius = collider._velocityWorldLength + Math.max(collider._radius.x, collider._radius.y, collider._radius.z);
  146. const intersections = mesh._submeshesOctree.intersects(collider._basePointWorld, radius);
  147. return intersections;
  148. }
  149. return this.scene._getDefaultSubMeshCandidates(mesh);
  150. }
  151. /**
  152. * Rebuilds the elements related to this component in case of
  153. * context lost for instance.
  154. */
  155. rebuild() {
  156. // Nothing to do here.
  157. }
  158. /**
  159. * Disposes the component and the associated resources.
  160. */
  161. dispose() {
  162. // Nothing to do here.
  163. }
  164. }
  165. //# sourceMappingURL=octreeSceneComponent.js.map