Explorar el Código

Merge branch 'subEmitters' of https://github.com/TrevorDev/Babylon.js into subEmitters

Trevor Baron hace 7 años
padre
commit
b8bfb44fdb
Se han modificado 100 ficheros con 9981 adiciones y 6257 borrados
  1. 4731 4156
      Playground/babylon.d.txt
  2. BIN
      Playground/textures/Logo.png
  3. BIN
      Playground/textures/SpecularHDR.env
  4. BIN
      Playground/textures/checkerBJS.png
  5. BIN
      Playground/textures/co.png
  6. BIN
      Playground/textures/cubemap_blank.jpg
  7. BIN
      Playground/textures/customProceduralTextures/land/textures/dirt.jpg
  8. BIN
      Playground/textures/customProceduralTextures/land/textures/grass.png
  9. BIN
      Playground/textures/environment.env
  10. BIN
      Playground/textures/hollow.png
  11. BIN
      Playground/textures/lensdirt.jpg
  12. BIN
      Playground/textures/mercator.jpg
  13. BIN
      Playground/textures/misc.jpg
  14. BIN
      Playground/textures/mr.jpg
  15. BIN
      Playground/textures/orient.jpg
  16. BIN
      Playground/textures/palm.png
  17. BIN
      Playground/textures/reflectivity.png
  18. BIN
      Playground/textures/skybox2_nx.jpg
  19. BIN
      Playground/textures/skybox2_ny.jpg
  20. BIN
      Playground/textures/skybox2_nz.jpg
  21. BIN
      Playground/textures/skybox2_px.jpg
  22. BIN
      Playground/textures/skybox2_py.jpg
  23. BIN
      Playground/textures/skybox2_pz.jpg
  24. BIN
      Playground/textures/skybox3_nx.jpg
  25. BIN
      Playground/textures/skybox3_ny.jpg
  26. BIN
      Playground/textures/skybox3_nz.jpg
  27. BIN
      Playground/textures/skybox3_px.jpg
  28. BIN
      Playground/textures/skybox3_py.jpg
  29. BIN
      Playground/textures/skybox3_pz.jpg
  30. BIN
      Playground/textures/skybox4_nx.jpg
  31. BIN
      Playground/textures/skybox4_ny.jpg
  32. BIN
      Playground/textures/skybox4_nz.jpg
  33. BIN
      Playground/textures/skybox4_px.jpg
  34. BIN
      Playground/textures/skybox4_py.jpg
  35. BIN
      Playground/textures/skybox4_pz.jpg
  36. BIN
      Playground/textures/sphereMap.png
  37. BIN
      Playground/textures/walk.png
  38. BIN
      Playground/textures/worldHeightMap.jpg
  39. BIN
      Playground/textures/xStrip.jpg
  40. BIN
      Playground/textures/yStrip.jpg
  41. BIN
      Playground/textures/zStrip.jpg
  42. 18 2
      Tools/Gulp/config.json
  43. 2 2
      Viewer/tests/validation/karma.conf.browserstack.js
  44. 684 312
      dist/preview release/babylon.d.ts
  45. 1 1
      dist/preview release/babylon.js
  46. 780 383
      dist/preview release/babylon.max.js
  47. 780 383
      dist/preview release/babylon.no-module.max.js
  48. 1 1
      dist/preview release/babylon.worker.js
  49. 782 385
      dist/preview release/es6.js
  50. 1 1
      dist/preview release/glTF2Interface/package.json
  51. 202 5
      dist/preview release/gui/babylon.gui.d.ts
  52. 1 1
      dist/preview release/gui/babylon.gui.js
  53. 1 1
      dist/preview release/gui/babylon.gui.min.js
  54. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  55. 410 11
      dist/preview release/gui/babylon.gui.module.d.ts
  56. 1 1
      dist/preview release/gui/package.json
  57. 1 1
      dist/preview release/inspector/babylon.inspector.d.ts
  58. 2 2
      dist/preview release/inspector/babylon.inspector.module.d.ts
  59. 1 1
      dist/preview release/inspector/package.json
  60. 2 2
      dist/preview release/loaders/package.json
  61. 1 1
      dist/preview release/materialsLibrary/package.json
  62. 1 1
      dist/preview release/postProcessesLibrary/package.json
  63. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  64. 2 2
      dist/preview release/serializers/package.json
  65. 2 395
      dist/preview release/typedocValidationBaseline.json
  66. 3 17
      dist/preview release/viewer/babylon.viewer.d.ts
  67. 1 1
      dist/preview release/viewer/babylon.viewer.js
  68. 12 12
      dist/preview release/viewer/babylon.viewer.max.js
  69. 3 20
      dist/preview release/viewer/babylon.viewer.module.d.ts
  70. 9 0
      dist/preview release/what's new.md
  71. 32 1
      gui/src/2D/advancedDynamicTexture.ts
  72. 17 0
      gui/src/2D/controls/control.ts
  73. 1 0
      gui/src/2D/controls/index.ts
  74. 15 0
      gui/src/2D/controls/inputText.ts
  75. 568 0
      gui/src/2D/controls/selector.ts
  76. 106 46
      gui/src/2D/controls/virtualKeyboard.ts
  77. 2 0
      materialsLibrary/src/water/babylon.waterMaterial.ts
  78. 1 1
      package.json
  79. 7 3
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  80. 2 1
      src/Collisions/babylon.collisionWorker.ts
  81. 233 0
      src/Culling/Octrees/babylon.octreeSceneComponent.ts
  82. 31 0
      src/Debug/babylon.debugLayer.ts
  83. 1 1
      src/Engine/babylon.engine.ts
  84. 176 0
      src/Helpers/babylon.sceneHelpers.ts
  85. 15 0
      src/Materials/Background/babylon.backgroundMaterial.ts
  86. 16 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  87. 5 0
      src/Materials/babylon.material.ts
  88. 15 0
      src/Materials/babylon.standardMaterial.ts
  89. 7 70
      src/Mesh/babylon.abstractMesh.ts
  90. 2 6
      src/Mesh/babylon.geometry.ts
  91. 6 1
      src/Mesh/babylon.groundMesh.ts
  92. 4 3
      src/Mesh/babylon.mesh.ts
  93. 4 0
      src/Particles/babylon.IParticleSystem.ts
  94. 4 0
      src/Particles/babylon.baseParticleSystem.ts
  95. 21 1
      src/Particles/babylon.gpuParticleSystem.ts
  96. 28 2
      src/Particles/babylon.particle.ts
  97. 1 3
      src/Particles/babylon.particleSystem.ts
  98. 221 8
      src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts
  99. 3 8
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManagerSceneComponent.ts
  100. 0 0
      src/Probes/babylon.reflectionProbe.ts

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 4731 - 4156
Playground/babylon.d.txt


