Jelajahi Sumber

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

Guide 7 tahun lalu
induk
melakukan
b0e30252a9
66 mengubah file dengan 27059 tambahan dan 21772 penghapusan
  1. 9464 8832
      Playground/babylon.d.txt
  2. 20 3
      Tools/Gulp/config.json
  3. 9382 8931
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 1265 455
      dist/preview release/babylon.max.js
  6. 1265 455
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 1267 457
      dist/preview release/es6.js
  9. 199 4
      dist/preview release/gui/babylon.gui.d.ts
  10. 1 1
      dist/preview release/gui/babylon.gui.js
  11. 1 1
      dist/preview release/gui/babylon.gui.min.js
  12. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  13. 404 9
      dist/preview release/gui/babylon.gui.module.d.ts
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  15. 1 0
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  16. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  17. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.js
  18. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  19. 2 152
      dist/preview release/typedocValidationBaseline.json
  20. 39 5
      dist/preview release/viewer/babylon.viewer.d.ts
  21. 2 2
      dist/preview release/viewer/babylon.viewer.js
  22. 3 3
      dist/preview release/viewer/babylon.viewer.max.js
  23. 43 6
      dist/preview release/viewer/babylon.viewer.module.d.ts
  24. 8 0
      dist/preview release/what's new.md
  25. 32 1
      gui/src/2D/advancedDynamicTexture.ts
  26. 17 0
      gui/src/2D/controls/control.ts
  27. 15 0
      gui/src/2D/controls/inputText.ts
  28. 106 46
      gui/src/2D/controls/virtualKeyboard.ts
  29. 9 2
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  30. 2 0
      materialsLibrary/src/water/babylon.waterMaterial.ts
  31. 2 2
      sandbox/index.js
  32. 7 3
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  33. 2 1
      src/Collisions/babylon.collisionWorker.ts
  34. 233 0
      src/Culling/Octrees/babylon.octreeSceneComponent.ts
  35. 31 0
      src/Debug/babylon.debugLayer.ts
  36. 176 0
      src/Helpers/babylon.sceneHelpers.ts
  37. 15 0
      src/Materials/Background/babylon.backgroundMaterial.ts
  38. 16 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  39. 5 0
      src/Materials/babylon.material.ts
  40. 15 0
      src/Materials/babylon.standardMaterial.ts
  41. 7 70
      src/Mesh/babylon.abstractMesh.ts
  42. 2 6
      src/Mesh/babylon.geometry.ts
  43. 6 1
      src/Mesh/babylon.groundMesh.ts
  44. 4 3
      src/Mesh/babylon.mesh.ts
  45. 50 0
      src/Particles/babylon.IParticleSystem.ts
  46. 44 1
      src/Particles/babylon.baseParticleSystem.ts
  47. 90 26
      src/Particles/babylon.gpuParticleSystem.ts
  48. 20 0
      src/Particles/babylon.particle.ts
  49. 2371 1935
      src/Particles/babylon.particleSystem.ts
  50. 68 0
      src/Particles/babylon.subEmitter.ts
  51. 27 4
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  52. 3 8
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManagerSceneComponent.ts
  53. 12 0
      src/Probes/babylon.reflectionProbe.ts
  54. 7 0
      src/Rendering/babylon.depthRenderer.ts
  55. 16 1
      src/Rendering/babylon.depthRendererSceneComponent.ts
  56. 17 2
      src/Shaders/particles.fragment.fx
  57. 11 0
      src/Shaders/particles.vertex.fx
  58. 0 2
      src/Sprites/babylon.spriteSceneComponent.ts
  59. 10 6
      src/Tools/babylon.sceneOptimizer.ts
  60. 87 8
      src/Tools/babylon.smartArray.ts
  61. 5 0
      src/babylon.abstractScene.ts
  62. 31 1
      src/babylon.node.ts
  63. 113 320
      src/babylon.scene.ts
  64. 2 1
      src/babylon.sceneComponent.ts
  65. TEMPAT SAMPAH
      tests/validation/ReferenceImages/LightProjectionTexture.png
  66. TEMPAT SAMPAH
      tests/validation/ReferenceImages/pbr.png

File diff ditekan karena terlalu besar
+ 9464 - 8832
Playground/babylon.d.txt


+ 20 - 3
Tools/Gulp/config.json

@@ -125,7 +125,8 @@
             "occlusionQuery",
             "transformFeedback",
             "noise",
-            "videoRecorder"
+            "videoRecorder",
+            "sceneHelpers"
         ],
         "minimal": [
             "meshBuilder",
@@ -299,7 +300,8 @@
                 "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.hemisphericParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.pointParticleEmitter.js",
-                "../../src/Particles/babylon.particleSystemComponent.js"
+                "../../src/Particles/babylon.particleSystemComponent.js",
+                "../../src/Particles/babylon.subEmitter.js"
             ],
             "dependUpon": [
                 "core"
@@ -1204,7 +1206,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 +1372,20 @@
                 "backgroundUboDeclaration"
             ]
         },
