Browse Source

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

Raanan Weber 7 years ago
parent
commit
a645d95a49
56 changed files with 39278 additions and 30351 deletions
  1. 17040 16867
      Playground/babylon.d.txt
  2. BIN
      Playground/textures/360photo.jpg
  3. 15 2
      Tools/Gulp/config.json
  4. 1 1
      Tools/Gulp/package.json
  5. 2 1
      Viewer/src/model/viewerModel.ts
  6. 63 62
      Viewer/webpack.config.js
  7. 8660 8551
      dist/preview release/babylon.d.ts
  8. 41 41
      dist/preview release/babylon.js
  9. 480 211
      dist/preview release/babylon.max.js
  10. 480 211
      dist/preview release/babylon.no-module.max.js
  11. 41 41
      dist/preview release/babylon.worker.js
  12. 482 213
      dist/preview release/es6.js
  13. 72 1
      dist/preview release/gui/babylon.gui.d.ts
  14. 334 44
      dist/preview release/gui/babylon.gui.js
  15. 2 2
      dist/preview release/gui/babylon.gui.min.js
  16. 72 1
      dist/preview release/gui/babylon.gui.module.d.ts
  17. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.js
  18. 1 1
      dist/preview release/inspector/babylon.inspector.d.ts
  19. 9 9
      dist/preview release/inspector/babylon.inspector.js
  20. 2 2
      dist/preview release/inspector/babylon.inspector.min.js
  21. 4 8
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  22. 2 0
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  23. 4 9
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  24. 2 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  25. 4 9
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  26. 2 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  27. 4 9
      dist/preview release/loaders/babylonjs.loaders.d.ts
  28. 2 1
      dist/preview release/loaders/babylonjs.loaders.js
  29. 4 9
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  30. 1 1
      dist/preview release/materialsLibrary/babylon.mixMaterial.js
  31. 1 1
      dist/preview release/materialsLibrary/babylon.mixMaterial.min.js
  32. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js
  33. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  34. 0 4
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  35. 0 4
      dist/preview release/serializers/babylon.glTF2Serializer.js
  36. 0 4
      dist/preview release/serializers/babylonjs.serializers.d.ts
  37. 0 4
      dist/preview release/serializers/babylonjs.serializers.js
  38. 0 4
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  39. 978 771
      dist/preview release/viewer/babylon.viewer.d.ts
  40. 39 38
      dist/preview release/viewer/babylon.viewer.js
  41. 8997 2453
      dist/preview release/viewer/babylon.viewer.max.js
  42. 865 687
      dist/preview release/viewer/babylon.viewer.module.d.ts
  43. 4 0
      dist/preview release/what's new.md
  44. 48 1
      gui/src/3D/controls/container3D.ts
  45. 31 2
      gui/src/3D/controls/control3D.ts
  46. 67 0
      gui/src/3D/controls/spherePanel.ts
  47. 3 1
      gui/src/3D/controls/stackPanel3D.ts
  48. 180 0
      gui/src/3D/controls/volumeBasedPanel.ts
  49. 48 48
      gui/src/3D/gui3DManager.ts
  50. 2 4
      materialsLibrary/src/mix/mix.fragment.fx
  51. 22 0
      src/Debug/babylon.debugLayer.ts
  52. 88 0
      src/Helpers/babylon.photoDome.ts
  53. 2 7
      src/Helpers/babylon.videoDome.ts
  54. 5 0
      src/Lights/Shadows/babylon.shadowGenerator.ts
  55. 44 3
      src/Rendering/babylon.utilityLayerRenderer.ts
  56. 24 2
      src/Tools/babylon.assetsManager.ts

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


BIN
Playground/textures/360photo.jpg


+ 15 - 2
Tools/Gulp/config.json

@@ -115,7 +115,8 @@
             "backgroundMaterial",
             "environmentHelper",
             "particleHelper",
-            "videoDome"
+            "videoDome",
+            "photoDome"
         ],
         "minimal": [
             "freeCamera",
@@ -1224,6 +1225,16 @@
                 "meshBuilder",
                 "additionalTextures"
             ]
+        },
+        "photoDome": {
+            "files": [
+                "../../src/Helpers/babylon.photoDome.js"
+            ],
+            "dependUpon": [
+                "core",
+                "meshBuilder",
+                "additionalTextures"
+            ]
         }
     },
     "typescript": [
@@ -1713,7 +1724,9 @@
                     "../../gui/src/3D/controls/container3D.ts",
                     "../../gui/src/3D/controls/button3D.ts",
                     "../../gui/src/3D/controls/holographicButton.ts",
-                    "../../gui/src/3D/controls/stackPanel3D.ts"
+                    "../../gui/src/3D/controls/stackPanel3D.ts",
+                    "../../gui/src/3D/controls/volumeBasedPanel.ts",
+                    "../../gui/src/3D/controls/spherePanel.ts"
                 ],
                 "shaderFiles": [
                     "../../gui/src/3D/materials/shaders/fluent.vertex.fx",

+ 1 - 1
Tools/Gulp/package.json

@@ -69,4 +69,4 @@
         "gulp-clean": "^0.4.0",
         "npm": "^5.8.0"
     }
-}
+}

+ 2 - 1
Viewer/src/model/viewerModel.ts

@@ -280,9 +280,10 @@ export class ViewerModel implements IDisposable {
      */
     private _enterScene(completeCallback?: () => void): void {
         const scene = this.rootMesh.getScene();
+        let previousValue = scene.animationPropertiesOverride!.enableBlending;
         let callback = () => {
             this.state = ModelState.ENTRYDONE;
-            scene.animationPropertiesOverride!.enableBlending = true;
+            scene.animationPropertiesOverride!.enableBlending = previousValue;
             this._checkCompleteState();
             if (completeCallback) completeCallback();
         }

+ 63 - 62
Viewer/webpack.config.js

@@ -1,7 +1,8 @@
 const path = require('path');
 const webpack = require('webpack');
 
-module.exports = [{
+module.exports = /*[
+    {
     entry: {
         'assets': './src/assets/index.ts'
     },
@@ -42,69 +43,69 @@ module.exports = [{
             loader: 'base64-font-loader'
         }]
     }
-},
-{
-    entry: {
-        'viewer': './src/index.ts',
-    },
-    output: {
-        path: path.resolve(__dirname, 'dist'),
-        filename: '[name].js',
-        libraryTarget: 'umd',
-        library: 'BabylonViewer',
-        umdNamedDefine: true,
-        devtoolModuleFilenameTemplate: '[relative-resource-path]'
-    },
-    resolve: {
-        extensions: ['.ts', '.js'],
-        alias: {
-            "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
-            "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
-            "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
-            "babylonjs-viewer-assets": __dirname + '/dist/assets.js'
-        }
-    },
-    externals: {
-        // until physics will be integrated in the viewer, ignore cannon
-        cannon: 'CANNON',
-        oimo: 'OIMO',
-        earcut: true
-    },
-    devtool: 'source-map',
-    plugins: [
-        new webpack.WatchIgnorePlugin([
-            /\.d\.ts$/
-        ])
-    ],
-    module: {
-        loaders: [{
-            test: /\.tsx?$/,
-            loader: 'ts-loader',
-            exclude: /node_modules/
+},*/
+    {
+        entry: {
+            'viewer': './src/index.ts',
         },
-        {
-            test: /\.(html)$/,
-            use: {
-                loader: 'html-loader',
-                options: {
-                    minimize: true
-                }
+        output: {
+            path: path.resolve(__dirname, 'dist'),
+            filename: '[name].js',
+            libraryTarget: 'umd',
+            library: 'BabylonViewer',
+            umdNamedDefine: true,
+            devtoolModuleFilenameTemplate: '[relative-resource-path]'
+        },
+        resolve: {
+            extensions: ['.ts', '.js'],
+            alias: {
+                "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
+                "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
+                "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
+                "babylonjs-viewer-assets": __dirname + '/src/assets/index.ts'
             }
         },
-        {
-            test: /\.(jpe?g|png|ttf|eot|svg?)(\?[a-z0-9=&.]+)?$/,
-            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        externals: {
+            // until physics will be integrated in the viewer, ignore cannon
+            cannon: 'CANNON',
+            oimo: 'OIMO',
+            earcut: true
         },
-        {
-            test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
-            loader: 'base64-font-loader'
-        }]
-    },
-    devServer: {
-        contentBase: path.join(__dirname, "dist"),
-        compress: false,
-        //open: true,
-        port: 9000
+        devtool: 'source-map',
+        plugins: [
+            new webpack.WatchIgnorePlugin([
+                /\.d\.ts$/
+            ])
+        ],
+        module: {
+            loaders: [{
+                test: /\.tsx?$/,
+                loader: 'ts-loader',
+                exclude: /node_modules/
+            },
+            {
+                test: /\.(html)$/,
+                use: {
+                    loader: 'html-loader',
+                    options: {
+                        minimize: true
+                    }
+                }
+            },
+            {
+                test: /\.(jpe?g|png|ttf|eot|svg?)(\?[a-z0-9=&.]+)?$/,
+                use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+            },
+            {
+                test: /\.(woff|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
+                loader: 'base64-font-loader'
+            }]
+        },
+        devServer: {
+            contentBase: path.join(__dirname, "dist"),
+            compress: false,
+            //open: true,
+            port: 9000
+        }
     }
-}
-]
+//]

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


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


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


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


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


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


+ 72 - 1
dist/preview release/gui/babylon.gui.d.ts

@@ -1876,6 +1876,7 @@ declare module BABYLON.GUI {
         private _utilityLayer;
         private _rootContainer;
         private _pointerObserver;
+        private _pointerOutObserver;
         /** @hidden */
         _lastPickedControl: Control3D;
         /** @hidden */
@@ -1903,7 +1904,8 @@ declare module BABYLON.GUI {
          * @param scene
          */
         constructor(scene?: Scene);
-        private _doPicking(type, pointerEvent, ray?);
+        private _handlePointerOut(pointerId, isPointerUp);
+        private _doPicking(pi);
         /**
          * Gets the root container
          */
@@ -2187,11 +2189,21 @@ declare module BABYLON.GUI {
      * Class used to create containers for controls
      */
     class Container3D extends Control3D {
+        private _blockLayout;
         /**
          * Gets the list of child controls
          */
         protected _children: Control3D[];
         /**
+         * Gets the list of child controls
+         */
+        readonly children: Array<Control3D>;
+        /**
+         * Gets or sets a boolean indicating if the layout must be blocked (default is false).
+         * This is helpful to optimize layout operation when adding multiple children in a row
+         */
+        blockLayout: boolean;
+        /**
          * Creates a new container
          * @param name defines the container name
          */
@@ -2224,6 +2236,16 @@ declare module BABYLON.GUI {
          * Releases all associated resources
          */
         dispose(): void;
+        /** Control rotation will remain unchanged  */
+        static readonly UNSET_ORIENTATION: number;
+        /** Control will rotate to make it look at sphere central axis */
+        static readonly FACEORIGIN_ORIENTATION: number;
+        /** Control will rotate to make it look back at sphere central axis */
+        static readonly FACEORIGINREVERSED_ORIENTATION: number;
+        /** Control will rotate to look at z axis (0, 0, 1) */
+        static readonly FACEFORWARD_ORIENTATION: number;
+        /** Control will rotate to look at negative z axis (0, 0, -1) */
+        static readonly FACEFORWARDREVERSED_ORIENTATION: number;
     }
 }
 
@@ -2353,7 +2375,56 @@ declare module BABYLON.GUI {
          * Creates new StackPanel
          * @param isVertical
          */
+        constructor(isVertical?: boolean);
+        protected _arrangeChildren(): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
+     * Class used to create a conainter panel deployed on the surface of a sphere
+     */
+    class SpherePanel extends Container3D {
+        private _radius;
+        private _columns;
+        private _rows;
+        private _rowThenColum;
+        private _orientation;
+        /**
+         * Gets or sets the distance between elements
+         */
+        margin: number;
+        /**
+         * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
+        * | Value | Type                                | Description |
+        * | ----- | ----------------------------------- | ----------- |
+        * | 0     | UNSET_ORIENTATION                   |  Control rotation will remain unchanged |
+        * | 1     | FACEORIGIN_ORIENTATION              |  Control will rotate to make it look at sphere central axis |
+        * | 2     | FACEORIGINREVERSED_ORIENTATION      |  Control will rotate to make it look back at sphere central axis |
+        * | 3     | FACEFORWARD_ORIENTATION             |  Control will rotate to look at z axis (0, 0, 1) |
+        * | 4     | FACEFORWARDREVERSED_ORIENTATION     |  Control will rotate to look at negative z axis (0, 0, -1) |
+         */
+        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).
+         * The panel will automatically compute the number of rows based on number of child controls.
+         */
+        columns: int;
+        /**
+         * Gets or sets a the number of rows requested.
+         * The panel will automatically compute the number of columns based on number of child controls.
+         */
+        rows: int;
+        /**
+         * Creates new SpherePanel
+         */
         constructor();
         protected _arrangeChildren(): void;
+        private _sphericalMapping(source);
     }
 }

+ 334 - 44
dist/preview release/gui/babylon.gui.js

@@ -6511,28 +6511,17 @@ var BABYLON;
                     _this.dispose();
                 });
                 this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene);
+                this._utilityLayer.onlyCheckPointerDownEvents = false;
                 // Root
                 this._rootContainer = new GUI.Container3D("RootContainer");
                 this._rootContainer._host = this;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 // Events
-                this._pointerObserver = this._scene.onPrePointerObservable.add(function (pi, state) {
-                    if (pi.skipOnPointerObservable) {
-                        return;
-                    }
-                    var pointerEvent = (pi.event);
-                    if (_this._scene.isPointerCaptured(pointerEvent.pointerId)) {
-                        return;
-                    }
-                    if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
-                        && pi.type !== BABYLON.PointerEventTypes.POINTERUP
-                        && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                        return;
-                    }
-                    var camera = _this._scene.cameraToUseForPointers || _this._scene.activeCamera;
-                    if (!camera) {
-                        return;
-                    }
-                    pi.skipOnPointerObservable = _this._doPicking(pi.type, pointerEvent, pi.ray);
+                this._pointerOutObserver = this._utilityLayer.onPointerOutObservable.add(function (pointerId) {
+                    _this._handlePointerOut(pointerId, true);
+                });
+                this._pointerObserver = utilityLayerScene.onPointerObservable.add(function (pi, state) {
+                    _this._doPicking(pi);
                 });
                 // Scene
                 this._utilityLayer.utilityLayerScene.autoClear = false;
@@ -6555,42 +6544,45 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
-            GUI3DManager.prototype._doPicking = function (type, pointerEvent, ray) {
+            GUI3DManager.prototype._handlePointerOut = function (pointerId, isPointerUp) {
+                var previousControlOver = this._lastControlOver[pointerId];
+                if (previousControlOver) {
+                    previousControlOver._onPointerOut(previousControlOver);
+                    delete this._lastControlOver[pointerId];
+                }
+                if (isPointerUp) {
+                    if (this._lastControlDown[pointerId]) {
+                        this._lastControlDown[pointerId].forcePointerUp();
+                        delete this._lastControlDown[pointerId];
+                    }
+                }
+                this.onPickedPointChangedObservable.notifyObservers(null);
+            };
+            GUI3DManager.prototype._doPicking = function (pi) {
                 if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
                     return false;
                 }
+                var pointerEvent = (pi.event);
                 var pointerId = pointerEvent.pointerId || 0;
                 var buttonIndex = pointerEvent.button;
-                var utilityScene = this._utilityLayer.utilityLayerScene;
-                var pickingInfo = ray ? utilityScene.pickWithRay(ray) : utilityScene.pick(this._scene.pointerX, this._scene.pointerY);
+                var pickingInfo = pi.pickInfo;
                 if (!pickingInfo || !pickingInfo.hit) {
-                    var previousControlOver = this._lastControlOver[pointerId];
-                    if (previousControlOver) {
-                        previousControlOver._onPointerOut(previousControlOver);
-                        delete this._lastControlOver[pointerId];
-                    }
-                    if (type === BABYLON.PointerEventTypes.POINTERUP) {
-                        if (this._lastControlDown[pointerEvent.pointerId]) {
-                            this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
-                            delete this._lastControlDown[pointerEvent.pointerId];
-                        }
-                    }
-                    this.onPickedPointChangedObservable.notifyObservers(null);
+                    this._handlePointerOut(pointerId, pi.type === BABYLON.PointerEventTypes.POINTERUP);
                     return false;
                 }
                 var control = (pickingInfo.pickedMesh.metadata);
                 if (pickingInfo.pickedPoint) {
                     this.onPickedPointChangedObservable.notifyObservers(pickingInfo.pickedPoint);
                 }
-                if (!control._processObservables(type, pickingInfo.pickedPoint, pointerId, buttonIndex)) {
-                    if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                if (!control._processObservables(pi.type, pickingInfo.pickedPoint, pointerId, buttonIndex)) {
+                    if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                         if (this._lastControlOver[pointerId]) {
                             this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
                         }
                         delete this._lastControlOver[pointerId];
                     }
                 }
-                if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                     if (this._lastControlDown[pointerEvent.pointerId]) {
                         this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                         delete this._lastControlDown[pointerEvent.pointerId];
@@ -6646,12 +6638,19 @@ var BABYLON;
                     this._sharedMaterials[materialName].dispose();
                 }
                 this._sharedMaterials = {};
+                if (this._pointerOutObserver && this._utilityLayer) {
+                    this._utilityLayer.onPointerOutObservable.remove(this._pointerOutObserver);
+                    this._pointerOutObserver = null;
+                }
                 this.onPickedPointChangedObservable.clear();
-                if (this._scene) {
+                var utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
+                if (utilityLayerScene) {
                     if (this._pointerObserver) {
-                        this._scene.onPrePointerObservable.remove(this._pointerObserver);
+                        utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
                         this._pointerObserver = null;
                     }
+                }
+                if (this._scene) {
                     if (this._sceneDisposeObserver) {
                         this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
                         this._sceneDisposeObserver = null;
@@ -6981,10 +6980,6 @@ var BABYLON;
                 this._enterCount = -1;
                 this._downPointerIds = {};
                 this._isVisible = true;
-                /** Gets or sets the control position  in world space */
-                this.position = new BABYLON.Vector3(0, 0, 0);
-                /** Gets or sets the control scaling  in world space */
-                this.scaling = new BABYLON.Vector3(1, 1, 1);
                 /**
                 * An event triggered when the pointer move over the control
                 */
@@ -7012,6 +7007,42 @@ var BABYLON;
                 // Behaviors
                 this._behaviors = new Array();
             }
+            Object.defineProperty(Control3D.prototype, "position", {
+                /** Gets or sets the control position  in world space */
+                get: function () {
+                    if (!this._node) {
+                        return BABYLON.Vector3.Zero();
+                    }
+                    return this._node.position;
+                },
+                set: function (value) {
+                    if (!this._node) {
+                        return;
+                    }
+                    this._node.position = value;
+                    ;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control3D.prototype, "scaling", {
+                /** Gets or sets the control scaling  in world space */
+                get: function () {
+                    if (!this._node) {
+                        return new BABYLON.Vector3(1, 1, 1);
+                    }
+                    return this._node.scaling;
+                },
+                set: function (value) {
+                    if (!this._node) {
+                        return;
+                    }
+                    this._node.scaling = value;
+                    ;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control3D.prototype, "behaviors", {
                 /**
                  * Gets the list of attached behaviors
@@ -7319,12 +7350,43 @@ var BABYLON;
              */
             function Container3D(name) {
                 var _this = _super.call(this, name) || this;
+                _this._blockLayout = false;
                 /**
                  * Gets the list of child controls
                  */
                 _this._children = new Array();
                 return _this;
             }
+            Object.defineProperty(Container3D.prototype, "children", {
+                /**
+                 * Gets the list of child controls
+                 */
+                get: function () {
+                    return this._children;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Container3D.prototype, "blockLayout", {
+                /**
+                 * Gets or sets a boolean indicating if the layout must be blocked (default is false).
+                 * This is helpful to optimize layout operation when adding multiple children in a row
+                 */
+                get: function () {
+                    return this._blockLayout;
+                },
+                set: function (value) {
+                    if (this._blockLayout === value) {
+                        return;
+                    }
+                    this._blockLayout = value;
+                    if (!this._blockLayout) {
+                        this._arrangeChildren();
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
             /**
              * Gets a boolean indicating if the given control is in the children of this control
              * @param control defines the control to check
@@ -7351,7 +7413,9 @@ var BABYLON;
                     if (control.node) {
                         control.node.parent = this.node;
                     }
-                    this._arrangeChildren();
+                    if (!this.blockLayout) {
+                        this._arrangeChildren();
+                    }
                 }
                 return this;
             };
@@ -7391,6 +7455,16 @@ var BABYLON;
                 this._children = [];
                 _super.prototype.dispose.call(this);
             };
+            /** Control rotation will remain unchanged  */
+            Container3D.UNSET_ORIENTATION = 0;
+            /** Control will rotate to make it look at sphere central axis */
+            Container3D.FACEORIGIN_ORIENTATION = 1;
+            /** Control will rotate to make it look back at sphere central axis */
+            Container3D.FACEORIGINREVERSED_ORIENTATION = 2;
+            /** Control will rotate to look at z axis (0, 0, 1) */
+            Container3D.FACEFORWARD_ORIENTATION = 3;
+            /** Control will rotate to look at negative z axis (0, 0, -1) */
+            Container3D.FACEFORWARDREVERSED_ORIENTATION = 4;
             return Container3D;
         }(GUI.Control3D));
         GUI.Container3D = Container3D;
@@ -7809,13 +7883,15 @@ var BABYLON;
              * Creates new StackPanel
              * @param isVertical
              */
-            function StackPanel3D() {
+            function StackPanel3D(isVertical) {
+                if (isVertical === void 0) { isVertical = false; }
                 var _this = _super.call(this) || this;
                 _this._isVertical = false;
                 /**
                  * Gets or sets the distance between elements
                  */
                 _this.margin = 0.1;
+                _this._isVertical = isVertical;
                 return _this;
             }
             Object.defineProperty(StackPanel3D.prototype, "isVertical", {
@@ -7904,6 +7980,220 @@ var BABYLON;
     })(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 conainter panel deployed on the surface of a sphere
+         */
+        var SpherePanel = /** @class */ (function (_super) {
+            __extends(SpherePanel, _super);
+            /**
+             * Creates new SpherePanel
+             */
+            function SpherePanel() {
+                var _this = _super.call(this) || this;
+                _this._radius = 5.0;
+                _this._columns = 10;
+                _this._rows = 0;
+                _this._rowThenColum = true;
+                _this._orientation = GUI.Container3D.FACEORIGIN_ORIENTATION;
+                /**
+                 * Gets or sets the distance between elements
+                 */
+                _this.margin = 0;
+                return _this;
+            }
+            Object.defineProperty(SpherePanel.prototype, "orientation", {
+                /**
+                 * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
+                * | Value | Type                                | Description |
+                * | ----- | ----------------------------------- | ----------- |
+                * | 0     | UNSET_ORIENTATION                   |  Control rotation will remain unchanged |
+                * | 1     | FACEORIGIN_ORIENTATION              |  Control will rotate to make it look at sphere central axis |
+                * | 2     | FACEORIGINREVERSED_ORIENTATION      |  Control will rotate to make it look back at sphere central axis |
+                * | 3     | FACEFORWARD_ORIENTATION             |  Control will rotate to look at z axis (0, 0, 1) |
+                * | 4     | FACEFORWARDREVERSED_ORIENTATION     |  Control will rotate to look at negative z axis (0, 0, -1) |
+                 */
+                get: function () {
+                    return this._orientation;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._orientation === value) {
+                        return;
+                    }
+                    this._orientation = value;
+                    BABYLON.Tools.SetImmediate(function () {
+                        _this._arrangeChildren();
+                    });
+                },
+                enumerable: 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", {
+                /**
+                 * 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.
+                 */
+                get: function () {
+                    return this._columns;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._columns === value) {
+                        return;
+                    }
+                    this._columns = value;
+                    this._rowThenColum = true;
+                    BABYLON.Tools.SetImmediate(function () {
+                        _this._arrangeChildren();
+                    });
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(SpherePanel.prototype, "rows", {
+                /**
+                 * Gets or sets a the number of rows requested.
+                 * The panel will automatically compute the number of columns based on number of child controls.
+                 */
+                get: function () {
+                    return this._rows;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._rows === value) {
+                        return;
+                    }
+                    this._rows = value;
+                    this._rowThenColum = false;
+                    BABYLON.Tools.SetImmediate(function () {
+                        _this._arrangeChildren();
+                    });
+                },
+                enumerable: true,
+                configurable: true
+            });
+            SpherePanel.prototype._arrangeChildren = function () {
+                var cellWidth = 0;
+                var cellHeight = 0;
+                var rows = 0;
+                var columns = 0;
+                var controlCount = 0;
+                var currentInverseWorld = BABYLON.Matrix.Invert(this.node.computeWorldMatrix(true));
+                // Measure
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var child = _a[_i];
+                    if (!child.mesh) {
+                        continue;
+                    }
+                    controlCount++;
+                    child.mesh.computeWorldMatrix(true);
+                    child.mesh.getWorldMatrix().multiplyToRef(currentInverseWorld, BABYLON.Tmp.Matrix[0]);
+                    var boundingBox = child.mesh.getBoundingInfo().boundingBox;
+                    var extendSize = BABYLON.Vector3.TransformNormal(boundingBox.extendSize, BABYLON.Tmp.Matrix[0]);
+                    cellWidth = Math.max(cellWidth, extendSize.x * 2);
+                    cellHeight = Math.max(cellHeight, extendSize.y * 2);
+                }
+                cellWidth += this.margin * 2;
+                cellHeight += this.margin * 2;
+                // Arrange
+                if (this._rowThenColum) {
+                    columns = this._columns;
+                    rows = Math.ceil(controlCount / this._columns);
+                }
+                else {
+                    rows = this._rows;
+                    columns = Math.ceil(controlCount / this._rows);
+                }
+                var startOffsetX = (columns * 0.5) * cellWidth;
+                var startOffsetY = (rows * 0.5) * cellHeight;
+                var nodeGrid = [];
+                var cellCounter = 0;
+                if (this._rowThenColum) {
+                    for (var r = 0; r < rows; r++) {
+                        for (var c = 0; c < columns; c++) {
+                            nodeGrid.push(new BABYLON.Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                            cellCounter++;
+                            if (cellCounter > controlCount) {
+                                break;
+                            }
+                        }
+                    }
+                }
+                else {
+                    for (var c = 0; c < columns; c++) {
+                        for (var r = 0; r < rows; r++) {
+                            nodeGrid.push(new BABYLON.Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                            cellCounter++;
+                            if (cellCounter > controlCount) {
+                                break;
+                            }
+                        }
+                    }
+                }
+                cellCounter = 0;
+                for (var _b = 0, _c = this._children; _b < _c.length; _b++) {
+                    var child = _c[_b];
+                    if (!child.mesh) {
+                        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;
+                    cellCounter++;
+                }
+            };
+            SpherePanel.prototype._sphericalMapping = function (source) {
+                var newPos = new BABYLON.Vector3(0, 0, this._radius);
+                var xAngle = (source.y / this._radius);
+                var yAngle = -(source.x / this._radius);
+                BABYLON.Matrix.RotationYawPitchRollToRef(yAngle, xAngle, 0, BABYLON.Tmp.Matrix[0]);
+                return BABYLON.Vector3.TransformNormal(newPos, BABYLON.Tmp.Matrix[0]);
+            };
+            return SpherePanel;
+        }(GUI.Container3D));
+        GUI.SpherePanel = SpherePanel;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
     
 
     return BABYLON.GUI;

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


+ 72 - 1
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1881,6 +1881,7 @@ declare module BABYLON.GUI {
         private _utilityLayer;
         private _rootContainer;
         private _pointerObserver;
+        private _pointerOutObserver;
         /** @hidden */
         _lastPickedControl: Control3D;
         /** @hidden */
@@ -1908,7 +1909,8 @@ declare module BABYLON.GUI {
          * @param scene
          */
         constructor(scene?: Scene);
-        private _doPicking(type, pointerEvent, ray?);
+        private _handlePointerOut(pointerId, isPointerUp);
+        private _doPicking(pi);
         /**
          * Gets the root container
          */
@@ -2192,11 +2194,21 @@ declare module BABYLON.GUI {
      * Class used to create containers for controls
      */
     class Container3D extends Control3D {
+        private _blockLayout;
         /**
          * Gets the list of child controls
          */
         protected _children: Control3D[];
         /**
+         * Gets the list of child controls
+         */
+        readonly children: Array<Control3D>;
+        /**
+         * Gets or sets a boolean indicating if the layout must be blocked (default is false).
+         * This is helpful to optimize layout operation when adding multiple children in a row
+         */
+        blockLayout: boolean;
+        /**
          * Creates a new container
          * @param name defines the container name
          */
@@ -2229,6 +2241,16 @@ declare module BABYLON.GUI {
          * Releases all associated resources
          */
         dispose(): void;
+        /** Control rotation will remain unchanged  */
+        static readonly UNSET_ORIENTATION: number;
+        /** Control will rotate to make it look at sphere central axis */
+        static readonly FACEORIGIN_ORIENTATION: number;
+        /** Control will rotate to make it look back at sphere central axis */
+        static readonly FACEORIGINREVERSED_ORIENTATION: number;
+        /** Control will rotate to look at z axis (0, 0, 1) */
+        static readonly FACEFORWARD_ORIENTATION: number;
+        /** Control will rotate to look at negative z axis (0, 0, -1) */
+        static readonly FACEFORWARDREVERSED_ORIENTATION: number;
     }
 }
 
@@ -2358,7 +2380,56 @@ declare module BABYLON.GUI {
          * Creates new StackPanel
          * @param isVertical
          */
+        constructor(isVertical?: boolean);
+        protected _arrangeChildren(): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    /**
+     * Class used to create a conainter panel deployed on the surface of a sphere
+     */
+    class SpherePanel extends Container3D {
+        private _radius;
+        private _columns;
+        private _rows;
+        private _rowThenColum;
+        private _orientation;
+        /**
+         * Gets or sets the distance between elements
+         */
+        margin: number;
+        /**
+         * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
+        * | Value | Type                                | Description |
+        * | ----- | ----------------------------------- | ----------- |
+        * | 0     | UNSET_ORIENTATION                   |  Control rotation will remain unchanged |
+        * | 1     | FACEORIGIN_ORIENTATION              |  Control will rotate to make it look at sphere central axis |
+        * | 2     | FACEORIGINREVERSED_ORIENTATION      |  Control will rotate to make it look back at sphere central axis |
+        * | 3     | FACEFORWARD_ORIENTATION             |  Control will rotate to look at z axis (0, 0, 1) |
+        * | 4     | FACEFORWARDREVERSED_ORIENTATION     |  Control will rotate to look at negative z axis (0, 0, -1) |
+         */
+        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).
+         * The panel will automatically compute the number of rows based on number of child controls.
+         */
+        columns: int;
+        /**
+         * Gets or sets a the number of rows requested.
+         * The panel will automatically compute the number of columns based on number of child controls.
+         */
+        rows: int;
+        /**
+         * Creates new SpherePanel
+         */
         constructor();
         protected _arrangeChildren(): void;
+        private _sphericalMapping(source);
     }
 }

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


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

@@ -1105,7 +1105,7 @@ declare module INSPECTOR {
     abstract class AbstractTool {
         private _elem;
         protected _inspector: Inspector;
-        constructor(icon: string, parent: HTMLElement, inspector: Inspector, tooltip: string);
+        constructor(iconSet: string, icon: string, parent: HTMLElement, inspector: Inspector, tooltip: string);
         toHtml(): HTMLElement;
         /**
          * Returns the total width in pixel of this tool, 0 by default

+ 9 - 9
dist/preview release/inspector/babylon.inspector.js

@@ -4468,11 +4468,11 @@ var INSPECTOR;
 var INSPECTOR;
 (function (INSPECTOR) {
     var AbstractTool = /** @class */ (function () {
-        function AbstractTool(icon, parent, inspector, tooltip) {
+        function AbstractTool(iconSet, icon, parent, inspector, tooltip) {
             var _this = this;
             this._inspector = inspector;
             this._elem = INSPECTOR.Inspector.DOCUMENT.createElement('i');
-            this._elem.className = "tool fa " + icon;
+            this._elem.className = "tool " + iconSet + " " + icon;
             parent.appendChild(this._elem);
             this._elem.addEventListener('click', function (e) {
                 _this.action();
@@ -4520,7 +4520,7 @@ var INSPECTOR;
     var PauseScheduleTool = /** @class */ (function (_super) {
         __extends(PauseScheduleTool, _super);
         function PauseScheduleTool(parent, inspector) {
-            var _this = _super.call(this, 'fa-pause', parent, inspector, 'Pause the automatic update of properties') || this;
+            var _this = _super.call(this, 'fa', 'fa-pause', parent, inspector, 'Pause the automatic update of properties') || this;
             _this._isPause = false;
             return _this;
         }
@@ -4556,7 +4556,7 @@ var INSPECTOR;
     var PickTool = /** @class */ (function (_super) {
         __extends(PickTool, _super);
         function PickTool(parent, inspector) {
-            var _this = _super.call(this, 'fa-mouse-pointer', parent, inspector, 'Select a mesh in the scene') || this;
+            var _this = _super.call(this, 'fa', 'fa-mouse-pointer', parent, inspector, 'Select a mesh in the scene') || this;
             _this._isActive = false;
             // Create handler
             _this._pickHandler = _this._pickMesh.bind(_this);
@@ -4619,7 +4619,7 @@ var INSPECTOR;
     var PopupTool = /** @class */ (function (_super) {
         __extends(PopupTool, _super);
         function PopupTool(parent, inspector) {
-            return _super.call(this, 'fa-external-link-alt', parent, inspector, 'Open the inspector in a popup') || this;
+            return _super.call(this, 'fas', 'fa-external-link-alt', parent, inspector, 'Open the inspector in a popup') || this;
         }
         // Action : refresh the whole panel
         PopupTool.prototype.action = function () {
@@ -4645,7 +4645,7 @@ var INSPECTOR;
     var RefreshTool = /** @class */ (function (_super) {
         __extends(RefreshTool, _super);
         function RefreshTool(parent, inspector) {
-            return _super.call(this, 'fa-sync', parent, inspector, 'Refresh the current tab') || this;
+            return _super.call(this, 'fa', 'fa-sync', parent, inspector, 'Refresh the current tab') || this;
         }
         // Action : refresh the whole panel
         RefreshTool.prototype.action = function () {
@@ -4671,7 +4671,7 @@ var INSPECTOR;
     var LabelTool = /** @class */ (function (_super) {
         __extends(LabelTool, _super);
         function LabelTool(parent, inspector) {
-            var _this = _super.call(this, 'fa-tags', parent, inspector, 'Display mesh names on the canvas') || this;
+            var _this = _super.call(this, 'fa', 'fa-tags', parent, inspector, 'Display mesh names on the canvas') || this;
             /** True if label are displayed, false otherwise */
             _this._isDisplayed = false;
             _this._advancedTexture = null;
@@ -4860,7 +4860,7 @@ var INSPECTOR;
     var DisposeTool = /** @class */ (function (_super) {
         __extends(DisposeTool, _super);
         function DisposeTool(parent, inspector) {
-            return _super.call(this, 'fa-times', parent, inspector, 'Close the inspector panel') || this;
+            return _super.call(this, 'fa', 'fa-times', parent, inspector, 'Close the inspector panel') || this;
         }
         // Action : refresh the whole panel
         DisposeTool.prototype.action = function () {
@@ -4886,7 +4886,7 @@ var INSPECTOR;
     var FullscreenTool = /** @class */ (function (_super) {
         __extends(FullscreenTool, _super);
         function FullscreenTool(parent, inspector) {
-            return _super.call(this, 'fa-expand', parent, inspector, 'Open the scene in fullscreen, press Esc to exit') || this;
+            return _super.call(this, 'fa', 'fa-expand', parent, inspector, 'Open the scene in fullscreen, press Esc to exit') || this;
         }
         // Action : refresh the whole panel
         FullscreenTool.prototype.action = function () {

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


+ 4 - 8
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -162,15 +162,9 @@ declare module BABYLON {
      * File loader for loading glTF files into a scene.
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
-        /**
-         * Factory function that creates a glTF 1.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV1: () => IGLTFLoader;
-        /**
-         * Factory function that creates a glTF 2.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
@@ -185,11 +179,13 @@ declare module BABYLON {
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         static IncrementalLoading: boolean;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         static HomogeneousCoordinates: boolean;
         /**

+ 2 - 0
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -546,11 +546,13 @@ var BABYLON;
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         GLTFFileLoader.IncrementalLoading = true;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;

+ 4 - 9
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -162,15 +162,9 @@ declare module BABYLON {
      * File loader for loading glTF files into a scene.
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
-        /**
-         * Factory function that creates a glTF 1.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV1: () => IGLTFLoader;
-        /**
-         * Factory function that creates a glTF 2.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
@@ -185,11 +179,13 @@ declare module BABYLON {
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         static IncrementalLoading: boolean;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         static HomogeneousCoordinates: boolean;
         /**
@@ -865,7 +861,6 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        /** @hidden */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         private _loadSpecularGlossinessPropertiesAsync(context, material, properties, babylonMaterial);
     }

+ 2 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -546,11 +546,13 @@ var BABYLON;
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         GLTFFileLoader.IncrementalLoading = true;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
@@ -2772,7 +2774,6 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                /** @hidden */
                 KHR_materials_pbrSpecularGlossiness.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                     var _this = this;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {

+ 4 - 9
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -162,15 +162,9 @@ declare module BABYLON {
      * File loader for loading glTF files into a scene.
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
-        /**
-         * Factory function that creates a glTF 1.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV1: () => IGLTFLoader;
-        /**
-         * Factory function that creates a glTF 2.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
@@ -185,11 +179,13 @@ declare module BABYLON {
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         static IncrementalLoading: boolean;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         static HomogeneousCoordinates: boolean;
         /**
@@ -1442,7 +1438,6 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        /** @hidden */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         private _loadSpecularGlossinessPropertiesAsync(context, material, properties, babylonMaterial);
     }

+ 2 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -546,11 +546,13 @@ var BABYLON;
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         GLTFFileLoader.IncrementalLoading = true;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
@@ -4988,7 +4990,6 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                /** @hidden */
                 KHR_materials_pbrSpecularGlossiness.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                     var _this = this;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {

+ 4 - 9
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -258,15 +258,9 @@ declare module BABYLON {
      * File loader for loading glTF files into a scene.
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
-        /**
-         * Factory function that creates a glTF 1.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV1: () => IGLTFLoader;
-        /**
-         * Factory function that creates a glTF 2.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
@@ -281,11 +275,13 @@ declare module BABYLON {
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         static IncrementalLoading: boolean;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         static HomogeneousCoordinates: boolean;
         /**
@@ -1538,7 +1534,6 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        /** @hidden */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         private _loadSpecularGlossinessPropertiesAsync(context, material, properties, babylonMaterial);
     }

+ 2 - 1
dist/preview release/loaders/babylonjs.loaders.js

@@ -1546,11 +1546,13 @@ var BABYLON;
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         GLTFFileLoader.IncrementalLoading = true;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
@@ -5925,7 +5927,6 @@ var BABYLON;
                     _this.name = NAME;
                     return _this;
                 }
-                /** @hidden */
                 KHR_materials_pbrSpecularGlossiness.prototype._loadMaterialAsync = function (context, material, mesh, babylonMesh, babylonDrawMode, assign) {
                     var _this = this;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {

+ 4 - 9
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -265,15 +265,9 @@ declare module BABYLON {
      * File loader for loading glTF files into a scene.
      */
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
-        /**
-         * Factory function that creates a glTF 1.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV1: () => IGLTFLoader;
-        /**
-         * Factory function that creates a glTF 2.0 loader
-         * @hidden
-         */
+        /** @hidden */
         static _CreateGLTFLoaderV2: () => IGLTFLoader;
         /**
          * Raised when the asset has been parsed
@@ -288,11 +282,13 @@ declare module BABYLON {
          * Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders.
          * Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled.
          * Defaults to true.
+         * @hidden
          */
         static IncrementalLoading: boolean;
         /**
          * Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters.
          * Defaults to false. See https://en.wikipedia.org/wiki/Homogeneous_coordinates.
+         * @hidden
          */
         static HomogeneousCoordinates: boolean;
         /**
@@ -1545,7 +1541,6 @@ declare module BABYLON.GLTF2.Extensions {
      */
     class KHR_materials_pbrSpecularGlossiness extends GLTFLoaderExtension {
         readonly name: string;
-        /** @hidden */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         private _loadSpecularGlossinessPropertiesAsync(context, material, properties, babylonMaterial);
     }

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


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.mixMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 0 - 4
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -40,10 +40,6 @@ declare module BABYLON {
 }
 
 
-/**
- * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
- * @hidden
- */
 declare module BABYLON.GLTF2 {
     /**
      * Converts Babylon Scene into glTF 2.0.

+ 0 - 4
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -47,10 +47,6 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFSerializer.js.map
 
 /// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
-/**
- * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
- * @hidden
- */
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;

+ 0 - 4
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -48,10 +48,6 @@ declare module BABYLON {
 }
 
 
-/**
- * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
- * @hidden
- */
 declare module BABYLON.GLTF2 {
     /**
      * Converts Babylon Scene into glTF 2.0.

+ 0 - 4
dist/preview release/serializers/babylonjs.serializers.js

@@ -197,10 +197,6 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFSerializer.js.map
 
 
-/**
- * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
- * @hidden
- */
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;

+ 0 - 4
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -55,10 +55,6 @@ declare module BABYLON {
 }
 
 
-/**
- * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
- * @hidden
- */
 declare module BABYLON.GLTF2 {
     /**
      * Converts Babylon Scene into glTF 2.0.

File diff suppressed because it is too large
+ 978 - 771
dist/preview release/viewer/babylon.viewer.d.ts


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


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


File diff suppressed because it is too large
+ 865 - 687
dist/preview release/viewer/babylon.viewer.module.d.ts


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

@@ -4,6 +4,8 @@
 
 - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style ([DevChris](https://github.com/yovanoc))
 - 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))
+- New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 
 ## Updates
 
@@ -24,6 +26,7 @@
 - Pointer drag behavior to enable drag and drop with mouse or 6dof controller on a mesh ([TrevorDev](https://github.com/TrevorDev))
 - Gizmo and gizmoManager class used to manipulate meshes in a scene, position, rotation, scale gizmos ([TrevorDev](https://github.com/TrevorDev))
 - Added a new `mesh.ignoreNonUniformScaling` to turn off non uniform scaling compensation ([Deltakosh](https://github.com/deltakosh))
+- AssetsManager tasks will only run when their state is INIT. It is now possible to remove a task from the assets manager ([RaananW](https://github.com/RaananW))
 
 ### glTF Loader
 
@@ -68,6 +71,7 @@
 - Ground material didn't take the default main color is no material definition was provided ([RaananW](https://github.com/RaananW))
 - Model configuration was not extended correctly if loaded more than one model ([RaananW](https://github.com/RaananW))
 - It wasn't possible to disable camera behavior(s) using configuration  [#4348](https://github.com/BabylonJS/Babylon.js/issues/4348) ([RaananW](https://github.com/RaananW))
+- Animation blending was always set to true, ignoring configuration [#4412](https://github.com/BabylonJS/Babylon.js/issues/4412) ([RaananW](https://github.com/RaananW))
 
 ## Breaking changes
 

+ 48 - 1
gui/src/3D/controls/container3D.ts

@@ -5,12 +5,41 @@ module BABYLON.GUI {
      * Class used to create containers for controls
      */
     export class Container3D extends Control3D {
+        private _blockLayout = false;
+
         /**
          * Gets the list of child controls
          */
         protected _children = new Array<Control3D>();
 
         /**
+         * Gets the list of child controls
+         */
+        public get children(): Array<Control3D> {
+            return this._children;
+        }
+
+        /**
+         * Gets or sets a boolean indicating if the layout must be blocked (default is false).
+         * This is helpful to optimize layout operation when adding multiple children in a row
+         */
+        public get blockLayout(): boolean {
+            return this._blockLayout;
+        }
+
+        public set blockLayout(value: boolean) {
+            if (this._blockLayout === value) {
+                return;
+            }
+
+            this._blockLayout = value;
+
+            if (!this._blockLayout) {
+                this._arrangeChildren();
+            }
+        }
+
+        /**
          * Creates a new container
          * @param name defines the container name
          */
@@ -50,7 +79,9 @@ module BABYLON.GUI {
                     control.node.parent = this.node;
                 }
 
-                this._arrangeChildren();
+                if (!this.blockLayout) {
+                    this._arrangeChildren();
+                }
             }
 
             return this;
@@ -101,5 +132,21 @@ module BABYLON.GUI {
 
             super.dispose();
         }
+
+        /** Control rotation will remain unchanged  */
+        public static readonly UNSET_ORIENTATION = 0;
+
+        /** Control will rotate to make it look at sphere central axis */
+        public static readonly FACEORIGIN_ORIENTATION = 1;
+
+        /** Control will rotate to make it look back at sphere central axis */
+        public static readonly FACEORIGINREVERSED_ORIENTATION = 2;
+
+        /** Control will rotate to look at z axis (0, 0, 1) */
+        public static readonly FACEFORWARD_ORIENTATION = 3;
+
+        /** Control will rotate to look at negative z axis (0, 0, -1) */
+        public static readonly FACEFORWARDREVERSED_ORIENTATION = 4;
+
     }
 }

+ 31 - 2
gui/src/3D/controls/control3D.ts

@@ -14,9 +14,38 @@ module BABYLON.GUI {
         private _isVisible = true;
     
         /** Gets or sets the control position  in world space */
-        public position = new Vector3(0, 0, 0);
+        public get position(): Vector3 {
+            if (!this._node) {
+                return Vector3.Zero();
+            }
+
+            return this._node.position;
+        }
+
+        public set position(value: Vector3) {
+            if (!this._node) {
+                return;
+            }
+
+            this._node.position = value;;
+        }
+
         /** Gets or sets the control scaling  in world space */
-        public scaling = new Vector3(1, 1, 1);
+        public get scaling(): Vector3 {
+            if (!this._node) {
+                return new Vector3(1, 1, 1);
+            }
+
+            return this._node.scaling;
+        }
+
+        public set scaling(value: Vector3) {
+            if (!this._node) {
+                return;
+            }
+
+            this._node.scaling = value;;
+        }
 
         /** Callback used to start pointer enter animation */
         public pointerEnterAnimation: () => void;

+ 67 - 0
gui/src/3D/controls/spherePanel.ts

@@ -0,0 +1,67 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Class used to create a container panel deployed on the surface of a sphere
+     */
+    export class SpherePanel extends VolumeBasedPanel {
+        private _radius = 4.0;
+
+        /**
+         * Gets or sets the radius of the sphere where to project controls (5 by default)
+         */
+        public get radius(): float {
+            return this._radius;
+        }
+
+        public set radius(value: float) {
+            if (this._radius === value) {
+                return;
+            }
+
+            this._radius = value;
+
+            Tools.SetImmediate(() => {
+                this._arrangeChildren();               
+            });
+        }              
+
+        protected _mapGridNode(control: Control3D, nodePosition: Vector3) {            
+            let newPos = this._sphericalMapping(nodePosition);
+            let mesh = control.mesh;
+
+            if (!mesh) {
+                return;
+            }
+
+            switch (this.orientation) {
+                case Container3D.FACEORIGIN_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(-newPos.x, -newPos.y, -newPos.z));
+                    break;
+                case Container3D.FACEORIGINREVERSED_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(newPos.x, newPos.y, newPos.z));
+                    break;
+                case Container3D.FACEFORWARD_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(0, 0, 1));
+                    break;
+                case Container3D.FACEFORWARDREVERSED_ORIENTATION:
+                    mesh.lookAt(new BABYLON.Vector3(0, 0, -1));
+                    break;
+            }
+            
+            control.position = newPos;
+        }
+
+        private _sphericalMapping(source: Vector3)
+        {
+            let newPos = new Vector3(0, 0, this._radius);
+
+            let xAngle = (source.y / this._radius);
+            let yAngle = -(source.x / this._radius);
+
+            Matrix.RotationYawPitchRollToRef(yAngle, xAngle, 0, Tmp.Matrix[0]);
+
+            return Vector3.TransformNormal(newPos, Tmp.Matrix[0]);
+        }
+    }
+}

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

@@ -35,8 +35,10 @@ module BABYLON.GUI {
          * Creates new StackPanel
          * @param isVertical 
          */
-        public constructor() {
+        public constructor(isVertical = false) {
             super();
+
+            this._isVertical = isVertical;
         }
 
         protected _arrangeChildren() {

+ 180 - 0
gui/src/3D/controls/volumeBasedPanel.ts

@@ -0,0 +1,180 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Abstract class used to create a container panel deployed on the surface of a volume
+     */
+    export abstract class VolumeBasedPanel extends Container3D {
+        private _columns = 10;
+        private _rows = 0;
+        private _rowThenColum = true;
+        
+        private _orientation = Container3D.FACEORIGIN_ORIENTATION;
+
+        /**
+         * Gets or sets the distance between elements
+         */
+        public margin = 0;        
+
+        /**
+         * Gets or sets the orientation to apply to all controls (BABYLON.Container3D.FaceOriginReversedOrientation by default)
+        * | Value | Type                                | Description |
+        * | ----- | ----------------------------------- | ----------- |
+        * | 0     | UNSET_ORIENTATION                   |  Control rotation will remain unchanged |
+        * | 1     | FACEORIGIN_ORIENTATION              |  Control will rotate to make it look at sphere central axis |
+        * | 2     | FACEORIGINREVERSED_ORIENTATION      |  Control will rotate to make it look back at sphere central axis |
+        * | 3     | FACEFORWARD_ORIENTATION             |  Control will rotate to look at z axis (0, 0, 1) |
+        * | 4     | FACEFORWARDREVERSED_ORIENTATION     |  Control will rotate to look at negative z axis (0, 0, -1) |
+         */
+        public get orientation(): number {
+            return this._orientation;
+        }
+
+        public set orientation(value: number) {
+            if (this._orientation === value) {
+                return;
+            }
+
+            this._orientation = value;
+
+            Tools.SetImmediate(() => {
+                this._arrangeChildren();               
+            });
+        }             
+
+        /**
+         * 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. 
+         */
+        public get columns(): int {
+            return this._columns;
+        }
+
+        public set columns(value: int) {
+            if (this._columns === value) {
+                return;
+            }
+
+            this._columns = value;
+            this._rowThenColum = true;
+
+            Tools.SetImmediate(() => {
+                this._arrangeChildren();               
+            });
+        }     
+        
+        /**
+         * Gets or sets a the number of rows requested. 
+         * The panel will automatically compute the number of columns based on number of child controls. 
+         */
+        public get rows(): int {
+            return this._rows;
+        }
+
+        public set rows(value: int) {
+            if (this._rows === value) {
+                return;
+            }
+
+            this._rows = value;
+            this._rowThenColum = false;
+
+            Tools.SetImmediate(() => {
+                this._arrangeChildren();               
+            });
+        }           
+
+        /**
+         * Creates new SpherePanel
+         */
+        public constructor() {
+            super();
+        }        
+
+        protected _arrangeChildren() {
+            let cellWidth = 0;
+            let cellHeight = 0;
+            let rows = 0;
+            let columns = 0;
+            let controlCount = 0;
+
+            let currentInverseWorld = Matrix.Invert(this.node!.computeWorldMatrix(true));
+
+            // Measure
+            for (var child of this._children) {
+                if (!child.mesh) {
+                    continue;
+                }
+
+                controlCount++;
+                child.mesh.computeWorldMatrix(true);
+                child.mesh.getWorldMatrix().multiplyToRef(currentInverseWorld, Tmp.Matrix[0]);
+
+                let boundingBox = child.mesh.getBoundingInfo().boundingBox;
+                let extendSize = Vector3.TransformNormal(boundingBox.extendSize, Tmp.Matrix[0]);
+
+                cellWidth = Math.max(cellWidth, extendSize.x * 2);
+                cellHeight = Math.max(cellHeight, extendSize.y * 2);
+            }
+
+            cellWidth += this.margin * 2;
+            cellHeight += this.margin * 2;
+
+            // Arrange
+            if (this._rowThenColum) {
+                columns = this._columns;
+                rows = Math.ceil(controlCount / this._columns);
+            } else {
+                rows = this._rows;
+                columns = Math.ceil(controlCount / this._rows);
+            }
+
+            let startOffsetX = (columns * 0.5) * cellWidth;
+            let startOffsetY = (rows * 0.5) * cellHeight;
+            let nodeGrid = [];
+            let cellCounter = 0;
+
+            if (this._rowThenColum) {
+                for (var r = 0; r < rows; r++)
+                {
+                    for (var c = 0; c < columns; c++)
+                    {
+                        nodeGrid.push(new Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                        cellCounter++;
+                        if (cellCounter > controlCount)
+                        {
+                            break;
+                        }
+                    }
+                }
+            } else {
+                for (var c = 0; c < columns; c++)
+                {
+                    for (var r = 0; r < rows; r++)
+                    {
+                        nodeGrid.push(new Vector3((c * cellWidth) - startOffsetX + cellWidth / 2, (r * cellHeight) - startOffsetY + cellHeight / 2, 0));
+                        cellCounter++;
+                        if (cellCounter > controlCount)
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            cellCounter = 0;
+            for (var child of this._children) {
+                if (!child.mesh) {
+                    continue;
+                }                
+
+                this._mapGridNode(child, nodeGrid[cellCounter]);
+
+                cellCounter++;
+            }
+        }
+
+        /** Child classes must implement this function to provide correct control positioning */
+        protected abstract _mapGridNode(control: Control3D, nodePosition: Vector3): void;
+    }
+}

+ 48 - 48
gui/src/3D/gui3DManager.ts

@@ -1,5 +1,6 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 
+
 module BABYLON.GUI {
     /**
      * Class used to manage 3D user interface
@@ -10,7 +11,8 @@ module BABYLON.GUI {
         private _sceneDisposeObserver: Nullable<Observer<Scene>>;
         private _utilityLayer: Nullable<UtilityLayerRenderer>;
         private _rootContainer: Container3D;
-        private _pointerObserver: Nullable<Observer<PointerInfoPre>>;
+        private _pointerObserver: Nullable<Observer<PointerInfo>>;
+        private _pointerOutObserver: Nullable<Observer<number>>;
         /** @hidden */
         public _lastPickedControl: Control3D;
         /** @hidden */
@@ -50,36 +52,20 @@ module BABYLON.GUI {
             })
 
             this._utilityLayer = new UtilityLayerRenderer(this._scene);
+            this._utilityLayer.onlyCheckPointerDownEvents = false;
 
             // Root
             this._rootContainer = new Container3D("RootContainer");
             this._rootContainer._host = this;
+            let utilityLayerScene = this._utilityLayer.utilityLayerScene;
             
             // Events
-            this._pointerObserver = this._scene.onPrePointerObservable.add((pi, state) => {
-
-                if (pi.skipOnPointerObservable) {
-                    return;
-                }
-
-                let pointerEvent = <PointerEvent>(pi.event);
-                if (this._scene.isPointerCaptured(pointerEvent.pointerId)) {
-                    return;
-                }
-
-                if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
-                    && pi.type !== BABYLON.PointerEventTypes.POINTERUP
-                    && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                    return;
-                }
-
-                let camera = this._scene.cameraToUseForPointers || this._scene.activeCamera;
-
-                if (!camera) {
-                    return;
-                }
+            this._pointerOutObserver = this._utilityLayer.onPointerOutObservable.add((pointerId) => {
+                this._handlePointerOut(pointerId, true);
+            });
 
-                pi.skipOnPointerObservable = this._doPicking(pi.type, pointerEvent, pi.ray)
+            this._pointerObserver = utilityLayerScene.onPointerObservable.add((pi, state) => {
+                this._doPicking(pi)
             });
 
             // Scene
@@ -88,31 +74,36 @@ module BABYLON.GUI {
             new BABYLON.HemisphericLight("hemi", Vector3.Up(), this._utilityLayer.utilityLayerScene);
         }
 
-        private _doPicking(type: number, pointerEvent: PointerEvent, ray?:Nullable<Ray>): boolean {
+        private _handlePointerOut(pointerId: number, isPointerUp: boolean) {
+            var previousControlOver = this._lastControlOver[pointerId];
+            if (previousControlOver) {
+                previousControlOver._onPointerOut(previousControlOver);
+                delete this._lastControlOver[pointerId];
+            }               
+            
+            if (isPointerUp) {
+                if (this._lastControlDown[pointerId]) {
+                    this._lastControlDown[pointerId].forcePointerUp();
+                    delete this._lastControlDown[pointerId];
+                }
+            }        
+            
+            this.onPickedPointChangedObservable.notifyObservers(null);
+        }
+
+        private _doPicking(pi: PointerInfo): boolean {
             if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
                 return false;                
             }
 
+            let pointerEvent = <PointerEvent>(pi.event);
+
             let pointerId = pointerEvent.pointerId || 0;
             let buttonIndex = pointerEvent.button;
-            var utilityScene = this._utilityLayer.utilityLayerScene;
-
-            let pickingInfo = ray ? utilityScene.pickWithRay(ray): utilityScene.pick(this._scene.pointerX, this._scene.pointerY);
+            
+            let pickingInfo = pi.pickInfo;
             if (!pickingInfo || !pickingInfo.hit) {
-                var previousControlOver = this._lastControlOver[pointerId];
-                if (previousControlOver) {
-                    previousControlOver._onPointerOut(previousControlOver);
-                    delete this._lastControlOver[pointerId];
-                }               
-                
-                if (type === BABYLON.PointerEventTypes.POINTERUP) {
-                    if (this._lastControlDown[pointerEvent.pointerId]) {
-                        this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
-                        delete this._lastControlDown[pointerEvent.pointerId];
-                    }
-                }        
-                
-                this.onPickedPointChangedObservable.notifyObservers(null);
+                this._handlePointerOut(pointerId, pi.type === BABYLON.PointerEventTypes.POINTERUP);
                 return false;
             }
 
@@ -121,9 +112,9 @@ module BABYLON.GUI {
                 this.onPickedPointChangedObservable.notifyObservers(pickingInfo.pickedPoint);
             }
 
-            if (!control._processObservables(type, pickingInfo.pickedPoint!, pointerId, buttonIndex)) {
+            if (!control._processObservables(pi.type, pickingInfo.pickedPoint!, pointerId, buttonIndex)) {
 
-                if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                if (pi.type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (this._lastControlOver[pointerId]) {
                         this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
                     }
@@ -132,7 +123,7 @@ module BABYLON.GUI {
                 }
             }
 
-            if (type === BABYLON.PointerEventTypes.POINTERUP) {
+            if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (this._lastControlDown[pointerEvent.pointerId]) {
                     this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
                     delete this._lastControlDown[pointerEvent.pointerId];
@@ -194,14 +185,23 @@ module BABYLON.GUI {
 
             this._sharedMaterials = {};
 
+            if (this._pointerOutObserver && this._utilityLayer) {
+                this._utilityLayer.onPointerOutObservable.remove(this._pointerOutObserver);
+                this._pointerOutObserver = null;
+            }
+
             this.onPickedPointChangedObservable.clear();
 
-            if (this._scene) {
+            let utilityLayerScene = this._utilityLayer ? this._utilityLayer.utilityLayerScene : null;
+
+            if (utilityLayerScene) {
                 if (this._pointerObserver) {
-                    this._scene.onPrePointerObservable.remove(this._pointerObserver);
+                    utilityLayerScene.onPointerObservable.remove(this._pointerObserver);
                     this._pointerObserver = null;
                 }
-                if (this._sceneDisposeObserver) {
+            }
+            if (this._scene) {
+                 if (this._sceneDisposeObserver) {
                     this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
                     this._sceneDisposeObserver = null;
                 }                

+ 2 - 4
materialsLibrary/src/mix/mix.fragment.fx

@@ -127,12 +127,10 @@ void main(void) {
 	vec4 diffuse7Color = texture2D(diffuse7Sampler, vTextureUV * diffuse7Infos);
 	vec4 diffuse8Color = texture2D(diffuse8Sampler, vTextureUV * diffuse8Infos);
 
-	diffuse5Color.rgb *= mixColor.r;
+	diffuse5Color.rgb = mix(finalMixColor.rgb, diffuse5Color.rgb, mixColor.r);
    	diffuse6Color.rgb = mix(diffuse5Color.rgb, diffuse6Color.rgb, mixColor.g);
    	diffuse7Color.rgb = mix(diffuse6Color.rgb, diffuse7Color.rgb, mixColor.b);
-	mixColor.rgb = mix(diffuse7Color.rgb, diffuse8Color.rgb, 1.0 - mixColor.a);
-
-	finalMixColor.rgb = mix(finalMixColor.rgb, mixColor.rgb, 0.5);
+	finalMixColor.rgb = mix(diffuse7Color.rgb, diffuse8Color.rgb, 1.0 - mixColor.a);
 #endif
 	
 #endif

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

@@ -60,6 +60,28 @@ module BABYLON {
                 this._inspector = null;
             }
         }
+        
+        /**
+        *
+        * Launch the debugLayer.
+        *
+        * initialTab:
+        * | Value | Tab Name |
+        * | --- | --- |
+        * | 0 | Scene |
+        * | 1 | Console |
+        * | 2 | Stats |
+        * | 3 | Textures |
+        * | 4 | Mesh |
+        * | 5 | Light |
+        * | 6 | Material |
+        * | 7 | GLTF |
+        * | 8 | GUI |
+        * | 9 | Physics |
+        * | 10 | Camera |
+        * | 11 | Audio |
+        *
+        */
 
         public show(config: {
             popup?: boolean,

+ 88 - 0
src/Helpers/babylon.photoDome.ts

@@ -0,0 +1,88 @@
+module BABYLON {
+    /**
+     * Display a 360 degree photo on an approximately spherical surface, useful for VR applications or skyboxes.
+     * As a subclass of Node, this allow parenting to the camera with different locations in the scene.
+     * This class achieves its effect with a Texture and a correctly configured BackgroundMaterial on an inverted sphere.
+     * Potential additions to this helper include zoom and and non-infinite distance rendering effects.
+     */
+    export class PhotoDome extends Node {
+
+        /**
+         * The texture being displayed on the sphere
+         */
+        protected _photoTexture: Texture;
+
+        /**
+         * The skybox material
+         */
+        protected _material: BackgroundMaterial;
+
+        /**
+         * The surface used for the skybox
+         */
+        protected _mesh: Mesh;
+
+        /**
+         * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
+         * Also see the options.resolution property.
+         */
+        public get fovMultiplier(): number {
+            return this._material.fovMultiplier;
+        }
+        public set fovMultiplier(value: number) {
+            this._material.fovMultiplier = value;
+        }
+
+        /**
+         * Create an instance of this class and pass through the parameters to the relevant classes, Texture, StandardMaterial, and Mesh.
+         * @param name Element's name, child elements will append suffixes for their own names.
+         * @param urlsOfPhoto define the url of the photo to display
+         * @param options An object containing optional or exposed sub element properties
+         */
+        constructor(name: string, urlOfPhoto: string, options: {
+            resolution?: number,
+            size?: number
+        }, scene: Scene) {
+            super(name, scene);
+
+            // set defaults and manage values
+            name = name || "photoDome";
+            options.resolution = (Math.abs(options.resolution as any) | 0) || 12;
+            options.size = Math.abs(options.size as any) || (scene.activeCamera ? scene.activeCamera.maxZ * 0.48 : 1000);
+
+            // create
+            let material = this._material = new BackgroundMaterial(name + "_material", scene);
+            let texture = this._photoTexture = new Texture(urlOfPhoto, scene);
+            this._mesh = MeshBuilder.CreateIcoSphere(name + "_mesh", {
+                flat: false, // saves on vertex data
+                radius: options.size,
+                subdivisions: options.resolution,
+                sideOrientation: Mesh.BACKSIDE // needs to be inside out
+            }, scene);
+
+            // configure material
+            texture.coordinatesMode = Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE; // matches orientation
+            texture.wrapV = Texture.CLAMP_ADDRESSMODE; // always clamp the up/down
+            material.reflectionTexture = this._photoTexture;
+            material.useEquirectangularFOV = true;
+            material.fovMultiplier = 1.0;
+
+            // configure mesh
+            this._mesh.material = material;
+            this._mesh.parent = this;
+        }
+
+        /**
+         * Releases resources associated with this node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
+         */
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
+            this._photoTexture.dispose();
+            this._mesh.dispose();
+            this._material.dispose();
+
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
+        }
+    }
+}

+ 2 - 7
src/Helpers/babylon.videoDome.ts

@@ -36,13 +36,8 @@ module BABYLON {
         /**
          * Create an instance of this class and pass through the parameters to the relevant classes, VideoTexture, StandardMaterial, and Mesh.
          * @param name Element's name, child elements will append suffixes for their own names.
-         * @param urlsOrVideo
-         * @param options An object containing optional or exposed sub element properties:
-         * @param options **resolution=12** Integer, lower resolutions have more artifacts at extreme fovs
-         * @param options **clickToPlay=false** Add a click to play listener to the video, does not prevent autoplay.
-         * @param options **autoPlay=true** Automatically attempt to being playing the video.
-         * @param options **loop=true** Automatically loop video on end.
-         * @param options **size=1000** Physical radius to create the dome at, defaults to approximately half the far clip plane.
+         * @param urlsOrVideo defines the url(s) or the video element to use
+         * @param options An object containing optional or exposed sub element properties
          */
         constructor(name: string, urlsOrVideo: string | string[] | HTMLVideoElement, options: {
             resolution?: number,

+ 5 - 0
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -1374,6 +1374,7 @@
             serializationObject.blurScale = this.blurScale;
             serializationObject.useKernelBlur = this.useKernelBlur;
             serializationObject.transparencyShadow = this._transparencyShadow;
+            serializationObject.frustumEdgeFalloff = this.frustumEdgeFalloff;
 
             serializationObject.bias = this.bias;
             serializationObject.normalBias = this.normalBias;
@@ -1486,6 +1487,10 @@
                 shadowGenerator.normalBias = parsedShadowGenerator.normalBias;
             }
 
+            if (parsedShadowGenerator.frustumEdgeFalloff !== undefined) {
+                shadowGenerator.frustumEdgeFalloff = parsedShadowGenerator.frustumEdgeFalloff;
+            }
+
             if (parsedShadowGenerator.darkness) {
                 shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
             }

+ 44 - 3
src/Rendering/babylon.utilityLayerRenderer.ts

@@ -3,6 +3,9 @@ module BABYLON {
      * Renders a layer on top of an existing scene
      */
     export class UtilityLayerRenderer implements IDisposable {
+        private _pointerCaptures: {[pointerId:number]: boolean} = {};
+        private _lastPointerEvents: {[pointerId:number]: number} = {};
+
         /** 
          * The scene that is rendered on top of the original scene
          */ 
@@ -16,6 +19,17 @@ module BABYLON {
          * If set to true, only pointer down onPointerObservable events will be blocked when picking is occluded by original scene
          */
         public onlyCheckPointerDownEvents = true;
+
+        /**
+         * If set to false, only pointerUp, pointerDown and pointerMove will be sent to the utilityLayerScene (false by default)
+         */
+        public processAllEvents = false;
+
+        /**
+         * Observable raised when the pointer move from the utility layer scene to the main scene
+         */
+        public onPointerOutObservable = new Observable<number>();
+
         private _afterRenderObserver:Nullable<Observer<Scene>>;
         private _sceneDisposeObserver:Nullable<Observer<Scene>>;
         private _originalPointerObserver:Nullable<Observer<PointerInfoPre>>;
@@ -30,7 +44,16 @@ module BABYLON {
 
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority
             this.utilityLayerScene.detachControl();
-            this._originalPointerObserver = originalScene.onPrePointerObservable.add((prePointerInfo, eventState)=>{
+            this._originalPointerObserver = originalScene.onPrePointerObservable.add((prePointerInfo, eventState) => {
+
+                if (!this.processAllEvents) {
+                    if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
+                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                        return;
+                    }
+                }
+
                 var utilityScenePick = prePointerInfo.ray ? this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
                 if(!prePointerInfo.ray && utilityScenePick){
                     prePointerInfo.ray = utilityScenePick.ray;
@@ -58,14 +81,32 @@ module BABYLON {
                     }
                 }else{
                     var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
+                    let pointerEvent = <PointerEvent>(prePointerInfo.event);
 
                     // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
                     if(originalScenePick && utilityScenePick){
-                        if(utilityScenePick.distance < originalScenePick.distance){
+                        if (utilityScenePick.distance === 0) {
+                            if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                                this._pointerCaptures[pointerEvent.pointerId] = true;
+                            } 
+                        }
+
+                        if (!this._pointerCaptures[pointerEvent.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)){
                             if(!prePointerInfo.skipOnPointerObservable){
                                 this.utilityLayerScene.onPointerObservable.notifyObservers(new PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick))
+                                this._lastPointerEvents[pointerEvent.pointerId] = pointerEvent.pointerType;
+                            }
+                            prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                        } else if (!this._pointerCaptures[pointerEvent.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
+                            // We need to send a last pointup to the utilityLayerScene to make sure animations can complete
+                            if (this._lastPointerEvents[pointerEvent.pointerId]) {
+                                this.onPointerOutObservable.notifyObservers(pointerEvent.pointerId);
+                                delete this._lastPointerEvents[pointerEvent.pointerId];
                             }
-                            prePointerInfo.skipOnPointerObservable = true;
+                        }
+
+                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && this._pointerCaptures[pointerEvent.pointerId]) {
+                            this._pointerCaptures[pointerEvent.pointerId] = false;
                         }
                     }
                 }

+ 24 - 2
src/Tools/babylon.assetsManager.ts

@@ -111,6 +111,14 @@ module BABYLON {
             throw new Error("runTask is not implemented");
         }
 
+        /**
+         * Reset will set the task state back to INIT, so the next load call of the assets manager will execute this task again.
+         * This can be used with failed tasks that have the reason for failure fixed.
+         */
+        public reset() {
+            this._taskState = AssetTaskState.INIT;
+        }
+
         private onErrorCallback(onError: (message?: string, exception?: any) => void, message?: string, exception?: any) {
             this._taskState = AssetTaskState.ERROR;
 
@@ -832,6 +840,18 @@ module BABYLON {
             return task;
         }
 
+        /**
+         * Remove a task from the assets manager.
+         * @param task the task to remove
+         */
+        public removeTask(task: AbstractAssetTask) {
+            let index = this._tasks.indexOf(task);
+
+            if (index > -1) {
+                this._tasks.splice(index, 1);
+            }
+        }
+
         private _decreaseWaitingTasksCount(task: AbstractAssetTask): void {
             this._waitingTasksCount--;
 
@@ -865,7 +885,7 @@ module BABYLON {
                     // Let's remove successfull tasks
                     var currentTasks = this._tasks.slice();
                     for (var task of currentTasks) {
-                        if (task.taskState === AssetTaskState.DONE) {                  
+                        if (task.taskState === AssetTaskState.DONE) {
                             let index = this._tasks.indexOf(task);
 
                             if (index > -1) {
@@ -949,7 +969,9 @@ module BABYLON {
 
             for (var index = 0; index < this._tasks.length; index++) {
                 var task = this._tasks[index];
-                this._runTask(task);
+                if (task.taskState === AssetTaskState.INIT) {
+                    this._runTask(task);
+                }
             }
 
             return this;