BIN
Playground/textures/Logo.png


BIN
Playground/textures/SpecularHDR.env


BIN
Playground/textures/checkerBJS.png


BIN
Playground/textures/co.png


BIN
Playground/textures/cubemap_blank.jpg


BIN
Playground/textures/customProceduralTextures/land/textures/dirt.jpg


BIN
Playground/textures/customProceduralTextures/land/textures/grass.png


BIN
Playground/textures/environment.env


BIN
Playground/textures/hollow.png


BIN
Playground/textures/lensdirt.jpg


BIN
Playground/textures/mercator.jpg


BIN
Playground/textures/misc.jpg


BIN
Playground/textures/mr.jpg


BIN
Playground/textures/orient.jpg


BIN
Playground/textures/palm.png


BIN
Playground/textures/reflectivity.png


BIN
Playground/textures/skybox2_nx.jpg


BIN
Playground/textures/skybox2_ny.jpg


BIN
Playground/textures/skybox2_nz.jpg


BIN
Playground/textures/skybox2_px.jpg


BIN
Playground/textures/skybox2_py.jpg


BIN
Playground/textures/skybox2_pz.jpg


BIN
Playground/textures/skybox3_nx.jpg


BIN
Playground/textures/skybox3_ny.jpg


BIN
Playground/textures/skybox3_nz.jpg


BIN
Playground/textures/skybox3_px.jpg


BIN
Playground/textures/skybox3_py.jpg


BIN
Playground/textures/skybox3_pz.jpg


BIN
Playground/textures/skybox4_nx.jpg


BIN
Playground/textures/skybox4_ny.jpg


BIN
Playground/textures/skybox4_nz.jpg


BIN
Playground/textures/skybox4_px.jpg


BIN
Playground/textures/skybox4_py.jpg


BIN
Playground/textures/skybox4_pz.jpg


BIN
Playground/textures/sphereMap.png


BIN
Playground/textures/walk.png


BIN
Playground/textures/worldHeightMap.jpg


BIN
Playground/textures/xStrip.jpg


BIN
Playground/textures/yStrip.jpg


BIN
Playground/textures/zStrip.jpg


+ 18 - 2
Tools/Gulp/config.json

@@ -125,7 +125,8 @@
             "occlusionQuery",
             "transformFeedback",
             "noise",
-            "videoRecorder"
+            "videoRecorder",
+            "sceneHelpers"
         ],
         "minimal": [
             "meshBuilder",
@@ -1205,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"
@@ -1370,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"

+ 2 - 2
Viewer/tests/validation/karma.conf.browserstack.js

@@ -81,8 +81,8 @@ module.exports = function (config) {
                 real_mobile: 'true'
             }
         },
-        browsers: ['bs_chrome_android'],
+        browsers: ['bs_chrome_win'],
         reporters: ['dots', 'BrowserStack'],
         singleRun: true
     });
-};
+};

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 684 - 312
dist/preview release/babylon.d.ts


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 780 - 383
dist/preview release/babylon.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 780 - 383
dist/preview release/babylon.no-module.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.worker.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 782 - 385
dist/preview release/es6.js


+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 202 - 5
dist/preview release/gui/babylon.gui.d.ts

@@ -1,6 +1,6 @@
 /*BabylonJS GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
@@ -27,6 +27,12 @@ declare module BABYLON.GUI {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -1076,6 +1082,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: Container): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -1365,6 +1377,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 +1430,12 @@ declare module BABYLON.GUI {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -1596,6 +1616,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 +1943,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 {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 410 - 11
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1,6 +1,6 @@
 /*BabylonJS GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 
 declare module 'babylonjs-gui' {
     export * from "babylonjs-gui/2D";
@@ -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,12 @@ declare module 'babylonjs-gui/2D/advancedDynamicTexture' {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -1178,6 +1185,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: Container): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -1476,13 +1489,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 +1550,12 @@ declare module 'babylonjs-gui/2D/controls/inputText' {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -1733,6 +1755,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 +2093,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;
     }
 }
 
@@ -2606,7 +2808,7 @@ declare module 'babylonjs-gui/3D/materials/fluentMaterial' {
 
 /*BabylonJS GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
@@ -2633,6 +2835,12 @@ declare module BABYLON.GUI {
                 * @param evt defines the current keyboard event
                 */
             processKeyboard(evt: KeyboardEvent): void;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
     }
     /**
         * Class used to create texture to support 2D GUI elements
@@ -3682,6 +3890,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: Container): boolean;
+            /**
                 * Gets coordinates in local control space
                 * @param globalCoordinates defines the coordinates to transform
                 * @returns the new coordinates in local space
@@ -3971,6 +4185,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 +4238,12 @@ declare module BABYLON.GUI {
             /** @hidden */
             onFocus(): void;
             protected _getTypeName(): string;
+            /**
+                * Function called to let the current focused control keeps the focus
+                * @param pointerId defines the unique id of the current pointer
+                * @returns a boolean indicating if the control wants to keep the focus
+                */
+            keepFocus(pointerId: number): boolean;
             /** @hidden */
             processKey(keyCode: number, key?: string): void;
             /** @hidden */
