瀏覽代碼

Merge remote-tracking branch 'BabylonJS/master' into viewer-modules

Raanan Weber 7 年之前
父節點
當前提交
42727e63b5
共有 63 個文件被更改,包括 19657 次插入14975 次删除
  1. 11648 11480
      Playground/babylon.d.txt
  2. 6 1
      Tools/Gulp/config.json
  3. 二進制
      assets/environments/environmentSpecular.env
  4. 2874 2734
      dist/preview release/babylon.d.ts
  5. 54 54
      dist/preview release/babylon.js
  6. 804 86
      dist/preview release/babylon.max.js
  7. 804 86
      dist/preview release/babylon.no-module.max.js
  8. 54 54
      dist/preview release/babylon.worker.js
  9. 806 88
      dist/preview release/es6.js
  10. 1 1
      dist/preview release/gltf2Interface/package.json
  11. 36 8
      dist/preview release/gui/babylon.gui.d.ts
  12. 109 47
      dist/preview release/gui/babylon.gui.js
  13. 2 2
      dist/preview release/gui/babylon.gui.min.js
  14. 36 8
      dist/preview release/gui/babylon.gui.module.d.ts
  15. 1 1
      dist/preview release/gui/package.json
  16. 5 5
      dist/preview release/inspector/babylon.inspector.bundle.js
  17. 54 0
      dist/preview release/inspector/babylon.inspector.css
  18. 9 0
      dist/preview release/inspector/babylon.inspector.d.ts
  19. 132 0
      dist/preview release/inspector/babylon.inspector.js
  20. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  21. 1 1
      dist/preview release/inspector/package.json
  22. 2 2
      dist/preview release/loaders/package.json
  23. 1 1
      dist/preview release/materialsLibrary/package.json
  24. 1 1
      dist/preview release/postProcessesLibrary/package.json
  25. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  26. 2 2
      dist/preview release/serializers/package.json
  27. 62 62
      dist/preview release/viewer/babylon.viewer.js
  28. 804 86
      dist/preview release/viewer/babylon.viewer.max.js
  29. 1 1
      dist/preview release/viewer/package.json
  30. 4 0
      dist/preview release/what's new.md
  31. 25 0
      gui/src/3D/controls/abstractButton3D.ts
  32. 1 1
      gui/src/3D/controls/button3D.ts
  33. 5 1
      gui/src/3D/gui3DManager.ts
  34. 3 2
      inspector/sass/defines.scss
  35. 1 0
      inspector/sass/main.scss
  36. 80 0
      inspector/sass/tabs/_toolsTab.scss
  37. 1 0
      inspector/src/tabs/TabBar.ts
  38. 142 0
      inspector/src/tabs/ToolsTab.ts
  39. 1 1
      package.json
  40. 7 5
      sandbox/index.js
  41. 90 19
      src/Engine/babylon.engine.ts
  42. 12 5
      src/Gamepad/Controllers/babylon.windowsMotionController.ts
  43. 1 1
      src/Helpers/babylon.environmentHelper.ts
  44. 30 19
      src/Helpers/babylon.particleHelper.ts
  45. 3 0
      src/Materials/Background/babylon.backgroundMaterial.ts
  46. 5 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  47. 44 5
      src/Materials/Textures/babylon.baseTexture.ts
  48. 25 11
      src/Materials/Textures/babylon.cubeTexture.ts
  49. 4 0
      src/Materials/Textures/babylon.hdrCubeTexture.ts
  50. 12 1
      src/Materials/Textures/babylon.internalTexture.ts
  51. 1 1
      src/Mesh/babylon.abstractMesh.ts
  52. 9 8
      src/Mesh/babylon.mesh.ts
  53. 1 1
      src/Mesh/babylon.meshLODLevel.ts
  54. 4 2
      src/PostProcess/babylon.postProcessManager.ts
  55. 2 0
      src/Rendering/babylon.utilityLayerRenderer.ts
  56. 51 26
      src/Shaders/ShadersInclude/helperFunctions.fx
  57. 15 11
      src/Shaders/background.fragment.fx
  58. 26 18
      src/Shaders/pbr.fragment.fx
  59. 10 0
      src/Shaders/rgbdDecode.fragment.fx
  60. 10 0
      src/Shaders/rgbdEncode.fragment.fx
  61. 686 0
      src/Tools/babylon.environmentTextureTools.ts
  62. 6 6
      src/Tools/babylon.sceneSerializer.ts
  63. 27 16
      src/Tools/babylon.tools.ts

File diff suppressed because it is too large
+ 11648 - 11480
Playground/babylon.d.txt


+ 6 - 1
Tools/Gulp/config.json

@@ -425,7 +425,9 @@
             ],
             ],
             "shaders": [
             "shaders": [
                 "pbr.vertex",
                 "pbr.vertex",
-                "pbr.fragment"
+                "pbr.fragment",
+                "rgbdEncode.fragment",
+                "rgbdDecode.fragment"
             ],
             ],
             "shaderIncludes": [
             "shaderIncludes": [
                 "pbrVertexDeclaration",
                 "pbrVertexDeclaration",
@@ -956,6 +958,7 @@
                 "../../src/Tools/HDR/babylon.cubemapToSphericalPolynomial.js",
                 "../../src/Tools/HDR/babylon.cubemapToSphericalPolynomial.js",
                 "../../src/Tools/HDR/babylon.panoramaToCubemap.js",
                 "../../src/Tools/HDR/babylon.panoramaToCubemap.js",
                 "../../src/Tools/HDR/babylon.hdr.js",
                 "../../src/Tools/HDR/babylon.hdr.js",
+                "../../src/Tools/babylon.environmentTextureTools.js",
                 "../../src/Materials/Textures/babylon.hdrCubeTexture.js"
                 "../../src/Materials/Textures/babylon.hdrCubeTexture.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
@@ -1722,6 +1725,7 @@
                     "../../gui/src/3D/vector3WithInfo.ts",
                     "../../gui/src/3D/vector3WithInfo.ts",
                     "../../gui/src/3D/controls/control3D.ts",
                     "../../gui/src/3D/controls/control3D.ts",
                     "../../gui/src/3D/controls/container3D.ts",
                     "../../gui/src/3D/controls/container3D.ts",
+                    "../../gui/src/3D/controls/abstractButton3D.ts",
                     "../../gui/src/3D/controls/button3D.ts",
                     "../../gui/src/3D/controls/button3D.ts",
                     "../../gui/src/3D/controls/holographicButton.ts",
                     "../../gui/src/3D/controls/holographicButton.ts",
                     "../../gui/src/3D/controls/stackPanel3D.ts",
                     "../../gui/src/3D/controls/stackPanel3D.ts",
@@ -1790,6 +1794,7 @@
                     "../../inspector/src/tabs/ConsoleTab.ts",
                     "../../inspector/src/tabs/ConsoleTab.ts",
                     "../../inspector/src/tabs/StatsTab.ts",
                     "../../inspector/src/tabs/StatsTab.ts",
                     "../../inspector/src/tabs/GLTFTab.ts",
                     "../../inspector/src/tabs/GLTFTab.ts",
+                    "../../inspector/src/tabs/ToolsTab.ts",
                     "../../inspector/src/tabs/TabBar.ts",
                     "../../inspector/src/tabs/TabBar.ts",
                     "../../inspector/src/tools/AbstractTool.ts",
                     "../../inspector/src/tools/AbstractTool.ts",
                     "../../inspector/src/tools/PauseScheduleTool.ts",
                     "../../inspector/src/tools/PauseScheduleTool.ts",

二進制
assets/environments/environmentSpecular.env


File diff suppressed because it is too large
+ 2874 - 2734
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 54 - 54
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 804 - 86
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 804 - 86
dist/preview release/babylon.no-module.max.js


File diff suppressed because it is too large
+ 54 - 54
dist/preview release/babylon.worker.js


File diff suppressed because it is too large
+ 806 - 88
dist/preview release/es6.js


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

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

+ 36 - 8
dist/preview release/gui/babylon.gui.d.ts

@@ -2252,9 +2252,25 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     /**
     /**
+     * Class used as a root to all buttons
+     */
+    class AbstractButton3D extends Control3D {
+        /**
+         * Creates a new button
+         * @param name defines the control name
+         */
+        constructor(name?: string);
+        protected _getTypeName(): string;
+        protected _createNode(scene: Scene): TransformNode;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to create a button in 3D
      * Class used to create a button in 3D
      */
      */
-    class Button3D extends Control3D {
+    class Button3D extends AbstractButton3D {
         /** @hidden */
         /** @hidden */
         protected _currentMaterial: Material;
         protected _currentMaterial: Material;
         private _facadeTexture;
         private _facadeTexture;
@@ -2383,10 +2399,9 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     /**
     /**
-     * Class used to create a conainter panel deployed on the surface of a sphere
+     * Abstract class used to create a container panel deployed on the surface of a volume
      */
      */
-    class SpherePanel extends Container3D {
-        private _radius;
+    abstract class VolumeBasedPanel extends Container3D {
         private _columns;
         private _columns;
         private _rows;
         private _rows;
         private _rowThenColum;
         private _rowThenColum;
@@ -2407,10 +2422,6 @@ declare module BABYLON.GUI {
          */
          */
         orientation: number;
         orientation: number;
         /**
         /**
-         * Gets or sets the radius of the sphere where to project controls (5 by default)
-         */
-        radius: float;
-        /**
          * Gets or sets the number of columns requested (10 by default).
          * Gets or sets the number of columns requested (10 by default).
          * The panel will automatically compute the number of rows based on number of child controls.
          * The panel will automatically compute the number of rows based on number of child controls.
          */
          */
@@ -2425,6 +2436,23 @@ declare module BABYLON.GUI {
          */
          */
         constructor();
         constructor();
         protected _arrangeChildren(): void;
         protected _arrangeChildren(): void;
+        /** Child classes must implement this function to provide correct control positioning */
+        protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
+     * Class used to create a container panel deployed on the surface of a sphere
+     */
+    class SpherePanel extends VolumeBasedPanel {
+        private _radius;
+        /**
+         * Gets or sets the radius of the sphere where to project controls (5 by default)
+         */
+        radius: float;
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3): void;
         private _sphericalMapping(source);
         private _sphericalMapping(source);
     }
     }
 }
 }

+ 109 - 47
dist/preview release/gui/babylon.gui.js

@@ -6587,6 +6587,9 @@ var BABYLON;
                         this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                         this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                         delete this._lastControlDown[pointerEvent.pointerId];
                         delete this._lastControlDown[pointerEvent.pointerId];
                     }
                     }
+                    if (pointerEvent.pointerType === "touch") {
+                        this._handlePointerOut(pointerId, false);
+                    }
                 }
                 }
                 return true;
                 return true;
             };
             };
@@ -7478,6 +7481,37 @@ var BABYLON;
     var GUI;
     var GUI;
     (function (GUI) {
     (function (GUI) {
         /**
         /**
+         * Class used as a root to all buttons
+         */
+        var AbstractButton3D = /** @class */ (function (_super) {
+            __extends(AbstractButton3D, _super);
+            /**
+             * Creates a new button
+             * @param name defines the control name
+             */
+            function AbstractButton3D(name) {
+                return _super.call(this, name) || this;
+            }
+            AbstractButton3D.prototype._getTypeName = function () {
+                return "AbstractButton3D";
+            };
+            // Mesh association
+            AbstractButton3D.prototype._createNode = function (scene) {
+                return new BABYLON.TransformNode("button" + this.name);
+            };
+            return AbstractButton3D;
+        }(GUI.Control3D));
+        GUI.AbstractButton3D = AbstractButton3D;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        /**
          * Class used to create a button in 3D
          * Class used to create a button in 3D
          */
          */
         var Button3D = /** @class */ (function (_super) {
         var Button3D = /** @class */ (function (_super) {
@@ -7626,7 +7660,7 @@ var BABYLON;
                 }
                 }
             };
             };
             return Button3D;
             return Button3D;
-        }(GUI.Control3D));
+        }(GUI.AbstractButton3D));
         GUI.Button3D = Button3D;
         GUI.Button3D = Button3D;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));