+        "sceneHelpers": {
+            "files": [
+                "../../src/Helpers/babylon.sceneHelpers.js"
+            ],
+            "dependUpon": [
+                "core",
+                "arcRotateCamera",
+                "freeCamera",
+                "hemisphericLight",
+                "pbrMaterial",
+                "environmentHelper",
+                "vr"
+            ]
+        },
         "environmentHelper": {
             "files": [
                 "../../src/Helpers/babylon.environmentHelper.js"

File diff ditekan karena terlalu besar
+ 9382 - 8931
dist/preview release/babylon.d.ts


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/babylon.js


File diff ditekan karena terlalu besar
+ 1265 - 455
dist/preview release/babylon.max.js


File diff ditekan karena terlalu besar
+ 1265 - 455
dist/preview release/babylon.no-module.max.js


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/babylon.worker.js


File diff ditekan karena terlalu besar
+ 1267 - 457
dist/preview release/es6.js


+ 199 - 4
dist/preview release/gui/babylon.gui.d.ts

@@ -27,6 +27,11 @@ declare module BABYLON.GUI {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): BABYLON.Nullable<Control[]>;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -1076,6 +1081,12 @@ declare module BABYLON.GUI {
             /** @hidden */
             _resetFontCache(): void;
             /**
+                * Determines if a container is an ascendant of the current control
+                * @param container defines the container to look for
+                * @returns true if the container is one of the ascendant of the control
+                */
+            isAscendant(container: Control): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -1365,6 +1376,8 @@ declare module BABYLON.GUI {
         */
     export class InputText extends Control implements IFocusableControl {
             name?: string | undefined;
+            /** @hidden */
+            _connectedVirtualKeyboard: BABYLON.Nullable<VirtualKeyboard>;
             /** Gets or sets a string representing the message displayed on mobile when the control gets the focus */
             promptMessage: string;
             /** BABYLON.Observable raised when the text changes */
@@ -1416,6 +1429,11 @@ declare module BABYLON.GUI {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): BABYLON.Nullable<Control[]>;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -1596,6 +1614,174 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class SelectorGroup {
+            /** name of SelectorGroup */
+            name: string;
+            /**
+                * Creates a new SelectorGroup
+                * @param name of group, used as a group heading
+                */
+            constructor(
+            /** name of SelectorGroup */
+            name: string);
+            /** Gets the groupPanel of the SelectorGroup  */
+            readonly groupPanel: StackPanel;
+            /** Gets the selectors array */
+            readonly selectors: StackPanel[];
+            /** Gets and sets the group header */
+            header: string;
+            /** @hidden*/
+            _getSelector(selectorNb: number): StackPanel | undefined;
+            /** Removes the selector at the given position
+             * @param selectorNb the position of the selector within the group
+            */
+            removeSelector(selectorNb: number): void;
+    }
+    /** Class used to create a CheckboxGroup
+        * which contains groups of checkbox buttons
+     */
+    export class CheckboxGroup extends SelectorGroup {
+            /** Adds a checkbox as a control
+                * @param text is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addCheckbox(text: string, func?: (s: boolean) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class RadioGroup extends SelectorGroup {
+            /** Adds a radio button as a control
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addRadio(label: string, func?: (n: number) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a SliderGroup
+        * which contains groups of slider buttons
+     */
+    export class SliderGroup extends SelectorGroup {
+            /**
+                * Adds a slider to the SelectorGroup
+                * @param label is the label for the SliderBar
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onValueChange is the function used to format the value displayed, eg radians to degrees
+                */
+            addSlider(label: string, func?: (v: number) => void, unit?: string, min?: number, max?: number, value?: number, onValueChange?: (v: number) => number): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to hold the controls for the checkboxes, radio buttons and sliders */
+    export class SelectionPanel extends Rectangle {
+            /** name of SelectionPanel */
+            name: string;
+            /** an array of SelectionGroups */
+            groups: SelectorGroup[];
+            /**
+             * Creates a new SelectionPanel
+             * @param name of SelectionPanel
+             * @param groups is an array of SelectionGroups
+             */
+            constructor(
+            /** name of SelectionPanel */
+            name: string, 
+            /** an array of SelectionGroups */
+            groups?: SelectorGroup[]);
+            protected _getTypeName(): string;
+            /** Gets or sets the headerColor */
+            headerColor: string;
+            /** Gets or sets the button color */
+            buttonColor: string;
+            /** Gets or sets the label color */
+            labelColor: string;
+            /** Gets or sets the button background */
+            buttonBackground: string;
+            /** Gets or sets the color of separator bar */
+            barColor: string;
+            /** Add a group to the selection panel
+                * @param group is the selector group to add
+                */
+            addGroup(group: SelectorGroup): void;
+            /** Remove the group from the given position
+                * @param groupNb is the position of the group in the list
+                */
+            removeGroup(groupNb: number): void;
+            /** Change a group header label
+                * @param label is the new group header label
+                * @param groupNb is the number of the group to relabel
+                * */
+            setHeaderName(label: string, groupNb: number): void;
+            /** Change selector label to the one given
+                * @param label is the new selector label
+                * @param groupNb is the number of the groupcontaining the selector
+                * @param selectorNb is the number of the selector within a group to relabel
+                * */
+            relabel(label: string, groupNb: number, selectorNb: number): void;
+            /** For a given group position remove the selector at the given position
+                * @param groupNb is the number of the group to remove the selector from
+                * @param selectorNb is the number of the selector within the group
+                */
+            removeFromGroupSelector(groupNb: number, selectorNb: number): void;
+            /** For a given group position of correct type add a checkbox button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupCheckbox(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /** For a given group position of correct type add a radio button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupRadio(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /**
+                * For a given slider group add a slider
+                * @param groupNb is the number of the group to add the slider to
+                * @param label is the label for the Slider
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onVal is the function used to format the value displayed, eg radians to degrees
+                */
+            addToGroupSlider(groupNb: number, label: string, func?: () => void, unit?: string, min?: number, max?: number, value?: number, onVal?: (v: number) => number): void;
+    }
+}
+declare module BABYLON.GUI {
     /**
         * Enum that determines the text-wrapping mode to use.
         */
@@ -1755,22 +1941,31 @@ declare module BABYLON.GUI {
                 * @param shiftState defines the new shift state
                 */
             applyShiftState(shiftState: number): void;
-            /** Gets the input text control attached with the keyboard */
+            /** Gets the input text control currently attached to the keyboard */
             readonly connectedInputText: BABYLON.Nullable<InputText>;
             /**
                 * Connects the keyboard with an input text control
+                *
                 * @param input defines the target control
                 */
             connect(input: InputText): void;
             /**
-                * Disconnects the keyboard from an input text control
+                * Disconnects the keyboard from connected InputText controls
+                *
+                * @param input optionally defines a target control, otherwise all are disconnected
                 */
-            disconnect(): void;
+            disconnect(input?: InputText): void;
+            /**
+                * Release all resources
+                */
+            dispose(): void;
             /**
                 * Creates a new keyboard using a default layout
+                *
+                * @param name defines control name
                 * @returns a new VirtualKeyboard
                 */
-            static CreateDefaultLayout(): VirtualKeyboard;
+            static CreateDefaultLayout(name?: string): VirtualKeyboard;
     }
 }
 declare module BABYLON.GUI {

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/gui/babylon.gui.js


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 404 - 9
dist/preview release/gui/babylon.gui.module.d.ts

@@ -39,6 +39,7 @@ declare module 'babylonjs-gui/2D/controls' {
     export * from "babylonjs-gui/2D/controls/multiLine";
     export * from "babylonjs-gui/2D/controls/radioButton";
     export * from "babylonjs-gui/2D/controls/stackPanel";
+    export * from "babylonjs-gui/2D/controls/selector";
     export * from "babylonjs-gui/2D/controls/textBlock";
     export * from "babylonjs-gui/2D/controls/virtualKeyboard";
     export * from "babylonjs-gui/2D/controls/slider";
@@ -69,6 +70,11 @@ declare module 'babylonjs-gui/2D/advancedDynamicTexture' {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): Nullable<Control[]>;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -1178,6 +1184,12 @@ declare module 'babylonjs-gui/2D/controls/control' {
             /** @hidden */
             _resetFontCache(): void;
             /**
+                * Determines if a container is an ascendant of the current control
+                * @param container defines the container to look for
+                * @returns true if the container is one of the ascendant of the control
+                */
+            isAscendant(container: Control): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -1476,13 +1488,16 @@ declare module 'babylonjs-gui/2D/controls/image' {
 declare module 'babylonjs-gui/2D/controls/inputText' {
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { IFocusableControl } from "babylonjs-gui/2D/advancedDynamicTexture";
-    import { Observable, Vector2 } from "babylonjs";
+    import { Nullable, Observable, Vector2 } from "babylonjs";
     import { Measure } from "babylonjs-gui/2D/measure";
+    import { VirtualKeyboard } from "babylonjs-gui/2D/controls/virtualKeyboard";
     /**
         * Class used to create input text control
         */
     export class InputText extends Control implements IFocusableControl {
             name?: string | undefined;
+            /** @hidden */
+            _connectedVirtualKeyboard: Nullable<VirtualKeyboard>;
             /** Gets or sets a string representing the message displayed on mobile when the control gets the focus */
             promptMessage: string;
             /** Observable raised when the text changes */
@@ -1534,6 +1549,11 @@ declare module 'babylonjs-gui/2D/controls/inputText' {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): Nullable<Control[]>;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -1733,6 +1753,177 @@ declare module 'babylonjs-gui/2D/controls/stackPanel' {
     }
 }
 
+declare module 'babylonjs-gui/2D/controls/selector' {
+    import { Rectangle } from "babylonjs-gui/2D/controls/rectangle";
+    import { StackPanel } from "babylonjs-gui/2D/controls/stackPanel";
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class SelectorGroup {
+            /** name of SelectorGroup */
+            name: string;
+            /**
+                * Creates a new SelectorGroup
+                * @param name of group, used as a group heading
+                */
+            constructor(
+            /** name of SelectorGroup */
+            name: string);
+            /** Gets the groupPanel of the SelectorGroup  */
+            readonly groupPanel: StackPanel;
+            /** Gets the selectors array */
+            readonly selectors: StackPanel[];
+            /** Gets and sets the group header */
+            header: string;
+            /** @hidden*/
+            _getSelector(selectorNb: number): StackPanel | undefined;
+            /** Removes the selector at the given position
+             * @param selectorNb the position of the selector within the group
+            */
+            removeSelector(selectorNb: number): void;
+    }
+    /** Class used to create a CheckboxGroup
+        * which contains groups of checkbox buttons
+     */
+    export class CheckboxGroup extends SelectorGroup {
+            /** Adds a checkbox as a control
+                * @param text is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addCheckbox(text: string, func?: (s: boolean) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class RadioGroup extends SelectorGroup {
+            /** Adds a radio button as a control
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addRadio(label: string, func?: (n: number) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a SliderGroup
+        * which contains groups of slider buttons
+     */
+    export class SliderGroup extends SelectorGroup {
+            /**
+                * Adds a slider to the SelectorGroup
+                * @param label is the label for the SliderBar
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onValueChange is the function used to format the value displayed, eg radians to degrees
+                */
+            addSlider(label: string, func?: (v: number) => void, unit?: string, min?: number, max?: number, value?: number, onValueChange?: (v: number) => number): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to hold the controls for the checkboxes, radio buttons and sliders */
+    export class SelectionPanel extends Rectangle {
+            /** name of SelectionPanel */
+            name: string;
+            /** an array of SelectionGroups */
+            groups: SelectorGroup[];
+            /**
+             * Creates a new SelectionPanel
+             * @param name of SelectionPanel
+             * @param groups is an array of SelectionGroups
+             */
+            constructor(
+            /** name of SelectionPanel */
+            name: string, 
+            /** an array of SelectionGroups */
+            groups?: SelectorGroup[]);
+            protected _getTypeName(): string;
+            /** Gets or sets the headerColor */
+            headerColor: string;
+            /** Gets or sets the button color */
+            buttonColor: string;
+            /** Gets or sets the label color */
+            labelColor: string;
+            /** Gets or sets the button background */
+            buttonBackground: string;
+            /** Gets or sets the color of separator bar */
+            barColor: string;
+            /** Add a group to the selection panel
+                * @param group is the selector group to add
+                */
+            addGroup(group: SelectorGroup): void;
+            /** Remove the group from the given position
+                * @param groupNb is the position of the group in the list
+                */
+            removeGroup(groupNb: number): void;
+            /** Change a group header label
+                * @param label is the new group header label
+                * @param groupNb is the number of the group to relabel
+                * */
+            setHeaderName(label: string, groupNb: number): void;
+            /** Change selector label to the one given
+                * @param label is the new selector label
+                * @param groupNb is the number of the groupcontaining the selector
+                * @param selectorNb is the number of the selector within a group to relabel
+                * */
+            relabel(label: string, groupNb: number, selectorNb: number): void;
+            /** For a given group position remove the selector at the given position
+                * @param groupNb is the number of the group to remove the selector from
+                * @param selectorNb is the number of the selector within the group
+                */
+            removeFromGroupSelector(groupNb: number, selectorNb: number): void;
+            /** For a given group position of correct type add a checkbox button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupCheckbox(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /** For a given group position of correct type add a radio button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupRadio(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /**
+                * For a given slider group add a slider
+                * @param groupNb is the number of the group to add the slider to
+                * @param label is the label for the Slider
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onVal is the function used to format the value displayed, eg radians to degrees
+                */
+            addToGroupSlider(groupNb: number, label: string, func?: () => void, unit?: string, min?: number, max?: number, value?: number, onVal?: (v: number) => number): void;
+    }
+}
+
 declare module 'babylonjs-gui/2D/controls/textBlock' {
     import { Observable } from "babylonjs";
     import { Measure } from "babylonjs-gui/2D/measure";
@@ -1900,22 +2091,31 @@ declare module 'babylonjs-gui/2D/controls/virtualKeyboard' {
                 * @param shiftState defines the new shift state
                 */
             applyShiftState(shiftState: number): void;
-            /** Gets the input text control attached with the keyboard */
+            /** Gets the input text control currently attached to the keyboard */
             readonly connectedInputText: Nullable<InputText>;
             /**
                 * Connects the keyboard with an input text control
+                *
                 * @param input defines the target control
                 */
             connect(input: InputText): void;
             /**
-                * Disconnects the keyboard from an input text control
+                * Disconnects the keyboard from connected InputText controls
+                *
+                * @param input optionally defines a target control, otherwise all are disconnected
                 */
-            disconnect(): void;
+            disconnect(input?: InputText): void;
+            /**
+                * Release all resources
+                */
+            dispose(): void;
             /**
                 * Creates a new keyboard using a default layout
+                *
+                * @param name defines control name
                 * @returns a new VirtualKeyboard
                 */
-            static CreateDefaultLayout(): VirtualKeyboard;
+            static CreateDefaultLayout(name?: string): VirtualKeyboard;
     }
 }
 
@@ -2633,6 +2833,11 @@ declare module BABYLON.GUI {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): BABYLON.Nullable<Control[]>;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -3682,6 +3887,12 @@ declare module BABYLON.GUI {
             /** @hidden */
             _resetFontCache(): void;
             /**
+                * Determines if a container is an ascendant of the current control
+                * @param container defines the container to look for
+                * @returns true if the container is one of the ascendant of the control
+                */
+            isAscendant(container: Control): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -3971,6 +4182,8 @@ declare module BABYLON.GUI {
         */
     export class InputText extends Control implements IFocusableControl {
             name?: string | undefined;
+            /** @hidden */
+            _connectedVirtualKeyboard: BABYLON.Nullable<VirtualKeyboard>;
             /** Gets or sets a string representing the message displayed on mobile when the control gets the focus */
             promptMessage: string;
             /** BABYLON.Observable raised when the text changes */
@@ -4022,6 +4235,11 @@ declare module BABYLON.GUI {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to get the list of controls that should not steal the focus from this control
+                * @returns an array of controls
+                */
+            keepsFocusWith(): BABYLON.Nullable<Control[]>;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -4202,6 +4420,174 @@ declare module BABYLON.GUI {
     }
 }
 declare module BABYLON.GUI {
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class SelectorGroup {
+            /** name of SelectorGroup */
+            name: string;
+            /**
+                * Creates a new SelectorGroup
+                * @param name of group, used as a group heading
+                */
+            constructor(
+            /** name of SelectorGroup */
+            name: string);
+            /** Gets the groupPanel of the SelectorGroup  */
+            readonly groupPanel: StackPanel;
+            /** Gets the selectors array */
+            readonly selectors: StackPanel[];
+            /** Gets and sets the group header */
+            header: string;
+            /** @hidden*/
+            _getSelector(selectorNb: number): StackPanel | undefined;
+            /** Removes the selector at the given position
+             * @param selectorNb the position of the selector within the group
+            */
+            removeSelector(selectorNb: number): void;
+    }
+    /** Class used to create a CheckboxGroup
+        * which contains groups of checkbox buttons
+     */
+    export class CheckboxGroup extends SelectorGroup {
+            /** Adds a checkbox as a control
+                * @param text is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addCheckbox(text: string, func?: (s: boolean) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a RadioGroup
+        * which contains groups of radio buttons
+     */
+    export class RadioGroup extends SelectorGroup {
+            /** Adds a radio button as a control
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addRadio(label: string, func?: (n: number) => void, checked?: boolean): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to create a SliderGroup
+        * which contains groups of slider buttons
+     */
+    export class SliderGroup extends SelectorGroup {
+            /**
+                * Adds a slider to the SelectorGroup
+                * @param label is the label for the SliderBar
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onValueChange is the function used to format the value displayed, eg radians to degrees
+                */
+            addSlider(label: string, func?: (v: number) => void, unit?: string, min?: number, max?: number, value?: number, onValueChange?: (v: number) => number): void;
+            /** @hidden */
+            _setSelectorLabel(selectorNb: number, label: string): void;
+            /** @hidden */
+            _setSelectorLabelColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonColor(selectorNb: number, color: string): void;
+            /** @hidden */
+            _setSelectorButtonBackground(selectorNb: number, color: string): void;
+    }
+    /** Class used to hold the controls for the checkboxes, radio buttons and sliders */
+    export class SelectionPanel extends Rectangle {
+            /** name of SelectionPanel */
+            name: string;
+            /** an array of SelectionGroups */
+            groups: SelectorGroup[];
+            /**
+             * Creates a new SelectionPanel
+             * @param name of SelectionPanel
+             * @param groups is an array of SelectionGroups
+             */
+            constructor(
+            /** name of SelectionPanel */
+            name: string, 
+            /** an array of SelectionGroups */
+            groups?: SelectorGroup[]);
+            protected _getTypeName(): string;
+            /** Gets or sets the headerColor */
+            headerColor: string;
+            /** Gets or sets the button color */
+            buttonColor: string;
+            /** Gets or sets the label color */
+            labelColor: string;
+            /** Gets or sets the button background */
+            buttonBackground: string;
+            /** Gets or sets the color of separator bar */
+            barColor: string;
+            /** Add a group to the selection panel
+                * @param group is the selector group to add
+                */
+            addGroup(group: SelectorGroup): void;
+            /** Remove the group from the given position
+                * @param groupNb is the position of the group in the list
+                */
+            removeGroup(groupNb: number): void;
+            /** Change a group header label
+                * @param label is the new group header label
+                * @param groupNb is the number of the group to relabel
+                * */
+            setHeaderName(label: string, groupNb: number): void;
+            /** Change selector label to the one given
+                * @param label is the new selector label
+                * @param groupNb is the number of the groupcontaining the selector
+                * @param selectorNb is the number of the selector within a group to relabel
+                * */
+            relabel(label: string, groupNb: number, selectorNb: number): void;
+            /** For a given group position remove the selector at the given position
+                * @param groupNb is the number of the group to remove the selector from
+                * @param selectorNb is the number of the selector within the group
+                */
+            removeFromGroupSelector(groupNb: number, selectorNb: number): void;
+            /** For a given group position of correct type add a checkbox button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupCheckbox(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /** For a given group position of correct type add a radio button
+                * @param groupNb is the number of the group to remove the selector from
+                * @param label is the label for the selector
+                * @param func is the function called when the Selector is checked
+                * @param checked is true when Selector is checked
+                */
+            addToGroupRadio(groupNb: number, label: string, func?: () => void, checked?: boolean): void;
+            /**
+                * For a given slider group add a slider
+                * @param groupNb is the number of the group to add the slider to
+                * @param label is the label for the Slider
+                * @param func is the function called when the Slider moves
+                * @param unit is a string describing the units used, eg degrees or metres
+                * @param min is the minimum value for the Slider
+                * @param max is the maximum value for the Slider
+                * @param value is the start value for the Slider between min and max
+                * @param onVal is the function used to format the value displayed, eg radians to degrees
+                */
+            addToGroupSlider(groupNb: number, label: string, func?: () => void, unit?: string, min?: number, max?: number, value?: number, onVal?: (v: number) => number): void;
+    }
+}
+declare module BABYLON.GUI {
     /**
         * Enum that determines the text-wrapping mode to use.
         */
@@ -4361,22 +4747,31 @@ declare module BABYLON.GUI {
                 * @param shiftState defines the new shift state
                 */
             applyShiftState(shiftState: number): void;
-            /** Gets the input text control attached with the keyboard */
+            /** Gets the input text control currently attached to the keyboard */
             readonly connectedInputText: BABYLON.Nullable<InputText>;
             /**
                 * Connects the keyboard with an input text control
+                *
                 * @param input defines the target control
                 */
             connect(input: InputText): void;
             /**
-                * Disconnects the keyboard from an input text control
+                * Disconnects the keyboard from connected InputText controls
+                *
+                * @param input optionally defines a target control, otherwise all are disconnected
                 */
-            disconnect(): void;
+            disconnect(input?: InputText): void;
+            /**
+                * Release all resources
+                */
+            dispose(): void;
             /**
                 * Creates a new keyboard using a default layout
+                *
+                * @param name defines control name
                 * @returns a new VirtualKeyboard
                 */
-            static CreateDefaultLayout(): VirtualKeyboard;
+            static CreateDefaultLayout(name?: string): VirtualKeyboard;
     }
 }
 declare module BABYLON.GUI {

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 1 - 0
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -127,6 +127,7 @@ var BABYLON;
             _this._lastTime = 0;
             _this._lastDeltaTime = 0;
             _this._createRenderTargets(scene, renderTargetSize);
+            _this.hasRenderTargetTextures = true;
             // Create render targets
             _this.getRenderTargetTextures = function () {
                 _this._renderTargets.reset();

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


+ 1 - 0
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -1601,6 +1601,7 @@ var BABYLON;
             _this._lastTime = 0;
             _this._lastDeltaTime = 0;
             _this._createRenderTargets(scene, renderTargetSize);
+            _this.hasRenderTargetTextures = true;
             // Create render targets
             _this.getRenderTargetTextures = function () {
                 _this._renderTargets.reset();

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 2 - 152
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 3899,
+  "errors": 3875,
   "babylon.typedoc.json": {
-    "errors": 3899,
+    "errors": 3875,
     "AnimationGroup": {
       "Constructor": {
         "new AnimationGroup": {
@@ -14824,156 +14824,6 @@
         }
       }
     },
-    "SmartArray": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Constructor": {
-        "new SmartArray": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "capacity": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
-      "Property": {
-        "data": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "length": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
-      "Method": {
-        "concat": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "array": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "contains": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "value": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "dispose": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "forEach": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "func": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "indexOf": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "value": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "push": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "value": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "reset": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "sort": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "compareFn": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
-    "SmartArrayNoDuplicate": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Method": {
-        "concatWithNoDuplicate": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "array": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "pushNoDuplicate": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "value": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      }
-    },
     "Sound": {
       "Class": {
         "Comments": {

+ 39 - 5
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
@@ -2079,6 +2093,26 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
 }
 declare module BabylonViewer {
     /**

File diff ditekan karena terlalu besar
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


File diff ditekan karena terlalu besar
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


+ 43 - 6
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
@@ -2236,7 +2253,27 @@ declare module 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfigur
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration' {
-    
+    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/templateConfiguration' {

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

@@ -40,6 +40,8 @@
   - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
   - Added support for emit rate gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#emit-rate-over-time)
   - Start size gradient support for particles. [Doc](http://doc.babylonjs.com/babylon101/particles#start-size-over-time) ([TrevorDev](https://github.com/TrevorDev))
+  - Attached sub emitters. [Doc](http://doc.babylonjs.com/how_to/sub_emitters) ([TrevorDev](https://github.com/TrevorDev))
+  - Cylinder particle emitter and constructor in baseParticle [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
   - Added support for cylinder particle emitter. [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
   - Added support for random start cell when using animated sprite sheets. [Doc](http://doc.babylonjs.com/how_to/animate)
 - Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
@@ -62,9 +64,11 @@
 - Added `TextBlock.computeExpectedHeight`, added `TextWrapping.Ellipsis` as `TextBlock.wordWrapping` possible value ([adrientetar](https://github.com/adrientetar))
 - New vertical mode for sliders in 2D GUI. [Demo](https://www.babylonjs-playground.com/#U9AC0N#53) ([Saket Saurabh](https://github.com/ssaket))
 - Added `isEnabled` and `disabledColor` property to Gui Control ([barteq100](https://github.com/barteq100))
+- Added support for connecting multiple InputText controls to VirtualKeyboard and can disconnect individual InputTexts. ([brian Zinn](https://github.com/brianzinn))
 
 ### Core Engine
 
+- Added `scene.rootNodes` to track root nodes (ie. nodes with no parent) ([Deltakosh](https://github.com/deltakosh))
 - Added `scene.pickSpriteWithRay` function ([Deltakosh](https://github.com/deltakosh))
 - Added support for multiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
@@ -119,6 +123,8 @@
 - Added supports for reflectionMatrix in Skybox Mode Cube Texture allowing offsetting the world center or rotating the matrix ([sebavan](http://www.github.com/sebavan))
 - Improved performance of cached nodes but ensuring parent always updates cache. This removes failed isSynchronized test that meant computeWorldMatrix would always have to rebuild. On large scenes this could double framerate. ([Bolloxim](https://github.com/Bolloxim))
 - Added FXAA and MSAA support to the StandardRenderingPipeline ([julien-moreau](https://github.com/julien-moreau))
+- Make teleportCamera public in VR experience helper ([TrevorDev](https://github.com/TrevorDev))
+
 
 ### glTF Loader
 
@@ -202,6 +208,7 @@
 - Oimo.js now receives quaternion and not euler when a body is being constructed ([RaananW](https://github.com/RaananW))
 - Improving visual quality on SSAO2 shader ([CraigFeldspar](https://github.com/CraigFeldspar))
 - Fixed a bug where changing the sample count on `PostProcess` would not update the WebGL Texture ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fixed multi camera support in defaultRenderingPipeline depth of field ([sebavan](http://www.github.com/sebavan))
 
 ### Viewer
 
@@ -233,3 +240,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.

+ 32 - 1
gui/src/2D/advancedDynamicTexture.ts

@@ -21,6 +21,12 @@ export interface IFocusableControl {
      * @param evt defines the current keyboard event
      */
     processKeyboard(evt: KeyboardEvent): void;
+
+    /**
+     * Function called to get the list of controls that should not steal the focus from this control
+     * @returns an array of controls
+     */
+    keepsFocusWith(): Nullable<Control[]>;
 }
 
 /**
@@ -658,7 +664,32 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 }
                 delete this._lastControlDown[pointerId];
 
-                this.focusedControl = null;
+                if (this.focusedControl) {
+                    const friendlyControls = this.focusedControl.keepsFocusWith();
+                    
+                    let canMoveFocus = true;
+
+                    if (friendlyControls) {
+                        for (var control of friendlyControls) {
+                            // Same host, no need to keep the focus
+                            if (this === control._host) {
+                                continue;
+                            }
+
+                            // Different hosts
+                            const otherHost = control._host;
+
+                            if (otherHost._lastControlOver[pointerId] && otherHost._lastControlOver[pointerId].isAscendant(control)) {
+                                canMoveFocus = false;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (canMoveFocus) {
+                        this.focusedControl = null;
+                    }
+                }
             } else if (pi.type === PointerEventTypes.POINTERMOVE) {
                 if (this._lastControlOver[pointerId]) {
                     this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);

+ 17 - 0
gui/src/2D/controls/control.ts

@@ -745,6 +745,23 @@ export class Control {
         this._markAsDirty();
     }
 
+    /**
+     * Determines if a container is an ascendant of the current control
+     * @param container defines the container to look for
+     * @returns true if the container is one of the ascendant of the control
+     */
+    public isAscendant(container: Control): boolean {
+        if (!this.parent) {
+            return false;
+        }
+
+        if (this.parent === container) {
+            return true;
+        }
+
+        return this.parent.isAscendant(container);
+    }
+
     /** 
      * Gets coordinates in local control space 
      * @param globalCoordinates defines the coordinates to transform

+ 15 - 0
gui/src/2D/controls/inputText.ts

@@ -3,6 +3,7 @@ import { IFocusableControl } from "../advancedDynamicTexture";
 import { ValueAndUnit } from "../valueAndUnit";
 import { Nullable, Observable, Vector2 } from "babylonjs";
 import { Measure } from "../measure";
+import { VirtualKeyboard } from "./virtualKeyboard";
 
 /**
  * Class used to create input text control
@@ -28,6 +29,9 @@ export class InputText extends Control implements IFocusableControl {
     private _addKey = true;
     private _currentKey = "";
 
+    /** @hidden */
+    public _connectedVirtualKeyboard: Nullable<VirtualKeyboard>;
+
     /** Gets or sets a string representing the message displayed on mobile when the control gets the focus */
     public promptMessage = "Please enter text:";
 
@@ -272,6 +276,17 @@ export class InputText extends Control implements IFocusableControl {
         return "InputText";
     }
 
+    /**
+     * Function called to get the list of controls that should not steal the focus from this control
+     * @returns an array of controls
+     */
+    public keepsFocusWith(): Nullable<Control[]> {
+        if (!this._connectedVirtualKeyboard) {
+            return null;
+        }
+        return [this._connectedVirtualKeyboard];
+    }
+
     /** @hidden */
     public processKey(keyCode: number, key?: string) {
         // Specific cases

+ 106 - 46
gui/src/2D/controls/virtualKeyboard.ts

@@ -28,6 +28,12 @@ export class KeyPropertySet {
     background?: string;
 }
 
+type ConnectedInputText = {
+    input: InputText,
+    onFocusObserver: Nullable<Observer<InputText>>,
+    onBlurObserver: Nullable<Observer<InputText>>
+}
+
 /**
  * Class used to create virtual keyboard
  */
@@ -151,84 +157,138 @@ export class VirtualKeyboard extends StackPanel {
         }
     }
 
-    private _connectedInputText: Nullable<InputText>;
-    private _onFocusObserver: Nullable<Observer<InputText>>;
-    private _onBlurObserver: Nullable<Observer<InputText>>;
-    private _onKeyPressObserver: Nullable<Observer<string>>;
+    private _currentlyConnectedInputText: Nullable<InputText> = null;
+    private _connectedInputTexts: ConnectedInputText[] = [];
+    private _onKeyPressObserver: Nullable<Observer<string>> = null;
 
-    /** Gets the input text control attached with the keyboard */
+    /** Gets the input text control currently attached to the keyboard */
     public get connectedInputText(): Nullable<InputText> {
-        return this._connectedInputText;
+        return this._currentlyConnectedInputText;
     }
 
     /**
      * Connects the keyboard with an input text control
+     * 
      * @param input defines the target control
      */
     public connect(input: InputText): void {
-        this.isVisible = false;
-        this._connectedInputText = input;
+        const inputTextAlreadyConnected = this._connectedInputTexts.some(a => a.input === input);
+        if (inputTextAlreadyConnected) {
+            return;
+        }
 
+        if (this._onKeyPressObserver === null) {
+            this._onKeyPressObserver = this.onKeyPressObservable.add((key) => {
+                if (!this._currentlyConnectedInputText) {
+                    return;
+                }
+
+                this._currentlyConnectedInputText._host.focusedControl = this._currentlyConnectedInputText;
+
+                switch (key) {
+                    case "\u21E7":
+                        this.shiftState++;
+                        if (this.shiftState > 2) {
+                            this.shiftState = 0;
+                        }
+                        this.applyShiftState(this.shiftState);
+                        return;
+                    case "\u2190":
+                        this._currentlyConnectedInputText.processKey(8);
+                        return;
+                    case "\u21B5":
+                        this._currentlyConnectedInputText.processKey(13);
+                        return;
+                }
+                this._currentlyConnectedInputText.processKey(-1, (this.shiftState ? key.toUpperCase() : key));
+    
+                if (this.shiftState === 1) {
+                    this.shiftState = 0;
+                    this.applyShiftState(this.shiftState);
+                }
+            });
+        }
+
+        this.isVisible = false;
+        this._currentlyConnectedInputText = input;
+        input._connectedVirtualKeyboard = this;
+        
         // Events hooking
-        this._onFocusObserver = input.onFocusObservable.add(() => {
+        const onFocusObserver: Nullable<Observer<InputText>> = input.onFocusObservable.add(() => {
+            this._currentlyConnectedInputText = input;
+            input._connectedVirtualKeyboard = this;
             this.isVisible = true;
         });
 
-        this._onBlurObserver = input.onBlurObservable.add(() => {
+        const onBlurObserver: Nullable<Observer<InputText>> = input.onBlurObservable.add(() => {
+            input._connectedVirtualKeyboard = null;
+            this._currentlyConnectedInputText = null;
             this.isVisible = false;
         });
 
-        this._onKeyPressObserver = this.onKeyPressObservable.add((key) => {
-            if (!this._connectedInputText) {
-                return;
-            }
-            switch (key) {
-                case "\u21E7":
-                    this.shiftState++;
-                    if (this.shiftState > 2) {
-                        this.shiftState = 0;
-                    }
-                    this.applyShiftState(this.shiftState);
-                    return;
-                case "\u2190":
-                    this._connectedInputText.processKey(8);
-                    return;
-                case "\u21B5":
-                    this._connectedInputText.processKey(13);
-                    return;
-            }
-            this._connectedInputText.processKey(-1, (this.shiftState ? key.toUpperCase() : key));
-
-            if (this.shiftState === 1) {
-                this.shiftState = 0;
-                this.applyShiftState(this.shiftState);
-            }
-        });
+        this._connectedInputTexts.push({
+            input,
+            onBlurObserver,
+            onFocusObserver
+        })
     }
 
     /**
-     * Disconnects the keyboard from an input text control
+     * Disconnects the keyboard from connected InputText controls
+     * 
+     * @param input optionally defines a target control, otherwise all are disconnected
      */
-    public disconnect(): void {
-        if (!this._connectedInputText) {
-            return;
+    public disconnect(input?: InputText): void {
+        if (input) {
+            // .find not available on IE
+            let filtered = this._connectedInputTexts.filter(a => a.input === input);
+            if (filtered.length === 1) {
+                this._removeConnectedInputObservables(filtered[0]);
+                
+                this._connectedInputTexts = this._connectedInputTexts.filter(a => a.input !== input);
+                if (this._currentlyConnectedInputText === input) {
+                    this._currentlyConnectedInputText = null;
+                }
+            }
+        } else {
+            this._connectedInputTexts.forEach((connectedInputText: ConnectedInputText) => {
+                this._removeConnectedInputObservables(connectedInputText)
+            });
+            this._connectedInputTexts = []
+        }
+
+        if (this._connectedInputTexts.length === 0) {
+            this._currentlyConnectedInputText = null;
+            this.onKeyPressObservable.remove(this._onKeyPressObserver);
+            this._onKeyPressObserver = null;
         }
+    }
 
-        this._connectedInputText.onFocusObservable.remove(this._onFocusObserver);
-        this._connectedInputText.onBlurObservable.remove(this._onBlurObserver);
-        this.onKeyPressObservable.remove(this._onKeyPressObserver);
+    private _removeConnectedInputObservables(connectedInputText: ConnectedInputText) : void {
+        connectedInputText.input._connectedVirtualKeyboard = null;
+        connectedInputText.input.onFocusObservable.remove(connectedInputText.onFocusObserver);
+        connectedInputText.input.onBlurObservable.remove(connectedInputText.onBlurObserver);
+    }
+
+    /**
+     * Release all resources
+     */
+    public dispose(): void {
+        super.dispose();
 
-        this._connectedInputText = null;
+        this.disconnect();
     }
 
     // Statics
 
     /**
      * Creates a new keyboard using a default layout
+     *
+     * @param name defines control name
      * @returns a new VirtualKeyboard
      */
-    public static CreateDefaultLayout(): VirtualKeyboard {
-        let returnValue = new VirtualKeyboard();
+    public static CreateDefaultLayout(name?: string): VirtualKeyboard {
+        let returnValue = new VirtualKeyboard(name);
 
         returnValue.addKeysRow(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\u2190"]);
         returnValue.addKeysRow(["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]);

+ 9 - 2
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1357,11 +1357,18 @@ module BABYLON.GLTF2 {
                     return new VertexBuffer(this.babylonScene.getEngine(), data, kind, false);
                 });
             }
+            // HACK: If byte offset is not a multiple of component type byte length then load as a float array instead of using Babylon buffers.
+            else if (accessor.byteOffset && accessor.byteOffset % VertexBuffer.GetTypeByteLength(accessor.componentType) !== 0) {
+                Tools.Warn("Accessor byte offset is not a multiple of component type byte length");
+                accessor._babylonVertexBuffer = this._loadFloatAccessorAsync(`#/accessors/${accessor.index}`, accessor).then(data => {
+                    return new VertexBuffer(this.babylonScene.getEngine(), data, kind, false);
+                });
+            }
             else {
                 const bufferView = ArrayItem.Get(`${context}/bufferView`, this.gltf.bufferViews, accessor.bufferView);
-                accessor._babylonVertexBuffer = this._loadVertexBufferViewAsync(bufferView, kind).then(buffer => {
+                accessor._babylonVertexBuffer = this._loadVertexBufferViewAsync(bufferView, kind).then(babylonBuffer => {
                     const size = GLTFLoader._GetNumComponents(context, accessor.type);
-                    return new VertexBuffer(this.babylonScene.getEngine(), buffer, kind, false, false, bufferView.byteStride,
+                    return new VertexBuffer(this.babylonScene.getEngine(), babylonBuffer, kind, false, false, bufferView.byteStride,
                         false, accessor.byteOffset, size, accessor.componentType, accessor.normalized, true);
                 });
             }

+ 2 - 0
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -164,6 +164,8 @@ module BABYLON {
 
             this._createRenderTargets(scene, renderTargetSize);
 
+            this.hasRenderTargetTextures = true;
+
             // Create render targets
             this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
                 this._renderTargets.reset();

+ 2 - 2
sandbox/index.js

@@ -313,9 +313,9 @@ if (BABYLON.Engine.isSupported()) {
             else {
                 footer.style.display = "none";
                 errorZone.style.display = "none";
-                if (enableDebugLayer) {
+                if (debugLayerEnabled) {
                     currentScene.debugLayer.hide();
-                    enableDebugLayer = false;
+                    debugLayerEnabled = false;
                 }
             }
         }

+ 7 - 3
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -1253,7 +1253,7 @@ module BABYLON {
                 // Listening to the proper controller values changes to confirm teleportation
                 if (Math.sqrt(stateObject.y * stateObject.y + stateObject.x * stateObject.x) < this._padSensibilityDown) {
                     if (this._teleportActive) {
-                        this._teleportCamera(this._haloCenter);
+                        this.teleportCamera(this._haloCenter);
                     }
 
                     gazer._teleportationRequestInitiated = false;
@@ -1328,7 +1328,7 @@ module BABYLON {
                     var ray = new Ray(position, this._workingVector);
                     var hit = this._scene.pickWithRay(ray, this._raySelectionPredicate);
                     if (hit && hit.pickedPoint && hit.pickedMesh && this._isTeleportationFloor(hit.pickedMesh) && hit.distance < 5) {
-                        this._teleportCamera(hit.pickedPoint);
+                        this.teleportCamera(hit.pickedPoint);
                     }
 
                     gazer._teleportationBackRequestInitiated = true;
@@ -1558,7 +1558,11 @@ module BABYLON {
         private _workingVector = Vector3.Zero();
         private _workingQuaternion = Quaternion.Identity();
         private _workingMatrix = Matrix.Identity();
-        private _teleportCamera(location: Vector3) {
+        /**
+         * Teleports the users feet to the desired location
+         * @param location The location where the user's feet should be placed
+         */
+        public teleportCamera(location: Vector3) {
             if (!(this.currentVRCamera instanceof FreeCamera)) {
                 return;
             }

+ 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.
+        }
+    }
+} 

+ 31 - 0
src/Debug/babylon.debugLayer.ts

@@ -4,6 +4,31 @@ module BABYLON {
     declare var INSPECTOR: any;
     // load the inspector using require, if not present in the global namespace.
 
+    export interface Scene {
+        /**
+         * @hidden
+         * Backing field
+         */
+        _debugLayer: DebugLayer;
+
+        /**
+         * Gets the debug layer (aka Inspector) associated with the scene
+         * @see http://doc.babylonjs.com/features/playground_debuglayer
+         */
+        debugLayer: DebugLayer;
+    }
+    
+    Object.defineProperty(Scene.prototype, "debugLayer", {
+        get: function (this: Scene) {
+            if (!this._debugLayer) {
+                this._debugLayer = new DebugLayer(this);
+            }
+            return this._debugLayer;
+        },
+        enumerable: true,
+        configurable: true
+    });
+
     export class DebugLayer {
         private _scene: Scene;
         public static InspectorURL = 'https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js';
@@ -16,6 +41,12 @@ module BABYLON {
 
         constructor(scene: Scene) {
             this._scene = scene;
+            this._scene.onDisposeObservable.add(() => {
+                // Debug layer
+                if (this._scene._debugLayer) {
+                    this._scene._debugLayer.hide();
+                }
+            })
         }
 
         /** Creates the inspector window. */

+ 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);
+    }
+}

+ 15 - 0
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -584,6 +584,21 @@
         }
 
         /**
+         * Gets a boolean indicating that current material needs to register RTT
+         */        
+        public get hasRenderTargetTextures(): boolean {
+            if (this._diffuseTexture && this._diffuseTexture.isRenderTarget) {
+                return true;
+            }
+
+            if (this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
+                return true;
+            }
+
+            return false;
+        }
+
+        /**
          * The entire material has been created in order to prevent overdraw.
          * @returns false
          */

+ 16 - 0
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -609,6 +609,22 @@
             this._environmentBRDFTexture = TextureTools.GetEnvironmentBRDFTexture(scene);
         }
 
+
+        /**
+         * Gets a boolean indicating that current material needs to register RTT
+         */               
+        public get hasRenderTargetTextures(): boolean {
+            if (StandardMaterial.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
+                return true;
+            }
+
+            if (StandardMaterial.RefractionTextureEnabled && this._refractionTexture && this._refractionTexture.isRenderTarget) {
+                return true;
+            }
+
+            return false;
+        }        
+
         /**
          * Gets the name of the material class.
          */

+ 5 - 0
src/Materials/babylon.material.ts

@@ -494,6 +494,11 @@
         public getRenderTargetTextures: () => SmartArray<RenderTargetTexture>;
 
         /**
+         * Gets a boolean indicating that current material needs to register RTT
+         */
+        public hasRenderTargetTextures = false;
+
+        /**
          * Specifies if the material should be serialized
          */
         public doNotSerialize = false;

+ 15 - 0
src/Materials/babylon.standardMaterial.ts

@@ -513,6 +513,21 @@ module BABYLON {
             }
         }
 
+        /**
+         * Gets a boolean indicating that current material needs to register RTT
+         */               
+        public get hasRenderTargetTextures(): boolean {
+            if (StandardMaterial.ReflectionTextureEnabled && this._reflectionTexture && this._reflectionTexture.isRenderTarget) {
+                return true;
+            }
+
+            if (StandardMaterial.RefractionTextureEnabled && this._refractionTexture && this._refractionTexture.isRenderTarget) {
+                return true;
+            }
+
+            return false;
+        }
+
         public getClassName(): string {
             return "StandardMaterial";
         }

+ 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) {

+ 2 - 6
src/Mesh/babylon.geometry.ts

@@ -42,7 +42,7 @@
         /** @hidden */
         public _delayLoadingFunction: Nullable<(any: any, geometry: Geometry) => void>;
         /** @hidden */
-        public _softwareSkinningRenderId: number;
+        public _softwareSkinningFrameId: number;
         private _vertexArrayObjects: { [key: string]: WebGLVertexArrayObject; };
         private _updatable: boolean;
 
@@ -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);
+            }
         }
 
         /**

+ 4 - 3
src/Mesh/babylon.mesh.ts

@@ -831,7 +831,8 @@
 
             var data = this._getPositionData(applySkeleton);
             if (data) {
-                var extend = Tools.ExtractMinAndMax(data, 0, this.getTotalVertices());
+                const bias = this.geometry ? this.geometry.boundingBias : null;
+                var extend = Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
                 this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
             }
 
@@ -3295,11 +3296,11 @@
                 return this;
             }
 
-            if (this.geometry._softwareSkinningRenderId == this.getScene().getRenderId()) {
+            if (this.geometry._softwareSkinningFrameId == this.getScene().getFrameId()) {
                 return this;
             }
 
-            this.geometry._softwareSkinningRenderId = this.getScene().getRenderId();
+            this.geometry._softwareSkinningFrameId = this.getScene().getFrameId();
 
             if (!this.isVerticesDataPresent(VertexBuffer.PositionKind)) {
                 return this;

+ 50 - 0
src/Particles/babylon.IParticleSystem.ts

@@ -422,7 +422,57 @@ module BABYLON {
          * @returns the list of start size gradients
          */
         getStartSizeGradients(): Nullable<Array<FactorGradient>>;  
+
+        /**
+         * Gets the current list of color gradients.
+         * You must use addColorGradient and removeColorGradient to udpate this list
+         * @returns the list of color gradients
+         */
+        getColorGradients(): Nullable<Array<ColorGradient>>;      
+        
+        /**
+         * Adds a new ramp gradient used to remap particle colors
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param color defines the color to affect to the specified gradient
+         * @returns the current particle system
+         */
+        addRampGradient(gradient: number, color: Color4): IParticleSystem;     
+        /**
+         * Gets the current list of ramp gradients.
+         * You must use addRampGradient and removeRampGradient to udpate this list
+         * @returns the list of ramp gradients
+         */
+        getRampGradients(): Nullable<Array<ColorGradient>>;             
         
+        /**
+         * Adds a new color remap gradient
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param min defines the color remap minimal range        
+         * @param max defines the color remap maximal range        
+         * @returns the current particle system
+         */
+        addColorRemapGradient(gradient: number, min: number, max: number): IParticleSystem;    
+        /**
+         * Gets the current list of color remap gradients.
+         * You must use addColorRemapGradient and removeColorRemapGradient to udpate this list
+         * @returns the list of color remap gradients
+         */
+        getColorRemapGradients(): Nullable<Array<FactorGradient>>;
+        
+        /**
+         * Adds a new alpha remap gradient
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param min defines the alpha remap minimal range        
+         * @param max defines the alpha remap maximal range        
+         * @returns the current particle system
+         */
+        addAlphaRemapGradient(gradient: number, min: number, max: number): IParticleSystem; 
+        /**
+         * Gets the current list of alpha remap gradients.
+         * You must use addAlphaRemapGradient and removeAlphaRemapGradient to udpate this list
+         * @returns the list of alpha remap gradients
+         */
+        getAlphaRemapGradients(): Nullable<Array<FactorGradient>>;            
 
         /**
          * Creates a Point Emitter for the particle system (emits directly from the emitter position)

+ 44 - 1
src/Particles/babylon.baseParticleSystem.ts

@@ -218,7 +218,7 @@ module BABYLON {
 
         /** @hidden */
         protected _isAnimationSheetEnabled: boolean;
-        
+       
         /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
@@ -258,6 +258,9 @@ module BABYLON {
         protected _dragGradients: Nullable<Array<FactorGradient>> = null;
         protected _emitRateGradients: Nullable<Array<FactorGradient>> = null;
         protected _startSizeGradients: Nullable<Array<FactorGradient>> = null;
+        protected _rampGradients: Nullable<Array<ColorGradient>> = null;
+        protected _colorRemapGradients: Nullable<Array<FactorGradient>> = null;
+        protected _alphaRemapGradients: Nullable<Array<FactorGradient>> = null;        
 
         /**
          * Gets the current list of drag gradients.
@@ -299,6 +302,24 @@ module BABYLON {
         }        
 
         /**
+         * Gets the current list of color remap gradients.
+         * You must use addColorRemapGradient and removeColorRemapGradient to udpate this list
+         * @returns the list of color remap gradients
+         */
+        public getColorRemapGradients(): Nullable<Array<FactorGradient>> {
+            return this._colorRemapGradients;
+        }   
+
+        /**
+         * Gets the current list of alpha remap gradients.
+         * You must use addAlphaRemapGradient and removeAlphaRemapGradient to udpate this list
+         * @returns the list of alpha remap gradients
+         */
+        public getAlphaRemapGradients(): Nullable<Array<FactorGradient>> {
+            return this._alphaRemapGradients;
+        }   
+
+        /**
          * Gets the current list of life time gradients.
          * You must use addLifeTimeGradient and removeLifeTimeGradient to udpate this list
          * @returns the list of life time gradients
@@ -515,6 +536,28 @@ module BABYLON {
         protected _reset() {
         }
 
+        /** @hidden */
+        protected _removeGradientAndTexture(gradient: number, gradients: Nullable<IValueGradient[]>, texture: RawTexture): BaseParticleSystem {
+            if (!gradients) {
+                return this;
+            }
+
+            let index = 0;
+            for (var valueGradient of gradients) {
+                if (valueGradient.gradient === gradient) {
+                    gradients.splice(index, 1);
+                    break;
+                }
+                index++;
+            }
+
+            if (texture) {
+                texture.dispose();
+            }            
+
+            return this;
+        } 
+
         /**
          * Instantiates a particle system.
          * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.

+ 90 - 26
src/Particles/babylon.gpuParticleSystem.ts

@@ -157,29 +157,13 @@
         }            
                
         private _colorGradientsTexture: RawTexture;
-
-        private _removeGradient(gradient: number, gradients: Nullable<IValueGradient[]>, texture: RawTexture): GPUParticleSystem {
-            if (!gradients) {
-                return this;
-            }
-
-            let index = 0;
-            for (var valueGradient of gradients) {
-                if (valueGradient.gradient === gradient) {
-                    gradients.splice(index, 1);
-                    break;
-                }
-                index++;
-            }
-
-            if (texture) {
-                texture.dispose();
-            }            
-
+        
+        protected _removeGradientAndTexture(gradient: number, gradients: Nullable<IValueGradient[]>, texture: RawTexture): BaseParticleSystem {
+            super._removeGradientAndTexture(gradient, gradients, texture);
             this._releaseBuffers();
 
             return this;
-        }    
+        }
         
         /**
          * Adds a new color gradient
@@ -224,7 +208,7 @@
          * @returns the current particle system
          */
         public removeColorGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._colorGradients, this._colorGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._colorGradients, this._colorGradientsTexture);
             (<any>this._colorGradientsTexture) = null;
 
             return this;
@@ -284,7 +268,7 @@
          * @returns the current particle system
          */
         public removeSizeGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._sizeGradients, this._sizeGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._sizeGradients, this._sizeGradientsTexture);
             (<any>this._sizeGradientsTexture) = null;
 
             return this;            
@@ -319,7 +303,7 @@
          * @returns the current particle system
          */
         public removeAngularSpeedGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._angularSpeedGradients, this._angularSpeedGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._angularSpeedGradients, this._angularSpeedGradientsTexture);
             (<any>this._angularSpeedGradientsTexture) = null;
 
             return this;           
@@ -354,7 +338,7 @@
          * @returns the current particle system
          */
         public removeVelocityGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._velocityGradients, this._velocityGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._velocityGradients, this._velocityGradientsTexture);
             (<any>this._velocityGradientsTexture) = null;
 
             return this;           
@@ -389,7 +373,7 @@
          * @returns the current particle system
          */
         public removeLimitVelocityGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._limitVelocityGradients, this._limitVelocityGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._limitVelocityGradients, this._limitVelocityGradientsTexture);
             (<any>this._limitVelocityGradientsTexture) = null;
 
             return this;
@@ -424,7 +408,7 @@
          * @returns the current particle system
          */
         public removeDragGradient(gradient: number): GPUParticleSystem {
-            this._removeGradient(gradient, this._dragGradients, this._dragGradientsTexture);
+            this._removeGradientAndTexture(gradient, this._dragGradients, this._dragGradientsTexture);
             (<any>this._dragGradientsTexture) = null;
 
             return this;
@@ -475,6 +459,86 @@
         } 
 
         /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param min defines the color remap minimal range        
+         * @param max defines the color remap maximal range        
+         * @returns the current particle system
+         */
+        public addColorRemapGradient(gradient: number, min: number, max: number): IParticleSystem {
+            // Do nothing as start size is not supported by GPUParticleSystem
+
+            return this;
+        }
+
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeColorRemapGradient(gradient: number): IParticleSystem {
+            // Do nothing as start size is not supported by GPUParticleSystem
+
+            return this;
+        }  
+
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param min defines the alpha remap minimal range        
+         * @param max defines the alpha remap maximal range        
+         * @returns the current particle system
+         */
+        public addAlphaRemapGradient(gradient: number, min: number, max: number): IParticleSystem {
+            // Do nothing as start size is not supported by GPUParticleSystem
+
+            return this;
+        }
+
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeAlphaRemapGradient(gradient: number): IParticleSystem {
+            // Do nothing as start size is not supported by GPUParticleSystem
+
+            return this;
+        }   
+        
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to use (between 0 and 1)
+         * @param color defines the color to affect to the specified gradient
+         * @returns the current particle system
+         */
+        public addRampGradient(gradient: number, color: Color4): IParticleSystem {
+            //Not supported by GPUParticleSystem          
+
+            return this;
+        }
+
+        /**
+         * Not supported by GPUParticleSystem
+         * @param gradient defines the gradient to remove
+         * @returns the current particle system
+         */
+        public removeRampGradient(gradient: number): IParticleSystem {
+            //Not supported by GPUParticleSystem
+
+            return this;
+        }  
+        
+        /**
+         * Not supported by GPUParticleSystem
+         * @returns the list of ramp gradients
+         */
+        public getRampGradients(): Nullable<Array<ColorGradient>> {
+            return null;
+        }             
+        
+
+        /**
          * Instantiates a GPU particle system.
          * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
          * @param name The name of the particle system

+ 20 - 0
src/Particles/babylon.particle.ts

@@ -5,6 +5,11 @@
      * This is mainly define by its coordinates, direction, velocity and age.
      */
     export class Particle {
+        private static _Count = 0;
+        /**
+         * Unique ID of the particle
+         */
+        public id:number;
         /**
          * The world position of the particle in the scene.
          */
@@ -60,6 +65,11 @@
          */
         public cellIndex: number = 0;  
 
+        /**
+         * The information required to support color remapping
+         */
+        public remapData: Vector4;
+
         /** @hidden */
         public _randomCellOffset?: number;
 
@@ -67,6 +77,9 @@
         public _initialDirection: Nullable<Vector3>;
 
         /** @hidden */
+        public _attachedSubEmitters: Nullable<Array<SubEmitter>> = null;
+
+        /** @hidden */
         public _initialStartSpriteCellID: number;
         public _initialEndSpriteCellID: number;
 
@@ -111,6 +124,7 @@
         public _currentDrag1 = 0;
         /** @hidden */
         public _currentDrag2 = 0;  
+     
 
         /**
          * Creates a new instance Particle
@@ -121,6 +135,7 @@
              * The particle system the particle belongs to.
              */
             public particleSystem: ParticleSystem) {
+            this.id = Particle._Count++;
             if (!this.particleSystem.isAnimationSheetEnabled) {
                 return;
             }
@@ -191,6 +206,8 @@
             other.angularSpeed = this.angularSpeed;
             other.particleSystem = this.particleSystem;
             other.cellIndex = this.cellIndex;
+            other.id = this.id;
+            other._attachedSubEmitters = this._attachedSubEmitters;
             if (this._currentColorGradient) {
                 other._currentColorGradient = this._currentColorGradient;
                 other._currentColor1.copyFrom(this._currentColor1);
@@ -225,6 +242,9 @@
                 other._initialStartSpriteCellID = this._initialStartSpriteCellID;
                 other._initialEndSpriteCellID = this._initialEndSpriteCellID;
             }
+            if (this.particleSystem.useRampGradients) {
+                other.remapData.copyFrom(this.remapData);
+            }
         }
     }
 } 

File diff ditekan karena terlalu besar
+ 2371 - 1935
src/Particles/babylon.particleSystem.ts


+ 68 - 0
src/Particles/babylon.subEmitter.ts

@@ -0,0 +1,68 @@
+module BABYLON {
+    /**
+     * Type of sub emitter
+     */
+    export enum SubEmitterType {
+        /**
+         * Attached to the particle over it's lifetime
+         */
+        ATTACHED,
+        /**
+         * Created when the particle dies
+         */
+        END
+    }
+
+    /**
+     * Sub emitter class used to emit particles from an existing particle
+     */
+    export class SubEmitter {
+        /**
+         * Type of the submitter (Default: END)
+         */
+        public type = SubEmitterType.END;
+        /**
+         * If the particle should inherit the direction from the particle it's attached to. (+Y will face the direction the particle is moving) (Default: false)
+         * Note: This only is supported when using an emitter of type Mesh
+         */
+        public inheritDirection = false;
+        /**
+         * How much of the attached particles speed should be added to the sub emitted particle (default: 0)
+         */
+        public inheritedVelocityAmount = 0;
+        /**
+         * Creates a sub emitter
+         * @param particleSystem the particle system to be used by the sub emitter
+         */
+        constructor(
+            /**
+             * the particle system to be used by the sub emitter
+             */
+            public particleSystem: ParticleSystem) {
+        }
+        /**
+         * Clones the sub emitter
+         * @returns the cloned sub emitter
+         */
+        clone(): SubEmitter {
+            // Clone particle system
+            var emitter = this.particleSystem.emitter;
+            if (!emitter) {
+                emitter = new Vector3();
+            } else if (emitter instanceof Vector3) {
+                emitter = emitter.clone();
+            } else if (emitter instanceof AbstractMesh) {
+                emitter = new Mesh("", emitter._scene);
+            }
+            var clone = new SubEmitter(this.particleSystem.clone("", emitter));
+
+            // Clone properties
+            clone.type = this.type;
+            clone.inheritDirection = this.inheritDirection;
+            clone.inheritedVelocityAmount = this.inheritedVelocityAmount;
+
+            clone.particleSystem._disposeEmitterOnDispose = true;
+            return clone;
+        }
+    }
+}

+ 27 - 4
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -457,6 +457,8 @@
             }
         }
 
+        private _depthOfFieldSceneObserver: Nullable<Observer<Scene>> = null;
+
         private _buildPipeline() {
             if (!this._buildAllowed) {
                 return;
@@ -474,17 +476,37 @@
             this._reset();
             this._prevPostProcess = null;
             this._prevPrevPostProcess = null;
-            this._hasCleared = false;            
+            this._hasCleared = false;
 
             if (this.depthOfFieldEnabled) {
-                var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
-                this.depthOfField.depthTexture = depthTexture;
+                // Multi camera suport
+                if (this._cameras.length > 1) {
+                    for (let camera of this._cameras) {
+                        const depthRenderer = this._scene.enableDepthRenderer(camera);
+                        depthRenderer.useOnlyInActiveCamera = true;
+                    }
+
+                    this._depthOfFieldSceneObserver = this._scene.onAfterRenderTargetsRenderObservable.add((scene) => {
+                        if (this._cameras.indexOf(scene.activeCamera!) > -1) {
+                            this.depthOfField.depthTexture = scene.enableDepthRenderer(scene.activeCamera).getDepthMap();
+                        }
+                    });
+                }
+                else {
+                    this._scene.onAfterRenderTargetsRenderObservable.remove(this._depthOfFieldSceneObserver);
+                    const depthRenderer = this._scene.enableDepthRenderer(this._cameras[0]);
+                    this.depthOfField.depthTexture = depthRenderer.getDepthMap();
+                }
+
                 if(!this.depthOfField._isReady()){
                     this.depthOfField._updateEffects();
                 }
                 this.addEffect(this.depthOfField);
                 this._setAutoClearAndTextureSharing(this.depthOfField._effects[0], true);
             }
+            else {
+                this._scene.onAfterRenderTargetsRenderObservable.remove(this._depthOfFieldSceneObserver);
+            }
 
             if (this.bloomEnabled) {
                 if(!this.bloom._isReady()){
@@ -562,7 +584,8 @@
                         this.sharpen.dispose(camera);
                     }
     
-                    if(this.depthOfField){
+                    if(this.depthOfField) {
+                        this._scene.onAfterRenderTargetsRenderObservable.remove(this._depthOfFieldSceneObserver);
                         this.depthOfField.disposeEffects(camera);
                     }
 

+ 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);

+ 7 - 0
src/Rendering/babylon.depthRenderer.ts

@@ -12,6 +12,13 @@
         private _camera:Nullable<Camera>;
 
         /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        public useOnlyInActiveCamera: boolean = false;
+
+        /**
          * Instantiates a depth renderer
          * @param scene The scene the renderer belongs to
          * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)

+ 16 - 1
src/Rendering/babylon.depthRendererSceneComponent.ts

@@ -79,6 +79,7 @@
          */
         public register(): void {
             this.scene._gatherRenderTargetsStage.registerStep(SceneComponentConstants.STEP_GATHERRENDERTARGETS_DEPTHRENDERER, this, this._gatherRenderTargets);
+            this.scene._gatherActiveCameraRenderTargetsStage.registerStep(SceneComponentConstants.STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER, this, this._gatherActiveCameraRenderTargets);
         }
 
         /**
@@ -101,7 +102,21 @@
         private _gatherRenderTargets(renderTargets: SmartArrayNoDuplicate<RenderTargetTexture>): void {
             if (this.scene._depthRenderer) {
                 for (var key in this.scene._depthRenderer) {
-                    renderTargets.push(this.scene._depthRenderer[key].getDepthMap());
+                    let depthRenderer = this.scene._depthRenderer[key];
+                    if (!depthRenderer.useOnlyInActiveCamera) {
+                        renderTargets.push(depthRenderer.getDepthMap());
+                    }
+                }
+            }
+        }
+
+        private _gatherActiveCameraRenderTargets(renderTargets: SmartArrayNoDuplicate<RenderTargetTexture>): void {
+            if (this.scene._depthRenderer) {
+                for (var key in this.scene._depthRenderer) {
+                    let depthRenderer = this.scene._depthRenderer[key];
+                    if (depthRenderer.useOnlyInActiveCamera && this.scene.activeCamera!.id === key) {
+                        renderTargets.push(depthRenderer.getDepthMap());
+                    }
                 }
             }
         }

+ 17 - 2
src/Shaders/particles.fragment.fx

@@ -12,15 +12,30 @@ uniform sampler2D diffuseSampler;
 
 #include<imageProcessingFunctions>
 
+#ifdef RAMPGRADIENT
+varying vec4 remapRanges;
+uniform sampler2D rampSampler;
+#endif
+
 void main(void) {
 	#include<clipPlaneFragment>
 
 	vec4 textureColor = texture2D(diffuseSampler, vUV);
 	vec4 baseColor = (textureColor * textureMask + (vec4(1., 1., 1., 1.) - textureMask)) * vColor;
 
+	#ifdef RAMPGRADIENT
+		float alpha = textureColor.a;
+		float remappedColorIndex = clamp((alpha - remapRanges.x) / remapRanges.y, 0.0, 1.0);
+
+		baseColor.rgb *= texture2D(rampSampler, vec2(remappedColorIndex, 0.)).rgb;
+
+		// Remapped alpha
+		baseColor.a = clamp((alpha - remapRanges.z) / remapRanges.w, 0.0, 1.0);
+	#endif
+
 	#ifdef BLENDMULTIPLYMODE
-	float alpha = vColor.a * textureColor.a;
-	baseColor.rgb = baseColor.rgb * alpha + vec3(1.0) * (1.0 - alpha);
+		float sourceAlpha = vColor.a * textureColor.a;
+		baseColor.rgb = baseColor.rgb * sourceAlpha + vec3(1.0) * (1.0 - sourceAlpha);
 	#endif
 
 // Apply image processing if relevant. As this applies in linear space, 

+ 11 - 0
src/Shaders/particles.vertex.fx

@@ -9,6 +9,9 @@ attribute float cellIndex;
 #ifndef BILLBOARD	
 attribute vec3 direction;
 #endif
+#ifdef RAMPGRADIENT
+attribute vec4 remapData;
+#endif
 attribute vec2 offset;
 
 // Uniforms
@@ -24,6 +27,10 @@ uniform vec3 particlesInfos; // x (number of rows) y(number of columns) z(rowSiz
 varying vec2 vUV;
 varying vec4 vColor;
 
+#ifdef RAMPGRADIENT
+varying vec4 remapRanges;
+#endif
+
 #if defined(CLIPPLANE) || defined(CLIPPLANE2) || defined(CLIPPLANE3) || defined(CLIPPLANE4)
 uniform mat4 invView;
 #endif
@@ -75,6 +82,10 @@ void main(void) {
 	vec3 viewPos = (view * vec4(position, 1.0)).xyz + rotatedCorner; 
 #endif
 
+#ifdef RAMPGRADIENT
+	remapRanges = remapData;
+#endif
+
 	// Position
 	gl_Position = projection * vec4(viewPos, 1.0);   
 #else

+ 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;

+ 5 - 0
src/babylon.abstractScene.ts

@@ -86,6 +86,11 @@
             }
         }
 
+       /**
+        * Gets the list of root nodes (ie. nodes with no parent)
+        */
+       public rootNodes = new Array<Node>();
+
         /** All of the cameras added to this scene
          * @see http://doc.babylonjs.com/babylon101/cameras
          */

+ 31 - 1
src/babylon.node.ts

@@ -120,12 +120,19 @@
                 return;
             }
 
+            const previousParentNode = this._parentNode;
+
             // Remove self from list of children of parent
             if (this._parentNode && this._parentNode._children !== undefined && this._parentNode._children !== null) {
                 var index = this._parentNode._children.indexOf(this);
                 if (index !== -1) {
                     this._parentNode._children.splice(index, 1);
                 }
+
+                if (!parent) {
+                    // Need to add this node to the rootNodes
+                    this._scene.rootNodes.push(this);
+                }
             }
 
             // Store new parent
@@ -137,6 +144,15 @@
                     this._parentNode._children = new Array<Node>();
                 }
                 this._parentNode._children.push(this);
+
+                if (!previousParentNode) {
+                    // Need to remove from rootNodes
+                    const rootNodeIndex = this._scene.rootNodes.indexOf(this);
+
+                    if (rootNodeIndex > -1) {
+                        this._scene.rootNodes.splice(rootNodeIndex, 1);
+                    }
+                }
             }
         }
 
@@ -195,6 +211,8 @@
             this._scene = <Scene>(scene || Engine.LastCreatedScene);
             this.uniqueId = this._scene.getUniqueId();
             this._initCache();
+
+            this._scene.rootNodes.push(this);
         }
 
         /**
@@ -496,6 +514,10 @@
          * @returns an array of {BABYLON.Node}
          */
         public getChildren(predicate?: (node: Node) => boolean): Node[] {
+            if (!predicate) {
+                return this._children;
+            }
+
             return this.getDescendants(true, predicate);
         }
 
@@ -640,7 +662,15 @@
                 }
             }
 
-            this.parent = null;
+            if (!this.parent) {
+                const rootNodeIndex = this._scene.rootNodes.indexOf(this);
+
+                if (rootNodeIndex > -1) {
+                    this._scene.rootNodes.splice(rootNodeIndex, 1);
+                }
+            } else {
+                this.parent = null;
+            }
 
             // Callback
             this.onDisposeObservable.notifyObservers(this);

+ 113 - 320
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
         /**
@@ -920,13 +904,6 @@
             return this._mainSoundTrack;
         }
 
-        /**
-         * Gets or sets the VRExperienceHelper attached to the scene
-         * @see http://doc.babylonjs.com/how_to/webvr_helper
-         * @ignorenaming
-         */
-        public VRHelper: VRExperienceHelper;
-
         // Private
         private _engine: Engine;
 
@@ -957,6 +934,7 @@
         public _cachedVisibility: Nullable<number>;
 
         private _renderId = 0;
+        private _frameId = 0;
         private _executeWhenReadyTimeoutId = -1;
         private _intermediateRendering = false;
 
@@ -1025,12 +1003,8 @@
          */
         public requireLightSorting = false;
 
-        private _selectionOctree: Octree<AbstractMesh>;
-
         private _pointerOverMesh: Nullable<AbstractMesh>;
 
-        private _debugLayer: DebugLayer;
-
         private _pickedDownMesh: Nullable<AbstractMesh>;
         private _pickedUpMesh: Nullable<AbstractMesh>;
         private _externalData: StringDictionary<Object>;
@@ -1110,11 +1084,16 @@
         public _beforeClearStage = Stage.Create<SimpleStageAction>();
         /**
          * @hidden
-         * Defines the actions happening before camera updates.
+         * Defines the actions when collecting render targets for the frame.
          */
         public _gatherRenderTargetsStage = Stage.Create<RenderTargetsStageAction>();
         /**
          * @hidden
+         * Defines the actions happening for one camera in the frame.
+         */
+        public _gatherActiveCameraRenderTargetsStage = Stage.Create<RenderTargetsStageAction>();
+        /**
+         * @hidden
          * Defines the actions happening during the per mesh ready checks.
          */
         public _isReadyForMeshStage = Stage.Create<MeshStageAction>();
@@ -1170,11 +1149,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,17 +1194,49 @@
             if (ImageProcessingConfiguration) {
                 this._imageProcessingConfiguration = new ImageProcessingConfiguration();
             }
+
+            this.setDefaultCandidateProviders();
+        }
+
+        private _defaultMeshCandidates: ISmartArrayLike<AbstractMesh> = {
+            data: [],
+            length: 0
         }
 
         /**
-         * Gets the debug layer (aka Inspector) associated with the scene
-         * @see http://doc.babylonjs.com/features/playground_debuglayer
+         * @hidden
          */
-        public get debugLayer(): DebugLayer {
-            if (!this._debugLayer) {
-                this._debugLayer = new DebugLayer(this);
-            }
-            return this._debugLayer;
+        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);
         }
 
         public set workerCollisions(enabled: boolean) {
@@ -1259,14 +1265,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> {
@@ -1489,13 +1487,21 @@
         }
 
         /** 
-         * Gets an unique Id for the current frame
+         * Gets an unique Id for the current render phase
          * @returns a number
          */
         public getRenderId(): number {
             return this._renderId;
         }
 
+        /** 
+         * Gets an unique Id for the current frame
+         * @returns a number
+         */
+        public getFrameId(): number {
+            return this._frameId;
+        }
+
         /** Call this function if you want to manually increment the render Id*/
         public incrementRenderId(): void {
             this._renderId++;
@@ -1560,9 +1566,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 +2944,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) {
@@ -3939,7 +3956,7 @@
                 const material = subMesh.getMaterial();
                 if (material !== null && material !== undefined) {
                     // Render targets
-                    if (material.getRenderTargetTextures !== undefined) {
+                    if (material.hasRenderTargetTextures && material.getRenderTargetTextures !== undefined) {
                         if (this._processedMaterials.indexOf(material) === -1) {
                             this._processedMaterials.push(material);
 
@@ -4001,21 +4018,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 +4089,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 +4114,7 @@
                 }
 
                 // Switch to current LOD
-                meshLOD = mesh.getLOD(this.activeCamera);
-
+                const meshLOD = mesh.getLOD(this.activeCamera);
                 if (meshLOD === undefined || meshLOD === null) {
                     continue;
                 }
@@ -4161,7 +4158,7 @@
         }
 
         private _activeMesh(sourceMesh: AbstractMesh, mesh: AbstractMesh): void {
-            if (this.skeletonsEnabled && mesh.skeleton !== null && mesh.skeleton !== undefined) {
+            if (this._skeletonsEnabled && mesh.skeleton !== null && mesh.skeleton !== undefined) {
                 if (this._activeSkeletons.pushNoDuplicate(mesh.skeleton)) {
                     mesh.skeleton.prepare();
                 }
@@ -4179,23 +4176,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);
                 }
             }
@@ -4269,6 +4253,11 @@
                 this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
             }
 
+            // Collects render targets from external components.
+            for (let step of this._gatherActiveCameraRenderTargetsStage) {
+                step.action(this._renderTargets);
+            }
+
             if (this.renderTargetsEnabled) {
                 this._intermediateRendering = true;
 
@@ -4401,6 +4390,8 @@
                 return;
             }
 
+            this._frameId++;
+
             // Register components that have been associated lately to the scene.
             this._registerTransientComponents();
 
@@ -4599,7 +4590,6 @@
                 if (data) {
                     data.dispose();
                 }
-                this._toBeDisposed[index] = null;
             }
 
             this._toBeDisposed.reset();
@@ -4787,7 +4777,7 @@
             this._beforeCameraUpdateStage.clear();
             this._beforeClearStage.clear();
             this._gatherRenderTargetsStage.clear();
-            this._rebuildGeometryStage.clear();
+            this._gatherActiveCameraRenderTargetsStage.clear();
             this._pointerMoveStage.clear();
             this._pointerDownStage.clear();
             this._pointerUpStage.clear();
@@ -4823,11 +4813,6 @@
                 request.abort();
             }
 
-            // Debug layer
-            if (this._debugLayer) {
-                this._debugLayer.hide();
-            }
-
             // Events
             this.onDisposeObservable.notifyObservers(this);
 
@@ -4851,6 +4836,7 @@
             this.onDataLoadedObservable.clear();
             this.onBeforeRenderingGroupObservable.clear();
             this.onAfterRenderingGroupObservable.clear();
+            this.onMeshImportedObservable.clear();
 
             this.detachControl();
 
@@ -4859,11 +4845,6 @@
                 this.disposeSounds();
             }
 
-            // VR Helper
-            if (this.VRHelper) {
-                this.VRHelper.dispose();
-            }
-
             // Detach cameras
             var canvas = this._engine.getRenderingCanvas();
 
@@ -5007,9 +4988,6 @@
             }
         }
 
-
-        // Octrees
-
         /**
          * Get the world extend vectors with an optional filter
          * 
@@ -5042,26 +5020,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 +5385,6 @@
             for (var system of this.particleSystems) {
                 system.rebuild();
             }
-
-            for (let step of this._rebuildGeometryStage) {
-                step.action();
-            }
         }
 
         /** @hidden */
@@ -5442,167 +5396,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) {

+ 2 - 1
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,7 +55,7 @@
         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_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER = 0;
 
         public static readonly STEP_POINTERMOVE_SPRITE = 0;
         public static readonly STEP_POINTERDOWN_SPRITE = 0;

TEMPAT SAMPAH
tests/validation/ReferenceImages/LightProjectionTexture.png


TEMPAT SAMPAH
tests/validation/ReferenceImages/pbr.png