@@ -4202,6 +4424,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 +4751,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 {

+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1,6 +1,6 @@
 /*BabylonJS Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {

+ 2 - 2
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -1,6 +1,6 @@
 /*BabylonJS Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 
 declare module 'babylonjs-inspector' {
     export * from 'babylonjs-inspector/adapters';
@@ -1340,7 +1340,7 @@ declare module 'babylonjs-inspector/treetools/SoundInteractions' {
 
 /*BabylonJS Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/Gulp/babylonjs
+//   ../../../../tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {

+ 1 - 1
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-beta.4"
+        "babylonjs-gltf2interface": "3.3.0-beta.5"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 1 - 1
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-beta.4"
+        "babylonjs-gltf2interface": "3.3.0-beta.5"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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

@@ -1,7 +1,7 @@
 {
-  "errors": 3950,
+  "errors": 3875,
   "babylon.typedoc.json": {
-    "errors": 3950,
+    "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": {
@@ -15979,274 +15829,31 @@
         "BloomEnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
           }
         },
         "DepthOfFieldEnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
           }
         },
         "HDREnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
           }
         },
         "LensFlareEnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
           }
         },
         "MotionBlurEnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
           }
         },
         "VLSEnabled": {
           "Naming": {
             "NotCamelCase": true
-          },
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "animations": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "blurHPostProcesses": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "blurVPostProcesses": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "blurWidth": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "brightPassPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "brightThreshold": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "depthOfFieldBlurWidth": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "depthOfFieldDistance": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "depthOfFieldPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "downSampleX4PostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "exposure": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hdrDecreaseRate": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hdrFinalPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hdrIncreaseRate": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hdrMinimumLuminance": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "hdrPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "horizontalBlur": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensColorTexture": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareComposePostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareDirtTexture": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareDistortionStrength": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareFinalPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareGhostDispersal": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareHaloWidth": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlarePostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensFlareStrength": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensStarTexture": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "lensTexture": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "luminanceDownSamplePostProcesses": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "luminancePostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "motionBlurPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "motionBlurSamples": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "motionStrength": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "sourceLight": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "textureAdderFinalPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "textureAdderPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightBlurScale": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightCoefficient": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightFinalPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightMergePostProces": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightPower": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightSmoothXPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightSmoothYPostProcess": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "volumetricLightStepsCount": {
-          "Comments": {
-            "MissingText": true
           }
         },
         "LuminanceSteps": {

+ 3 - 17
dist/preview release/viewer/babylon.viewer.d.ts

@@ -4,8 +4,8 @@
 declare module "babylonjs-loaders"{ export=BABYLON;}
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/Gulp/babylonjs
-//   ../../../../../Tools/Gulp/babylonjs-loaders
+//   ../../../../../tools/Gulp/babylonjs
+//   ../../../../../tools/Gulp/babylonjs-loaders
 declare module BabylonViewer {
     /**
         * BabylonJS Viewer
@@ -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): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,20 +1558,6 @@ 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 {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 12 - 12
dist/preview release/viewer/babylon.viewer.max.js


+ 3 - 20
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -5,8 +5,8 @@ declare module "babylonjs-loaders"{ export=BABYLON;}
 
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/Gulp/babylonjs
-//   ../../../../../Tools/Gulp/babylonjs-loaders
+//   ../../../../../tools/Gulp/babylonjs
+//   ../../../../../tools/Gulp/babylonjs-loaders
 
 declare module 'babylonjs-viewer' {
     import { mapperManager } from 'babylonjs-viewer/configuration/mappers';
@@ -985,14 +985,13 @@ 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): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1663,22 +1662,6 @@ 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';

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

@@ -6,6 +6,7 @@
   - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
   - New GUI control: [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
   - New GUI control: [InputPassword](https://doc.babylonjs.com/how_to/gui#inputpassword) ([theom](https://github.com/theom))
+  -New GUI container SelectionPanel ([JohnK](https://github.com/BabylonJSGuide))
 - Gizmo Support ([TrevorDev](https://github.com/TrevorDev))
   - Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box. [Doc](http://doc.babylonjs.com/how_to/gizmo) ([TrevorDev](https://github.com/TrevorDev))
   - New behaviors: PointerDragBehavior, SixDofDragBehavior and MultiPointerScaleBehavior to enable smooth drag and drop/scaling with mouse or 6dof controller on a mesh. [Doc](http://doc.babylonjs.com/how_to/meshbehavior) ([TrevorDev](https://github.com/TrevorDev))
@@ -41,6 +42,8 @@
   - 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))
 - Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
 - Playground can now be used with TypeScript directly!. [Demo](https://www.babylonjs-playground.com/ts.html) ([Deltakosh](https://github.com/deltakosh), [NasimiAsl](https://github.com/NasimiAsl))
@@ -61,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))
@@ -117,6 +122,9 @@
 - Improved _isSyncronized performance and reduced GC in TransformNode.computeWorldMatrix by directly reading property. ([Bolloxim](https://github.com/Bolloxim))
 - 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
 
@@ -231,3 +239,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

+ 1 - 0
gui/src/2D/controls/index.ts

@@ -12,6 +12,7 @@ export * from "./line";
 export * from "./multiLine";
 export * from "./radioButton";
 export * from "./stackPanel";
+export * from "./selector";
 export * from "./textBlock";
 export * from "./virtualKeyboard";
 export * from "./slider";

+ 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

+ 568 - 0
gui/src/2D/controls/selector.ts

@@ -0,0 +1,568 @@
+import {Rectangle} from "./rectangle";
+import {StackPanel} from "./stackPanel";
+import {Control} from "./control";
+import {TextBlock} from "./textBlock";
+import {Checkbox} from "./checkbox";
+import {RadioButton} from "./radioButton";
+import {Slider} from "./slider";
+
+/** Class used to create a RadioGroup 
+ * which contains groups of radio buttons
+*/
+export class SelectorGroup {
+    private _groupPanel = new StackPanel();
+    private _selectors: StackPanel[] = new Array();
+    private _groupHeader: TextBlock;
+
+    /**
+     * Creates a new SelectorGroup
+     * @param name of group, used as a group heading
+     */
+    constructor(
+        /** name of SelectorGroup */
+        public name: string, ) {
+
+        this._groupPanel.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+        this._groupPanel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this._groupHeader = this._addGroupHeader(name);
+    }
+
+    /** Gets the groupPanel of the SelectorGroup  */
+    public get groupPanel(): StackPanel {
+        return this._groupPanel;
+    }
+
+    /** Gets the selectors array */
+    public get selectors(): StackPanel[] {
+        return this._selectors;
+    }
+
+    /** Gets and sets the group header */
+    public get header() {
+        return this._groupHeader.text;
+    }
+
+    public set header(label: string) {
+        if(this._groupHeader.text === "label") {
+            return
+        }
+
+        this._groupHeader.text = label
+    }
+
+    /** @hidden */
+    private _addGroupHeader(text: string): TextBlock {
+        var groupHeading = new TextBlock("groupHead", text);
+        groupHeading.width = 0.9;
+        groupHeading.height = "30px";
+        groupHeading.textWrapping = true;
+        groupHeading.color = "black";
+        groupHeading.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        groupHeading.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        groupHeading.left = "2px";
+        this._groupPanel.addControl(groupHeading);
+        return groupHeading;
+    }
+
+    /** @hidden*/
+    public _getSelector(selectorNb: number) {
+        if(selectorNb < 0 || selectorNb >= this._selectors.length) {
+            return;
+        }
+        return this._selectors[selectorNb];
+    }
+
+     /** Removes the selector at the given position 
+     * @param selectorNb the position of the selector within the group
+    */
+    public removeSelector(selectorNb: number) {
+        if(selectorNb < 0 || selectorNb >= this._selectors.length) {
+            return;
+        }
+        this._groupPanel.removeControl(this._selectors[selectorNb]);
+        this._selectors.splice(selectorNb, 1);
+    }
+
+}
+
+/** 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
+     */
+    public addCheckbox(text: string, func = (s: boolean)=>{}, checked: boolean = false): void {
+        var checked = checked || false;
+        var button = new Checkbox();
+        button.width = "20px";
+        button.height = "20px";
+        button.color = "#364249";
+        button.background = "#CCCCCC"; 
+        button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+    
+        button.onIsCheckedChangedObservable.add(function(state) {				
+            func(state);	
+        }); 
+    
+        var _selector = Control.AddHeader(button, text, "200px", { isHorizontal: true, controlFirst: true });
+        _selector.height = "30px";
+        _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        _selector.left = "4px";
+    
+        this.groupPanel.addControl(_selector);
+        this.selectors.push(_selector);
+        button.isChecked = checked;
+
+        if(this.groupPanel.parent && this.groupPanel.parent.parent) {
+            button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
+            button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
+        } 
+    }
+
+    /** @hidden */
+    public _setSelectorLabel(selectorNb: number, label: string) {
+        (<TextBlock>this.selectors[selectorNb].children[1]).text = label;
+    }
+
+    /** @hidden */
+    public _setSelectorLabelColor(selectorNb: number, color: string) {
+        (<TextBlock>this.selectors[selectorNb].children[1]).color = color;
+    }
+
+
+    /** @hidden */
+    public _setSelectorButtonColor(selectorNb: number, color: string) {
+        this.selectors[selectorNb].children[0].color = color;
+    }
+
+    /** @hidden */
+    public _setSelectorButtonBackground(selectorNb: number, color: string) {
+        (<Checkbox>this.selectors[selectorNb].children[0]).background = color;
+    }
+}
+
+/** Class used to create a RadioGroup 
+ * which contains groups of radio buttons
+*/
+export class RadioGroup extends SelectorGroup{
+    private _selectNb = 0;
+
+    /** 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
+     */
+    public addRadio(label: string, func = (n:number) => {} , checked = false): void {				
+        var nb = this._selectNb++;
+        var button = new RadioButton();
+        button.name = label;
+        button.width = "20px";
+        button.height = "20px";
+        button.color = "#364249";
+        button.background = "#CCCCCC"; 
+        button.group = this.name;
+        button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+
+        button.onIsCheckedChangedObservable.add(function(state) {
+            if(state) {
+                func(nb);
+            }
+        });
+        
+        var _selector = Control.AddHeader(button, label, "200px", { isHorizontal: true, controlFirst: true });
+        _selector.height = "30px";
+        _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        _selector.left = "4px";
+        this.groupPanel.addControl(_selector);
+        this.selectors.push(_selector);
+        button.isChecked = checked;
+        
+        if(this.groupPanel.parent && this.groupPanel.parent.parent) {
+            button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
+            button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
+        } 
+    }
+
+    /** @hidden */
+    public _setSelectorLabel(selectorNb: number, label: string) {
+        (<TextBlock>this.selectors[selectorNb].children[1]).text = label;
+    }
+
+    /** @hidden */
+    public _setSelectorLabelColor(selectorNb: number, color: string) {
+        (<TextBlock>this.selectors[selectorNb].children[1]).color = color;
+    }
+
+    /** @hidden */
+    public _setSelectorButtonColor(selectorNb: number, color: string) {
+        this.selectors[selectorNb].children[0].color = color;
+    }
+
+    /** @hidden */
+    public _setSelectorButtonBackground(selectorNb: number, color: string) {
+        (<RadioButton>this.selectors[selectorNb].children[0]).background = color;
+    }
+}
+
+/** 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
+     */
+    public addSlider(label: string, func = (v:number) => {}, unit: string = "Units", min: number = 0, max: number = 0, value: number = 0, onValueChange = (v:number)=>{return v | 0}): void {
+        var button = new Slider();
+        button.name = unit;
+        button.value = value;
+        button.minimum = min;
+        button.maximum = max;				
+        button.width = 0.9;
+        button.height = "20px";
+        button.color = "#364249";
+        button.background = "#CCCCCC";
+        button.borderColor = "black";
+        button.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        button.left = "4px";
+        button.paddingBottom = "4px";
+
+        button.onValueChangedObservable.add(function(value) {
+            (<TextBlock>button.parent!.children[0]).text = button.parent!.children[0].name + ": " + onValueChange(value) + " " + button.name;
+            func(value);
+        });
+        
+        var _selector = Control.AddHeader(button, label + ": " + onValueChange(value) + " " + unit, "30px", { isHorizontal: false, controlFirst: false });
+        _selector.height = "60px";
+        _selector.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        _selector.left = "4px";
+        _selector.children[0].name = label;
+        this.groupPanel.addControl(_selector);
+        this.selectors.push(_selector);
+        
+        if(this.groupPanel.parent && this.groupPanel.parent.parent) {
+            button.color = (<SelectionPanel>this.groupPanel.parent.parent).buttonColor;
+            button.background = (<SelectionPanel>this.groupPanel.parent.parent).buttonBackground;
+        }
+    }
+
+    /** @hidden */
+    public _setSelectorLabel(selectorNb: number, label: string) {
+        this.selectors[selectorNb].children[0].name = label;
+        (<TextBlock>this.selectors[selectorNb].children[0]).text = label + ": " + (<Slider>this.selectors[selectorNb].children[1]).value + " " + this.selectors[selectorNb].children[1].name;
+    }
+
+    /** @hidden */
+    public _setSelectorLabelColor(selectorNb: number, color: string) {
+        (<TextBlock>this.selectors[selectorNb].children[0]).color = color;
+    }
+
+    /** @hidden */
+    public _setSelectorButtonColor(selectorNb: number, color: string) {
+        this.selectors[selectorNb].children[1].color = color;
+    }
+
+    /** @hidden */
+    public _setSelectorButtonBackground(selectorNb: number, color: string) {
+        (<Slider>this.selectors[selectorNb].children[1]).background = color;
+    }
+}
+
+
+/** Class used to hold the controls for the checkboxes, radio buttons and sliders */
+export class SelectionPanel extends Rectangle {
+    private _panel: StackPanel;
+    private _buttonColor: string = "#364249";
+    private _buttonBackground: string = "#CCCCCC"; 
+    private _headerColor: string = "black";
+    private _barColor: string = "white";
+    private _labelColor: string;
+    private _groups: SelectorGroup[];
+    private _bars: any[] = new Array();
+
+
+    /**
+    * Creates a new SelectionPanel
+    * @param name of SelectionPanel
+    * @param groups is an array of SelectionGroups
+    */
+    constructor(
+        /** name of SelectionPanel */
+        public name: string, 
+        /** an array of SelectionGroups */
+        public groups: SelectorGroup[] = []) {
+        super(name);
+        this._groups = groups;
+        this.thickness = 4;
+        this._panel = new StackPanel();
+        this._panel.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+        this._panel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this._panel.top = 5;
+        this._panel.left = 5;
+        this._panel.width = 0.95;
+        if(groups.length > 0) {
+            for(var i = 0; i < groups.length - 1; i++) {
+                this._panel.addControl(groups[i].groupPanel);
+                this._addSpacer();
+            }
+            this._panel.addControl(groups[groups.length - 1].groupPanel);
+        }				
+        this.addControl(this._panel);
+    }
+
+    protected _getTypeName(): string {
+        return "SelectionPanel";
+    }
+    
+    /** Gets or sets the headerColor */
+    public get headerColor(): string {
+        return this._headerColor;
+    }
+
+    public set headerColor(color: string) {
+        if(this._headerColor === color) {
+            return;
+        }
+        this._headerColor = color;
+        this._setHeaderColor();
+
+    }
+
+    private _setHeaderColor() {
+        for(var i = 0; i < this._groups.length; i++) {
+            this._groups[i].groupPanel.children[0].color = this._headerColor;
+        }
+    }
+
+    /** Gets or sets the button color */
+    public get buttonColor(): string {
+        return this._buttonColor;
+    }
+
+    public set buttonColor(color: string) {
+        if(this._buttonColor === color) {
+            return;
+        }
+
+        this._buttonColor = color;
+        this._setbuttonColor();
+
+    }
+
+    private _setbuttonColor() {
+        for(var i = 0; i < this._groups.length; i++) {
+            for(var j = 0; j < this._groups[i].selectors.length; j++) {
+                (<CheckboxGroup|RadioGroup|SliderGroup>this._groups[i])._setSelectorButtonColor(j, this._buttonColor);
+            }         
+        }
+    }
+
+    /** Gets or sets the label color */
+    public get labelColor(): string {
+        return this._labelColor;
+    }
+
+    public set labelColor(color: string) {
+        if(this._labelColor === color) {
+            return;
+        }
+        this._labelColor = color;
+        this._setLabelColor();
+    }
+
+    private _setLabelColor() {
+        for(var i = 0; i < this._groups.length; i++) {
+            for(var j = 0; j < this._groups[i].selectors.length; j++) {
+                (<CheckboxGroup|RadioGroup|SliderGroup>this._groups[i])._setSelectorLabelColor(j, this._labelColor);
+            }         
+        }
+    }
+
+    /** Gets or sets the button background */
+    public get buttonBackground(): string {
+        return this._buttonBackground;
+    }
+
+    public set buttonBackground(color: string) {
+        if(this._buttonBackground === color) {
+            return;
+        }
+
+        this._buttonBackground = color;
+        this._setButtonBackground();
+
+    }
+
+    private _setButtonBackground() {
+        for(var i = 0; i < this._groups.length; i++) {
+            for(var j = 0; j < this._groups[i].selectors.length; j++) {
+                (<CheckboxGroup|RadioGroup|SliderGroup>this._groups[i])._setSelectorButtonBackground(j, this._buttonBackground);
+            }         
+        }
+    }
+
+    /** Gets or sets the color of separator bar */
+    public get barColor(): string {
+        return this._barColor;
+    }
+
+    public set barColor(color: string) {
+       if(this._barColor === color) {
+           return;
+       }
+       
+       this._barColor = color;
+       this._setBarColor();
+    }
+
+    private _setBarColor() {
+        for(var i = 0; i < this._bars.length; i++) {
+            this._bars[i].background = this._barColor;
+        }
+    }
+
+    /** Adds a bar between groups */
+    private _addSpacer(): void {
+        var separator = new Rectangle();
+        separator.width = 1;
+        separator.height = "5px";
+        separator.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        separator.background = this._barColor;
+        separator.color = "transparent";
+        this._panel.addControl(separator);
+        this._bars.push(separator);
+    }
+
+    /** Add a group to the selection panel
+     * @param group is the selector group to add
+     */
+    public addGroup(group: SelectorGroup): void {
+        if(this._groups.length > 0) {
+            this._addSpacer();
+        }
+        this._panel.addControl(group.groupPanel);
+        this._groups.push(group);
+        group.groupPanel.children[0].color = this._headerColor;
+        for(var j = 0; j < group.selectors.length; j++) {
+            (<CheckboxGroup|RadioGroup|SliderGroup>group)._setSelectorButtonColor(j, this._buttonColor);
+            (<CheckboxGroup|RadioGroup|SliderGroup>group)._setSelectorButtonBackground(j, this._buttonBackground);
+        }
+    }
+
+    /** Remove the group from the given position
+     * @param groupNb is the position of the group in the list
+     */
+    public removeGroup(groupNb: number): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        this._panel.removeControl(group.groupPanel);
+        this._groups.splice(groupNb, 1);
+        if(groupNb < this._bars.length) {
+            this._panel.removeControl(this._bars[groupNb]);
+            this._bars.splice(groupNb, 1);
+        }
+    }
+
+    /** Change a group header label
+     * @param label is the new group header label
+     * @param groupNb is the number of the group to relabel
+     * */
+    public setHeaderName(label: string, groupNb: number) {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        (<TextBlock>group.groupPanel.children[0]).text = label;
+    }
+
+
+    /** 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
+     * */ 
+    public relabel(label: string, groupNb: number, selectorNb: number): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        if(selectorNb < 0 || selectorNb >= group.selectors.length) {
+            return;
+        }
+        (<CheckboxGroup|RadioGroup|SliderGroup>group)._setSelectorLabel(selectorNb, label);
+    }
+
+    /** 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
+     */
+    public removeFromGroupSelector(groupNb: number, selectorNb: number): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        if(selectorNb < 0 || selectorNb >= group.selectors.length) {
+            return;
+        }
+        group.removeSelector(selectorNb);
+    }
+
+    /** 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
+     */
+    public addToGroupCheckbox(groupNb: number, label: string, func = () => {} , checked: boolean = false): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        (<CheckboxGroup>group).addCheckbox(label, func, checked);
+    }
+
+    /** 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
+     */
+    public addToGroupRadio(groupNb: number, label: string, func = () => {} , checked: boolean = false): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        (<RadioGroup>group).addRadio(label, func, checked);
+    }
+
+    /**
+     * 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
+     */
+    public addToGroupSlider(groupNb: number, label: string, func = () => {}, unit: string = "Units", min: number = 0, max: number = 0, value: number = 0, onVal = (v:number)=>{return v | 0}): void {
+        if(groupNb < 0 || groupNb >= this._groups.length) {
+            return;
+        }
+        var group = this._groups[groupNb];
+        (<SliderGroup>group).addSlider(label, func, unit, min, max, value, onVal);
+    }
+    
+}

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

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