@@ -7987,16 +8021,15 @@ var BABYLON;
     var GUI;
     var GUI;
     (function (GUI) {
     (function (GUI) {
         /**
         /**
-         * Class used to create a conainter panel deployed on the surface of a sphere
+         * Abstract class used to create a container panel deployed on the surface of a volume
          */
          */
-        var SpherePanel = /** @class */ (function (_super) {
-            __extends(SpherePanel, _super);
+        var VolumeBasedPanel = /** @class */ (function (_super) {
+            __extends(VolumeBasedPanel, _super);
             /**
             /**
              * Creates new SpherePanel
              * Creates new SpherePanel
              */
              */
-            function SpherePanel() {
+            function VolumeBasedPanel() {
                 var _this = _super.call(this) || this;
                 var _this = _super.call(this) || this;
-                _this._radius = 5.0;
                 _this._columns = 10;
                 _this._columns = 10;
                 _this._rows = 0;
                 _this._rows = 0;
                 _this._rowThenColum = true;
                 _this._rowThenColum = true;
@@ -8007,7 +8040,7 @@ var BABYLON;
                 _this.margin = 0;
                 _this.margin = 0;
                 return _this;
                 return _this;
             }
             }
-            Object.defineProperty(SpherePanel.prototype, "orientation", {
+            Object.defineProperty(VolumeBasedPanel.prototype, "orientation", {
                 /**
                 /**
                  * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
                  * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
                 * | Value | Type                                | Description |
                 * | Value | Type                                | Description |
@@ -8034,27 +8067,7 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
-            Object.defineProperty(SpherePanel.prototype, "radius", {
-                /**
-                 * Gets or sets the radius of the sphere where to project controls (5 by default)
-                 */
-                get: function () {
-                    return this._radius;
-                },
-                set: function (value) {
-                    var _this = this;
-                    if (this._radius === value) {
-                        return;
-                    }
-                    this._radius = value;
-                    BABYLON.Tools.SetImmediate(function () {
-                        _this._arrangeChildren();
-                    });
-                },
-                enumerable: true,
-                configurable: true
-            });
-            Object.defineProperty(SpherePanel.prototype, "columns", {
+            Object.defineProperty(VolumeBasedPanel.prototype, "columns", {
                 /**
                 /**
                  * Gets or sets the number of columns requested (10 by default).
                  * Gets or sets the number of columns requested (10 by default).
                  * The panel will automatically compute the number of rows based on number of child controls.
                  * The panel will automatically compute the number of rows based on number of child controls.
@@ -8076,7 +8089,7 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
-            Object.defineProperty(SpherePanel.prototype, "rows", {
+            Object.defineProperty(VolumeBasedPanel.prototype, "rows", {
                 /**
                 /**
                  * Gets or sets a the number of rows requested.
                  * Gets or sets a the number of rows requested.
                  * The panel will automatically compute the number of columns based on number of child controls.
                  * The panel will automatically compute the number of columns based on number of child controls.
@@ -8098,7 +8111,7 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
-            SpherePanel.prototype._arrangeChildren = function () {
+            VolumeBasedPanel.prototype._arrangeChildren = function () {
                 var cellWidth = 0;
                 var cellWidth = 0;
                 var cellHeight = 0;
                 var cellHeight = 0;
                 var rows = 0;
                 var rows = 0;
@@ -8162,25 +8175,74 @@ var BABYLON;
                     if (!child.mesh) {
                     if (!child.mesh) {
                         continue;
                         continue;
                     }
                     }
-                    var newPos = this._sphericalMapping(nodeGrid[cellCounter]);
-                    switch (this._orientation) {
-                        case GUI.Container3D.FACEORIGIN_ORIENTATION:
-                            child.mesh.lookAt(new BABYLON.Vector3(-newPos.x, -newPos.y, -newPos.z));
-                            break;
-                        case GUI.Container3D.FACEORIGINREVERSED_ORIENTATION:
-                            child.mesh.lookAt(new BABYLON.Vector3(newPos.x, newPos.y, newPos.z));
-                            break;
-                        case GUI.Container3D.FACEFORWARD_ORIENTATION:
-                            child.mesh.lookAt(new BABYLON.Vector3(0, 0, 1));
-                            break;
-                        case GUI.Container3D.FACEFORWARDREVERSED_ORIENTATION:
-                            child.mesh.lookAt(new BABYLON.Vector3(0, 0, -1));
-                            break;
-                    }
-                    child.position = newPos;
+                    this._mapGridNode(child, nodeGrid[cellCounter]);
                     cellCounter++;
                     cellCounter++;
                 }
                 }
             };
             };
+            return VolumeBasedPanel;
+        }(GUI.Container3D));
+        GUI.VolumeBasedPanel = VolumeBasedPanel;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        /**
+         * Class used to create a container panel deployed on the surface of a sphere
+         */
+        var SpherePanel = /** @class */ (function (_super) {
+            __extends(SpherePanel, _super);
+            function SpherePanel() {
+                var _this = _super !== null && _super.apply(this, arguments) || this;
+                _this._radius = 4.0;
+                return _this;
+            }
+            Object.defineProperty(SpherePanel.prototype, "radius", {
+                /**
+                 * Gets or sets the radius of the sphere where to project controls (5 by default)
+                 */
+                get: function () {
+                    return this._radius;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._radius === value) {
+                        return;
+                    }
+                    this._radius = value;
+                    BABYLON.Tools.SetImmediate(function () {
+                        _this._arrangeChildren();
+                    });
+                },
+                enumerable: true,
+                configurable: true
+            });
+            SpherePanel.prototype._mapGridNode = function (control, nodePosition) {
+                var newPos = this._sphericalMapping(nodePosition);
+                var mesh = control.mesh;
+                if (!mesh) {
+                    return;
+                }
+                switch (this.orientation) {
+                    case GUI.Container3D.FACEORIGIN_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(-newPos.x, -newPos.y, -newPos.z));
+                        break;
+                    case GUI.Container3D.FACEORIGINREVERSED_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(newPos.x, newPos.y, newPos.z));
+                        break;
+                    case GUI.Container3D.FACEFORWARD_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(0, 0, 1));
+                        break;
+                    case GUI.Container3D.FACEFORWARDREVERSED_ORIENTATION:
+                        mesh.lookAt(new BABYLON.Vector3(0, 0, -1));
+                        break;
+                }
+                control.position = newPos;
+            };
             SpherePanel.prototype._sphericalMapping = function (source) {
             SpherePanel.prototype._sphericalMapping = function (source) {
                 var newPos = new BABYLON.Vector3(0, 0, this._radius);
                 var newPos = new BABYLON.Vector3(0, 0, this._radius);
                 var xAngle = (source.y / this._radius);
                 var xAngle = (source.y / this._radius);
@@ -8189,7 +8251,7 @@ var BABYLON;
                 return BABYLON.Vector3.TransformNormal(newPos, BABYLON.Tmp.Matrix[0]);
                 return BABYLON.Vector3.TransformNormal(newPos, BABYLON.Tmp.Matrix[0]);
             };
             };
             return SpherePanel;
             return SpherePanel;
-        }(GUI.Container3D));
+        }(GUI.VolumeBasedPanel));
         GUI.SpherePanel = SpherePanel;
         GUI.SpherePanel = SpherePanel;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 36 - 8
dist/preview release/gui/babylon.gui.module.d.ts

@@ -2257,9 +2257,25 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     /**
     /**
+     * Class used as a root to all buttons
+     */
+    class AbstractButton3D extends Control3D {
+        /**
+         * Creates a new button
+         * @param name defines the control name
+         */
+        constructor(name?: string);
+        protected _getTypeName(): string;
+        protected _createNode(scene: Scene): TransformNode;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
      * Class used to create a button in 3D
      * Class used to create a button in 3D
      */
      */
-    class Button3D extends Control3D {
+    class Button3D extends AbstractButton3D {
         /** @hidden */
         /** @hidden */
         protected _currentMaterial: Material;
         protected _currentMaterial: Material;
         private _facadeTexture;
         private _facadeTexture;
@@ -2388,10 +2404,9 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     /**
     /**
-     * Class used to create a conainter panel deployed on the surface of a sphere
+     * Abstract class used to create a container panel deployed on the surface of a volume
      */
      */
-    class SpherePanel extends Container3D {
-        private _radius;
+    abstract class VolumeBasedPanel extends Container3D {
         private _columns;
         private _columns;
         private _rows;
         private _rows;
         private _rowThenColum;
         private _rowThenColum;
@@ -2412,10 +2427,6 @@ declare module BABYLON.GUI {
          */
          */
         orientation: number;
         orientation: number;
         /**
         /**
-         * Gets or sets the radius of the sphere where to project controls (5 by default)
-         */
-        radius: float;
-        /**
          * Gets or sets the number of columns requested (10 by default).
          * Gets or sets the number of columns requested (10 by default).
          * The panel will automatically compute the number of rows based on number of child controls.
          * The panel will automatically compute the number of rows based on number of child controls.
          */
          */
@@ -2430,6 +2441,23 @@ declare module BABYLON.GUI {
          */
          */
         constructor();
         constructor();
         protected _arrangeChildren(): void;
         protected _arrangeChildren(): void;
+        /** Child classes must implement this function to provide correct control positioning */
+        protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
+     * Class used to create a container panel deployed on the surface of a sphere
+     */
+    class SpherePanel extends VolumeBasedPanel {
+        private _radius;
+        /**
+         * Gets or sets the radius of the sphere where to project controls (5 by default)
+         */
+        radius: float;
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3): void;
         private _sphericalMapping(source);
         private _sphericalMapping(source);
     }
     }
 }
 }

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "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.",
     "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-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

File diff suppressed because it is too large
+ 5 - 5
dist/preview release/inspector/babylon.inspector.bundle.js


+ 54 - 0
dist/preview release/inspector/babylon.inspector.css

@@ -297,6 +297,60 @@
         background-color: #383838; }
         background-color: #383838; }
       .insp-wrapper .tab-panel .gltf-actions .gltf-button:active {
       .insp-wrapper .tab-panel .gltf-actions .gltf-button:active {
         background-color: #454545; }
         background-color: #454545; }
+  .insp-wrapper .tab-panel.tools-panel {
+    overflow-y: auto; }
+  .insp-wrapper .tab-panel .tool-title1 {
+    font-size: 1.1em;
+    padding: 10px; }
+  .insp-wrapper .tab-panel .tool-title2 {
+    margin: 10px 0 10px 0;
+    font-size: 1.05em;
+    border-bottom: 1px solid #5db0d7;
+    box-sizing: border-box; }
+  .insp-wrapper .tab-panel .tool-label, .insp-wrapper .tab-panel .tool-label-line, .insp-wrapper .tab-panel .tool-label-error {
+    background-color: #2c2c2c;
+    border: none;
+    outline: none;
+    font-family: "Inconsolata", sans-serif;
+    color: #b3b3b3;
+    padding: 5px;
+    margin: 0px 6px 0px 0; }
+  .insp-wrapper .tab-panel .tool-label-line {
+    width: 100%; }
+  .insp-wrapper .tab-panel .tool-label-error {
+    color: #fa371d;
+    width: 100%;
+    background-color: none; }
+  .insp-wrapper .tab-panel .tool-value {
+    display: inline-block;
+    width: 25%;
+    padding: 2px;
+    background-color: #2c2c2c;
+    border-top: 1px solid #242424;
+    border-bottom: 1px solid #242424;
+    height: 30px;
+    line-height: 30px;
+    box-sizing: border-box; }
+  .insp-wrapper .tab-panel .tool-infos {
+    width: 100%;
+    padding: 4px; }
+  .insp-wrapper .tab-panel .tool-input {
+    background-color: #2c2c2c;
+    border: none;
+    outline: none;
+    font-family: "Inconsolata", sans-serif;
+    color: #ccc;
+    padding: 5px 10px;
+    margin: 0px 6px 0px 0;
+    width: 100%;
+    border-top: 1px solid #242424;
+    border-bottom: 1px solid #242424;
+    text-align: left; }
+    .insp-wrapper .tab-panel .tool-input:hover {
+      background-color: #383838;
+      cursor: pointer; }
+    .insp-wrapper .tab-panel .tool-input:active {
+      background-color: #454545; }
   .insp-wrapper .property-type {
   .insp-wrapper .property-type {
     color: #5db0d7; }
     color: #5db0d7; }
   .insp-wrapper .property-name, .insp-wrapper .insp-details .base-row .prop-name, .insp-wrapper .insp-details .row .prop-name, .insp-wrapper .insp-details .header-row .prop-name {
   .insp-wrapper .property-name, .insp-wrapper .insp-details .base-row .prop-name, .insp-wrapper .insp-details .row .prop-name, .insp-wrapper .insp-details .header-row .prop-name {

+ 9 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1052,6 +1052,15 @@ declare module INSPECTOR {
 }
 }
 
 
 declare module INSPECTOR {
 declare module INSPECTOR {
+    class ToolsTab extends Tab {
+        private _inspector;
+        private _scene;
+        constructor(tabbar: TabBar, insp: Inspector);
+        dispose(): void;
+    }
+}
+
+declare module INSPECTOR {
     /**
     /**
      * A tab bar will contains each view the inspector can have : Canvas2D, Meshes...
      * A tab bar will contains each view the inspector can have : Canvas2D, Meshes...
      * The default active tab is the first one of the list.
      * The default active tab is the first one of the list.

+ 132 - 0
dist/preview release/inspector/babylon.inspector.js

@@ -4253,6 +4253,137 @@ var __extends = (this && this.__extends) || (function () {
 })();
 })();
 var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
 (function (INSPECTOR) {
+    var ToolsTab = /** @class */ (function (_super) {
+        __extends(ToolsTab, _super);
+        function ToolsTab(tabbar, insp) {
+            var _this = _super.call(this, tabbar, 'Tools') || this;
+            _this._inspector = insp;
+            _this._scene = _this._inspector.scene;
+            // Build the tools panel: a div that will contains all tools
+            _this._panel = INSPECTOR.Helpers.CreateDiv('tab-panel');
+            _this._panel.classList.add("tools-panel");
+            var title = INSPECTOR.Helpers.CreateDiv('tool-title1', _this._panel);
+            var versionSpan = INSPECTOR.Helpers.CreateElement('span');
+            versionSpan.textContent = "Babylon.js v" + BABYLON.Engine.Version + " - Tools";
+            title.appendChild(versionSpan);
+            // Environment block
+            title = INSPECTOR.Helpers.CreateDiv('tool-title2', _this._panel);
+            title.textContent = "Environment Texture (.dds, .env)";
+            {
+                var errorElemm_1 = INSPECTOR.Inspector.DOCUMENT.createElement('div');
+                errorElemm_1.className = "tool-label-error";
+                errorElemm_1.style.display = "none";
+                var elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
+                var inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
+                inputElement.className = "tool-input";
+                inputElement.type = "file";
+                inputElement.accept = ".dds, .env";
+                inputElement.onchange = function (event) {
+                    var files = event.target.files;
+                    var file = null;
+                    if (files && files.length) {
+                        file = files[0];
+                    }
+                    if (!file) {
+                        errorElemm_1.style.display = "block";
+                        errorElemm_1.textContent = "Please, select a file first.";
+                        return;
+                    }
+                    var isFileDDS = file.name.toLowerCase().indexOf(".dds") > 0;
+                    var isFileEnv = file.name.toLowerCase().indexOf(".env") > 0;
+                    if (!isFileDDS && !isFileEnv) {
+                        errorElemm_1.style.display = "block";
+                        errorElemm_1.textContent = "Please, select a dds or env file.";
+                        return;
+                    }
+                    BABYLON.Tools.ReadFile(file, function (data) {
+                        var blob = new Blob([data], { type: "octet/stream" });
+                        var url = URL.createObjectURL(blob);
+                        if (isFileDDS) {
+                            _this._scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(url, _this._scene, ".dds");
+                            errorElemm_1.style.display = "none";
+                        }
+                        else {
+                            _this._scene.environmentTexture = new BABYLON.CubeTexture(url, _this._scene, undefined, undefined, undefined, function () {
+                                errorElemm_1.style.display = "none";
+                            }, function (message) {
+                                if (message) {
+                                    errorElemm_1.style.display = "block";
+                                    errorElemm_1.textContent = message;
+                                }
+                            }, undefined, undefined, ".env");
+                        }
+                    }, undefined, true);
+                };
+                elemValue.appendChild(inputElement);
+                elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
+                inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
+                inputElement.value = "Compress current texture to .env";
+                inputElement.className = "tool-input";
+                inputElement.type = "button";
+                inputElement.onclick = function () {
+                    if (!_this._scene.environmentTexture) {
+                        errorElemm_1.style.display = "block";
+                        errorElemm_1.textContent = "You must load an environment texture first.";
+                        return;
+                    }
+                    if (_this._scene.activeCamera) {
+                        BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(_this._scene.environmentTexture)
+                            .then(function (buffer) {
+                            var blob = new Blob([buffer], { type: "octet/stream" });
+                            BABYLON.Tools.Download(blob, "environment.env");
+                            errorElemm_1.style.display = "none";
+                        })
+                            .catch(function (error) {
+                            errorElemm_1.style.display = "block";
+                            errorElemm_1.textContent = error;
+                        });
+                    }
+                    else {
+                        errorElemm_1.style.display = "block";
+                        errorElemm_1.textContent = "An active camera is required.";
+                    }
+                };
+                elemValue.appendChild(inputElement);
+                _this._panel.appendChild(errorElemm_1);
+            }
+            title = INSPECTOR.Helpers.CreateDiv('tool-title2', _this._panel);
+            title.textContent = "Capture";
+            {
+                var elemValue = INSPECTOR.Helpers.CreateDiv(null, _this._panel);
+                var inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
+                inputElement.value = "Take Screenshot";
+                inputElement.type = "button";
+                inputElement.className = "tool-input";
+                inputElement.onclick = function () {
+                    if (_this._scene.activeCamera) {
+                        BABYLON.Tools.CreateScreenshot(_this._scene.getEngine(), _this._scene.activeCamera, { precision: 0.5 });
+                    }
+                };
+                elemValue.appendChild(inputElement);
+            }
+            return _this;
+        }
+        ToolsTab.prototype.dispose = function () {
+            // Nothing to dispose
+        };
+        return ToolsTab;
+    }(INSPECTOR.Tab));
+    INSPECTOR.ToolsTab = ToolsTab;
+})(INSPECTOR || (INSPECTOR = {}));
+
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var INSPECTOR;
+(function (INSPECTOR) {
     /**
     /**
      * A tab bar will contains each view the inspector can have : Canvas2D, Meshes...
      * A tab bar will contains each view the inspector can have : Canvas2D, Meshes...
      * The default active tab is the first one of the list.
      * The default active tab is the first one of the list.
@@ -4285,6 +4416,7 @@ var INSPECTOR;
             _this._tabs.push(new INSPECTOR.PhysicsTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.PhysicsTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.CameraTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.CameraTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.SoundTab(_this, _this._inspector));
             _this._tabs.push(new INSPECTOR.SoundTab(_this, _this._inspector));
+            _this._tabs.push(new INSPECTOR.ToolsTab(_this, _this._inspector));
             _this._toolBar = new INSPECTOR.Toolbar(_this._inspector);
             _this._toolBar = new INSPECTOR.Toolbar(_this._inspector);
             _this._build();
             _this._build();
             //Check initialTab is defined and between tabs bounds
             //Check initialTab is defined and between tabs bounds

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


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

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

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "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.",
     "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-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0-alpha.3"
+        "babylonjs-gltf2interface": "3.3.0-alpha.4"
     },
     },
     "peerDependencies": {
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"
         "babylonjs": ">=3.2.0-alpha"

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-materials",
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.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",
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.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",
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.3.0-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

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

File diff suppressed because it is too large
+ 62 - 62
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 804 - 86
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-viewer",
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.3.0-alpha.3",
+    "version": "3.3.0-alpha.4",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -6,10 +6,12 @@
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 - Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
 - Added new `PhotoDome` object to display 360 photos. [Demo](https://www.babylonjs-playground.com/#14KRGG#0) ([SzeyinLee](https://github.com/SzeyinLee))
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
+- Added Environmnent Texture Tools to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan)). [How to](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture)
 
 
 ## Updates
 ## Updates
 
 
 - All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
 - All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
+- Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
 
 
 ### Core Engine
 ### Core Engine
 
 
@@ -52,6 +54,8 @@
 
 
 - VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
 - VR experience helper will now fire pointer events even when no mesh is currently hit ([TrevorDev](https://github.com/TrevorDev))
 - RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
 - RawTexture.CreateAlphaTexture no longer fails to create a usable texture ([TrevorDev](https://github.com/TrevorDev))
+- SceneSerializer.SerializeMesh now serializes all materials kinds (not only StandardMaterial) ([julien-moreau](https://github.com/julien-moreau))
+- WindowsMotionController's trackpad field will be updated prior to it's onTrackpadChangedObservable event ([TrevorDev](https://github.com/TrevorDev))
 
 
 ### Core Engine
 ### Core Engine
 
 

+ 25 - 0
gui/src/3D/controls/abstractButton3D.ts

@@ -0,0 +1,25 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Class used as a root to all buttons
+     */
+    export class AbstractButton3D extends Control3D {
+        /**
+         * Creates a new button
+         * @param name defines the control name
+         */
+        constructor(name?: string) {
+            super(name);
+        }
+
+        protected _getTypeName(): string {
+            return "AbstractButton3D";
+        }        
+
+        // Mesh association
+        protected _createNode(scene: Scene): TransformNode {
+            return new TransformNode("button" + this.name);
+        }    
+    }
+}

+ 1 - 1
gui/src/3D/controls/button3D.ts

@@ -4,7 +4,7 @@ module BABYLON.GUI {
     /**
     /**
      * Class used to create a button in 3D
      * Class used to create a button in 3D
      */
      */
-    export class Button3D extends Control3D {
+    export class Button3D extends AbstractButton3D {
         /** @hidden */
         /** @hidden */
         protected _currentMaterial: Material;
         protected _currentMaterial: Material;
         private _facadeTexture: Nullable<AdvancedDynamicTexture>;
         private _facadeTexture: Nullable<AdvancedDynamicTexture>;

+ 5 - 1
gui/src/3D/gui3DManager.ts

@@ -65,7 +65,7 @@ module BABYLON.GUI {
             });
             });
 
 
             this._pointerObserver = utilityLayerScene.onPointerObservable.add((pi, state) => {
             this._pointerObserver = utilityLayerScene.onPointerObservable.add((pi, state) => {
-                this._doPicking(pi)
+                this._doPicking(pi);
             });
             });
 
 
             // Scene
             // Scene
@@ -128,6 +128,10 @@ module BABYLON.GUI {
                     this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                     this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                     delete this._lastControlDown[pointerEvent.pointerId];
                     delete this._lastControlDown[pointerEvent.pointerId];
                 }
                 }
+
+                if (pointerEvent.pointerType === "touch") {
+                    this._handlePointerOut(pointerId, false);
+                }
             }
             }
 
 
             return true;
             return true;

+ 3 - 2
inspector/sass/defines.scss

@@ -13,8 +13,9 @@ $font               : 'Inconsolata', sans-serif;
 $color              : #ccc;
 $color              : #ccc;
 $background         : #242424;
 $background         : #242424;
 $background-active  : #2c2c2c;
 $background-active  : #2c2c2c;
-$color-top         : #f29766;
-$color-bot         : #5db0d7;
+$color-top          : #f29766;
+$color-bot          : #5db0d7;
+$color-error        : #fa371d;
 
 
 $background-lighter : lighten($color: $background, $amount         : 3%);
 $background-lighter : lighten($color: $background, $amount         : 3%);
 $background-lighter2: lighten($color: $background-lighter, $amount : 5%);
 $background-lighter2: lighten($color: $background-lighter, $amount : 5%);

+ 1 - 0
inspector/sass/main.scss

@@ -94,6 +94,7 @@
   @import "tabs/consoleTab";
   @import "tabs/consoleTab";
   @import "tabs/statsTab";
   @import "tabs/statsTab";
   @import "tabs/gltfTab";
   @import "tabs/gltfTab";
+  @import "tabs/toolsTab";
 
 
   @import "tree";
   @import "tree";
   @import "detailPanel";
   @import "detailPanel";

+ 80 - 0
inspector/sass/tabs/_toolsTab.scss

@@ -0,0 +1,80 @@
+.tab-panel {
+
+    &.tools-panel {
+        overflow-y      : auto;
+    }
+
+    .tool-title1 {        
+        font-size       : 1.1em;
+        padding         : 10px;
+    }
+
+    .tool-title2 {
+        margin          : 10px 0 10px 0;
+        font-size       : 1.05em; 
+        border-bottom   : 1px solid $color-bot;
+        box-sizing      : border-box;
+    }
+
+    .tool-label {
+        background-color: $background-lighter;
+        border          : none;
+        outline         : none;
+        font-family     : $font;
+        color           : darken($color, 10%);
+        padding         : 5px;
+        margin          : 0px 6px 0px 0;
+    }
+
+    .tool-label-line {
+        @extend .tool-label;
+        width           : 100%;
+    }
+
+    .tool-label-error {
+        @extend .tool-label;
+        color           : $color-error;
+        width           : 100%;
+        background-color: none;
+    }
+
+    .tool-value {
+        display         : inline-block;
+        width           : 25%;
+        padding         : 2px;
+        background-color: $background-lighter;
+        border-top      : 1px solid $background;
+        border-bottom   : 1px solid $background;
+        height          : 30px;
+        line-height     : 30px;
+        box-sizing      : border-box;
+    }
+
+    .tool-infos {
+        width           : 100%;
+        padding         : 4px;
+    }
+
+    .tool-input {
+        background-color: $background-lighter;
+        border          : none;
+        outline         : none;
+        font-family     : $font;
+        color           : $color;
+        padding         : 5px 10px;
+        margin          : 0px 6px 0px 0;
+        width           : 100%;
+        border-top      : 1px solid $background;
+        border-bottom   : 1px solid $background;
+        text-align: left;
+
+        &:hover {
+            background-color:$background-lighter2;
+            cursor: pointer;
+        }
+
+        &:active {
+            background-color:$background-lighter3;
+        }
+    }
+}

+ 1 - 0
inspector/src/tabs/TabBar.ts

@@ -41,6 +41,7 @@ module INSPECTOR {
             this._tabs.push(new PhysicsTab(this, this._inspector));
             this._tabs.push(new PhysicsTab(this, this._inspector));
             this._tabs.push(new CameraTab(this, this._inspector));
             this._tabs.push(new CameraTab(this, this._inspector));
             this._tabs.push(new SoundTab(this, this._inspector));
             this._tabs.push(new SoundTab(this, this._inspector));
+            this._tabs.push(new ToolsTab(this, this._inspector));
             this._toolBar = new Toolbar(this._inspector);
             this._toolBar = new Toolbar(this._inspector);
 
 
             this._build();
             this._build();

+ 142 - 0
inspector/src/tabs/ToolsTab.ts

@@ -0,0 +1,142 @@
+module INSPECTOR {
+
+    export class ToolsTab extends Tab {
+
+        private _inspector: Inspector;
+
+        private _scene: BABYLON.Scene;
+
+        constructor(tabbar: TabBar, insp: Inspector) {
+            super(tabbar, 'Tools');
+
+            this._inspector = insp;
+
+            this._scene = this._inspector.scene;
+
+            // Build the tools panel: a div that will contains all tools
+            this._panel = Helpers.CreateDiv('tab-panel') as HTMLDivElement;
+            this._panel.classList.add("tools-panel")
+
+            let title = Helpers.CreateDiv('tool-title1', this._panel);
+            let versionSpan = Helpers.CreateElement('span');
+            versionSpan.textContent = `Babylon.js v${BABYLON.Engine.Version} - Tools`;
+            title.appendChild(versionSpan);
+
+            // Environment block
+            title = Helpers.CreateDiv('tool-title2', this._panel);
+            title.textContent = "Environment Texture (.dds, .env)";
+            {
+                let errorElemm = Inspector.DOCUMENT.createElement('div');
+                errorElemm.className = "tool-label-error";
+                errorElemm.style.display = "none";
+
+                let elemValue = Helpers.CreateDiv(null, this._panel);
+
+                let inputElement = Inspector.DOCUMENT.createElement('input');
+                inputElement.className = "tool-input";
+                inputElement.type = "file";
+                inputElement.accept =".dds, .env";
+                inputElement.onchange = (event: any) => {
+                    var files: File[] = event.target.files;
+                    let file: BABYLON.Nullable<File> = null;
+                    if (files && files.length) {
+                        file = files[0];
+                    }
+
+                    if (!file) {
+                        errorElemm.style.display = "block";
+                        errorElemm.textContent = "Please, select a file first."
+                        return;
+                    }
+
+                    let isFileDDS = file.name.toLowerCase().indexOf(".dds") > 0;
+                    let isFileEnv = file.name.toLowerCase().indexOf(".env") > 0;
+                    if (!isFileDDS && ! isFileEnv) {
+                        errorElemm.style.display = "block";
+                        errorElemm.textContent = "Please, select a dds or env file."
+                        return;
+                    }
+
+                    BABYLON.Tools.ReadFile(file, data => {
+                        var blob = new Blob([data], {type: "octet/stream"});
+                        var url = URL.createObjectURL(blob);
+                        if (isFileDDS) {
+                            this._scene.environmentTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(url, this._scene, ".dds");
+                            errorElemm.style.display = "none";
+                        }
+                        else {
+                            this._scene.environmentTexture = new BABYLON.CubeTexture(url, this._scene, 
+                                undefined, undefined, undefined, 
+                                () => {
+                                    errorElemm.style.display = "none";
+                                }, 
+                                (message) => {
+                                    if (message) {
+                                        errorElemm.style.display = "block";
+                                        errorElemm.textContent = message;
+                                    }
+                                }, 
+                                undefined, undefined,
+                                ".env");
+                        }
+                    }, undefined, true);
+                };
+                elemValue.appendChild(inputElement);
+
+                elemValue = Helpers.CreateDiv(null, this._panel);
+
+                inputElement = Inspector.DOCUMENT.createElement('input');
+                inputElement.value = "Compress current texture to .env";
+                inputElement.className = "tool-input";
+                inputElement.type = "button";
+                inputElement.onclick = () => {
+                    if (!this._scene.environmentTexture) {
+                        errorElemm.style.display = "block";
+                        errorElemm.textContent = "You must load an environment texture first.";
+                        return;
+                    }
+                    if (this._scene.activeCamera) {
+                        BABYLON.EnvironmentTextureTools.CreateEnvTextureAsync(<BABYLON.CubeTexture>this._scene.environmentTexture)
+                        .then((buffer: ArrayBuffer) => {
+                            var blob = new Blob([buffer], {type: "octet/stream"});
+                            BABYLON.Tools.Download(blob, "environment.env");
+                            errorElemm.style.display = "none";
+                        })
+                        .catch((error: any) => {
+                            errorElemm.style.display = "block";
+                            errorElemm.textContent = error;
+                        });
+                    }
+                    else {
+                        errorElemm.style.display = "block";
+                        errorElemm.textContent = "An active camera is required.";
+                    }
+                };
+                elemValue.appendChild(inputElement);
+                
+                this._panel.appendChild(errorElemm);
+            }
+
+            title = Helpers.CreateDiv('tool-title2', this._panel);
+            title.textContent = "Capture";
+            {
+                let elemValue = Helpers.CreateDiv(null, this._panel);
+
+                let inputElement = Inspector.DOCUMENT.createElement('input');
+                inputElement.value = "Take Screenshot";
+                inputElement.type = "button";
+                inputElement.className = "tool-input";
+                inputElement.onclick = () => {
+                    if (this._scene.activeCamera) {
+                        BABYLON.Tools.CreateScreenshot(this._scene.getEngine(), this._scene.activeCamera, {precision: 0.5});
+                    }
+                };
+                elemValue.appendChild(inputElement);
+            }
+        }
+
+        public dispose() {
+            // Nothing to dispose
+        }
+    }
+}

+ 1 - 1
package.json

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

+ 7 - 5
sandbox/index.js

@@ -43,7 +43,7 @@ if (indexOf !== -1) {
 
 
 if (BABYLON.Engine.isSupported()) {
 if (BABYLON.Engine.isSupported()) {
     var canvas = document.getElementById("renderCanvas");
     var canvas = document.getElementById("renderCanvas");
-    var engine = new BABYLON.Engine(canvas, true);
+    var engine = new BABYLON.Engine(canvas, true, { premultipliedAlpha: false, preserveDrawingBuffer: true });
     var htmlInput = document.getElementById("files");
     var htmlInput = document.getElementById("files");
     var footer = document.getElementById("footer");
     var footer = document.getElementById("footer");
     var btnFullScreen = document.getElementById("btnFullscreen");
     var btnFullScreen = document.getElementById("btnFullscreen");
@@ -235,10 +235,12 @@ if (BABYLON.Engine.isSupported()) {
     else {
     else {
         filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
         filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
         filesInput.onProcessFileCallback = (function (file, name, extension) {
         filesInput.onProcessFileCallback = (function (file, name, extension) {
-            if (filesInput._filesToLoad && filesInput._filesToLoad.length === 1 && extension && extension.toLowerCase() === "dds") {
-                BABYLON.FilesInput.FilesToLoad[name] = file;
-                skyboxPath = "file:" + file.correctName;
-                return false;
+            if (filesInput._filesToLoad && filesInput._filesToLoad.length === 1 && extension) {
+                if (extension.toLowerCase() === "dds" || extension.toLowerCase() === "env") {
+                    BABYLON.FilesInput.FilesToLoad[name] = file;
+                    skyboxPath = "file:" + file.correctName;
+                    return false;
+                }
             }
             }
             return true;
             return true;
         }).bind(this);
         }).bind(this);

+ 90 - 19
src/Engine/babylon.engine.ts

@@ -710,7 +710,7 @@
          * Returns the current version of the framework
          * Returns the current version of the framework
          */
          */
         public static get Version(): string {
         public static get Version(): string {
-            return "3.3.0-alpha.3";
+            return "3.3.0-alpha.4";
         }
         }
 
 
         // Updatable statics so stick with vars here
         // Updatable statics so stick with vars here
@@ -1129,6 +1129,11 @@
         }
         }
 
 
         /**
         /**
+         * Defines whether the engine has been created with the premultipliedAlpha option on or not.
+         */
+        public readonly premultipliedAlpha: boolean = true;
+
+        /**
          * Creates a new engine
          * Creates a new engine
          * @param canvasOrContext defines the canvas or WebGL context to use for rendering
          * @param canvasOrContext defines the canvas or WebGL context to use for rendering
          * @param antialias defines enable antialiasing (default: false)
          * @param antialias defines enable antialiasing (default: false)
@@ -1177,6 +1182,10 @@
                     options.stencil = true;
                     options.stencil = true;
                 }
                 }
 
 
+                if (options.premultipliedAlpha === false) {
+                    this.premultipliedAlpha = false;
+                }
+
                 this._deterministicLockstep = options.deterministicLockstep;
                 this._deterministicLockstep = options.deterministicLockstep;
                 this._lockstepMaxSteps = options.lockstepMaxSteps;
                 this._lockstepMaxSteps = options.lockstepMaxSteps;
                 this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;
                 this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;
@@ -2415,8 +2424,9 @@
          * @param requiredHeight The height of the target to render to
          * @param requiredHeight The height of the target to render to
          * @param forceFullscreenViewport Forces the viewport to be the entire texture/screen if true
          * @param forceFullscreenViewport Forces the viewport to be the entire texture/screen if true
          * @param depthStencilTexture The depth stencil texture to use to render
          * @param depthStencilTexture The depth stencil texture to use to render
+         * @param lodLevel defines le lod level to bind to the frame buffer
          */
          */
-        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean, depthStencilTexture?: InternalTexture): void {
+        public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean, depthStencilTexture?: InternalTexture, lodLevel = 0): void {
             if (this._currentRenderTarget) {
             if (this._currentRenderTarget) {
                 this.unBindFramebuffer(this._currentRenderTarget);
                 this.unBindFramebuffer(this._currentRenderTarget);
             }
             }
@@ -2427,14 +2437,14 @@
                 if (faceIndex === undefined) {
                 if (faceIndex === undefined) {
                     faceIndex = 0;
                     faceIndex = 0;
                 }
                 }
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, 0);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, lodLevel);
 
 
                 if (depthStencilTexture) {
                 if (depthStencilTexture) {
                     if (depthStencilTexture._generateStencilBuffer) {
                     if (depthStencilTexture._generateStencilBuffer) {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, lodLevel);
                     }
                     }
                     else {
                     else {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, lodLevel);
                     }
                     }
                 }
                 }
             }
             }
@@ -2442,7 +2452,20 @@
             if (this._cachedViewport && !forceFullscreenViewport) {
             if (this._cachedViewport && !forceFullscreenViewport) {
                 this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
                 this.setViewport(this._cachedViewport, requiredWidth, requiredHeight);
             } else {
             } else {
-                gl.viewport(0, 0, requiredWidth || texture.width, requiredHeight || texture.height);
+                if (!requiredWidth) {
+                    requiredWidth = texture.width;
+                    if (lodLevel) {
+                        requiredWidth = requiredWidth / Math.pow(2, lodLevel);
+                    }
+                }
+                if (!requiredHeight) {
+                    requiredHeight = texture.height;
+                    if (lodLevel) {
+                        requiredHeight = requiredHeight / Math.pow(2, lodLevel);
+                    }
+                }
+
+                gl.viewport(0, 0, requiredWidth, requiredHeight);
             }
             }
 
 
             this.wipeCaches();
             this.wipeCaches();
@@ -5259,6 +5282,28 @@
             this._gl.compressedTexImage2D(target, lod, internalFormat, width, height, 0, <DataView>data);
             this._gl.compressedTexImage2D(target, lod, internalFormat, width, height, 0, <DataView>data);
         }
         }
 
 
+        /** @hidden */
+        public _uploadImageToTexture(texture: InternalTexture, faceIndex: number, lod: number, image: HTMLImageElement) {
+            var gl = this._gl;
+
+            var textureType = this._getWebGLTextureType(texture.type);
+            var format = this._getInternalFormat(texture.format);
+            var internalFormat = this._getRGBABufferInternalSizedFormat(texture.type, format);
+
+            var bindTarget = texture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
+
+            this._bindTextureDirectly(bindTarget, texture, true);
+            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, texture.invertY ? 1 : 0);
+
+            var target = gl.TEXTURE_2D;
+            if (texture.isCube) {
+                var target = gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex;
+            }
+
+            gl.texImage2D(target, lod, internalFormat, format, textureType, image);
+            this._bindTextureDirectly(bindTarget, null, true);
+        }
+
         /**
         /**
          * Creates a new render target cube texture
          * Creates a new render target cube texture
          * @param size defines the size of the texture
          * @param size defines the size of the texture
@@ -5343,8 +5388,8 @@
          * Create a cube texture from prefiltered data (ie. the mipmaps contain ready to use data for PBR reflection)
          * Create a cube texture from prefiltered data (ie. the mipmaps contain ready to use data for PBR reflection)
          * @param rootUrl defines the url where the file to load is located
          * @param rootUrl defines the url where the file to load is located
          * @param scene defines the current scene
          * @param scene defines the current scene
-         * @param scale defines scale to apply to the mip map selection
-         * @param offset defines offset to apply to the mip map selection
+         * @param lodScale defines scale to apply to the mip map selection
+         * @param lodOffset defines offset to apply to the mip map selection
          * @param onLoad defines an optional callback raised when the texture is loaded
          * @param onLoad defines an optional callback raised when the texture is loaded
          * @param onError defines an optional callback raised if there is an issue to load the texture
          * @param onError defines an optional callback raised if there is an issue to load the texture
          * @param format defines the format of the data
          * @param format defines the format of the data
@@ -5352,7 +5397,7 @@
          * @param createPolynomials defines wheter or not to create polynomails harmonics for the texture
          * @param createPolynomials defines wheter or not to create polynomails harmonics for the texture
          * @returns the cube texture as an InternalTexture
          * @returns the cube texture as an InternalTexture
          */
          */
-        public createPrefilteredCubeTexture(rootUrl: string, scene: Nullable<Scene>, scale: number, offset: number,
+        public createPrefilteredCubeTexture(rootUrl: string, scene: Nullable<Scene>, lodScale: number, lodOffset: number,
             onLoad: Nullable<(internalTexture: Nullable<InternalTexture>) => void> = null,
             onLoad: Nullable<(internalTexture: Nullable<InternalTexture>) => void> = null,
             onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null,
             onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null,
             createPolynomials: boolean = true): InternalTexture {
             createPolynomials: boolean = true): InternalTexture {
@@ -5372,8 +5417,6 @@
                     texture._sphericalPolynomial = loadData.info.sphericalPolynomial;
                     texture._sphericalPolynomial = loadData.info.sphericalPolynomial;
                 }
                 }
                 texture._dataSource = InternalTexture.DATASOURCE_CUBEPREFILTERED;
                 texture._dataSource = InternalTexture.DATASOURCE_CUBEPREFILTERED;
-                texture._lodGenerationScale = scale;
-                texture._lodGenerationOffset = offset;
 
 
                 if (this._caps.textureLOD) {
                 if (this._caps.textureLOD) {
                     // Do not add extra process if texture lod is supported.
                     // Do not add extra process if texture lod is supported.
@@ -5397,8 +5440,8 @@
                     let smoothness = i / (mipSlices - 1);
                     let smoothness = i / (mipSlices - 1);
                     let roughness = 1 - smoothness;
                     let roughness = 1 - smoothness;
 
 
-                    let minLODIndex = offset; // roughness = 0
-                    let maxLODIndex = Scalar.Log2(width) * scale + offset; // roughness = 1
+                    let minLODIndex = lodOffset; // roughness = 0
+                    let maxLODIndex = Scalar.Log2(width) * lodScale + lodOffset; // roughness = 1
 
 
                     let lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
                     let lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
                     let mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
                     let mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
@@ -5443,7 +5486,7 @@
                 }
                 }
             };
             };
 
 
-            return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension, createPolynomials);
+            return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension, createPolynomials, lodScale, lodOffset);
         }
         }
 
 
         /**
         /**
@@ -5457,15 +5500,19 @@
          * @param format defines the format of the data
          * @param format defines the format of the data
          * @param forcedExtension defines the extension to use to pick the right loader
          * @param forcedExtension defines the extension to use to pick the right loader
          * @param createPolynomials if a polynomial sphere should be created for the cube texture
          * @param createPolynomials if a polynomial sphere should be created for the cube texture
+         * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
+         * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          * @returns the cube texture as an InternalTexture
          * @returns the cube texture as an InternalTexture
          */
          */
-        public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials = false): InternalTexture {
+        public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials = false, lodScale: number = 0, lodOffset: number = 0): InternalTexture {
             var gl = this._gl;
             var gl = this._gl;
 
 
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
             texture.isCube = true;
             texture.isCube = true;
             texture.url = rootUrl;
             texture.url = rootUrl;
             texture.generateMipMaps = !noMipmap;
             texture.generateMipMaps = !noMipmap;
+            texture._lodGenerationScale = lodScale;
+            texture._lodGenerationOffset = lodOffset;
 
 
             if (!this._doNotHandleContextLost) {
             if (!this._doNotHandleContextLost) {
                 texture._extension = forcedExtension;
                 texture._extension = forcedExtension;
@@ -5474,6 +5521,7 @@
 
 
             var isKTX = false;
             var isKTX = false;
             var isDDS = false;
             var isDDS = false;
+            var isEnv = false;
             var lastDot = rootUrl.lastIndexOf('.');
             var lastDot = rootUrl.lastIndexOf('.');
             var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
             var extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
             if (this._textureFormatInUse) {
             if (this._textureFormatInUse) {
@@ -5482,6 +5530,7 @@
                 isKTX = true;
                 isKTX = true;
             } else {
             } else {
                 isDDS = (extension === ".dds");
                 isDDS = (extension === ".dds");
+                isEnv = (extension === ".env");
             }
             }
 
 
             let onerror = (request?: XMLHttpRequest, exception?: any) => {
             let onerror = (request?: XMLHttpRequest, exception?: any) => {
@@ -5507,7 +5556,29 @@
                     texture.height = ktx.pixelHeight;
                     texture.height = ktx.pixelHeight;
                     texture.isReady = true;
                     texture.isReady = true;
                 }, undefined, undefined, true, onerror);
                 }, undefined, undefined, true, onerror);
-            } else if (isDDS) {
+            }
+            else if (isEnv) {
+                this._loadFile(rootUrl, (data) => {
+                    data = data as ArrayBuffer;
+                    var info = EnvironmentTextureTools.GetEnvInfo(data);
+                    if (info) {
+                        texture.width = info.width;
+                        texture.height = info.width;
+
+                        EnvironmentTextureTools.UploadPolynomials(texture, data, info!);
+                        EnvironmentTextureTools.UploadLevelsAsync(texture, data, info!).then(() => {
+                            texture.isReady = true;
+                            if (onLoad) {
+                                onLoad();
+                            }
+                        });
+                    }
+                    else if (onError) {
+                        onError("Can not parse the environment file", null);
+                    }
+                }, undefined, undefined, true, onerror);
+            }
+            else if (isDDS) {
                 if (files && files.length === 6) {
                 if (files && files.length === 6) {
                     this._cascadeLoadFiles(
                     this._cascadeLoadFiles(
                         scene,
                         scene,
@@ -6939,7 +7010,7 @@
         }
         }
 
 
         /** @hidden */
         /** @hidden */
-        public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1): ArrayBufferView {
+        public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0): ArrayBufferView {
             let gl = this._gl;
             let gl = this._gl;
             if (!this._dummyFramebuffer) {
             if (!this._dummyFramebuffer) {
                 let dummy = gl.createFramebuffer();
                 let dummy = gl.createFramebuffer();
@@ -6953,9 +7024,9 @@
             gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
             gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
 
 
             if (faceIndex > -1) {
             if (faceIndex > -1) {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, 0);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, level);
             } else {
             } else {
-                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, 0);
+                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, level);
             }
             }
 
 
             let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
             let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;

+ 12 - 5
src/Gamepad/Controllers/babylon.windowsMotionController.ts

@@ -189,17 +189,21 @@ module BABYLON {
             return this.onTrackpadValuesChangedObservable;
             return this.onTrackpadValuesChangedObservable;
         }
         }
 
 
+        private _updateTrackpad(){
+            if (this.browserGamepad.axes && (this.browserGamepad.axes[2] != this.trackpad.x || this.browserGamepad.axes[3] != this.trackpad.y)) {
+                this.trackpad.x = this.browserGamepad["axes"][2];
+                this.trackpad.y = this.browserGamepad["axes"][3];
+                this.onTrackpadValuesChangedObservable.notifyObservers(this.trackpad);
+            }
+        }
+
         /**
         /**
          * Called once per frame by the engine.
          * Called once per frame by the engine.
          */
          */
         public update() {
         public update() {
             super.update();
             super.update();
             if (this.browserGamepad.axes) {
             if (this.browserGamepad.axes) {
-                if (this.browserGamepad.axes[2] != this.trackpad.x || this.browserGamepad.axes[3] != this.trackpad.y) {
-                    this.trackpad.x = this.browserGamepad["axes"][2];
-                    this.trackpad.y = this.browserGamepad["axes"][3];
-                    this.onTrackpadValuesChangedObservable.notifyObservers(this.trackpad);
-                }
+                this._updateTrackpad();
                 // Only need to animate axes if there is a loaded mesh
                 // Only need to animate axes if there is a loaded mesh
                 if (this._loadedMeshInfo) {
                 if (this._loadedMeshInfo) {
                     for (let axis = 0; axis < this._mapping.axisMeshNames.length; axis++) {
                     for (let axis = 0; axis < this._mapping.axisMeshNames.length; axis++) {
@@ -221,6 +225,9 @@ module BABYLON {
                 return;
                 return;
             }
             }
 
 
+            // Update the trackpad to ensure trackpad.x/y are accurate during button events between frames
+            this._updateTrackpad();
+
             // Only emit events for buttons that we know how to map from index to name
             // Only emit events for buttons that we know how to map from index to name
             let observable = (<any>this)[(<any>(this._mapping.buttonObservableNames))[buttonName]];
             let observable = (<any>this)[(<any>(this._mapping.buttonObservableNames))[buttonName]];
             if (observable) {
             if (observable) {

+ 1 - 1
src/Helpers/babylon.environmentHelper.ts

@@ -186,7 +186,7 @@ module BABYLON {
         /**
         /**
          * Default environment texture URL.
          * Default environment texture URL.
          */
          */
-        private static _environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.dds";
+        private static _environmentTextureCDNUrl = "https://assets.babylonjs.com/environments/environmentSpecular.env";
 
 
         /**
         /**
          * Creates the default options for the helper.
          * Creates the default options for the helper.

+ 30 - 19
src/Helpers/babylon.particleHelper.ts

@@ -113,10 +113,6 @@ module BABYLON {
          */
          */
         private static _baseAssetsUrl = "https://assets.babylonjs.com/particles";
         private static _baseAssetsUrl = "https://assets.babylonjs.com/particles";
 
 
-        private static _scene: Scene;
-
-        private static _emitter: AbstractMesh;
-
         /**
         /**
          * This is the main static method (one-liner) of this helper to create different particle systems.
          * This is the main static method (one-liner) of this helper to create different particle systems.
          * @param type This string represents the type to the particle system to create
          * @param type This string represents the type to the particle system to create
@@ -129,21 +125,17 @@ module BABYLON {
                                    scene: Nullable<Scene> = Engine.LastCreatedScene, gpu: boolean = false): Promise<ParticleSystem> {
                                    scene: Nullable<Scene> = Engine.LastCreatedScene, gpu: boolean = false): Promise<ParticleSystem> {
             
             
             return new Promise((resolve, reject) => {
             return new Promise((resolve, reject) => {
-                if (scene) {
-                    this._scene = scene;
-                } else {
-                    return reject("A particle system need a scene.");
+                if (!scene) {
+                    scene = Engine.LastCreatedScene;;
                 }
                 }
 
 
                 if (gpu && !GPUParticleSystem.IsSupported) {
                 if (gpu && !GPUParticleSystem.IsSupported) {
                     return reject("Particle system with GPU is not supported.");
                     return reject("Particle system with GPU is not supported.");
                 }
                 }
 
 
-                this._emitter = emitter;
-
-                Tools.LoadFile(`${this._baseAssetsUrl}/systems/${type}.json`, (data, response) => {
+                Tools.LoadFile(`${ParticleHelper._baseAssetsUrl}/systems/${type}.json`, (data, response) => {
                     const newData = JSON.parse(data.toString()) as IParticleSystemData;
                     const newData = JSON.parse(data.toString()) as IParticleSystemData;
-                    return resolve(this._createSystem(newData));
+                    return resolve(ParticleHelper.CreateSystem(newData, scene!, emitter));
                 }, undefined, undefined, undefined, (req, exception) => {
                 }, undefined, undefined, undefined, (req, exception) => {
                     return reject(`An error occured while the creation of your particle system. Check if your type '${type}' exists.`);
                     return reject(`An error occured while the creation of your particle system. Check if your type '${type}' exists.`);
                 });
                 });
@@ -151,13 +143,34 @@ module BABYLON {
             });
             });
         }
         }
 
 
-        private static _createSystem(data: IParticleSystemData): ParticleSystem {
+        /**
+         * Static function used to create a new particle system from a IParticleSystemData
+         * @param data defines the source data
+         * @param scene defines the hosting scene
+         * @param emitter defines the particle emitter
+         * @returns a new ParticleSystem based on referenced data
+         */
+        public static CreateSystem(data: IParticleSystemData, scene: Scene, emitter: AbstractMesh): ParticleSystem {
             // Create a particle system
             // Create a particle system
-            const system = new ParticleSystem(data.type, data.capacity, this._scene);
-            // Texture of each particle
-            system.particleTexture = new Texture(`${this._baseAssetsUrl}/textures/${data.textureFile}`, this._scene);
+            const system = new ParticleSystem(data.type, data.capacity, scene);
+
             // Where the particles come from
             // Where the particles come from
-            system.emitter = this._emitter; // the starting object, the emitter
+            system.emitter = emitter; // the starting object, the emitter            
+
+            ParticleHelper.UpdateSystem(system, data, scene);
+
+            return system;
+        }
+
+        /**
+         * Static function used to update a particle system from a IParticleSystemData
+         * @param system defines the particle system to update
+         * @param data defines the source data
+         * @param scene defines the hosting scene
+         */
+        public static UpdateSystem(system: ParticleSystem, data: IParticleSystemData, scene: Scene): void {
+            // Texture of each particle
+            system.particleTexture = new Texture(`${ParticleHelper._baseAssetsUrl}/textures/${data.textureFile}`, scene);
 
 
             // Colors of all particles
             // Colors of all particles
             system.color1 = new Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
             system.color1 = new Color4(data.color1.r, data.color1.g, data.color1.b, data.color1.a);
@@ -229,8 +242,6 @@ module BABYLON {
                 default:
                 default:
                     break;
                     break;
             }
             }
-
-            return system;
         }
         }
     }
     }
 
 

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

@@ -106,6 +106,7 @@
         public REFLECTIONMAP_OPPOSITEZ = false;
         public REFLECTIONMAP_OPPOSITEZ = false;
         public LODINREFLECTIONALPHA = false;
         public LODINREFLECTIONALPHA = false;
         public GAMMAREFLECTION = false;
         public GAMMAREFLECTION = false;
+        public RGBDREFLECTION = false;
         public EQUIRECTANGULAR_RELFECTION_FOV = false;
         public EQUIRECTANGULAR_RELFECTION_FOV = false;
 
 
         // Default BJS.
         // Default BJS.
@@ -655,6 +656,7 @@
 
 
                         defines.REFLECTION = true;
                         defines.REFLECTION = true;
                         defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
                         defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
+                        defines.RGBDREFLECTION = reflectionTexture.isRGBD;
                         defines.REFLECTIONBLUR = this._reflectionBlur > 0;
                         defines.REFLECTIONBLUR = this._reflectionBlur > 0;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
@@ -730,6 +732,7 @@
                         defines.REFLECTIONMAP_OPPOSITEZ = false;
                         defines.REFLECTIONMAP_OPPOSITEZ = false;
                         defines.LODINREFLECTIONALPHA = false;
                         defines.LODINREFLECTIONALPHA = false;
                         defines.GAMMAREFLECTION = false;
                         defines.GAMMAREFLECTION = false;
+                        defines.RGBDREFLECTION = false;
                     }
                     }
                 }
                 }
 
 

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

@@ -86,6 +86,7 @@
         public REFLECTIONMAP_OPPOSITEZ = false;
         public REFLECTIONMAP_OPPOSITEZ = false;
         public LODINREFLECTIONALPHA = false;
         public LODINREFLECTIONALPHA = false;
         public GAMMAREFLECTION = false;
         public GAMMAREFLECTION = false;
+        public RGBDREFLECTION = false;
         public RADIANCEOCCLUSION = false;
         public RADIANCEOCCLUSION = false;
         public HORIZONOCCLUSION = false;
         public HORIZONOCCLUSION = false;
 
 
@@ -94,6 +95,7 @@
         public REFRACTIONMAP_OPPOSITEZ = false;
         public REFRACTIONMAP_OPPOSITEZ = false;
         public LODINREFRACTIONALPHA = false;
         public LODINREFRACTIONALPHA = false;
         public GAMMAREFRACTION = false;
         public GAMMAREFRACTION = false;
+        public RGBDREFRACTION = false;
         public LINKREFRACTIONTOTRANSPARENCY = false;
         public LINKREFRACTIONTOTRANSPARENCY = false;
 
 
         public INSTANCES = false;
         public INSTANCES = false;
@@ -1047,6 +1049,7 @@
                     if (reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                     if (reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                         defines.REFLECTION = true;
                         defines.REFLECTION = true;
                         defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
                         defines.GAMMAREFLECTION = reflectionTexture.gammaSpace;
+                        defines.RGBDREFLECTION = reflectionTexture.isRGBD;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.REFLECTIONMAP_OPPOSITEZ = this.getScene().useRightHandedSystem ? !reflectionTexture.invertZ : reflectionTexture.invertZ;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
                         defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
 
 
@@ -1119,6 +1122,7 @@
                         defines.REFLECTIONMAP_OPPOSITEZ = false;
                         defines.REFLECTIONMAP_OPPOSITEZ = false;
                         defines.LODINREFLECTIONALPHA = false;
                         defines.LODINREFLECTIONALPHA = false;
                         defines.GAMMAREFLECTION = false;
                         defines.GAMMAREFLECTION = false;
+                        defines.RGBDREFLECTION = false;
                     }
                     }
 
 
                     if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
                     if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
@@ -1182,6 +1186,7 @@
                         defines.REFRACTION = true;
                         defines.REFRACTION = true;
                         defines.REFRACTIONMAP_3D = refractionTexture.isCube;
                         defines.REFRACTIONMAP_3D = refractionTexture.isCube;
                         defines.GAMMAREFRACTION = refractionTexture.gammaSpace;
                         defines.GAMMAREFRACTION = refractionTexture.gammaSpace;
+                        defines.RGBDREFRACTION = refractionTexture.isRGBD;
                         defines.REFRACTIONMAP_OPPOSITEZ = refractionTexture.invertZ;
                         defines.REFRACTIONMAP_OPPOSITEZ = refractionTexture.invertZ;
                         defines.LODINREFRACTIONALPHA = refractionTexture.lodLevelInAlpha;
                         defines.LODINREFRACTIONALPHA = refractionTexture.lodLevelInAlpha;
 
 

+ 44 - 5
src/Materials/Textures/babylon.baseTexture.ts

@@ -103,6 +103,13 @@
         @serialize()
         @serialize()
         public gammaSpace = true;
         public gammaSpace = true;
 
 
+        /**
+         * Gets whether or not the texture contains RGBD data.
+         */
+        public get isRGBD(): boolean {
+            return this._texture != null && this._texture._isRGBD;
+        }
+
         @serialize()
         @serialize()
         public invertZ = false;
         public invertZ = false;
 
 
@@ -110,10 +117,24 @@
         public lodLevelInAlpha = false;
         public lodLevelInAlpha = false;
 
 
         @serialize()
         @serialize()
-        public lodGenerationOffset = 0.0;
+        public get lodGenerationOffset(): number {
+            if (this._texture) return this._texture._lodGenerationOffset;
+
+            return 0.0;
+        }
+        public set lodGenerationOffset(value: number) {
+            if (this._texture) this._texture._lodGenerationOffset = value;
+        }
 
 
         @serialize()
         @serialize()
-        public lodGenerationScale = 0.8;
+        public get lodGenerationScale(): number {
+            if (this._texture) return this._texture._lodGenerationScale;
+
+            return 0.0;
+        }
+        public set lodGenerationScale(value: number) {
+            if (this._texture) this._texture._lodGenerationScale = value;
+        }
 
 
         @serialize()
         @serialize()
         public isRenderTarget = false;
         public isRenderTarget = false;
@@ -276,12 +297,22 @@
             return (this._texture.format !== undefined) ? this._texture.format : Engine.TEXTUREFORMAT_RGBA;
             return (this._texture.format !== undefined) ? this._texture.format : Engine.TEXTUREFORMAT_RGBA;
         }
         }
 
 
-        public readPixels(faceIndex = 0): Nullable<ArrayBufferView> {
+        /**
+         * Reads the pixels stored in the webgl texture and returns them as an ArrayBuffer.
+         * This will returns an RGBA array buffer containing either in values (0-255) or
+         * float values (0-1) depending of the underlying buffer type.
+         * @param faceIndex The face of the texture to read (in case of cube texture)
+         * @param level The LOD level of the texture to read (in case of Mip Maps)
+         * @returns The Array buffer containing the pixels data.
+         */
+        public readPixels(faceIndex = 0, level = 0): Nullable<ArrayBufferView> {
             if (!this._texture) {
             if (!this._texture) {
                 return null;
                 return null;
             }
             }
 
 
             var size = this.getSize();
             var size = this.getSize();
+            var width = size.width;
+            var height = size.height;
             let scene = this.getScene();
             let scene = this.getScene();
 
 
             if (!scene) {
             if (!scene) {
@@ -290,11 +321,19 @@
 
 
             var engine = scene.getEngine();
             var engine = scene.getEngine();
 
 
+            if (level != 0) {
+                width = width / Math.pow(2, level);
+                height = height / Math.pow(2, level);
+
+                width = Math.round(width);
+                height = Math.round(height);
+            }
+
             if (this._texture.isCube) {
             if (this._texture.isCube) {
-                return engine._readTexturePixels(this._texture, size.width, size.height, faceIndex);
+                return engine._readTexturePixels(this._texture, width, height, faceIndex, level);
             }
             }
 
 
-            return engine._readTexturePixels(this._texture, size.width, size.height, -1);
+            return engine._readTexturePixels(this._texture, width, height, -1, level);
         }
         }
 
 
         public releaseInternalTexture(): void {
         public releaseInternalTexture(): void {

+ 25 - 11
src/Materials/Textures/babylon.cubeTexture.ts

@@ -53,9 +53,11 @@
         private _extensions: string[];
         private _extensions: string[];
         private _textureMatrix: Matrix;
         private _textureMatrix: Matrix;
         private _format: number;
         private _format: number;
-        private _prefiltered: boolean;
         private _createPolynomials: boolean;
         private _createPolynomials: boolean;
 
 
+        /** @hidden */
+        public readonly _prefiltered: boolean = false;
+
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
             let rootUrlKey = "";
             let rootUrlKey = "";
 
 
@@ -90,11 +92,14 @@
          * @param prefiltered defines whether or not the texture is created from prefiltered data
          * @param prefiltered defines whether or not the texture is created from prefiltered data
          * @param forcedExtension defines the extensions to use (force a special type of file to load) in case it is different from the file name
          * @param forcedExtension defines the extensions to use (force a special type of file to load) in case it is different from the file name
          * @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
          * @param createPolynomials defines whether or not to create polynomial harmonics from the texture data if necessary
+         * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
+         * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          * @return the cube texture
          * @return the cube texture
          */
          */
         constructor(rootUrl: string, scene: Scene, extensions: Nullable<string[]> = null, noMipmap: boolean = false, files: Nullable<string[]> = null,
         constructor(rootUrl: string, scene: Scene, extensions: Nullable<string[]> = null, noMipmap: boolean = false, files: Nullable<string[]> = null,
             onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false, 
             onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false, 
-            forcedExtension: any = null, createPolynomials: boolean = false) {
+            forcedExtension: any = null, createPolynomials: boolean = false,
+            lodScale: number = 0.8, lodOffset: number = 0) {
             super(scene);
             super(scene);
 
 
             this.name = rootUrl;
             this.name = rootUrl;
@@ -102,26 +107,35 @@
             this._noMipmap = noMipmap;
             this._noMipmap = noMipmap;
             this.hasAlpha = false;
             this.hasAlpha = false;
             this._format = format;
             this._format = format;
-            this._prefiltered = prefiltered;
             this.isCube = true;
             this.isCube = true;
             this._textureMatrix = Matrix.Identity();
             this._textureMatrix = Matrix.Identity();
             this._createPolynomials = createPolynomials;
             this._createPolynomials = createPolynomials;
-            if (prefiltered) {
-                this.gammaSpace = false;
-            }
 
 
             if (!rootUrl && !files) {
             if (!rootUrl && !files) {
                 return;
                 return;
             }
             }
 
 
-            this._texture = this._getFromCache(rootUrl, noMipmap);
-
             const lastDot = rootUrl.lastIndexOf(".");
             const lastDot = rootUrl.lastIndexOf(".");
             const extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
             const extension = forcedExtension ? forcedExtension : (lastDot > -1 ? rootUrl.substring(lastDot).toLowerCase() : "");
             const isDDS = (extension === ".dds");
             const isDDS = (extension === ".dds");
+            const isEnv = (extension === ".env");
+
+            if (isEnv) {
+                this.gammaSpace = false;
+                this._prefiltered = false;
+            }
+            else {
+                this._prefiltered = prefiltered;
+                
+                if (prefiltered) {
+                    this.gammaSpace = false;
+                }
+            }
+
+            this._texture = this._getFromCache(rootUrl, noMipmap);
 
 
             if (!files) {
             if (!files) {
-                if (!isDDS && !extensions) {
+                if (!isEnv && !isDDS && !extensions) {
                     extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
                     extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
                 }
                 }
 
 
@@ -140,10 +154,10 @@
             if (!this._texture) {
             if (!this._texture) {
                 if (!scene.useDelayedTextureLoading) {
                 if (!scene.useDelayedTextureLoading) {
                     if (prefiltered) {
                     if (prefiltered) {
-                        this._texture = scene.getEngine().createPrefilteredCubeTexture(rootUrl, scene, this.lodGenerationScale, this.lodGenerationOffset, onLoad, onError, format, forcedExtension, this._createPolynomials);
+                        this._texture = scene.getEngine().createPrefilteredCubeTexture(rootUrl, scene, lodScale, lodOffset, onLoad, onError, format, forcedExtension, this._createPolynomials);
                     }
                     }
                     else {
                     else {
-                        this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format, forcedExtension);
+                        this._texture = scene.getEngine().createCubeTexture(rootUrl, scene, files, noMipmap, onLoad, onError, this._format, forcedExtension, false, lodScale, lodOffset);
                     }
                     }
                 } else {
                 } else {
                     this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;
                     this.delayLoadState = Engine.DELAYLOADSTATE_NOTLOADED;

+ 4 - 0
src/Materials/Textures/babylon.hdrCubeTexture.ts

@@ -137,6 +137,10 @@ module BABYLON {
          */
          */
         private loadTexture() {
         private loadTexture() {
             var callback = (buffer: ArrayBuffer): Nullable<ArrayBufferView[]> => {
             var callback = (buffer: ArrayBuffer): Nullable<ArrayBufferView[]> => {
+
+                this.lodGenerationOffset = 0.0;
+                this.lodGenerationScale = 0.8;
+
                 let scene = this.getScene();
                 let scene = this.getScene();
 
 
                 if (!scene) {
                 if (!scene) {

+ 12 - 1
src/Materials/Textures/babylon.internalTexture.ts

@@ -201,14 +201,25 @@ module BABYLON {
         public _lodTextureMid: BaseTexture;
         public _lodTextureMid: BaseTexture;
         /** @hidden */
         /** @hidden */
         public _lodTextureLow: BaseTexture;
         public _lodTextureLow: BaseTexture;
+        /** @hidden */
+        public _isRGBD: boolean = false;
 
 
         /** @hidden */
         /** @hidden */
         public _webGLTexture: Nullable<WebGLTexture>;
         public _webGLTexture: Nullable<WebGLTexture>;
         /** @hidden */
         /** @hidden */
         public _references: number = 1;
         public _references: number = 1;
+
         private _engine: Engine;
         private _engine: Engine;
 
 
         /**
         /**
+         * Gets the Engine the texture belongs to.
+         * @returns The babylon engine
+         */
+        public getEngine(): Engine {
+            return this._engine;
+        }
+
+        /**
          * Gets the data source type of the texture (can be one of the BABYLON.InternalTexture.DATASOURCE_XXXX)
          * Gets the data source type of the texture (can be one of the BABYLON.InternalTexture.DATASOURCE_XXXX)
          */
          */
         public get dataSource(): number {
         public get dataSource(): number {
@@ -358,7 +369,7 @@ module BABYLON {
             }
             }
         }
         }
 
 
-        private _swapAndDie(target: InternalTexture): void {
+        public _swapAndDie(target: InternalTexture): void {
             target._webGLTexture = this._webGLTexture;
             target._webGLTexture = this._webGLTexture;
 
 
             if (this._framebuffer) {
             if (this._framebuffer) {

+ 1 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -811,7 +811,7 @@
          * @param camera defines the camera to use to pick the right LOD level
          * @param camera defines the camera to use to pick the right LOD level
          * @returns the currentAbstractMesh 
          * @returns the currentAbstractMesh 
          */
          */
-        public getLOD(camera: Camera): AbstractMesh {
+        public getLOD(camera: Camera): Nullable<AbstractMesh> {
             return this;
             return this;
         }
         }
 
 

+ 9 - 8
src/Mesh/babylon.mesh.ts

@@ -98,7 +98,7 @@
         public delayLoadingFile: string;
         public delayLoadingFile: string;
         public _binaryInfo: any;
         public _binaryInfo: any;
         private _LODLevels = new Array<MeshLODLevel>();
         private _LODLevels = new Array<MeshLODLevel>();
-        public onLODLevelSelection: (distance: number, mesh: Mesh, selectedLevel: Mesh) => void;
+        public onLODLevelSelection: (distance: number, mesh: Mesh, selectedLevel: Nullable<Mesh>) => void;
 
 
         // Morph
         // Morph
         private _morphTargetManager: Nullable<MorphTargetManager>;
         private _morphTargetManager: Nullable<MorphTargetManager>;
@@ -331,11 +331,11 @@
         /**
         /**
          * Add a mesh as LOD level triggered at the given distance.
          * Add a mesh as LOD level triggered at the given distance.
          * tuto : http://doc.babylonjs.com/tutorials/How_to_use_LOD
          * tuto : http://doc.babylonjs.com/tutorials/How_to_use_LOD
-         * @param {number} distance The distance from the center of the object to show this level
-         * @param {Mesh} mesh The mesh to be added as LOD level
-         * @return {Mesh} This mesh (for chaining)
+         * @param distance The distance from the center of the object to show this level
+         * @param mesh The mesh to be added as LOD level (can be null)
+         * @return This mesh (for chaining)
          */
          */
-        public addLODLevel(distance: number, mesh: Mesh): Mesh {
+        public addLODLevel(distance: number, mesh: Nullable<Mesh>): Mesh {
             if (mesh && mesh._masterMesh) {
             if (mesh && mesh._masterMesh) {
                 Tools.Warn("You cannot use a mesh as LOD level twice");
                 Tools.Warn("You cannot use a mesh as LOD level twice");
                 return this;
                 return this;
@@ -392,9 +392,9 @@
 
 
         /**
         /**
          * Returns the registered LOD mesh distant from the parameter `camera` position if any, else returns the current mesh.
          * Returns the registered LOD mesh distant from the parameter `camera` position if any, else returns the current mesh.
-         * tuto : http://doc.babylonjs.com/tutorials/How_to_use_LOD
+         * tuto : http://doc.babylonjs.com/how_to/how_to_use_lod
          */
          */
-        public getLOD(camera: Camera, boundingSphere?: BoundingSphere): AbstractMesh {
+        public getLOD(camera: Camera, boundingSphere?: BoundingSphere): Nullable<AbstractMesh> {
             if (!this._LODLevels || this._LODLevels.length === 0) {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
                 return this;
             }
             }
@@ -430,7 +430,8 @@
                     if (this.onLODLevelSelection) {
                     if (this.onLODLevelSelection) {
                         this.onLODLevelSelection(distanceToCamera, this, level.mesh);
                         this.onLODLevelSelection(distanceToCamera, this, level.mesh);
                     }
                     }
-                    return level.mesh;
+
+                    return level.mesh;                   
                 }
                 }
             }
             }
 
 

+ 1 - 1
src/Mesh/babylon.meshLODLevel.ts

@@ -1,6 +1,6 @@
 module BABYLON {
 module BABYLON {
     export class MeshLODLevel {
     export class MeshLODLevel {
-        constructor(public distance: number, public mesh: Mesh) {
+        constructor(public distance: number, public mesh: Nullable<Mesh>) {
         }
         }
     }
     }
 } 
 } 

+ 4 - 2
src/PostProcess/babylon.postProcessManager.ts

@@ -88,8 +88,10 @@
          * @param postProcesses An array of post processes to be run.
          * @param postProcesses An array of post processes to be run.
          * @param targetTexture The target texture to render to.
          * @param targetTexture The target texture to render to.
          * @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight
          * @param forceFullscreenViewport force gl.viewport to be full screen eg. 0,0,textureWidth,textureHeight
+         * @param faceIndex defines the face to render to if a cubemap is defined as the target
+         * @param lodLevel defines which lod of the texture to render to
          */
          */
-        public directRender(postProcesses: PostProcess[], targetTexture: Nullable<InternalTexture> = null, forceFullscreenViewport = false): void {
+        public directRender(postProcesses: PostProcess[], targetTexture: Nullable<InternalTexture> = null, forceFullscreenViewport = false, faceIndex = 0, lodLevel = 0): void {
             var engine = this._scene.getEngine();
             var engine = this._scene.getEngine();
 
 
             for (var index = 0; index < postProcesses.length; index++) {
             for (var index = 0; index < postProcesses.length; index++) {
@@ -97,7 +99,7 @@
                     postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
                     postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
                 } else {
                 } else {
                     if (targetTexture) {
                     if (targetTexture) {
-                        engine.bindFramebuffer(targetTexture, 0, undefined, undefined, forceFullscreenViewport);
+                        engine.bindFramebuffer(targetTexture, faceIndex, undefined, undefined, forceFullscreenViewport, undefined, lodLevel);
                     } else {
                     } else {
                         engine.restoreDefaultFramebuffer();
                         engine.restoreDefaultFramebuffer();
                     }
                     }

+ 2 - 0
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -141,6 +141,8 @@ module BABYLON {
          * Disposes of the renderer
          * Disposes of the renderer
          */
          */
         public dispose(){
         public dispose(){
+            this.onPointerOutObservable.clear();
+
             if(this._afterRenderObserver){
             if(this._afterRenderObserver){
                 this.originalScene.onAfterRenderObservable.remove(this._afterRenderObserver);
                 this.originalScene.onAfterRenderObservable.remove(this._afterRenderObserver);
             }
             }

+ 51 - 26
src/Shaders/ShadersInclude/helperFunctions.fx

@@ -5,49 +5,49 @@ const float GammaEncodePowerApprox = 1.0 / LinearEncodePowerApprox;
 const vec3 LuminanceEncodeApprox = vec3(0.2126, 0.7152, 0.0722);
 const vec3 LuminanceEncodeApprox = vec3(0.2126, 0.7152, 0.0722);
 
 
 mat3 transposeMat3(mat3 inMatrix) {
 mat3 transposeMat3(mat3 inMatrix) {
-	vec3 i0 = inMatrix[0];
-	vec3 i1 = inMatrix[1];
-	vec3 i2 = inMatrix[2];
+    vec3 i0 = inMatrix[0];
+    vec3 i1 = inMatrix[1];
+    vec3 i2 = inMatrix[2];
 
 
-	mat3 outMatrix = mat3(
-		vec3(i0.x, i1.x, i2.x),
-		vec3(i0.y, i1.y, i2.y),
-		vec3(i0.z, i1.z, i2.z)
-		);
+    mat3 outMatrix = mat3(
+        vec3(i0.x, i1.x, i2.x),
+        vec3(i0.y, i1.y, i2.y),
+        vec3(i0.z, i1.z, i2.z)
+        );
 
 
-	return outMatrix;
+    return outMatrix;
 }
 }
 
 
 // https://github.com/glslify/glsl-inverse/blob/master/index.glsl
 // https://github.com/glslify/glsl-inverse/blob/master/index.glsl
 mat3 inverseMat3(mat3 inMatrix) {
 mat3 inverseMat3(mat3 inMatrix) {
-	float a00 = inMatrix[0][0], a01 = inMatrix[0][1], a02 = inMatrix[0][2];
-  	float a10 = inMatrix[1][0], a11 = inMatrix[1][1], a12 = inMatrix[1][2];
-  	float a20 = inMatrix[2][0], a21 = inMatrix[2][1], a22 = inMatrix[2][2];
+    float a00 = inMatrix[0][0], a01 = inMatrix[0][1], a02 = inMatrix[0][2];
+      float a10 = inMatrix[1][0], a11 = inMatrix[1][1], a12 = inMatrix[1][2];
+      float a20 = inMatrix[2][0], a21 = inMatrix[2][1], a22 = inMatrix[2][2];
 
 
-  	float b01 = a22 * a11 - a12 * a21;
-  	float b11 = -a22 * a10 + a12 * a20;
-  	float b21 = a21 * a10 - a11 * a20;
+      float b01 = a22 * a11 - a12 * a21;
+      float b11 = -a22 * a10 + a12 * a20;
+      float b21 = a21 * a10 - a11 * a20;
 
 
-  	float det = a00 * b01 + a01 * b11 + a02 * b21;
+      float det = a00 * b01 + a01 * b11 + a02 * b21;
 
 
-  	return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
+      return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
               b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
               b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
               b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
               b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
 }
 }
 
 
 float computeFallOff(float value, vec2 clipSpace, float frustumEdgeFalloff)
 float computeFallOff(float value, vec2 clipSpace, float frustumEdgeFalloff)
 {
 {
-	float mask = smoothstep(1.0 - frustumEdgeFalloff, 1.0, clamp(dot(clipSpace, clipSpace), 0., 1.));
-	return mix(value, 1.0, mask);
+    float mask = smoothstep(1.0 - frustumEdgeFalloff, 1.0, clamp(dot(clipSpace, clipSpace), 0., 1.));
+    return mix(value, 1.0, mask);
 }
 }
 
 
 vec3 applyEaseInOut(vec3 x){
 vec3 applyEaseInOut(vec3 x){
-	return x * x * (3.0 - 2.0 * x);
+    return x * x * (3.0 - 2.0 * x);
 }
 }
 
 
 vec3 toLinearSpace(vec3 color)
 vec3 toLinearSpace(vec3 color)
 {
 {
-	return pow(color, vec3(LinearEncodePowerApprox));
+    return pow(color, vec3(LinearEncodePowerApprox));
 }
 }
 
 
 vec3 toGammaSpace(vec3 color)
 vec3 toGammaSpace(vec3 color)
@@ -67,12 +67,37 @@ float getLuminance(vec3 color)
 
 
 // https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
 // https://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl
 float getRand(vec2 seed) {
 float getRand(vec2 seed) {
-	return fract(sin(dot(seed.xy ,vec2(12.9898,78.233))) * 43758.5453);
+    return fract(sin(dot(seed.xy ,vec2(12.9898,78.233))) * 43758.5453);
 }
 }
 
 
 float dither(vec2 seed, float varianceAmount) {
 float dither(vec2 seed, float varianceAmount) {
-	float rand = getRand(seed);
-	float dither = mix(-varianceAmount/255.0, varianceAmount/255.0, rand);
-	
-	return dither;
+    float rand = getRand(seed);
+    float dither = mix(-varianceAmount/255.0, varianceAmount/255.0, rand);
+    
+    return dither;
+}
+
+// Check if configurable value is needed.
+const float rgbdMaxRange = 255.0;
+
+vec4 toRGBD(vec3 color) {
+    float maxRGB = max(0.0000001, max(color.r, max(color.g, color.b)));
+    float D      = max(rgbdMaxRange / maxRGB, 1.);
+    D            = clamp(floor(D) / 255.0, 0., 1.);
+    // vec3 rgb = color.rgb * (D * (255.0 / rgbdMaxRange));
+    vec3 rgb = color.rgb * D;
+    
+    // Helps with png quantization.
+    rgb = toGammaSpace(rgb);
+
+    return vec4(rgb, D); 
+}
+
+vec3 fromRGBD(vec4 rgbd) {
+    // Helps with png quantization.
+    rgbd.rgb = toLinearSpace(rgbd.rgb);
+
+    // return rgbd.rgb * ((rgbdMaxRange / 255.0) / rgbd.a);
+
+    return rgbd.rgb / rgbd.a;
 }
 }

+ 15 - 11
src/Shaders/background.fragment.fx

@@ -137,7 +137,7 @@ void main(void) {
 #endif
 #endif
 
 
 // _____________________________ REFLECTION ______________________________________
 // _____________________________ REFLECTION ______________________________________
-vec3 reflectionColor = vec3(1., 1., 1.);
+vec4 reflectionColor = vec4(1., 1., 1., 1.);
 #ifdef REFLECTION
 #ifdef REFLECTION
     vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
     vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
     #ifdef REFLECTIONMAP_OPPOSITEZ
     #ifdef REFLECTIONMAP_OPPOSITEZ
@@ -161,41 +161,45 @@ vec3 reflectionColor = vec3(1., 1., 1.);
         #ifdef TEXTURELODSUPPORT
         #ifdef TEXTURELODSUPPORT
             // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection
             // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection
             reflectionLOD = reflectionLOD * log2(vReflectionMicrosurfaceInfos.x) * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z;
             reflectionLOD = reflectionLOD * log2(vReflectionMicrosurfaceInfos.x) * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z;
-            reflectionColor = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD).rgb;
+            reflectionColor = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD);
         #else
         #else
             float lodReflectionNormalized = clamp(reflectionLOD, 0., 1.);
             float lodReflectionNormalized = clamp(reflectionLOD, 0., 1.);
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
 
 
-            vec3 reflectionSpecularMid = sampleReflection(reflectionSampler, reflectionCoords).rgb;
+            vec4 reflectionSpecularMid = sampleReflection(reflectionSampler, reflectionCoords);
             if(lodReflectionNormalizedDoubled < 1.0){
             if(lodReflectionNormalizedDoubled < 1.0){
                 reflectionColor = mix(
                 reflectionColor = mix(
-                    sampleReflection(reflectionSamplerHigh, reflectionCoords).rgb,
+                    sampleReflection(reflectionSamplerHigh, reflectionCoords),
                     reflectionSpecularMid,
                     reflectionSpecularMid,
                     lodReflectionNormalizedDoubled
                     lodReflectionNormalizedDoubled
                 );
                 );
             } else {
             } else {
                 reflectionColor = mix(
                 reflectionColor = mix(
                     reflectionSpecularMid,
                     reflectionSpecularMid,
-                    sampleReflection(reflectionSamplerLow, reflectionCoords).rgb,
+                    sampleReflection(reflectionSamplerLow, reflectionCoords),
                     lodReflectionNormalizedDoubled - 1.0
                     lodReflectionNormalizedDoubled - 1.0
                 );
                 );
             }
             }
         #endif
         #endif
     #else
     #else
         vec4 reflectionSample = sampleReflection(reflectionSampler, reflectionCoords);
         vec4 reflectionSample = sampleReflection(reflectionSampler, reflectionCoords);
-        reflectionColor = reflectionSample.rgb;
+        reflectionColor = reflectionSample;
+    #endif
+
+    #ifdef RGBDREFLECTION
+        reflectionColor.rgb = fromRGBD(reflectionColor);
     #endif
     #endif
 
 
     #ifdef GAMMAREFLECTION
     #ifdef GAMMAREFLECTION
-        reflectionColor = toLinearSpace(reflectionColor.rgb);
+        reflectionColor.rgb = toLinearSpace(reflectionColor.rgb);
     #endif
     #endif
 
 
     #ifdef REFLECTIONBGR
     #ifdef REFLECTIONBGR
-        reflectionColor = reflectionColor.bgr;
+        reflectionColor.rgb = reflectionColor.bgr;
     #endif
     #endif
 
 
     // _____________________________ Levels _____________________________________
     // _____________________________ Levels _____________________________________
-    reflectionColor *= vReflectionInfos.x;
+    reflectionColor.rgb *= vReflectionInfos.x;
 #endif
 #endif
 
 
 // _____________________________ Diffuse Information _______________________________
 // _____________________________ Diffuse Information _______________________________
@@ -221,7 +225,7 @@ float finalAlpha = alpha;
 #ifdef REFLECTIONFRESNEL
 #ifdef REFLECTIONFRESNEL
     vec3 colorBase = diffuseColor;
     vec3 colorBase = diffuseColor;
 #else
 #else
-    vec3 colorBase = reflectionColor * diffuseColor;
+    vec3 colorBase = reflectionColor.rgb * diffuseColor;
 #endif
 #endif
     colorBase = max(colorBase, 0.0);
     colorBase = max(colorBase, 0.0);
 
 
@@ -254,7 +258,7 @@ float finalAlpha = alpha;
         reflectionAmount *= reflectionDistanceFalloff;
         reflectionAmount *= reflectionDistanceFalloff;
     #endif
     #endif
 
 
-    finalColor = mix(finalColor, reflectionColor, clamp(reflectionAmount, 0., 1.));
+    finalColor = mix(finalColor, reflectionColor.rgb, clamp(reflectionAmount, 0., 1.));
 #endif
 #endif
 
 
 #ifdef OPACITYFRESNEL
 #ifdef OPACITYFRESNEL

+ 26 - 18
src/Shaders/pbr.fragment.fx

@@ -442,7 +442,7 @@ void main(void) {
 
 
     // _____________________________ Refraction Info _______________________________________
     // _____________________________ Refraction Info _______________________________________
     #ifdef REFRACTION
     #ifdef REFRACTION
-        vec3 environmentRefraction = vec3(0., 0., 0.);
+        vec4 environmentRefraction = vec4(0., 0., 0., 0.);
 
 
         vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
         vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
         #ifdef REFRACTIONMAP_OPPOSITEZ
         #ifdef REFRACTIONMAP_OPPOSITEZ
@@ -487,38 +487,42 @@ void main(void) {
                 float requestedRefractionLOD = refractionLOD;
                 float requestedRefractionLOD = refractionLOD;
             #endif
             #endif
 
 
-            environmentRefraction = sampleRefractionLod(refractionSampler, refractionCoords, requestedRefractionLOD).rgb;
+            environmentRefraction = sampleRefractionLod(refractionSampler, refractionCoords, requestedRefractionLOD);
         #else
         #else
             float lodRefractionNormalized = clamp(refractionLOD / log2(vRefractionMicrosurfaceInfos.x), 0., 1.);
             float lodRefractionNormalized = clamp(refractionLOD / log2(vRefractionMicrosurfaceInfos.x), 0., 1.);
             float lodRefractionNormalizedDoubled = lodRefractionNormalized * 2.0;
             float lodRefractionNormalizedDoubled = lodRefractionNormalized * 2.0;
 
 
-            vec3 environmentRefractionMid = sampleRefraction(refractionSampler, refractionCoords).rgb;
+            vec4 environmentRefractionMid = sampleRefraction(refractionSampler, refractionCoords);
             if(lodRefractionNormalizedDoubled < 1.0){
             if(lodRefractionNormalizedDoubled < 1.0){
                 environmentRefraction = mix(
                 environmentRefraction = mix(
-                    sampleRefraction(refractionSamplerHigh, refractionCoords).rgb,
+                    sampleRefraction(refractionSamplerHigh, refractionCoords),
                     environmentRefractionMid,
                     environmentRefractionMid,
                     lodRefractionNormalizedDoubled
                     lodRefractionNormalizedDoubled
                 );
                 );
             }else{
             }else{
                 environmentRefraction = mix(
                 environmentRefraction = mix(
                     environmentRefractionMid,
                     environmentRefractionMid,
-                    sampleRefraction(refractionSamplerLow, refractionCoords).rgb,
+                    sampleRefraction(refractionSamplerLow, refractionCoords),
                     lodRefractionNormalizedDoubled - 1.0
                     lodRefractionNormalizedDoubled - 1.0
                 );
                 );
             }
             }
         #endif
         #endif
 
 
         #ifdef GAMMAREFRACTION
         #ifdef GAMMAREFRACTION
-            environmentRefraction = toLinearSpace(environmentRefraction.rgb);
+            environmentRefraction.rgb = fromRGBD(environmentRefraction);
+        #endif
+
+        #ifdef RGBDREFRACTION
+            environmentRefraction.rgb = toLinearSpace(environmentRefraction.rgb);
         #endif
         #endif
 
 
         // _____________________________ Levels _____________________________________
         // _____________________________ Levels _____________________________________
-        environmentRefraction *= vRefractionInfos.x;
+        environmentRefraction.rgb *= vRefractionInfos.x;
     #endif
     #endif
 
 
     // _____________________________ Reflection Info _______________________________________
     // _____________________________ Reflection Info _______________________________________
     #ifdef REFLECTION
     #ifdef REFLECTION
-        vec3 environmentRadiance = vec3(0., 0., 0.);
+        vec4 environmentRadiance = vec4(0., 0., 0., 0.);
         vec3 environmentIrradiance = vec3(0., 0., 0.);
         vec3 environmentIrradiance = vec3(0., 0., 0.);
 
 
         vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
         vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
@@ -564,29 +568,33 @@ void main(void) {
                 float requestedReflectionLOD = reflectionLOD;
                 float requestedReflectionLOD = reflectionLOD;
             #endif
             #endif
 
 
-            environmentRadiance = sampleReflectionLod(reflectionSampler, reflectionCoords, requestedReflectionLOD).rgb;
+            environmentRadiance = sampleReflectionLod(reflectionSampler, reflectionCoords, requestedReflectionLOD);
         #else
         #else
             float lodReflectionNormalized = clamp(reflectionLOD / log2(vReflectionMicrosurfaceInfos.x), 0., 1.);
             float lodReflectionNormalized = clamp(reflectionLOD / log2(vReflectionMicrosurfaceInfos.x), 0., 1.);
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
 
 
-            vec3 environmentSpecularMid = sampleReflection(reflectionSampler, reflectionCoords).rgb;
+            vec4 environmentSpecularMid = sampleReflection(reflectionSampler, reflectionCoords);
             if(lodReflectionNormalizedDoubled < 1.0){
             if(lodReflectionNormalizedDoubled < 1.0){
                 environmentRadiance = mix(
                 environmentRadiance = mix(
-                    sampleReflection(reflectionSamplerHigh, reflectionCoords).rgb,
+                    sampleReflection(reflectionSamplerHigh, reflectionCoords),
                     environmentSpecularMid,
                     environmentSpecularMid,
                     lodReflectionNormalizedDoubled
                     lodReflectionNormalizedDoubled
                 );
                 );
             }else{
             }else{
                 environmentRadiance = mix(
                 environmentRadiance = mix(
                     environmentSpecularMid,
                     environmentSpecularMid,
-                    sampleReflection(reflectionSamplerLow, reflectionCoords).rgb,
+                    sampleReflection(reflectionSamplerLow, reflectionCoords),
                     lodReflectionNormalizedDoubled - 1.0
                     lodReflectionNormalizedDoubled - 1.0
                 );
                 );
             }
             }
         #endif
         #endif
 
 
+        #ifdef RGBDREFLECTION
+            environmentRadiance.rgb = fromRGBD(environmentRadiance);
+        #endif
+
         #ifdef GAMMAREFLECTION
         #ifdef GAMMAREFLECTION
-            environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+            environmentRadiance.rgb = toLinearSpace(environmentRadiance.rgb);
         #endif
         #endif
 
 
         // _____________________________ Irradiance ________________________________
         // _____________________________ Irradiance ________________________________
@@ -603,8 +611,8 @@ void main(void) {
         #endif
         #endif
 
 
         // _____________________________ Levels _____________________________________
         // _____________________________ Levels _____________________________________
-        environmentRadiance *= vReflectionInfos.x;
-        environmentRadiance *= vReflectionColor.rgb;
+        environmentRadiance.rgb *= vReflectionInfos.x;
+        environmentRadiance.rgb *= vReflectionColor.rgb;
         environmentIrradiance *= vReflectionColor.rgb;
         environmentIrradiance *= vReflectionColor.rgb;
     #endif
     #endif
 
 
@@ -691,7 +699,7 @@ void main(void) {
             environmentIrradiance *= alpha;
             environmentIrradiance *= alpha;
 
 
             // Tint reflectance
             // Tint reflectance
-            environmentRefraction *= tint;
+            environmentRefraction.rgb *= tint;
 
 
             // Put alpha back to 1;
             // Put alpha back to 1;
             alpha = 1.0;
             alpha = 1.0;
@@ -731,7 +739,7 @@ void main(void) {
 
 
     // _____________________________ Radiance ________________________________________
     // _____________________________ Radiance ________________________________________
     #ifdef REFLECTION
     #ifdef REFLECTION
-        vec3 finalRadiance = environmentRadiance;
+        vec3 finalRadiance = environmentRadiance.rgb;
         finalRadiance *= specularEnvironmentReflectance;
         finalRadiance *= specularEnvironmentReflectance;
 
 
         // Full value needed for alpha. 
         // Full value needed for alpha. 
@@ -740,7 +748,7 @@ void main(void) {
 
 
     // _____________________________ Refraction ______________________________________
     // _____________________________ Refraction ______________________________________
     #ifdef REFRACTION
     #ifdef REFRACTION
-        vec3 finalRefraction = environmentRefraction;
+        vec3 finalRefraction = environmentRefraction.rgb;
         finalRefraction *= refractance;
         finalRefraction *= refractance;
     #endif
     #endif
 
 

+ 10 - 0
src/Shaders/rgbdDecode.fragment.fx

@@ -0,0 +1,10 @@
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+#include<helperFunctions>
+
+void main(void) 
+{
+	gl_FragColor = vec4(fromRGBD(texture2D(textureSampler, vUV)), 1.0);
+}

+ 10 - 0
src/Shaders/rgbdEncode.fragment.fx

@@ -0,0 +1,10 @@
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+
+#include<helperFunctions>
+
+void main(void) 
+{
+	gl_FragColor = toRGBD(texture2D(textureSampler, vUV).rgb);
+}

+ 686 - 0
src/Tools/babylon.environmentTextureTools.ts

@@ -0,0 +1,686 @@
+module BABYLON {
+    /**
+     * Raw texture data and descriptor sufficient for WebGL texture upload
+     */
+    export interface EnvironmentTextureInfo {
+        /**
+         * Version of the environment map
+         */
+        version: number;
+
+        /**
+         * Width of image
+         */
+        width: number;
+
+        /**
+         * Irradiance information stored in the file.
+         */
+        irradiance: any;
+
+        /**
+         * Specular information stored in the file.
+         */
+        specular: any;
+    }
+
+    /**
+     * Defines One Image in the file. It requires only the position in the file 
+     * as well as the length.
+     */
+    interface BufferImageData {
+        /**
+         * Length of the image data.
+         */
+        length: number;
+        /**
+         * Position of the data from the null terminator delimiting the end of the JSON.
+         */
+        position: number;
+    }
+
+    /**
+     * Defines the specular data enclosed in the file.
+     * This corresponds to the version 1 of the data.
+     */
+    interface EnvironmentTextureSpecularInfoV1 {
+        /**
+         * Defines where the specular Payload is located. It is a runtime value only not stored in the file.
+         */
+        specularDataPosition?: number;
+        /**
+         * This contains all the images data needed to reconstruct the cubemap.
+         */
+        mipmaps: Array<BufferImageData>
+    }
+
+    /**
+     * Defines the required storage to save the environment irradiance information.
+     */
+    interface EnvironmentTextureIrradianceInfoV1 {
+        polynomials: boolean;
+
+        l00: Array<number>;
+
+        l1_1: Array<number>;
+        l10: Array<number>;
+        l11: Array<number>;
+
+        l2_2: Array<number>;
+        l2_1: Array<number>;
+        l20: Array<number>;
+        l21: Array<number>;
+        l22: Array<number>;
+
+        x: Array<number>;
+        y: Array<number>;
+        z: Array<number>;
+
+        xx: Array<number>;
+        yy: Array<number>;
+        zz: Array<number>;
+
+        yz: Array<number>;
+        zx: Array<number>;
+        xy: Array<number>;
+    }
+
+    /**
+     * Sets of helpers addressing the serialization and deserialization of environment texture
+     * stored in a BabylonJS env file.
+     * Those files are usually stored as .env files.
+     */
+    export class EnvironmentTextureTools {
+
+        /**
+         * Magic number identifying the env file.
+         */
+        private static _MagicBytes = [0x86, 0x16, 0x87, 0x96, 0xf6, 0xd6, 0x96, 0x36];
+
+        /**
+         * Gets the environment info from an env file.
+         * @param data The array buffer containing the .env bytes.
+         * @returns the environment file info (the json header) if successfully parsed.
+         */
+        public static GetEnvInfo(data: ArrayBuffer): Nullable<EnvironmentTextureInfo> {
+            let dataView = new DataView(data);
+            let pos = 0;
+
+            for (let i = 0; i < EnvironmentTextureTools._MagicBytes.length; i++) {
+                if (dataView.getUint8(pos++) !== EnvironmentTextureTools._MagicBytes[i]) {
+                    Tools.Error('Not a babylon environment map');
+                    return null;
+                }
+            }
+            
+            // Read json manifest - collect characters up to null terminator
+            let manifestString = '';
+            let charCode = 0x00;
+            while ((charCode = dataView.getUint8(pos++))) {
+                manifestString += String.fromCharCode(charCode);
+            }
+
+            let manifest: EnvironmentTextureInfo = JSON.parse(manifestString);
+            if (manifest.specular) {
+                // Extend the header with the position of the payload.
+                manifest.specular.specularDataPosition = pos;
+            }
+
+            return manifest;
+        }
+
+        /**
+         * Creates an environment texture from a loaded cube texture.
+         * @param texture defines the cube texture to convert in env file
+         * @return a promise containing the environment data if succesfull.
+         */
+        public static CreateEnvTextureAsync(texture: CubeTexture): Promise<ArrayBuffer> {
+            let internalTexture = texture.getInternalTexture();
+            if (!internalTexture) {
+                return Promise.reject("The cube texture is invalid.");
+            }
+
+            if (!texture._prefiltered) {
+                return Promise.reject("The cube texture is invalid (not prefiltered).");
+            }
+
+            let engine = internalTexture.getEngine();
+            if (engine && engine.premultipliedAlpha) {
+                return Promise.reject("Env texture can only be created when the engine is created with the premultipliedAlpha option set to false.");
+            }
+
+            let canvas = engine.getRenderingCanvas();
+            if (!canvas) {
+                return Promise.reject("Env texture can only be created when the engine is associated to a canvas.");
+            }
+
+            let textureType = Engine.TEXTURETYPE_FLOAT;
+            if (!engine.getCaps().textureFloatRender) {
+                textureType = Engine.TEXTURETYPE_HALF_FLOAT;
+                if (!engine.getCaps().textureHalfFloatRender) {
+                    return Promise.reject("Env texture can only be created when the browser supports half float or full float rendering.");
+                }
+            }
+
+            let cubeWidth = internalTexture.width;
+            let hostingScene = new Scene(engine);
+            let specularTextures: { [key: number]: ArrayBuffer } = { };
+            let promises: Promise<void>[] = [];
+
+            // Read and collect all mipmaps data from the cube.
+            let mipmapsCount = Scalar.Log2(internalTexture.width);
+            mipmapsCount = Math.round(mipmapsCount);
+            for (let i = 0; i <= mipmapsCount; i++) {
+                let faceWidth = Math.pow(2, mipmapsCount - i);
+
+                // All faces of the cube.
+                for (let face = 0; face < 6; face++) {
+                    let data = texture.readPixels(face, i);
+
+                    // Creates a temp texture with the face data.
+                    let tempTexture = engine.createRawTexture(data, faceWidth, faceWidth, Engine.TEXTUREFORMAT_RGBA, false, false, Texture.NEAREST_SAMPLINGMODE, null, textureType);
+                    // And rgbdEncode them. 
+                    let promise = new Promise<void>((resolve, reject) => {
+                        let rgbdPostProcess = new PostProcess("rgbdEncode", "rgbdEncode", null, null, 1, null, Texture.NEAREST_SAMPLINGMODE, engine, false, undefined, Engine.TEXTURETYPE_UNSIGNED_INT, undefined, null, false);
+                        rgbdPostProcess.getEffect().executeWhenCompiled(() => {
+                            rgbdPostProcess.onApply = (effect) => {
+                                effect._bindTexture("textureSampler", tempTexture);
+                            }
+            
+                            // As the process needs to happen on the main canvas, keep track of the current size
+                            let currentW = engine.getRenderWidth();
+                            let currentH = engine.getRenderHeight();
+
+                            // Set the desired size for the texture
+                            engine.setSize(faceWidth, faceWidth);
+                            hostingScene.postProcessManager.directRender([rgbdPostProcess], null);
+
+                            // Reading datas from WebGL
+                            canvas!.toBlob((blob) => {
+                                let fileReader = new FileReader();
+                                fileReader.onload = (event: any) => {
+                                    let arrayBuffer = event.target!.result as ArrayBuffer;
+                                    specularTextures[i * 6 + face] = arrayBuffer;
+                                    resolve();
+                                };
+                                fileReader.readAsArrayBuffer(blob!);
+                            });
+
+                            // Reapply the previous canvas size
+                            engine.setSize(currentW, currentH);
+                        });
+                    });
+                    promises.push(promise);
+                }
+            }
+
+            // Once all the textures haves been collected as RGBD stored in PNGs
+            return Promise.all(promises).then(() => {
+                // We can delete the hosting scene keeping track of all the creation objects
+                hostingScene.dispose();
+
+                // Creates the json header for the env texture
+                let info: EnvironmentTextureInfo = {
+                    version: 1,
+                    width: cubeWidth,
+                    irradiance: this._CreateEnvTextureIrradiance(texture),
+                    specular: {
+                        mipmaps: []
+                    }
+                };
+
+                // Sets the specular image data information
+                let position = 0;
+                for (let i = 0; i <= mipmapsCount; i++) {
+                    for (let face = 0; face < 6; face++) {
+                        let byteLength = specularTextures[i * 6 + face].byteLength;
+                        info.specular.mipmaps.push({
+                            length: byteLength,
+                            position: position
+                        });
+                        position += byteLength;
+                    }
+                }
+
+                // Encode the JSON as an array buffer
+                let infoString = JSON.stringify(info);
+                let infoBuffer = new ArrayBuffer(infoString.length + 1);
+                let infoView = new Uint8Array(infoBuffer); // Limited to ascii subset matching unicode.
+                for (let i= 0, strLen = infoString.length; i < strLen; i++) {
+                    infoView[i] = infoString.charCodeAt(i);
+                }
+                // Ends up with a null terminator for easier parsing
+                infoView[infoString.length] = 0x00;
+
+                // Computes the final required size and creates the storage
+                let totalSize = EnvironmentTextureTools._MagicBytes.length + position + infoBuffer.byteLength;
+                let finalBuffer = new ArrayBuffer(totalSize);
+                let finalBufferView = new Uint8Array(finalBuffer);
+                let dataView = new DataView(finalBuffer);
+
+                // Copy the magic bytes identifying the file in
+                let pos = 0;
+                for (let i = 0; i < EnvironmentTextureTools._MagicBytes.length; i++) {
+                    dataView.setUint8(pos++, EnvironmentTextureTools._MagicBytes[i]);
+                }
+
+                // Add the json info
+                finalBufferView.set(new Uint8Array(infoBuffer), pos);
+                pos += infoBuffer.byteLength;
+
+                // Finally inserts the texture data
+                for (let i = 0; i <= mipmapsCount; i++) {
+                    for (let face = 0; face < 6; face++) {
+                        let dataBuffer = specularTextures[i * 6 + face];
+                        finalBufferView.set(new Uint8Array(dataBuffer), pos);
+                        pos += dataBuffer.byteLength;
+                    }
+                }
+
+                // Voila
+                return finalBuffer;
+            });
+        }
+
+        /**
+         * Creates a JSON representation of the spherical data.
+         * @param texture defines the texture containing the polynomials
+         * @return the JSON representation of the spherical info
+         */
+        private static _CreateEnvTextureIrradiance(texture: CubeTexture) : Nullable<EnvironmentTextureIrradianceInfoV1> {
+            let polynmials = texture.sphericalPolynomial;
+            if (polynmials == null) {
+                return null;
+            }
+
+            return {
+                polynomials: true,
+
+                x: [polynmials.x.x, polynmials.x.y, polynmials.x.z],
+                y: [polynmials.y.x, polynmials.y.y, polynmials.y.z],
+                z: [polynmials.z.x, polynmials.z.y, polynmials.z.z],
+
+                xx: [polynmials.xx.x, polynmials.xx.y, polynmials.xx.z],
+                yy: [polynmials.yy.x, polynmials.yy.y, polynmials.yy.z],
+                zz: [polynmials.zz.x, polynmials.zz.y, polynmials.zz.z],
+
+                yz: [polynmials.yz.x, polynmials.yz.y, polynmials.yz.z],
+                zx: [polynmials.zx.x, polynmials.zx.y, polynmials.zx.z],
+                xy: [polynmials.xy.x, polynmials.xy.y, polynmials.xy.z]
+            } as any;
+        }
+
+        /**
+         * Uploads the texture info contained in the env file to te GPU.
+         * @param texture defines the internal texture to upload to
+         * @param arrayBuffer defines the buffer cotaining the data to load
+         * @param info defines the texture info retrieved through the GetEnvInfo method
+         * @returns a promise
+         */
+        public static UploadLevelsAsync(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): Promise<void> {
+            if (info.version !== 1) {
+                Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
+            }
+
+            let specularInfo = info.specular as EnvironmentTextureSpecularInfoV1;
+            if (!specularInfo) {
+                // Nothing else parsed so far
+                return Promise.resolve();
+            }
+
+            // Double checks the enclosed info
+            let mipmapsCount = Scalar.Log2(info.width);
+            mipmapsCount = Math.round(mipmapsCount) + 1;
+            if (specularInfo.mipmaps.length !== 6 * mipmapsCount) {
+                Tools.Warn('Unsupported specular mipmaps number "' + specularInfo.mipmaps.length + '"');
+            }
+
+            // Gets everything ready.
+            let engine = texture.getEngine();
+            let expandTexture = false;
+            let generateNonLODTextures = false;
+            let rgbdPostProcess: Nullable<PostProcess> = null;
+            let cubeRtt: Nullable<InternalTexture> = null;
+            let lodTextures: Nullable<{ [lod: number]: BaseTexture}> = null;
+            let caps = engine.getCaps();
+
+            texture.format = Engine.TEXTUREFORMAT_RGBA;
+            texture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
+            texture.samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
+
+            // Add extra process if texture lod is not supported
+            if (!caps.textureLOD) {
+                expandTexture = false;
+                generateNonLODTextures = true;
+                lodTextures = { };
+            }
+            // in webgl 1 there are no ways to either render or copy lod level information for float textures.
+            else if (engine.webGLVersion < 2) {
+                expandTexture = false;
+            }
+            // If half float available we can uncompress the texture
+            else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
+                expandTexture = true;
+                texture.type = Engine.TEXTURETYPE_HALF_FLOAT;
+            }
+            // If full float available we can uncompress the texture
+            else if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
+                expandTexture = true;
+                texture.type = Engine.TEXTURETYPE_FLOAT;
+            }
+
+            // Expand the texture if possible
+            if (expandTexture) {
+                // Simply run through the decode PP
+                rgbdPostProcess = new PostProcess("rgbdDecode", "rgbdDecode", null, null, 1, null, Texture.TRILINEAR_SAMPLINGMODE, engine, false, undefined, texture.type, undefined, null, false);
+                
+                texture._isRGBD = false;
+                texture.invertY = false;
+                cubeRtt = engine.createRenderTargetCubeTexture(texture.width, {
+                    generateDepthBuffer: false,
+                    generateMipMaps: true,
+                    generateStencilBuffer: false,
+                    samplingMode: Texture.TRILINEAR_SAMPLINGMODE,
+                    type: texture.type,
+                    format: Engine.TEXTUREFORMAT_RGBA
+                });
+            }
+            else {
+                texture._isRGBD = true;
+                texture.invertY = true;
+
+                // In case of missing support, applies the same patch than DDS files.
+                if (generateNonLODTextures) {
+                    let mipSlices = 3;
+                    let scale = texture._lodGenerationScale;
+                    let offset = texture._lodGenerationOffset;
+    
+                    for (let i = 0; i < mipSlices; i++) {
+                        //compute LOD from even spacing in smoothness (matching shader calculation)
+                        let smoothness = i / (mipSlices - 1);
+                        let roughness = 1 - smoothness;
+    
+                        let minLODIndex = offset; // roughness = 0
+                        let maxLODIndex = Scalar.Log2(info.width) * scale + offset; // roughness = 1
+    
+                        let lodIndex = minLODIndex + (maxLODIndex - minLODIndex) * roughness;
+                        let mipmapIndex = Math.round(Math.min(Math.max(lodIndex, 0), maxLODIndex));
+    
+                        let glTextureFromLod = new InternalTexture(engine, InternalTexture.DATASOURCE_TEMP);
+                        glTextureFromLod.isCube = true;
+                        glTextureFromLod.invertY = true;
+                        glTextureFromLod.generateMipMaps = false;
+                        engine.updateTextureSamplingMode(Texture.LINEAR_LINEAR, glTextureFromLod);
+    
+                        // Wrap in a base texture for easy binding.
+                        let lodTexture = new BaseTexture(null);
+                        lodTexture.isCube = true;
+                        lodTexture._texture = glTextureFromLod;
+                        lodTextures![mipmapIndex] = lodTexture;
+
+                        switch (i) {
+                            case 0:
+                            texture._lodTextureLow = lodTexture;
+                            break;
+                            case 1:
+                            texture._lodTextureMid = lodTexture;
+                            break;
+                            case 2:
+                            texture._lodTextureHigh = lodTexture;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            let promises: Promise<void>[] = [];
+            // All mipmaps
+            for (let i = 0; i < mipmapsCount; i++) {
+                // All faces
+                for (let face = 0; face < 6; face++) {
+                    // Retrieves the face data
+                    let imageData = specularInfo.mipmaps[i * 6 + face];
+                    let bytes = new Uint8Array(arrayBuffer, specularInfo.specularDataPosition! + imageData.position, imageData.length);
+
+                    // Constructs an image element from bytes
+                    let blob = new Blob([bytes], { type: 'image/png' });
+                    let url = URL.createObjectURL(blob);
+                    let image = new Image();
+                    image.src = url;
+
+                    // Enqueue promise to upload to the texture.
+                    let promise = new Promise<void>((resolve, reject) => {;
+                        image.onload = () => {
+                            if (expandTexture) {
+                                let tempTexture = engine.createTexture(null, true, true, null, Texture.NEAREST_SAMPLINGMODE, null,
+                                (message) => {
+                                    reject(message);
+                                },
+                                image);
+
+                                rgbdPostProcess!.getEffect().executeWhenCompiled(() => {
+                                    // Uncompress the data to a RTT
+                                    rgbdPostProcess!.onApply = (effect) => {
+                                        effect._bindTexture("textureSampler", tempTexture);
+                                        effect.setFloat2("scale", 1, 1);
+                                    }
+                                    
+                                    engine.scenes[0].postProcessManager.directRender([rgbdPostProcess!], cubeRtt, true, face, i);
+
+                                    // Cleanup
+                                    engine.restoreDefaultFramebuffer();
+                                    tempTexture.dispose();
+                                    window.URL.revokeObjectURL(url);
+                                    resolve();
+                                });
+                            }
+                            else {
+                                engine._uploadImageToTexture(texture, face, i, image);
+
+                                // Upload the face to the none lod texture support
+                                if (generateNonLODTextures) {
+                                    let lodTexture = lodTextures![i];
+                                    if (lodTexture) {
+                                        engine._uploadImageToTexture(lodTexture._texture!, face, 0, image);
+                                    }
+                                }
+                                resolve();
+                            }
+                        };
+                        image.onerror = (error) => {
+                            reject(error);
+                        };
+                    });
+                    promises.push(promise);
+                }
+            }
+
+            // Once all done, finishes the cleanup and return
+            return Promise.all(promises).then(() => {
+                // Relase temp RTT.
+                if (cubeRtt) {
+                    engine._releaseFramebufferObjects(cubeRtt);
+                    cubeRtt._swapAndDie(texture);
+                }
+                // Relase temp Post Process.
+                if (rgbdPostProcess) {
+                    rgbdPostProcess.dispose();
+                }
+                // Flag internal texture as ready in case they are in use.
+                if (generateNonLODTextures) {
+                    if (texture._lodTextureHigh && texture._lodTextureHigh._texture) {
+                        texture._lodTextureHigh._texture.isReady = true;
+                    }
+                    if (texture._lodTextureMid && texture._lodTextureMid._texture) {
+                        texture._lodTextureMid._texture.isReady = true;
+                    }
+                    if (texture._lodTextureLow && texture._lodTextureLow._texture) {
+                        texture._lodTextureLow._texture.isReady = true;
+                    }
+                }
+            });
+        }
+
+        /**
+         * Uploads spherical polynomials information to the texture.
+         * @param texture defines the texture we are trying to upload the information to
+         * @param arrayBuffer defines the array buffer holding the data
+         * @param info defines the environment texture info retrieved through the GetEnvInfo method
+         */
+        public static UploadPolynomials(texture: InternalTexture, arrayBuffer: any, info: EnvironmentTextureInfo): void {
+            if (info.version !== 1) {
+                Tools.Warn('Unsupported babylon environment map version "' + info.version + '"');
+            }
+
+            let irradianceInfo = info.irradiance as EnvironmentTextureIrradianceInfoV1;
+            if (!irradianceInfo) {
+                return;
+            }
+            
+            //harmonics now represent radiance
+            texture._sphericalPolynomial = new SphericalPolynomial();
+
+            if (irradianceInfo.polynomials) {
+                EnvironmentTextureTools._UploadSP(irradianceInfo, texture._sphericalPolynomial);
+            }
+            else {
+                // convert From SH to SP.
+                EnvironmentTextureTools._ConvertSHIrradianceToLambertianRadiance(irradianceInfo);
+                EnvironmentTextureTools._ConvertSHToSP(irradianceInfo, texture._sphericalPolynomial);
+            }
+        }
+
+        /**
+         * Upload spherical polynomial coefficients to the texture
+         * @param polynmials Spherical polynmial coefficients (9)
+         * @param outPolynomialCoefficents Polynomial coefficients (9) object to store result
+         */
+        private static _UploadSP(polynmials: EnvironmentTextureIrradianceInfoV1, outPolynomialCoefficents: SphericalPolynomial) {
+            outPolynomialCoefficents.x.x = polynmials.x[0];
+            outPolynomialCoefficents.x.y = polynmials.x[1];
+            outPolynomialCoefficents.x.z = polynmials.x[2];
+
+            outPolynomialCoefficents.y.x = polynmials.y[0];
+            outPolynomialCoefficents.y.y = polynmials.y[1];
+            outPolynomialCoefficents.y.z = polynmials.y[2];
+
+            outPolynomialCoefficents.z.x = polynmials.z[0];
+            outPolynomialCoefficents.z.y = polynmials.z[1];
+            outPolynomialCoefficents.z.z = polynmials.z[2];
+
+            //xx
+            outPolynomialCoefficents.xx.x = polynmials.xx[0];
+            outPolynomialCoefficents.xx.y = polynmials.xx[1];
+            outPolynomialCoefficents.xx.z = polynmials.xx[2];
+
+            outPolynomialCoefficents.yy.x = polynmials.yy[0];
+            outPolynomialCoefficents.yy.y = polynmials.yy[1];
+            outPolynomialCoefficents.yy.z = polynmials.yy[2];
+
+            outPolynomialCoefficents.zz.x = polynmials.zz[0];
+            outPolynomialCoefficents.zz.y = polynmials.zz[1];
+            outPolynomialCoefficents.zz.z = polynmials.zz[2];
+
+            //yz
+            outPolynomialCoefficents.yz.x = polynmials.yz[0];
+            outPolynomialCoefficents.yz.y = polynmials.yz[1];
+            outPolynomialCoefficents.yz.z = polynmials.yz[2];
+
+            outPolynomialCoefficents.zx.x = polynmials.zx[0];
+            outPolynomialCoefficents.zx.y = polynmials.zx[1];
+            outPolynomialCoefficents.zx.z = polynmials.zx[2];
+
+            outPolynomialCoefficents.xy.x = polynmials.xy[0];
+            outPolynomialCoefficents.xy.y = polynmials.xy[1];
+            outPolynomialCoefficents.xy.z = polynmials.xy[2];
+        }
+
+        /**
+         * Convert from irradiance to outgoing radiance for Lambertian BDRF, suitable for efficient shader evaluation.
+         *	  L = (1/pi) * E * rho
+         * 
+         * This is done by an additional scale by 1/pi, so is a fairly trivial operation but important conceptually.
+         * @param harmonics Spherical harmonic coefficients (9)
+         */
+        private static _ConvertSHIrradianceToLambertianRadiance(harmonics: any): void {
+            let scaleFactor = 1 / Math.PI;
+            // The resultant SH now represents outgoing radiance, so includes the Lambert 1/pi normalisation factor but without albedo (rho) applied
+            // (The pixel shader must apply albedo after texture fetches, etc).
+            harmonics.l00[0] *= scaleFactor;
+            harmonics.l00[1] *= scaleFactor;
+            harmonics.l00[2] *= scaleFactor;
+            harmonics.l1_1[0] *= scaleFactor;
+            harmonics.l1_1[1] *= scaleFactor;
+            harmonics.l1_1[2] *= scaleFactor;
+            harmonics.l10[0] *= scaleFactor;
+            harmonics.l10[1] *= scaleFactor;
+            harmonics.l10[2] *= scaleFactor;
+            harmonics.l11[0] *= scaleFactor;
+            harmonics.l11[1] *= scaleFactor;
+            harmonics.l11[2] *= scaleFactor;
+            harmonics.l2_2[0] *= scaleFactor;
+            harmonics.l2_2[1] *= scaleFactor;
+            harmonics.l2_2[2] *= scaleFactor;
+            harmonics.l2_1[0] *= scaleFactor;
+            harmonics.l2_1[1] *= scaleFactor;
+            harmonics.l2_1[2] *= scaleFactor;
+            harmonics.l20[0] *= scaleFactor;
+            harmonics.l20[1] *= scaleFactor;
+            harmonics.l20[2] *= scaleFactor;
+            harmonics.l21[0] *= scaleFactor;
+            harmonics.l21[1] *= scaleFactor;
+            harmonics.l21[2] *= scaleFactor;
+            harmonics.l22[0] *= scaleFactor;
+            harmonics.l22[1] *= scaleFactor;
+            harmonics.l22[2] *= scaleFactor;
+        }
+
+        /**
+         * Convert spherical harmonics to spherical polynomial coefficients
+         * @param harmonics Spherical harmonic coefficients (9)
+         * @param outPolynomialCoefficents Polynomial coefficients (9) object to store result
+         */
+        private static _ConvertSHToSP(harmonics: any, outPolynomialCoefficents: SphericalPolynomial) {
+            let rPi = 1 / Math.PI;
+
+            //x
+            outPolynomialCoefficents.x.x = 1.02333 * harmonics.l11[0] * rPi;
+            outPolynomialCoefficents.x.y = 1.02333 * harmonics.l11[1] * rPi;
+            outPolynomialCoefficents.x.z = 1.02333 * harmonics.l11[2] * rPi;
+
+            outPolynomialCoefficents.y.x = 1.02333 * harmonics.l1_1[0] * rPi;
+            outPolynomialCoefficents.y.y = 1.02333 * harmonics.l1_1[1] * rPi;
+            outPolynomialCoefficents.y.z = 1.02333 * harmonics.l1_1[2] * rPi;
+
+            outPolynomialCoefficents.z.x = 1.02333 * harmonics.l10[0] * rPi;
+            outPolynomialCoefficents.z.y = 1.02333 * harmonics.l10[1] * rPi;
+            outPolynomialCoefficents.z.z = 1.02333 * harmonics.l10[2] * rPi;
+
+            //xx
+            outPolynomialCoefficents.xx.x = (0.886277 * harmonics.l00[0] - 0.247708 * harmonics.l20[0] + 0.429043 * harmonics.l22[0]) * rPi;
+            outPolynomialCoefficents.xx.y = (0.886277 * harmonics.l00[1] - 0.247708 * harmonics.l20[1] + 0.429043 * harmonics.l22[1]) * rPi;
+            outPolynomialCoefficents.xx.z = (0.886277 * harmonics.l00[2] - 0.247708 * harmonics.l20[2] + 0.429043 * harmonics.l22[2]) * rPi;
+
+            outPolynomialCoefficents.yy.x = (0.886277 * harmonics.l00[0] - 0.247708 * harmonics.l20[0] - 0.429043 * harmonics.l22[0]) * rPi;
+            outPolynomialCoefficents.yy.y = (0.886277 * harmonics.l00[1] - 0.247708 * harmonics.l20[1] - 0.429043 * harmonics.l22[1]) * rPi;
+            outPolynomialCoefficents.yy.z = (0.886277 * harmonics.l00[2] - 0.247708 * harmonics.l20[2] - 0.429043 * harmonics.l22[2]) * rPi;
+
+            outPolynomialCoefficents.zz.x = (0.886277 * harmonics.l00[0] + 0.495417 * harmonics.l20[0]) * rPi;
+            outPolynomialCoefficents.zz.y = (0.886277 * harmonics.l00[1] + 0.495417 * harmonics.l20[1]) * rPi;
+            outPolynomialCoefficents.zz.z = (0.886277 * harmonics.l00[2] + 0.495417 * harmonics.l20[2]) * rPi;
+
+            //yz
+            outPolynomialCoefficents.yz.x = 0.858086 * harmonics.l2_1[0] * rPi;
+            outPolynomialCoefficents.yz.y = 0.858086 * harmonics.l2_1[1] * rPi;
+            outPolynomialCoefficents.yz.z = 0.858086 * harmonics.l2_1[2] * rPi;
+
+            outPolynomialCoefficents.zx.x = 0.858086 * harmonics.l21[0] * rPi;
+            outPolynomialCoefficents.zx.y = 0.858086 * harmonics.l21[1] * rPi;
+            outPolynomialCoefficents.zx.z = 0.858086 * harmonics.l21[2] * rPi;
+
+            outPolynomialCoefficents.xy.x = 0.858086 * harmonics.l2_2[0] * rPi;
+            outPolynomialCoefficents.xy.y = 0.858086 * harmonics.l2_2[1] * rPi;
+            outPolynomialCoefficents.xy.z = 0.858086 * harmonics.l2_2[2] * rPi;
+        }
+    }
+}

+ 6 - 6
src/Tools/babylon.sceneSerializer.ts

@@ -65,17 +65,17 @@
         if (mesh.delayLoadState === Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === Engine.DELAYLOADSTATE_NONE) {
         if (mesh.delayLoadState === Engine.DELAYLOADSTATE_LOADED || mesh.delayLoadState === Engine.DELAYLOADSTATE_NONE) {
             //serialize material
             //serialize material
             if (mesh.material) {
             if (mesh.material) {
-                if (mesh.material instanceof StandardMaterial) {
-                    serializationObject.materials = serializationObject.materials || [];
-                    if (!serializationObject.materials.some((mat: Material) => (mat.id === (<Material>mesh.material).id))) {
-                        serializationObject.materials.push(mesh.material.serialize());
-                    }
-                } else if (mesh.material instanceof MultiMaterial) {
+                if (mesh.material instanceof MultiMaterial) {
                     serializationObject.multiMaterials = serializationObject.multiMaterials || [];
                     serializationObject.multiMaterials = serializationObject.multiMaterials || [];
                     if (!serializationObject.multiMaterials.some((mat: Material) => (mat.id === (<Material>mesh.material).id))) {
                     if (!serializationObject.multiMaterials.some((mat: Material) => (mat.id === (<Material>mesh.material).id))) {
                         serializationObject.multiMaterials.push(mesh.material.serialize());
                         serializationObject.multiMaterials.push(mesh.material.serialize());
                     }
                     }
 
 
+                } else {
+                    serializationObject.materials = serializationObject.materials || [];
+                    if (!serializationObject.materials.some((mat: Material) => (mat.id === (<Material>mesh.material).id))) {
+                        serializationObject.materials.push(mesh.material.serialize());
+                    }
                 }
                 }
             }
             }
             //serialize geometry
             //serialize geometry

+ 27 - 16
src/Tools/babylon.tools.ts

@@ -996,28 +996,18 @@
                     }
                     }
                 }
                 }
                 screenshotCanvas.toBlob(function (blob) {
                 screenshotCanvas.toBlob(function (blob) {
-                    var url = URL.createObjectURL(blob);
                     //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image.
                     //Creating a link if the browser have the download attribute on the a tag, to automatically start download generated image.
                     if (("download" in document.createElement("a"))) {
                     if (("download" in document.createElement("a"))) {
-                        var a = window.document.createElement("a");
-                        a.href = url;
-                        if (fileName) {
-                            a.setAttribute("download", fileName);
-                        }
-                        else {
+                        if (!fileName) {
                             var date = new Date();
                             var date = new Date();
-                            var stringDate = (date.getFullYear() + "-" + (date.getMonth() + 1)).slice(-2) + "-" + date.getDate() + "_" + date.getHours() + "-" + ('0' + date.getMinutes()).slice(-2);
-                            a.setAttribute("download", "screenshot_" + stringDate + ".png");
+                            var stringDate = (date.getFullYear() + "-" + (date.getMonth() + 1)).slice(2) + "-" + date.getDate() + "_" + date.getHours() + "-" + ('0' + date.getMinutes()).slice(-2);
+                            fileName = "screenshot_" + stringDate + ".png";
                         }
                         }
-                        window.document.body.appendChild(a);
-                        a.addEventListener("click", () => {
-                            if (a.parentElement) {
-                                a.parentElement.removeChild(a);
-                            }
-                        });
-                        a.click();
+                        Tools.Download(blob!, fileName);
                     }
                     }
                     else {
                     else {
+                        var url = URL.createObjectURL(blob);
+                    
                         var newWindow = window.open("");
                         var newWindow = window.open("");
                         if (!newWindow) return;
                         if (!newWindow) return;
                         var img = newWindow.document.createElement("img");
                         var img = newWindow.document.createElement("img");
@@ -1033,6 +1023,27 @@
             }
             }
         }
         }
 
 
+        /**
+         * Downloads a blob in the browser
+         * @param blob defines the blob to download
+         * @param fileName defines the name of the downloaded file
+         */
+        public static Download(blob: Blob, fileName: string): void {
+            var url = window.URL.createObjectURL(blob);
+            var a = document.createElement("a");
+            document.body.appendChild(a);
+            a.style.display = "none";
+            a.href = url;
+            a.download = fileName;
+            a.addEventListener("click", () => {
+                if (a.parentElement) {
+                    a.parentElement.removeChild(a);
+                }
+            });
+            a.click();
+            window.URL.revokeObjectURL(url);
+        }
+
         public static CreateScreenshot(engine: Engine, camera: Camera, size: any, successCallback?: (data: string) => void, mimeType: string = "image/png"): void {
         public static CreateScreenshot(engine: Engine, camera: Camera, size: any, successCallback?: (data: string) => void, mimeType: string = "image/png"): void {
             var width: number;
             var width: number;
             var height: number;
             var height: number;