فهرست منبع

Merge pull request #5061 from sebavan/master

Move Octree to component
David Catuhe 7 سال پیش
والد
کامیت
ce92d290ed

+ 18 - 2
Tools/Gulp/config.json

@@ -125,7 +125,8 @@
             "occlusionQuery",
             "transformFeedback",
             "noise",
-            "videoRecorder"
+            "videoRecorder",
+            "sceneHelpers"
         ],
         "minimal": [
             "meshBuilder",
@@ -1204,7 +1205,8 @@
         "octrees": {
             "files": [
                 "../../src/Culling/Octrees/babylon.octree.js",
-                "../../src/Culling/Octrees/babylon.octreeBlock.js"
+                "../../src/Culling/Octrees/babylon.octreeBlock.js",
+                "../../src/Culling/Octrees/babylon.octreeSceneComponent.js"
             ],
             "dependUpon": [
                 "core"
@@ -1369,6 +1371,20 @@
                 "backgroundUboDeclaration"
             ]
         },
+        "sceneHelpers": {
+            "files": [
+                "../../src/Helpers/babylon.sceneHelpers.js"
+            ],
+            "dependUpon": [
+                "core",
+                "arcRotateCamera",
+                "freeCamera",
+                "hemisphericLight",
+                "pbrMaterial",
+                "environmentHelper",
+                "vr"
+            ]
+        },
         "environmentHelper": {
             "files": [
                 "../../src/Helpers/babylon.environmentHelper.js"

+ 1 - 0
dist/preview release/what's new.md

@@ -236,3 +236,4 @@
 
 - Fixing support for R and RG texture formats made us remove TextureFormat_R32F and TextureFormat_RG32F as they were mixing formats and types. Please, use the respective TextureFormat_R and TextureFormat_RG with the Float types ([sebavan](http://www.github.com/sebavan))
 - Replacing `scene.onRenderingGroupObservable` by `onBeforeRenderingGroupObservable` and `onAfterRenderingGroupObservable` to prevent the stage check ([sebavan](http://www.github.com/sebavan))
+- Replacing `IActiveMeshCandidateProvider` and the according scene setter by a set of custom predicates `scene.getActiveMeshCandidates`, `scene.getActiveSubMeshCandidates`, `scene.getIntersectingSubMeshCandidates` and `scene.getCollidingSubMeshCandidates` ([sebavan](http://www.github.com/sebavan)). This helps opening more customization to everybody.

+ 2 - 1
src/Collisions/babylon.collisionWorker.ts

@@ -113,7 +113,8 @@ module BABYLON {
             //return colTransMat;
         }
 
-        private processCollisionsForSubMeshes(transformMatrix: Matrix, mesh: SerializedMesh): void { // No Octrees for now
+        private processCollisionsForSubMeshes(transformMatrix: Matrix, mesh: SerializedMesh): void { 
+            // No Octrees for now
             //if (this._submeshesOctree && this.useOctreeForCollisions) {
             //    var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
             //    var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);

+ 233 - 0
src/Culling/Octrees/babylon.octreeSceneComponent.ts

@@ -0,0 +1,233 @@
+module BABYLON {
+    export interface Scene {
+        /**
+         * @hidden
+         * Backing Filed
+         */
+        _selectionOctree: Octree<AbstractMesh>;
+
+        /**
+         * Gets the octree used to boost mesh selection (picking)
+         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
+         */
+        selectionOctree: Octree<AbstractMesh>;
+
+        /**
+         * Creates or updates the octree used to boost selection (picking)
+         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
+         * @param maxCapacity defines the maximum capacity per leaf
+         * @param maxDepth defines the maximum depth of the octree
+         * @returns an octree of AbstractMesh
+         */
+        createOrUpdateSelectionOctree(maxCapacity?: number, maxDepth?: number): Octree<AbstractMesh>;
+    }
+
+    Scene.prototype.createOrUpdateSelectionOctree = function(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
+        let component = this._getComponent(SceneComponentConstants.NAME_OCTREE);
+        if (!component) {
+            component = new OctreeSceneComponent(this);
+            this._addComponent(component);
+        }
+        
+        if (!this._selectionOctree) {
+            this._selectionOctree = new Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
+        }
+
+        var worldExtends = this.getWorldExtends();
+
+        // Update octree
+        this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes);
+
+        return this._selectionOctree;
+   }
+
+    Object.defineProperty(Scene.prototype, "selectionOctree", {
+        get: function (this:Scene) {
+            return this._selectionOctree;
+        },
+        enumerable: true,
+        configurable: true
+    });
+
+    export interface AbstractMesh {
+        /** 
+         * @hidden 
+         * Backing Field
+         */
+        _submeshesOctree: Octree<SubMesh>;
+
+        /**
+         * This function will create an octree to help to select the right submeshes for rendering, picking and collision computations.  
+         * Please note that you must have a decent number of submeshes to get performance improvements when using an octree
+         * @param maxCapacity defines the maximum size of each block (64 by default)
+         * @param maxDepth defines the maximum depth to use (no more than 2 levels by default)
+         * @returns the new octree
+         * @see https://www.babylonjs-playground.com/#NA4OQ#12
+         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
+         */
+        createOrUpdateSubmeshesOctree(maxCapacity?: number, maxDepth?: number): Octree<SubMesh>;
+    }
+
+    /**
+     * This function will create an octree to help to select the right submeshes for rendering, picking and collision computations.  
+     * Please note that you must have a decent number of submeshes to get performance improvements when using an octree
+     * @param maxCapacity defines the maximum size of each block (64 by default)
+     * @param maxDepth defines the maximum depth to use (no more than 2 levels by default)
+     * @returns the new octree
+     * @see https://www.babylonjs-playground.com/#NA4OQ#12
+     * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
+     */
+    AbstractMesh.prototype.createOrUpdateSubmeshesOctree = function(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
+        const scene = this.getScene();
+        let component = scene._getComponent(SceneComponentConstants.NAME_OCTREE);
+        if (!component) {
+            component = new OctreeSceneComponent(scene);
+            scene._addComponent(component);
+        }
+
+        if (!this._submeshesOctree) {
+            this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
+        }
+
+        this.computeWorldMatrix(true);
+
+        let boundingInfo = this.getBoundingInfo();
+
+        // Update octree
+        var bbox = boundingInfo.boundingBox;
+        this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
+
+        return this._submeshesOctree;
+    }
+
+    /**
+     * Defines the octree scene component responsible to manage any octrees
+     * in a given scene.
+     */
+    export class OctreeSceneComponent {
+        /**
+         * The component name helpfull to identify the component in the list of scene components.
+         */
+        public readonly name = SceneComponentConstants.NAME_OCTREE;
+
+        /**
+         * The scene the component belongs to.
+         */
+        public scene: Scene;
+
+        /** 
+         * Indicates if the meshes have been checked to make sure they are isEnabled()
+         */
+        public readonly checksIsEnabled = true;
+
+        /**
+         * Creates a new instance of the component for the given scene
+         * @param scene Defines the scene to register the component in
+         */
+        constructor(scene: Scene) {
+            this.scene = scene;
+
+            this.scene.getActiveMeshCandidates = this.getActiveMeshCandidates.bind(this);
+
+            this.scene.getActiveSubMeshCandidates = this.getActiveSubMeshCandidates.bind(this);
+            this.scene.getCollidingSubMeshCandidates = this.getCollidingSubMeshCandidates.bind(this);
+            this.scene.getIntersectingSubMeshCandidates = this.getIntersectingSubMeshCandidates.bind(this);
+        }
+
+        /**
+         * Registers the component in a given scene
+         */
+        public register(): void {
+            this.scene.onMeshRemovedObservable.add((mesh: AbstractMesh) => {
+                const sceneOctree = this.scene.selectionOctree;
+                if (sceneOctree !== undefined && sceneOctree !== null) {
+                    var index = sceneOctree.dynamicContent.indexOf(mesh);
+
+                    if (index !== -1) {
+                        sceneOctree.dynamicContent.splice(index, 1);
+                    }
+                }
+            });
+
+            this.scene.onMeshImportedObservable.add((mesh: AbstractMesh) => {
+                const sceneOctree = this.scene.selectionOctree;
+                if (sceneOctree !== undefined && sceneOctree !== null) {
+                    sceneOctree.addMesh(mesh);
+                }
+            })
+        }
+
+        /**
+         * Return the list of active meshes
+         * @returns the list of active meshes
+         */
+        public getActiveMeshCandidates(): ISmartArrayLike<AbstractMesh> {
+            if (this.scene._selectionOctree) {
+                var selection = this.scene._selectionOctree.select(this.scene.frustumPlanes);
+                return selection;
+            }
+            return this.scene._getDefaultMeshCandidates();
+        }
+
+        /**
+         * Return the list of active sub meshes
+         * @param mesh The mesh to get the candidates sub meshes from
+         * @returns the list of active sub meshes
+         */
+        public getActiveSubMeshCandidates(mesh: AbstractMesh): ISmartArrayLike<SubMesh> {
+            if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                var intersections = mesh._submeshesOctree.select(this.scene.frustumPlanes);
+                return intersections;
+            }
+            return this.scene._getDefaultSubMeshCandidates(mesh);
+        }
+
+        private _tempRay = new BABYLON.Ray(Vector3.Zero(), new Vector3(1, 1, 1));
+        /**
+         * Return the list of sub meshes intersecting with a given local ray
+         * @param mesh defines the mesh to find the submesh for
+         * @param localRay defines the ray in local space
+         * @returns the list of intersecting sub meshes
+         */
+        public getIntersectingSubMeshCandidates(mesh: AbstractMesh, localRay: Ray): ISmartArrayLike<SubMesh> {
+            if (mesh._submeshesOctree && mesh.useOctreeForPicking) {
+                Ray.TransformToRef(localRay, mesh.getWorldMatrix(), this._tempRay);
+                var intersections = mesh._submeshesOctree.intersectsRay(this._tempRay);
+
+                return intersections;
+            }
+            return this.scene._getDefaultSubMeshCandidates(mesh);
+        }
+
+        /**
+         * Return the list of sub meshes colliding with a collider
+         * @param mesh defines the mesh to find the submesh for
+         * @param collider defines the collider to evaluate the collision against
+         * @returns the list of colliding sub meshes
+         */
+        public getCollidingSubMeshCandidates(mesh: AbstractMesh, collider: Collider): ISmartArrayLike<SubMesh> {
+            if (mesh._submeshesOctree && mesh.useOctreeForCollisions) {
+                var radius = collider._velocityWorldLength + Math.max(collider._radius.x, collider._radius.y, collider._radius.z);
+                var intersections = mesh._submeshesOctree.intersects(collider._basePointWorld, radius);
+
+                return intersections;
+            }
+            return this.scene._getDefaultSubMeshCandidates(mesh);
+        }
+
+        /**
+         * Rebuilds the elements related to this component in case of
+         * context lost for instance.
+         */
+        public rebuild(): void {
+            // Nothing to do here.
+        }
+
+        /**
+         * Disposes the component and the associated ressources.
+         */
+        public dispose(): void {
+            // Nothing to do here.
+        }
+    }
+} 

+ 176 - 0
src/Helpers/babylon.sceneHelpers.ts

@@ -0,0 +1,176 @@
+module BABYLON {
+    export interface Scene {
+        /**
+         * Creates a default light for the scene.
+         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-light
+         * @param replace has the default false, when true replaces the existing lights in the scene with a hemispheric light
+         */
+        createDefaultLight(replace?: boolean): void;
+
+        /**
+         * Creates a default camera for the scene.
+         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-camera
+         * @param createArcRotateCamera has the default false which creates a free camera, when true creates an arc rotate camera
+         * @param replace has default false, when true replaces the active camera in the scene
+         * @param attachCameraControls has default false, when true attaches camera controls to the canvas.
+         */
+        createDefaultCamera(createArcRotateCamera?: boolean, replace?: boolean, attachCameraControls?: boolean): void;
+    
+        /**
+         * Creates a default camera and a default light.
+         * @see http://doc.babylonjs.com/how_to/Fast_Build#create-default-camera-or-light
+         * @param createArcRotateCamera has the default false which creates a free camera, when true creates an arc rotate camera
+         * @param replace has the default false, when true replaces the active camera/light in the scene
+         * @param attachCameraControls has the default false, when true attaches camera controls to the canvas.
+         */
+        createDefaultCameraOrLight(createArcRotateCamera?: boolean, replace?: boolean, attachCameraControls?: boolean): void;
+        
+        /**
+         * Creates a new sky box
+         * @see http://doc.babylonjs.com/how_to/Fast_Build#create-default-skybox
+         * @param environmentTexture defines the texture to use as environment texture
+         * @param pbr has default false which requires the StandardMaterial to be used, when true PBRMaterial must be used 
+         * @param scale defines the overall scale of the skybox
+         * @param blur is only available when pbr is true, default is 0, no blur, maximum value is 1
+         * @param setGlobalEnvTexture has default true indicating that scene.environmentTexture must match the current skybox texture
+         * @returns a new mesh holding the sky box
+         */
+        createDefaultSkybox(environmentTexture?: BaseTexture, pbr?: boolean, scale?: number, blur?: number, setGlobalEnvTexture?: boolean): Nullable<Mesh>;
+
+        /**
+         * Creates a new environment
+         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-environment
+         * @param options defines the options you can use to configure the environment
+         * @returns the new EnvironmentHelper
+         */
+        createDefaultEnvironment(options?: Partial<IEnvironmentHelperOptions>): Nullable<EnvironmentHelper>;
+
+        /**
+         * Creates a new VREXperienceHelper
+         * @see http://doc.babylonjs.com/how_to/webvr_helper
+         * @param webVROptions defines the options used to create the new VREXperienceHelper
+         * @returns a new VREXperienceHelper
+         */
+        createDefaultVRExperience(webVROptions?: VRExperienceHelperOptions): VRExperienceHelper;
+    }
+
+    Scene.prototype.createDefaultLight = function(replace = false): void {
+        // Dispose existing light in replace mode.
+        if (replace) {
+            if (this.lights) {
+                for (var i = 0; i < this.lights.length; i++) {
+                    this.lights[i].dispose();
+                }
+            }
+        }
+
+        // Light
+        if (this.lights.length === 0) {
+            new HemisphericLight("default light", Vector3.Up(), this);
+        }
+    }
+
+    Scene.prototype.createDefaultCamera = function(createArcRotateCamera = false, replace = false, attachCameraControls = false): void {
+        // Dispose existing camera in replace mode.
+        if (replace) {
+            if (this.activeCamera) {
+                this.activeCamera.dispose();
+                this.activeCamera = null;
+            }
+        }
+
+        // Camera
+        if (!this.activeCamera) {
+            var worldExtends = this.getWorldExtends();
+            var worldSize = worldExtends.max.subtract(worldExtends.min);
+            var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
+
+            var camera: TargetCamera;
+            var radius = worldSize.length() * 1.5;
+            // empty scene scenario!
+            if (!isFinite(radius)) {
+                radius = 1;
+                worldCenter.copyFromFloats(0, 0, 0);
+            }
+            if (createArcRotateCamera) {
+                var arcRotateCamera = new ArcRotateCamera("default camera", -(Math.PI / 2), Math.PI / 2, radius, worldCenter, this);
+                arcRotateCamera.lowerRadiusLimit = radius * 0.01;
+                arcRotateCamera.wheelPrecision = 100 / radius;
+                camera = arcRotateCamera;
+            }
+            else {
+                var freeCamera = new FreeCamera("default camera", new Vector3(worldCenter.x, worldCenter.y, -radius), this);
+                freeCamera.setTarget(worldCenter);
+                camera = freeCamera;
+            }
+            camera.minZ = radius * 0.01;
+            camera.maxZ = radius * 1000;
+            camera.speed = radius * 0.2;
+            this.activeCamera = camera;
+
+            let canvas = this.getEngine().getRenderingCanvas();
+            if (attachCameraControls && canvas) {
+                camera.attachControl(canvas);
+            }
+        }
+    }
+
+    Scene.prototype.createDefaultCameraOrLight = function(createArcRotateCamera = false, replace = false, attachCameraControls = false): void {
+        this.createDefaultLight(replace);
+        this.createDefaultCamera(createArcRotateCamera, replace, attachCameraControls);
+    }
+
+    Scene.prototype.createDefaultSkybox = function(environmentTexture?: BaseTexture, pbr = false, scale = 1000, blur = 0, setGlobalEnvTexture = true): Nullable<Mesh> {
+
+        if (!environmentTexture) {
+            Tools.Warn("Can not create default skybox without environment texture.");
+            return null;
+        }
+
+        if (setGlobalEnvTexture) {
+            if (environmentTexture) {
+                this.environmentTexture = environmentTexture;
+            }
+        }
+
+        // Skybox
+        var hdrSkybox = Mesh.CreateBox("hdrSkyBox", scale, this);
+        if (pbr) {
+            let hdrSkyboxMaterial = new PBRMaterial("skyBox", this);
+            hdrSkyboxMaterial.backFaceCulling = false;
+            hdrSkyboxMaterial.reflectionTexture = environmentTexture.clone();
+            if (hdrSkyboxMaterial.reflectionTexture) {
+                hdrSkyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
+            }
+            hdrSkyboxMaterial.microSurface = 1.0 - blur;
+            hdrSkyboxMaterial.disableLighting = true;
+            hdrSkyboxMaterial.twoSidedLighting = true;
+            hdrSkybox.infiniteDistance = true;
+            hdrSkybox.material = hdrSkyboxMaterial;
+        }
+        else {
+            let skyboxMaterial = new StandardMaterial("skyBox", this);
+            skyboxMaterial.backFaceCulling = false;
+            skyboxMaterial.reflectionTexture = environmentTexture.clone();
+            if (skyboxMaterial.reflectionTexture) {
+                skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
+            }
+            skyboxMaterial.disableLighting = true;
+            hdrSkybox.infiniteDistance = true;
+            hdrSkybox.material = skyboxMaterial;
+        }
+
+        return hdrSkybox;
+    }
+
+    Scene.prototype.createDefaultEnvironment = function(options: Partial<IEnvironmentHelperOptions>): Nullable<EnvironmentHelper> {
+        if (EnvironmentHelper) {
+            return new EnvironmentHelper(options, this);
+        }
+        return null;
+    }
+
+    Scene.prototype.createDefaultVRExperience = function(webVROptions: VRExperienceHelperOptions = {}): VRExperienceHelper {
+        return new VRExperienceHelper(this, webVROptions);
+    }
+}

+ 7 - 70
src/Mesh/babylon.abstractMesh.ts

@@ -541,8 +541,7 @@
          * @see http://doc.babylonjs.com/how_to/multi_materials
          */
         public subMeshes: SubMesh[];
-        /** @hidden */
-        public _submeshesOctree: Octree<SubMesh>;
+
         /** @hidden */
         public _intersectionsInProgress = new Array<AbstractMesh>();
 
@@ -1307,33 +1306,6 @@
             this.onCollisionPositionChangeObservable.notifyObservers(this.position);
         }
 
-        // Submeshes octree
-
-        /**
-        * This function will create an octree to help to select the right submeshes for rendering, picking and collision computations.  
-        * Please note that you must have a decent number of submeshes to get performance improvements when using an octree
-        * @param maxCapacity defines the maximum size of each block (64 by default)
-        * @param maxDepth defines the maximum depth to use (no more than 2 levels by default)
-        * @returns the new octree
-        * @see https://www.babylonjs-playground.com/#NA4OQ#12
-        * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
-        */
-        public createOrUpdateSubmeshesOctree(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
-            if (!this._submeshesOctree) {
-                this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
-            }
-
-            this.computeWorldMatrix(true);
-
-            let boundingInfo = this.getBoundingInfo();
-
-            // Update octree
-            var bbox = boundingInfo.boundingBox;
-            this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
-
-            return this._submeshesOctree;
-        }
-
         // Collisions
         /** @hidden */
         public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): AbstractMesh {
@@ -1364,23 +1336,11 @@
 
         /** @hidden */
         public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): AbstractMesh {
-            var subMeshes: SubMesh[];
-            var len: number;
-
-            // Octrees
-            if (this._submeshesOctree && this.useOctreeForCollisions) {
-                var radius = collider._velocityWorldLength + Math.max(collider._radius.x, collider._radius.y, collider._radius.z);
-                var intersections = this._submeshesOctree.intersects(collider._basePointWorld, radius);
-
-                len = intersections.length;
-                subMeshes = intersections.data;
-            } else {
-                subMeshes = this.subMeshes;
-                len = subMeshes.length;
-            }
+            const subMeshes = this._scene.getCollidingSubMeshCandidates(this, collider);
+            const len = subMeshes.length;
 
             for (var index = 0; index < len; index++) {
-                var subMesh = subMeshes[index];
+                var subMesh = subMeshes.data[index];
 
                 // Bounding test
                 if (len > 1 && !subMesh._checkCollision(collider))
@@ -1430,23 +1390,10 @@
 
             var intersectInfo: Nullable<IntersectionInfo> = null;
 
-            // Octrees
-            var subMeshes: SubMesh[];
-            var len: number;
-
-            if (this._submeshesOctree && this.useOctreeForPicking) {
-                var worldRay = Ray.Transform(ray, this.getWorldMatrix());
-                var intersections = this._submeshesOctree.intersectsRay(worldRay);
-
-                len = intersections.length;
-                subMeshes = intersections.data;
-            } else {
-                subMeshes = this.subMeshes;
-                len = subMeshes.length;
-            }
-
+            var subMeshes = this._scene.getIntersectingSubMeshCandidates(this, ray);
+            var len: number = subMeshes.length;
             for (var index = 0; index < len; index++) {
-                var subMesh = subMeshes[index];
+                var subMesh = subMeshes.data[index];
 
                 // Bounding test
                 if (len > 1 && !subMesh.canIntersects(ray))
@@ -1589,16 +1536,6 @@
                 this.releaseSubMeshes();
             }
 
-            // Octree
-            const sceneOctree = this.getScene().selectionOctree;
-            if (sceneOctree !== undefined && sceneOctree !== null) {
-                var index = sceneOctree.dynamicContent.indexOf(this);
-
-                if (index !== -1) {
-                    sceneOctree.dynamicContent.splice(index, 1);
-                }
-            }
-
             // Query
             let engine = this.getScene().getEngine();
             if (this._occlusionQuery) {

+ 1 - 5
src/Mesh/babylon.geometry.ts

@@ -1297,11 +1297,7 @@
             // Update
             mesh.computeWorldMatrix(true);
 
-            // Octree
-            const sceneOctree = scene.selectionOctree;
-            if (sceneOctree !== undefined && sceneOctree !== null) {
-                sceneOctree.addMesh(<AbstractMesh>mesh);
-            }
+            scene.onMeshImportedObservable.notifyObservers(<AbstractMesh>mesh);
         }
 
         private static _CleanMatricesWeights(parsedGeometry: any, mesh: Mesh): void {

+ 6 - 1
src/Mesh/babylon.groundMesh.ts

@@ -45,7 +45,12 @@
             this._subdivisionsX = chunksCount;
             this._subdivisionsY = chunksCount;
             this.subdivide(chunksCount);
-            this.createOrUpdateSubmeshesOctree(octreeBlocksSize);
+
+            // Call the octree system optimization if it is defined.
+            const thisAsAny = this as any;
+            if (thisAsAny.createOrUpdateSubmeshesOctree) {
+                thisAsAny.createOrUpdateSubmeshesOctree(octreeBlocksSize);
+            }
         }
 
         /**

+ 3 - 8
src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManagerSceneComponent.ts

@@ -56,7 +56,6 @@ module BABYLON {
          */
         public register(): void {
             this.scene._gatherRenderTargetsStage.registerStep(SceneComponentConstants.STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER, this, this._gatherRenderTargets);
-            this.scene._gatherRenderTargetsStage.registerStep(SceneComponentConstants.STEP_REBUILDGEOMETRY_POSTPROCESSRENDERPIPELINEMANAGER, this, this._rebuildGeometry);
         }
 
         /**
@@ -64,7 +63,9 @@ module BABYLON {
          * context lost for instance.
          */
         public rebuild(): void {
-            // Nothing to do for this component
+            if (this.scene._postProcessRenderPipelineManager) {
+                this.scene._postProcessRenderPipelineManager._rebuild();
+            }
         }
 
         /**
@@ -81,11 +82,5 @@ module BABYLON {
                 this.scene._postProcessRenderPipelineManager.update();
             }
         }
-
-        private _rebuildGeometry(): void {
-            if (this.scene._postProcessRenderPipelineManager) {
-                this.scene._postProcessRenderPipelineManager._rebuild();
-            }
-        }
     }
 } 

+ 12 - 0
src/Probes/babylon.reflectionProbe.ts

@@ -1,4 +1,12 @@
 module BABYLON {
+    export interface Scene {
+        /**
+         * The list of reflection probes added to the scene
+         * @see http://doc.babylonjs.com/how_to/how_to_use_reflection_probes
+         */
+        reflectionProbes: Array<ReflectionProbe>;
+    }
+
     /** 
      * Class used to generate realtime reflection / refraction cube textures
      * @see http://doc.babylonjs.com/how_to/how_to_use_reflection_probes
@@ -31,6 +39,10 @@
             size: number, scene: Scene, generateMipMaps = true, useFloat = false) {
             this._scene = scene;
 
+            // Create the scene field if not exist.
+            if (!this._scene.reflectionProbes) {
+                this._scene.reflectionProbes = new Array<ReflectionProbe>();
+            }
             this._scene.reflectionProbes.push(this);
 
             this._renderTargetTexture = new RenderTargetTexture(name, size, scene, generateMipMaps, true, useFloat ? Engine.TEXTURETYPE_FLOAT : Engine.TEXTURETYPE_UNSIGNED_INT, true);

+ 0 - 2
src/Sprites/babylon.spriteSceneComponent.ts

@@ -231,8 +231,6 @@
                     }
                 } else {
                     scene.setPointerOverSprite(null);
-                    // Restore pointer
-                    canvas.style.cursor = scene.defaultCursor;
                 }
             }
 

+ 10 - 6
src/Tools/babylon.sceneOptimizer.ts

@@ -436,13 +436,17 @@
                 Mesh.MergeMeshes(currentPool, undefined, true);
             }
 
-            if (updateSelectionTree != undefined) {
-                if (updateSelectionTree) {
-                    scene.createOrUpdateSelectionOctree();
+            // Call the octree system optimization if it is defined.
+            const sceneAsAny = scene as any;
+            if (sceneAsAny.createOrUpdateSelectionOctree) {
+                if (updateSelectionTree != undefined) {
+                    if (updateSelectionTree) {
+                        sceneAsAny.createOrUpdateSelectionOctree();
+                    }
+                }
+                else if (MergeMeshesOptimization.UpdateSelectionTree) {
+                    sceneAsAny.createOrUpdateSelectionOctree();
                 }
-            }
-            else if (MergeMeshesOptimization.UpdateSelectionTree) {
-                scene.createOrUpdateSelectionOctree();
             }
 
             return true;

+ 87 - 8
src/Tools/babylon.smartArray.ts

@@ -1,17 +1,48 @@
 module BABYLON {
-    export class SmartArray<T> {
+    /**
+     * Defines an array and its length.
+     * It can be helpfull to group result from both Arrays and smart arrays in one structure.
+     */
+    export interface ISmartArrayLike<T> {
+        /**
+         * The data of the array.
+         */
+        data: Array<T>;
+        /**
+         * The active length of the array.
+         */
+        length: number;
+    }
+
+    /**
+     * Defines an GC Friendly array where the backfield array do not shrink to prevent over allocations.
+     */
+    export class SmartArray<T> implements ISmartArrayLike<T> {
+        /**
+         * The full set of data from the array.
+         */
         public data: Array<T>;
+
+        /**
+         * The active length of the array.
+         */
         public length: number = 0;
 
         protected _id: number;
 
-        [index: number]: T;
-
+        /**
+         * Instantiates a Smart Array.
+         * @param capacity defines the default capacity of the array.
+         */
         constructor(capacity: number) {
             this.data = new Array(capacity);
             this._id = SmartArray._GlobalId++;
         }
 
+        /**
+         * Pushes a value at the end of the active data.
+         * @param value defines the object to push in the array.
+         */
         public push(value: T): void {
             this.data[this.length++] = value;
 
@@ -20,20 +51,34 @@
             }
         }
 
+        /**
+         * Iterates over the active data and apply the lambda to them.
+         * @param func defines the action to apply on each value.
+         */
         public forEach(func: (content: T) => void): void {
             for (var index = 0; index < this.length; index++) {
                 func(this.data[index]);
             }
         }
-    
+
+        /**
+         * Sorts the full sets of data.
+         * @param compareFn defines the comparison function to apply.
+         */
         public sort(compareFn: (a: T, b: T) => number): void {
             this.data.sort(compareFn);
         }
 
+        /**
+         * Resets the active data to an empty array.
+         */
         public reset(): void {
             this.length = 0;
         }
 
+        /**
+         * Releases all the data from the array as well as the array.
+         */
         public dispose(): void {
             this.reset();
 
@@ -43,6 +88,10 @@
             }
         }
 
+        /**
+         * Concats the active data with a given array.
+         * @param array defines the data to concatenate with.
+         */
         public concat(array: any): void {
             if (array.length === 0) {
                 return;
@@ -56,6 +105,11 @@
             }
         }
 
+        /**
+         * Returns the position of a value in the active data.
+         * @param value defines the value to find the index for
+         * @returns the index if found in the active data otherwise -1
+         */
         public indexOf(value: T): number {
             var position = this.data.indexOf(value);
 
@@ -66,19 +120,31 @@
             return position;
         }
 
+        /**
+         * Returns whether an element is part of the active data.
+         * @param value defines the value to look for
+         * @returns true if found in the active data otherwise false
+         */
         public contains(value: T): boolean {
-            return this.data.indexOf(value) !== -1;
+            return this.indexOf(value) !== -1;
         }
 
         // Statics
         private static _GlobalId = 0;
     }
 
+    /**
+     * Defines an GC Friendly array where the backfield array do not shrink to prevent over allocations.
+     * The data in this array can only be present once
+     */
     export class SmartArrayNoDuplicate<T> extends SmartArray<T> {
         private _duplicateId = 0;
 
-        [index: number]: T;
-
+        /**
+         * Pushes a value at the end of the active data.
+         * THIS DOES NOT PREVENT DUPPLICATE DATA
+         * @param value defines the object to push in the array.
+         */
         public push(value: T): void {
             super.push(value);
 
@@ -89,7 +155,12 @@
             (<any>value).__smartArrayFlags[this._id] = this._duplicateId;
         }
 
-
+        /**
+         * Pushes a value at the end of the active data.
+         * If the data is already present, it won t be added again
+         * @param value defines the object to push in the array.
+         * @returns true if added false if it was already present
+         */
         public pushNoDuplicate(value: T): boolean {
             if ((<any>value).__smartArrayFlags && (<any>value).__smartArrayFlags[this._id] === this._duplicateId) {
                 return false;
@@ -98,11 +169,19 @@
             return true;
         }
 
+        /**
+         * Resets the active data to an empty array.
+         */
         public reset(): void {
             super.reset();
             this._duplicateId++;
         }
 
+        /**
+         * Concats the active data with a given array.
+         * This ensures no dupplicate will be present in the result.
+         * @param array defines the data to concatenate with.
+         */
         public concatWithNoDuplicate(array: any): void {
             if (array.length === 0) {
                 return;

+ 91 - 290
src/babylon.scene.ts

@@ -9,22 +9,6 @@
         dispose(): void;
     }
 
-    /**
-     * Interface used to let developers provide their own mesh selection mechanism
-     */
-    export interface IActiveMeshCandidateProvider {
-        /**
-         * Return the list of active meshes
-         * @param scene defines the current scene
-         * @returns the list of active meshes
-         */
-        getMeshes(scene: Scene): AbstractMesh[];
-        /** 
-         * Indicates if the meshes have been checked to make sure they are isEnabled()
-         */
-        readonly checksIsEnabled: boolean;
-    }
-
     /** @hidden */
     class ClickInfo {
         private _singleClick = false;
@@ -502,6 +486,11 @@
          */
         public onAfterRenderingGroupObservable = new Observable<RenderingGroupInfo>();
 
+        /**
+         * This Observable will when a mesh has been imported into the scene.
+         */
+        public onMeshImportedObservable = new Observable<AbstractMesh>();
+
         // Animations
         private _registeredForLateAnimationBindings = new SmartArrayNoDuplicate<any>(256);
 
@@ -873,11 +862,6 @@
         * Gets or sets a boolean indicating if probes are enabled on this scene
         */
         public probesEnabled = true;
-        /**
-         * The list of reflection probes added to the scene
-         * @see http://doc.babylonjs.com/how_to/how_to_use_reflection_probes
-         */
-        public reflectionProbes = new Array<ReflectionProbe>();
 
         // Database
         /**
@@ -1025,8 +1009,6 @@
          */
         public requireLightSorting = false;
 
-        private _selectionOctree: Octree<AbstractMesh>;
-
         private _pointerOverMesh: Nullable<AbstractMesh>;
 
         private _debugLayer: DebugLayer;
@@ -1170,11 +1152,6 @@
         public _afterCameraDrawStage = Stage.Create<CameraStageAction>();
         /**
          * @hidden
-         * Defines the actions happening when Geometries are rebuilding.
-         */
-        public _rebuildGeometryStage = Stage.Create<SimpleStageAction>();
-        /**
-         * @hidden
          * Defines the actions happening when a pointer move event happens.
          */
         public _pointerMoveStage = Stage.Create<PointerMoveStageAction>();
@@ -1220,6 +1197,49 @@
             if (ImageProcessingConfiguration) {
                 this._imageProcessingConfiguration = new ImageProcessingConfiguration();
             }
+
+            this.setDefaultCandidateProviders();
+        }
+
+        private _defaultMeshCandidates: ISmartArrayLike<AbstractMesh> = {
+            data: [],
+            length: 0
+        }
+
+        /**
+         * @hidden
+         */
+        public _getDefaultMeshCandidates(): ISmartArrayLike<AbstractMesh> {
+            this._defaultMeshCandidates.data = this.meshes;
+            this._defaultMeshCandidates.length = this.meshes.length;
+            return this._defaultMeshCandidates;
+        }
+
+        private _defaultSubMeshCandidates: ISmartArrayLike<SubMesh> = {
+            data: [],
+            length: 0
+        }
+
+        /**
+         * @hidden
+         */
+        public _getDefaultSubMeshCandidates(mesh: AbstractMesh): ISmartArrayLike<SubMesh> {
+            this._defaultSubMeshCandidates.data = mesh.subMeshes;
+            this._defaultSubMeshCandidates.length = mesh.subMeshes.length;
+            return this._defaultSubMeshCandidates;
+        }
+
+        /**
+         * Sets the default candidate providers for the scene.
+         * This sets the getActiveMeshCandidates, getActiveSubMeshCandidates, getIntersectingSubMeshCandidates
+         * and getCollidingSubMeshCandidates to their default function
+         */
+        public setDefaultCandidateProviders(): void {
+            this.getActiveMeshCandidates = this._getDefaultMeshCandidates.bind(this);
+
+            this.getActiveSubMeshCandidates = this._getDefaultSubMeshCandidates.bind(this);
+            this.getIntersectingSubMeshCandidates = this._getDefaultSubMeshCandidates.bind(this);
+            this.getCollidingSubMeshCandidates = this._getDefaultSubMeshCandidates.bind(this);
         }
 
         /**
@@ -1259,14 +1279,6 @@
         }
 
         /**
-         * Gets the octree used to boost mesh selection (picking)
-         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
-         */
-        public get selectionOctree(): Octree<AbstractMesh> {
-            return this._selectionOctree;
-        }
-
-        /**
          * Gets the mesh that is currently under the pointer
          */
         public get meshUnderPointer(): Nullable<AbstractMesh> {
@@ -1560,9 +1572,20 @@
                 return this;
             }
 
+            // Restore pointer
+            canvas.style.cursor = this.defaultCursor;
+
             var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
             if (isMeshPicked) {
                 this.setPointerOverMesh(pickResult!.pickedMesh);
+
+                if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
+                    if (this._pointerOverMesh.actionManager.hoverCursor) {
+                        canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
+                    } else {
+                        canvas.style.cursor = this.hoverCursor;
+                    }
+                }
             } else {
                 this.setPointerOverMesh(null);
             }
@@ -2927,11 +2950,11 @@
         }
 
         /**
-           * Remove a mesh for the list of scene's meshes
-           * @param toRemove defines the mesh to remove
-           * @param recursive if all child meshes should also be removed from the scene
-           * @returns the index where the mesh was in the mesh list
-           */
+         * Remove a mesh for the list of scene's meshes
+         * @param toRemove defines the mesh to remove
+         * @param recursive if all child meshes should also be removed from the scene
+         * @returns the index where the mesh was in the mesh list
+         */
         public removeMesh(toRemove: AbstractMesh, recursive = false): number {
             var index = this.meshes.indexOf(toRemove);
             if (index !== -1) {
@@ -4001,21 +4024,25 @@
             return this._intermediateRendering
         }
 
-        private _activeMeshCandidateProvider: IActiveMeshCandidateProvider;
         /**
-         * Defines the current active mesh candidate provider
-         * @param provider defines the provider to use
+         * Lambda returning the list of potentially active meshes.
          */
-        public setActiveMeshCandidateProvider(provider: IActiveMeshCandidateProvider): void {
-            this._activeMeshCandidateProvider = provider;
-        }
+        public getActiveMeshCandidates: () => ISmartArrayLike<AbstractMesh>;
+
         /**
-         * Gets the current active mesh candidate provider
-         * @returns the current active mesh candidate provider
+         * Lambda returning the list of potentially active sub meshes.
          */
-        public getActiveMeshCandidateProvider(): IActiveMeshCandidateProvider {
-            return this._activeMeshCandidateProvider;
-        }
+        public getActiveSubMeshCandidates: (mesh: AbstractMesh) => ISmartArrayLike<SubMesh>;
+
+        /**
+         * Lambda returning the list of potentially intersecting sub meshes.
+         */
+        public getIntersectingSubMeshCandidates: (mesh: AbstractMesh, localRay: Ray) => ISmartArrayLike<SubMesh>;
+
+        /**
+         * Lambda returning the list of potentially colliding sub meshes.
+         */
+        public getCollidingSubMeshCandidates: (mesh: AbstractMesh, collider: Collider) => ISmartArrayLike<SubMesh>;
 
         private _activeMeshesFrozen = false;
 
@@ -4068,43 +4095,20 @@
                 step.action();
             }
 
-            // Meshes
-            var meshes: AbstractMesh[];
-            var len: number;
-            var checkIsEnabled = true;
-
             // Determine mesh candidates
-            if (this._activeMeshCandidateProvider !== undefined) {
-                // Use _activeMeshCandidateProvider
-                meshes = this._activeMeshCandidateProvider.getMeshes(this);
-                checkIsEnabled = this._activeMeshCandidateProvider.checksIsEnabled === false;
-                if (meshes !== undefined) {
-                    len = meshes.length;
-                } else {
-                    len = 0;
-                }
-            } else if (this._selectionOctree !== undefined) {
-                // Octree
-                var selection = this._selectionOctree.select(this._frustumPlanes);
-                meshes = selection.data;
-                len = selection.length;
-            } else {
-                // Full scene traversal
-                len = this.meshes.length;
-                meshes = this.meshes;
-            }
-
+            const meshes = this.getActiveMeshCandidates();
+            
             // Check each mesh
-            for (var meshIndex = 0, mesh, meshLOD; meshIndex < len; meshIndex++) {
-                mesh = meshes[meshIndex];
-
+            const len = meshes.length;
+            for (let i = 0; i < len; i++) {
+                const mesh = meshes.data[i];
                 if (mesh.isBlocked) {
                     continue;
                 }
 
                 this._totalVertices.addCount(mesh.getTotalVertices(), false);
 
-                if (!mesh.isReady() || (checkIsEnabled && !mesh.isEnabled())) {
+                if (!mesh.isReady() || !mesh.isEnabled()) {
                     continue;
                 }
 
@@ -4116,8 +4120,7 @@
                 }
 
                 // Switch to current LOD
-                meshLOD = mesh.getLOD(this.activeCamera);
-
+                const meshLOD = mesh.getLOD(this.activeCamera);
                 if (meshLOD === undefined || meshLOD === null) {
                     continue;
                 }
@@ -4179,23 +4182,10 @@
                 mesh !== undefined && mesh !== null
                 && mesh.subMeshes !== undefined && mesh.subMeshes !== null && mesh.subMeshes.length > 0
             ) {
-                // Submeshes Octrees
-                var len: number;
-                var subMeshes: SubMesh[];
-
-                if (mesh.useOctreeForRenderingSelection && mesh._submeshesOctree !== undefined && mesh._submeshesOctree !== null) {
-                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
-
-                    len = intersections.length;
-                    subMeshes = intersections.data;
-                } else {
-                    subMeshes = mesh.subMeshes;
-                    len = subMeshes.length;
-                }
-
-                for (var subIndex = 0, subMesh; subIndex < len; subIndex++) {
-                    subMesh = subMeshes[subIndex];
-
+                const subMeshes = this.getActiveSubMeshCandidates(mesh);
+                const len = subMeshes.length;
+                for (let i = 0; i < len; i++) {
+                    const subMesh = subMeshes.data[i];
                     this._evaluateSubMesh(subMesh, mesh);
                 }
             }
@@ -4599,7 +4589,6 @@
                 if (data) {
                     data.dispose();
                 }
-                this._toBeDisposed[index] = null;
             }
 
             this._toBeDisposed.reset();
@@ -4787,7 +4776,6 @@
             this._beforeCameraUpdateStage.clear();
             this._beforeClearStage.clear();
             this._gatherRenderTargetsStage.clear();
-            this._rebuildGeometryStage.clear();
             this._pointerMoveStage.clear();
             this._pointerDownStage.clear();
             this._pointerUpStage.clear();
@@ -4851,6 +4839,7 @@
             this.onDataLoadedObservable.clear();
             this.onBeforeRenderingGroupObservable.clear();
             this.onAfterRenderingGroupObservable.clear();
+            this.onMeshImportedObservable.clear();
 
             this.detachControl();
 
@@ -5007,9 +4996,6 @@
             }
         }
 
-
-        // Octrees
-
         /**
          * Get the world extend vectors with an optional filter
          * 
@@ -5042,26 +5028,6 @@
             };
         }
 
-        /**
-         * Creates or updates the octree used to boost selection (picking)
-         * @see http://doc.babylonjs.com/how_to/optimizing_your_scene_with_octrees
-         * @param maxCapacity defines the maximum capacity per leaf
-         * @param maxDepth defines the maximum depth of the octree
-         * @returns an octree of AbstractMesh
-         */
-        public createOrUpdateSelectionOctree(maxCapacity = 64, maxDepth = 2): Octree<AbstractMesh> {
-            if (!this._selectionOctree) {
-                this._selectionOctree = new Octree<AbstractMesh>(Octree.CreationFuncForMeshes, maxCapacity, maxDepth);
-            }
-
-            var worldExtends = this.getWorldExtends();
-
-            // Update octree
-            this._selectionOctree.update(worldExtends.min, worldExtends.max, this.meshes);
-
-            return this._selectionOctree;
-        }
-
         // Picking
 
         /**
@@ -5427,10 +5393,6 @@
             for (var system of this.particleSystems) {
                 system.rebuild();
             }
-
-            for (let step of this._rebuildGeometryStage) {
-                step.action();
-            }
         }
 
         /** @hidden */
@@ -5442,167 +5404,6 @@
             this.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
         }
 
-        /**
-         * Creates a default light for the scene.
-         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-light
-         * @param replace has the default false, when true replaces the existing lights in the scene with a hemispheric light
-         */
-        public createDefaultLight(replace = false): void {
-            // Dispose existing light in replace mode.
-            if (replace) {
-                if (this.lights) {
-                    for (var i = 0; i < this.lights.length; i++) {
-                        this.lights[i].dispose();
-                    }
-                }
-            }
-
-            // Light
-            if (this.lights.length === 0) {
-                new HemisphericLight("default light", Vector3.Up(), this);
-            }
-        }
-
-        /**
-         * Creates a default camera for the scene.
-         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-camera
-         * @param createArcRotateCamera has the default false which creates a free camera, when true creates an arc rotate camera
-         * @param replace has default false, when true replaces the active camera in the scene
-         * @param attachCameraControls has default false, when true attaches camera controls to the canvas.
-         */
-        public createDefaultCamera(createArcRotateCamera = false, replace = false, attachCameraControls = false): void {
-            // Dispose existing camera in replace mode.
-            if (replace) {
-                if (this.activeCamera) {
-                    this.activeCamera.dispose();
-                    this.activeCamera = null;
-                }
-            }
-
-            // Camera
-            if (!this.activeCamera) {
-                var worldExtends = this.getWorldExtends();
-                var worldSize = worldExtends.max.subtract(worldExtends.min);
-                var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
-
-                var camera: TargetCamera;
-                var radius = worldSize.length() * 1.5;
-                // empty scene scenario!
-                if (!isFinite(radius)) {
-                    radius = 1;
-                    worldCenter.copyFromFloats(0, 0, 0);
-                }
-                if (createArcRotateCamera) {
-                    var arcRotateCamera = new ArcRotateCamera("default camera", -(Math.PI / 2), Math.PI / 2, radius, worldCenter, this);
-                    arcRotateCamera.lowerRadiusLimit = radius * 0.01;
-                    arcRotateCamera.wheelPrecision = 100 / radius;
-                    camera = arcRotateCamera;
-                }
-                else {
-                    var freeCamera = new FreeCamera("default camera", new Vector3(worldCenter.x, worldCenter.y, -radius), this);
-                    freeCamera.setTarget(worldCenter);
-                    camera = freeCamera;
-                }
-                camera.minZ = radius * 0.01;
-                camera.maxZ = radius * 1000;
-                camera.speed = radius * 0.2;
-                this.activeCamera = camera;
-
-                let canvas = this.getEngine().getRenderingCanvas();
-                if (attachCameraControls && canvas) {
-                    camera.attachControl(canvas);
-                }
-            }
-        }
-
-        /**
-         * Creates a default camera and a default light.
-         * @see http://doc.babylonjs.com/how_to/Fast_Build#create-default-camera-or-light
-         * @param createArcRotateCamera has the default false which creates a free camera, when true creates an arc rotate camera
-         * @param replace has the default false, when true replaces the active camera/light in the scene
-         * @param attachCameraControls has the default false, when true attaches camera controls to the canvas.
-         */
-        public createDefaultCameraOrLight(createArcRotateCamera = false, replace = false, attachCameraControls = false): void {
-            this.createDefaultLight(replace);
-            this.createDefaultCamera(createArcRotateCamera, replace, attachCameraControls);
-        }
-
-        /**
-         * Creates a new sky box
-         * @see http://doc.babylonjs.com/how_to/Fast_Build#create-default-skybox
-         * @param environmentTexture defines the texture to use as environment texture
-         * @param pbr has default false which requires the StandardMaterial to be used, when true PBRMaterial must be used 
-         * @param scale defines the overall scale of the skybox
-         * @param blur is only available when pbr is true, default is 0, no blur, maximum value is 1
-         * @param setGlobalEnvTexture has default true indicating that scene.environmentTexture must match the current skybox texture
-         * @returns a new mesh holding the sky box
-         */
-        public createDefaultSkybox(environmentTexture?: BaseTexture, pbr = false, scale = 1000, blur = 0, setGlobalEnvTexture = true): Nullable<Mesh> {
-
-            if (!environmentTexture) {
-                Tools.Warn("Can not create default skybox without environment texture.");
-                return null;
-            }
-
-            if (setGlobalEnvTexture) {
-                if (environmentTexture) {
-                    this.environmentTexture = environmentTexture;
-                }
-            }
-
-            // Skybox
-            var hdrSkybox = Mesh.CreateBox("hdrSkyBox", scale, this);
-            if (pbr) {
-                let hdrSkyboxMaterial = new PBRMaterial("skyBox", this);
-                hdrSkyboxMaterial.backFaceCulling = false;
-                hdrSkyboxMaterial.reflectionTexture = environmentTexture.clone();
-                if (hdrSkyboxMaterial.reflectionTexture) {
-                    hdrSkyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
-                }
-                hdrSkyboxMaterial.microSurface = 1.0 - blur;
-                hdrSkyboxMaterial.disableLighting = true;
-                hdrSkyboxMaterial.twoSidedLighting = true;
-                hdrSkybox.infiniteDistance = true;
-                hdrSkybox.material = hdrSkyboxMaterial;
-            }
-            else {
-                let skyboxMaterial = new StandardMaterial("skyBox", this);
-                skyboxMaterial.backFaceCulling = false;
-                skyboxMaterial.reflectionTexture = environmentTexture.clone();
-                if (skyboxMaterial.reflectionTexture) {
-                    skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
-                }
-                skyboxMaterial.disableLighting = true;
-                hdrSkybox.infiniteDistance = true;
-                hdrSkybox.material = skyboxMaterial;
-            }
-
-            return hdrSkybox;
-        }
-
-        /**
-         * Creates a new environment
-         * @see http://doc.babylonjs.com/How_To/Fast_Build#create-default-environment
-         * @param options defines the options you can use to configure the environment
-         * @returns the new EnvironmentHelper
-         */
-        public createDefaultEnvironment(options: Partial<IEnvironmentHelperOptions>): Nullable<EnvironmentHelper> {
-            if (EnvironmentHelper) {
-                return new EnvironmentHelper(options, this);
-            }
-            return null;
-        }
-
-        /**
-         * Creates a new VREXperienceHelper
-         * @see http://doc.babylonjs.com/how_to/webvr_helper
-         * @param webVROptions defines the options used to create the new VREXperienceHelper
-         * @returns a new VREXperienceHelper
-         */
-        public createDefaultVRExperience(webVROptions: VRExperienceHelperOptions = {}): VRExperienceHelper {
-            return new VRExperienceHelper(this, webVROptions);
-        }
-
         // Tags
         private _getByTags(list: any[], tagsQuery: string, forEach?: (item: any) => void): any[] {
             if (tagsQuery === undefined) {

+ 1 - 2
src/babylon.sceneComponent.ts

@@ -18,6 +18,7 @@
         public static readonly NAME_OUTLINERENDERER = "Outline";
         public static readonly NAME_PROCEDURALTEXTURE = "ProceduralTexture";
         public static readonly NAME_SHADOWGENERATOR = "ShadowGenerator";
+        public static readonly NAME_OCTREE = "Octree";
 
         public static readonly STEP_ISREADYFORMESH_EFFECTLAYER = 0;
 
@@ -54,8 +55,6 @@
         public static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 2;
         public static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER = 3;
 
-        public static readonly STEP_REBUILDGEOMETRY_POSTPROCESSRENDERPIPELINEMANAGER = 0;
-
         public static readonly STEP_POINTERMOVE_SPRITE = 0;
         public static readonly STEP_POINTERDOWN_SPRITE = 0;
         public static readonly STEP_POINTERUP_SPRITE = 0;

BIN
tests/validation/ReferenceImages/LightProjectionTexture.png


BIN
tests/validation/ReferenceImages/pbr.png