Kaynağa Gözat

Merge pull request #5272 from barroij/optionalSceneGeometryMap

Enable optional scene geometry map for performance
David Catuhe 6 yıl önce
ebeveyn
işleme
dda0f9f1f3
1 değiştirilmiş dosya ile 72 ekleme ve 24 silme
  1. 72 24
      src/babylon.scene.ts

+ 72 - 24
src/babylon.scene.ts

@@ -63,6 +63,15 @@ module BABYLON {
         renderingGroupId: number;
     }
 
+    /** Interface defining initialization parameters for Scene class */
+    export interface SceneOptions {
+        /**
+         * Defines that scene should keep up-to-date a map of geometry to enable fast look-up by Id
+         * It will improve performance when the number of geometries becomes important.
+         */
+        useGeometryIdsMap?: boolean;
+    }
+
     /**
      * Represents a scene to be rendered by the engine.
      * @see http://doc.babylonjs.com/features/scene
@@ -1165,10 +1174,15 @@ module BABYLON {
         public _pointerUpStage = Stage.Create<PointerUpDownStageAction>();
 
         /**
+         * an optional map from Geometry Id to Geometry index in the 'geometries' array
+         */
+        private geometriesById: Nullable<{ [id: string] : number | undefined }> = null;
+
+        /**
          * Creates a new Scene
          * @param engine defines the engine to use to render this scene
          */
-        constructor(engine: Engine) {
+        constructor(engine: Engine, options?: SceneOptions) {
             super();
             this._engine = engine || Engine.LastCreatedEngine;
 
@@ -1197,6 +1211,10 @@ module BABYLON {
             }
 
             this.setDefaultCandidateProviders();
+
+            if (options && options.useGeometryIdsMap === true) {
+                this.geometriesById = {};
+            }
         }
 
         private _defaultMeshCandidates: ISmartArrayLike<AbstractMesh> = {
@@ -1846,7 +1864,7 @@ module BABYLON {
                 if (!checkPicking && ActionManager && ActionManager.HasPickTriggers) {
                     act = this._initActionManager(act, clickInfo);
                     if (act) {
-                        checkPicking = act.hasPickTriggers;
+                        checkPicking = act.hasPickTriggers;
                     }
                 }
                 if (checkPicking) {
@@ -1863,7 +1881,7 @@ module BABYLON {
                             if (checkSingleClickImmediately && !ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
                                 act = this._initActionManager(act, clickInfo);
                                 if (act) {
-                                    checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                                    checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
                                 }
                             }
                         }
@@ -1889,7 +1907,7 @@ module BABYLON {
                         if (!checkDoubleClick && ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
                             act = this._initActionManager(act, clickInfo);
                             if (act) {
-                                checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                                checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
                             }
                         }
                         if (checkDoubleClick) {
@@ -3270,6 +3288,10 @@ module BABYLON {
          * @param newGeometry The geometry to add
          */
         public addGeometry(newGeometry: Geometry): void {
+            if (this.geometriesById) {
+                this.geometriesById[newGeometry.id] = this.geometries.length;
+            }
+
             this.geometries.push(newGeometry);
         }
 
@@ -3535,11 +3557,19 @@ module BABYLON {
          * @return the geometry or null if none found.
          */
         public getGeometryByID(id: string): Nullable<Geometry> {
-            for (var index = 0; index < this.geometries.length; index++) {
-                if (this.geometries[index].id === id) {
+            if (this.geometriesById) {
+                const index = this.geometriesById[id];
+                if (index !== undefined) {
                     return this.geometries[index];
                 }
             }
+            else {
+                for (var index = 0; index < this.geometries.length; index++) {
+                    if (this.geometries[index].id === id) {
+                        return this.geometries[index];
+                    }
+                }
+            }
 
             return null;
         }
@@ -3555,7 +3585,7 @@ module BABYLON {
                 return false;
             }
 
-            this.geometries.push(geometry);
+            this.addGeometry(geometry);
 
             //notify the collision coordinator
             if (this.collisionCoordinator) {
@@ -3573,20 +3603,38 @@ module BABYLON {
          * @return a boolean defining if the geometry was removed or not
          */
         public removeGeometry(geometry: Geometry): boolean {
-            var index = this.geometries.indexOf(geometry);
-
-            if (index > -1) {
-                this.geometries.splice(index, 1);
+            let index;
+            if (this.geometriesById) {
+                index = this.geometriesById[geometry.id];
+                if (index === undefined) {
+                    return false;
+                }
+            }
+            else {
+                index = this.geometries.indexOf(geometry);
+                if (index < 0) {
+                    return false;
+                }
+            }
 
-                //notify the collision coordinator
-                if (this.collisionCoordinator) {
-                    this.collisionCoordinator.onGeometryDeleted(geometry);
+            if (index !== this.geometries.length - 1) {
+                const lastGeometry = this.geometries[this.geometries.length - 1];
+                this.geometries[index] = lastGeometry;
+                if (this.geometriesById) {
+                    this.geometriesById[lastGeometry.id] = index;
+                    this.geometriesById[geometry.id] = undefined;
                 }
+            }
 
-                this.onGeometryRemovedObservable.notifyObservers(geometry);
-                return true;
+            this.geometries.pop();
+
+            //notify the collision coordinator
+            if (this.collisionCoordinator) {
+                this.collisionCoordinator.onGeometryDeleted(geometry);
             }
-            return false;
+
+            this.onGeometryRemovedObservable.notifyObservers(geometry);
+            return true;
         }
 
         /**
@@ -4197,7 +4245,7 @@ module BABYLON {
             this.activeCamera = camera;
 
             if (!this.activeCamera) {
-                throw new Error("Active camera not set");
+                throw new Error("Active camera not set");
             }
 
             // Viewport
@@ -4498,7 +4546,7 @@ module BABYLON {
                         this.activeCamera = renderTarget.activeCamera || this.activeCamera;
 
                         if (!this.activeCamera) {
-                            throw new Error("Active camera not set");
+                            throw new Error("Active camera not set");
                         }
 
                         // Viewport
@@ -4906,7 +4954,7 @@ module BABYLON {
 
             if (!camera) {
                 if (!this.activeCamera) {
-                    throw new Error("Active camera not set");
+                    throw new Error("Active camera not set");
                 }
 
                 camera = this.activeCamera;
@@ -4955,7 +5003,7 @@ module BABYLON {
 
             if (!camera) {
                 if (!this.activeCamera) {
-                    throw new Error("Active camera not set");
+                    throw new Error("Active camera not set");
                 }
 
                 camera = this.activeCamera;
@@ -4995,11 +5043,11 @@ module BABYLON {
 
                 var result = mesh.intersects(ray, fastCheck);
                 if (!result || !result.hit) {
-                    continue;
+                    continue;
                 }
 
                 if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance) {
-                    continue;
+                    continue;
                 }
 
                 pickingInfo = result;
@@ -5034,7 +5082,7 @@ module BABYLON {
 
                 var result = mesh.intersects(ray, false);
                 if (!result || !result.hit) {
-                    continue;
+                    continue;
                 }
 
                 pickingInfos.push(result);