+ 1 - 1
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.3.0-beta.4",
+    "version": "3.3.0-beta.5",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 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. */

+ 1 - 1
src/Engine/babylon.engine.ts

@@ -475,7 +475,7 @@
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "3.3.0-beta.4";
+            return "3.3.0-beta.5";
         }
 
         // Updatable statics so stick with vars here

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

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

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

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

@@ -172,6 +172,10 @@ module BABYLON {
          * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell height to use
          */
         spriteCellHeight: number;           
+        /**
+         * This allows the system to random pick the start cell ID between startSpriteCellID and endSpriteCellID
+         */
+        spriteRandomStartCell: boolean;            
 
         /** Gets or sets a Vector2 used to move the pivot (by default (0,0)) */
         translationPivot: Vector2;

+ 4 - 0
src/Particles/babylon.baseParticleSystem.ts

@@ -208,6 +208,10 @@ module BABYLON {
          * If using a spritesheet (isAnimationSheetEnabled), defines the sprite cell height to use
          */
         public spriteCellHeight = 0;
+        /**
+         * This allows the system to random pick the start cell ID between startSpriteCellID and endSpriteCellID
+         */
+        public spriteRandomStartCell = false;   
 
         /** Gets or sets a Vector2 used to move the pivot (by default (0,0)) */
         public translationPivot = new Vector2(0, 0);        

+ 21 - 1
src/Particles/babylon.gpuParticleSystem.ts

@@ -516,7 +516,7 @@
             this._scene.particleSystems.push(this);
 
             this._updateEffectOptions = {
-                attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle", "cellIndex"],
+                attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle", "cellIndex", "cellStartOffset"],
                 uniformsNames: ["currentCount", "timeDelta", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange","gravity", "emitPower",
                                 "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor", 
                                 "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
@@ -597,6 +597,10 @@
             if (this._isAnimationSheetEnabled) {
                 updateVertexBuffers["cellIndex"] = source.createVertexBuffer("cellIndex", offset, 1);
                 offset += 1;
+                if (this.spriteRandomStartCell) {
+                    updateVertexBuffers["cellStartOffset"] = source.createVertexBuffer("cellStartOffset", offset, 1);
+                    offset += 1;
+                }
             }            
            
             let vao = this._engine.recordVertexArrayObject(updateVertexBuffers, null, this._updateEffect);
@@ -636,6 +640,10 @@
             if (this._isAnimationSheetEnabled) {
                 renderVertexBuffers["cellIndex"] = source.createVertexBuffer("cellIndex", offset, 1, this._attributesStrideSize, true);
                 offset += 1;
+                if (this.spriteRandomStartCell) {
+                    renderVertexBuffers["cellStartOffset"] = source.createVertexBuffer("cellStartOffset", offset, 1, this._attributesStrideSize, true);
+                    offset += 1;
+                }
             }               
 
             renderVertexBuffers["offset"] = spriteSource.createVertexBuffer("offset", 0, 2);
@@ -669,6 +677,9 @@
 
             if (this._isAnimationSheetEnabled) {
                 this._attributesStrideSize += 1;
+                if (this.spriteRandomStartCell) {
+                    this._attributesStrideSize += 1;
+                }
             }            
 
             for (var particleIndex = 0; particleIndex < this._capacity; particleIndex++) {
@@ -721,6 +732,9 @@
 
                 if (this._isAnimationSheetEnabled) {
                     data.push(0.0); 
+                    if (this.spriteRandomStartCell) {
+                        data.push(0.0); 
+                    }
                 }                
             }
 
@@ -785,6 +799,9 @@
             
             if (this.isAnimationSheetEnabled) {
                 defines += "\n#define ANIMATESHEET";
+                if (this.spriteRandomStartCell) {
+                    defines += "\n#define ANIMATESHEETRANDOMSTART";
+                }
             }   
             
             if (this.noiseTexture) {
@@ -811,6 +828,9 @@
 
             if (this.isAnimationSheetEnabled) {
                 this._updateEffectOptions.transformFeedbackVaryings.push("outCellIndex");
+                if (this.spriteRandomStartCell) {
+                    this._updateEffectOptions.transformFeedbackVaryings.push("outCellStartOffset");
+                }
             }               
 
             this._updateEffectOptions.defines = defines;

+ 28 - 2
src/Particles/babylon.particle.ts

@@ -66,6 +66,9 @@
         public cellIndex: number = 0;  
 
         /** @hidden */
+        public _randomCellOffset?: number;
+
+        /** @hidden */
         public _initialDirection: Nullable<Vector3>;
 
         /** @hidden */
@@ -123,7 +126,7 @@
          */
         constructor(
             /**
-             * particleSystem the particle system the particle belongs to.
+             * The particle system the particle belongs to.
              */
             public particleSystem: ParticleSystem) {
             this.id = Particle._Count++;
@@ -142,12 +145,34 @@
          * Defines how the sprite cell index is updated for the particle
          */
         public updateCellIndex(): void {
+            let offsetAge = this.age;
+
+            if (this.particleSystem.spriteRandomStartCell) {
+                if (this._randomCellOffset === undefined) {         
+                    this._randomCellOffset = Math.random() * this.lifeTime;
+                }
+                offsetAge += this._randomCellOffset;
+            }
+
             let dist = (this._initialEndSpriteCellID - this._initialStartSpriteCellID);
-            let ratio = Scalar.Clamp(((this.age * this.particleSystem.spriteCellChangeSpeed) % this.lifeTime) / this.lifeTime);
+            let ratio = Scalar.Clamp(((offsetAge * this.particleSystem.spriteCellChangeSpeed) % this.lifeTime) / this.lifeTime);
 
             this.cellIndex = this._initialStartSpriteCellID + (ratio * dist) | 0;
         }
 
+        /** @hidden */
+        public _reset() {
+            this.age = 0;
+            this._currentColorGradient = null;
+            this._currentSizeGradient = null;
+            this._currentAngularSpeedGradient = null;
+            this._currentVelocityGradient = null;
+            this._currentLimitVelocityGradient = null;
+            this._currentDragGradient = null;
+            this.cellIndex = this.particleSystem.startSpriteCellID;
+            this._randomCellOffset = undefined;
+        }
+
         /**
          * Copy the properties of particle to another one.
          * @param other the particle to copy the information to.
@@ -168,6 +193,7 @@
             other.colorStep.copyFrom(this.colorStep);
             other.lifeTime = this.lifeTime;
             other.age = this.age;
+            other._randomCellOffset = undefined;
             other.size = this.size;
             other.scale.copyFrom(this.scale);
             other.angle = this.angle;

+ 1 - 3
src/Particles/babylon.particleSystem.ts

@@ -945,9 +945,7 @@
             var particle: Particle;
             if (this._stockParticles.length !== 0) {
                 particle = <Particle>this._stockParticles.pop();
-                particle.age = 0;
-                particle._currentColorGradient = null;
-                particle.cellIndex = this.startSpriteCellID;
+                particle._reset();
             } else {
                 particle = new Particle(this);
             }

+ 221 - 8
src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts

@@ -4,89 +4,227 @@
         * Public members
         */
         // Post-processes
+        /**
+         * Post-process which contains the original scene color before the pipeline applies all the effects
+         */
         public originalPostProcess: Nullable<PostProcess>;
+        /**
+         * Post-process used to down scale an image x4
+         */
         public downSampleX4PostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process used to calculate the illuminated surfaces controlled by a threshold
+         */
         public brightPassPostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process array storing all the horizontal blur post-processes used by the pipeline
+         */
         public blurHPostProcesses: PostProcess[] = [];
+        /**
+         * Post-process array storing all the vertical blur post-processes used by the pipeline
+         */
         public blurVPostProcesses: PostProcess[] = [];
+        /**
+         * Post-process used to add colors of 2 textures (typically brightness + real scene color)
+         */
         public textureAdderPostProcess: Nullable<PostProcess> = null;
 
+        /**
+         * Post-process used to create volumetric lighting effect
+         */
         public volumetricLightPostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process used to smooth the previous volumetric light post-process on the X axis
+         */
         public volumetricLightSmoothXPostProcess: Nullable<BlurPostProcess> = null;
+        /**
+         * Post-process used to smooth the previous volumetric light post-process on the Y axis
+         */
         public volumetricLightSmoothYPostProcess: Nullable<BlurPostProcess> = null;
+        /**
+         * Post-process used to merge the volumetric light effect and the real scene color
+         */
         public volumetricLightMergePostProces: Nullable<PostProcess> = null;
+        /**
+         * Post-process used to store the final volumetric light post-process (attach/detach for debug purpose)
+         */
         public volumetricLightFinalPostProcess: Nullable<PostProcess> = null;
 
+        /**
+         * Base post-process used to calculate the average luminance of the final image for HDR
+         */
         public luminancePostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-processes used to create down sample post-processes in order to get
+         * the average luminance of the final image for HDR
+         * Array of length "StandardRenderingPipeline.LuminanceSteps"
+         */
         public luminanceDownSamplePostProcesses: PostProcess[] = [];
+        /**
+         * Post-process used to create a HDR effect (light adaptation)
+         */
         public hdrPostProcess: Nullable<PostProcess> = null;
-
+        /**
+         * Post-process used to store the final texture adder post-process (attach/detach for debug purpose)
+         */
         public textureAdderFinalPostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process used to store the final lens flare post-process (attach/detach for debug purpose)
+         */
         public lensFlareFinalPostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process used to merge the final HDR post-process and the real scene color
+         */
         public hdrFinalPostProcess: Nullable<PostProcess> = null;
-
+        /**
+         * Post-process used to create a lens flare effect
+         */
         public lensFlarePostProcess: Nullable<PostProcess> = null;
+        /**
+         * Post-process that merges the result of the lens flare post-process and the real scene color
+         */
         public lensFlareComposePostProcess: Nullable<PostProcess> = null;
-
+        /**
+         * Post-process used to create a motion blur effect
+         */
         public motionBlurPostProcess: Nullable<PostProcess> = null;
-
+        /**
+         * Post-process used to create a depth of field effect
+         */
         public depthOfFieldPostProcess: Nullable<PostProcess> = null;
+        /**
+         * The Fast Approximate Anti-Aliasing post process which attemps to remove aliasing from an image.
+         */
+        public fxaaPostProcess: Nullable<FxaaPostProcess> = null;
 
         // Values
+
+        /**
+         * Represents the brightness threshold in order to configure the illuminated surfaces
+         */
         @serialize()
         public brightThreshold: number = 1.0;
 
+        /**
+         * Configures the blur intensity used for surexposed surfaces are highlighted surfaces (light halo)
+         */
         @serialize()
         public blurWidth: number = 512.0;
+        /**
+         * Sets if the blur for highlighted surfaces must be only horizontal
+         */
         @serialize()
         public horizontalBlur: boolean = false;
 
+        /**
+         * Sets the overall exposure used by the pipeline
+         */
         @serialize()
         public exposure: number = 1.0;
+
+        /**
+         * Texture used typically to simulate "dirty" on camera lens
+         */
         @serializeAsTexture("lensTexture")
         public lensTexture: Nullable<Texture> = null;
 
+        /**
+         * Represents the offset coefficient based on Rayleigh principle. Typically in interval [-0.2, 0.2]
+         */
         @serialize()
         public volumetricLightCoefficient: number = 0.2;
+        /**
+         * The overall power of volumetric lights, typically in interval [0, 10] maximum
+         */
         @serialize()
         public volumetricLightPower: number = 4.0;
+        /**
+         * Used the set the blur intensity to smooth the volumetric lights
+         */
         @serialize()
         public volumetricLightBlurScale: number = 64.0;
-
+        /**
+         * Light (spot or directional) used to generate the volumetric lights rays
+         * The source light must have a shadow generate so the pipeline can get its 
+         * depth map
+         */
         public sourceLight: Nullable<SpotLight |  DirectionalLight> = null;
 
+        /**
+         * For eye adaptation, represents the minimum luminance the eye can see
+         */
         @serialize()
         public hdrMinimumLuminance: number = 1.0;
+        /**
+         * For eye adaptation, represents the decrease luminance speed
+         */
         @serialize()
         public hdrDecreaseRate: number = 0.5;
+        /**
+         * For eye adaptation, represents the increase luminance speed
+         */
         @serialize()
         public hdrIncreaseRate: number = 0.5;
 
+        /**
+         * Lens color texture used by the lens flare effect. Mandatory if lens flare effect enabled
+         */
         @serializeAsTexture("lensColorTexture")
         public lensColorTexture: Nullable<Texture> = null;
+        /**
+         * The overall strengh for the lens flare effect
+         */
         @serialize()
         public lensFlareStrength: number = 20.0;
+        /**
+         * Dispersion coefficient for lens flare ghosts
+         */
         @serialize()
         public lensFlareGhostDispersal: number = 1.4;
+        /**
+         * Main lens flare halo width
+         */
         @serialize()
         public lensFlareHaloWidth: number = 0.7;
+        /**
+         * Based on the lens distortion effect, defines how much the lens flare result
+         * is distorted
+         */
         @serialize()
         public lensFlareDistortionStrength: number = 16.0;
+        /**
+         * Lens star texture must be used to simulate rays on the flares and is available
+         * in the documentation
+         */
         @serializeAsTexture("lensStarTexture")
         public lensStarTexture: Nullable<Texture> = null;
+        /**
+         * As the "lensTexture" (can be the same texture or different), it is used to apply the lens
+         * flare effect by taking account of the dirt texture
+         */
         @serializeAsTexture("lensFlareDirtTexture")
         public lensFlareDirtTexture: Nullable<Texture> = null;
 
+        /**
+         * Represents the focal length for the depth of field effect
+         */
         @serialize()
         public depthOfFieldDistance: number = 10.0;
-
+        /**
+         * Represents the blur intensity for the blurred part of the depth of field effect
+         */
         @serialize()
         public depthOfFieldBlurWidth: number = 64.0;
 
+        /**
+         * For motion blur, defines how much the image is blurred by the movement
+         */
         @serialize()
         public motionStrength: number = 1.0;
 
-        // IAnimatable
+        /**
+         * List of animations for the pipeline (IAnimatable implementation)
+         */
         public animations: Animation[] = [];
 
         /**
@@ -104,16 +242,21 @@
         private _ratio: number;
 
         // Getters and setters
-        private _bloomEnabled: boolean = true;
+        private _bloomEnabled: boolean = false;
         private _depthOfFieldEnabled: boolean = false;
         private _vlsEnabled: boolean = false;
         private _lensFlareEnabled: boolean = false;
         private _hdrEnabled: boolean = false;
         private _motionBlurEnabled: boolean = false;
+        private _fxaaEnabled: boolean = false;
 
         private _motionBlurSamples: number = 64.0;
         private _volumetricLightStepsCount: number = 50.0;
+        private _samples: number = 1;
 
+        /**
+         * Specifies if the bloom pipeline is enabled
+         */
         @serialize()
         public get BloomEnabled(): boolean {
             return this._bloomEnabled;
@@ -128,6 +271,9 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if the depth of field pipeline is enabed
+         */
         @serialize()
         public get DepthOfFieldEnabled(): boolean {
             return this._depthOfFieldEnabled;
@@ -142,6 +288,9 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if the lens flare pipeline is enabed
+         */
         @serialize()
         public get LensFlareEnabled(): boolean {
             return this._lensFlareEnabled;
@@ -156,6 +305,9 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if the HDR pipeline is enabled
+         */
         @serialize()
         public get HDREnabled(): boolean {
             return this._hdrEnabled;
@@ -170,6 +322,9 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if the volumetric lights scattering effect is enabled
+         */
         @serialize()
         public get VLSEnabled(): boolean {
             return this._vlsEnabled;
@@ -192,6 +347,9 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if the motion blur effect is enabled
+         */
         @serialize()
         public get MotionBlurEnabled(): boolean {
             return this._motionBlurEnabled;
@@ -206,6 +364,27 @@
             this._buildPipeline();
         }
 
+        /**
+         * Specifies if anti-aliasing is enabled
+         */
+        @serialize()
+        public get fxaaEnabled(): boolean {
+            return this._fxaaEnabled;
+        }
+
+        public set fxaaEnabled(enabled: boolean) {
+            if (this._fxaaEnabled === enabled) {
+                return;
+            }
+
+            this._fxaaEnabled = enabled;
+            this._buildPipeline();
+        }
+
+        /**
+         * Specifies the number of steps used to calculate the volumetric lights
+         * Typically in interval [50, 200]
+         */
         @serialize()
         public get volumetricLightStepsCount(): number {
             return this._volumetricLightStepsCount;
@@ -219,6 +398,10 @@
             this._volumetricLightStepsCount = count;
         }
 
+        /**
+         * Specifies the number of samples used for the motion blur effect
+         * Typically in interval [16, 64]
+         */
         @serialize()
         public get motionBlurSamples(): number {
             return this._motionBlurSamples;
@@ -233,6 +416,23 @@
         }
 
         /**
+         * Specifies MSAA sample count, setting this to 4 will provide 4x anti aliasing. (default: 1)
+         */
+        @serialize()
+        public get samples(): number {
+            return this._samples;
+        }
+
+        public set samples(sampleCount: number) {
+            if (this._samples === sampleCount) {
+                return;
+            }
+
+            this._samples = sampleCount;
+            this._buildPipeline();
+        }
+
+        /**
          * @constructor
          * @param {string} name - The rendering pipeline name
          * @param {BABYLON.Scene} scene - The scene linked to this pipeline
@@ -340,9 +540,19 @@
                 this._createMotionBlurPostProcess(scene, ratio);
             }
 
+            if (this._fxaaEnabled) {
+                // Create fxaa post-process
+                this.fxaaPostProcess = new FxaaPostProcess("fxaa", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, Engine.TEXTURETYPE_UNSIGNED_INT);
+                this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRFxaa", () => { return this.fxaaPostProcess; }, true));
+            }
+
             if (this._cameras !== null) {
                 this._scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(this._name, this._cameras);
             }
+
+            if (!this._enableMSAAOnFirstPostProcess(this._samples) && this._samples > 1){
+                BABYLON.Tools.Warn("MSAA failed to enable, MSAA is only supported in browsers that support webGL >= 2.0");
+            }
         }
 
         // Down Sample X4 Post-Processs
@@ -780,6 +990,8 @@
 
                 if (this.motionBlurPostProcess) { this.motionBlurPostProcess.dispose(camera); }
 
+                if (this.fxaaPostProcess) { this.fxaaPostProcess.dispose(camera); }
+
                 for (var j = 0; j < this.blurHPostProcesses.length; j++) {
                     this.blurHPostProcesses[j].dispose(camera);
                 }
@@ -806,6 +1018,7 @@
             this.hdrFinalPostProcess = null;
             this.depthOfFieldPostProcess = null;
             this.motionBlurPostProcess = null;
+            this.fxaaPostProcess = null;
 
             this.luminanceDownSamplePostProcesses = [];
             this.blurHPostProcesses = [];

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

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


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio