瀏覽代碼

Merge branch 'master' into ammoPlugin

Trevor Baron 6 年之前
父節點
當前提交
8d117eee2f
共有 70 個文件被更改,包括 21308 次插入20309 次删除
  1. 9731 9644
      Playground/babylon.d.txt
  2. 21 15
      Tools/Gulp/gulpfile.js
  3. 10189 10171
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 124 85
      dist/preview release/babylon.max.js
  6. 124 85
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 124 85
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/glTF2Interface/package.json
  10. 69 0
      dist/preview release/gui/babylon.gui.d.ts
  11. 1 1
      dist/preview release/gui/babylon.gui.js
  12. 1 1
      dist/preview release/gui/babylon.gui.min.js
  13. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  14. 143 0
      dist/preview release/gui/babylon.gui.module.d.ts
  15. 2 2
      dist/preview release/gui/package.json
  16. 12 12
      dist/preview release/inspector/babylon.inspector.bundle.js
  17. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  18. 5 5
      dist/preview release/inspector/package.json
  19. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  20. 11 6
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  21. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  22. 11 6
      dist/preview release/loaders/babylon.glTFFileLoader.js
  23. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  24. 11 6
      dist/preview release/loaders/babylonjs.loaders.js
  25. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  26. 3 3
      dist/preview release/loaders/package.json
  27. 2 2
      dist/preview release/materialsLibrary/package.json
  28. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  29. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  30. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  31. 2 2
      dist/preview release/postProcessesLibrary/package.json
  32. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  33. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  34. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  35. 3 3
      dist/preview release/serializers/package.json
  36. 3 3
      dist/preview release/viewer/babylon.viewer.js
  37. 6 6
      dist/preview release/viewer/babylon.viewer.max.js
  38. 7 0
      dist/preview release/what's new.md
  39. 1 1
      gui/src/2D/controls/container.ts
  40. 58 4
      gui/src/2D/controls/control.ts
  41. 1 0
      gui/src/2D/controls/index.ts
  42. 364 0
      gui/src/2D/controls/scrollViewer.ts
  43. 8 0
      inspector/src/components/actionTabs/actionTabs.scss
  44. 3 2
      inspector/src/components/actionTabs/actionTabsComponent.tsx
  45. 31 6
      inspector/src/components/actionTabs/lineContainerComponent.tsx
  46. 1 1
      inspector/src/components/actionTabs/lines/optionsLineComponent.tsx
  47. 7 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx
  48. 15 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/textBlockPropertyGridComponent.tsx
  49. 8 10
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  50. 3 3
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/axesViewerComponent.tsx
  51. 4 0
      inspector/src/components/embedHost/embedHost.scss
  52. 4 2
      inspector/src/components/embedHost/embedHostComponent.tsx
  53. 2 1
      inspector/src/components/headerComponent.tsx
  54. 4 0
      inspector/src/components/sceneExplorer/sceneExplorer.scss
  55. 3 2
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  56. 10 2
      inspector/src/inspector.ts
  57. 11 6
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  58. 1 1
      package.json
  59. 3 1
      readme.md
  60. 1 0
      src/Cameras/XR/babylon.webXRCamera.ts
  61. 0 1
      src/Cameras/babylon.arcRotateCamera.ts
  62. 97 78
      src/Debug/babylon.axesViewer.ts
  63. 5 1
      src/Debug/babylon.debugLayer.ts
  64. 1 1
      src/Engine/babylon.engine.ts
  65. 30 21
      src/Gizmos/babylon.axisDragGizmo.ts
  66. 1 1
      src/Helpers/babylon.sceneHelpers.ts
  67. 1 1
      src/Mesh/babylon.transformNode.ts
  68. 1 1
      src/Particles/babylon.solidParticleSystem.ts
  69. 3 2
      src/babylon.node.ts
  70. 5 0
      tests/validation/config.json

文件差異過大導致無法顯示
+ 9731 - 9644
Playground/babylon.d.txt


+ 21 - 15
Tools/Gulp/gulpfile.js

@@ -793,21 +793,27 @@ gulp.task("watch", gulp.series("srcTscWatch", function startWatch() {
                 //config.stats = "minimal";
                 tasks.push(webpackStream(wpconfig, webpack).pipe(gulp.dest(outputDirectory)))
             } else {
-                tasks.push(gulp.watch(library.files, { interval: interval }, function() {
-                    console.log(library.output);
-                    return buildExternalLibrary(library, config[module], true)
-                        .pipe(debug());
-                }));
-                tasks.push(gulp.watch(library.shaderFiles, { interval: interval }, function() {
-                    console.log(library.output);
-                    return buildExternalLibrary(library, config[module], true)
-                        .pipe(debug())
-                }));
-                tasks.push(gulp.watch(library.sassFiles, { interval: interval }, function() {
-                    console.log(library.output);
-                    return buildExternalLibrary(library, config[module], true)
-                        .pipe(debug())
-                }));
+                if (library.files) {
+                    tasks.push(gulp.watch(library.files, { interval: interval }, function() {
+                        console.log(library.output);
+                        return buildExternalLibrary(library, config[module], true)
+                            .pipe(debug());
+                    }));
+                }
+                if (library.shaderFiles) {
+                    tasks.push(gulp.watch(library.shaderFiles, { interval: interval }, function() {
+                        console.log(library.output);
+                        return buildExternalLibrary(library, config[module], true)
+                            .pipe(debug())
+                    }));
+                }
+                if (library.sassFiles) {
+                    tasks.push(gulp.watch(library.sassFiles, { interval: interval }, function() {
+                        console.log(library.output);
+                        return buildExternalLibrary(library, config[module], true)
+                            .pipe(debug())
+                    }));
+                }
             }
         });
     });

文件差異過大導致無法顯示
+ 10189 - 10171
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.js


+ 124 - 85
dist/preview release/babylon.max.js

@@ -12953,7 +12953,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.8";
+                return "4.0.0-alpha.10";
             },
             enumerable: true,
             configurable: true
@@ -18918,7 +18918,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19390,6 +19390,7 @@ var BABYLON;
          */
         Node.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) {
             if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
+            this._isDisposed = true;
             if (!doNotRecurse) {
                 var nodes = this.getDescendants(true);
                 for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
@@ -19420,7 +19421,6 @@ var BABYLON;
                 behavior.detach();
             }
             this._behaviors = [];
-            this._isDisposed = true;
         };
         /**
          * Parse animation range data from a serialization object and store them into a given node
@@ -20306,7 +20306,7 @@ var BABYLON;
             if (this._cache.pivotMatrixUpdated) {
                 return false;
             }
-            if (this.infiniteDistance !== this._cache.infiniteDistance) {
+            if (this.infiniteDistance) {
                 return false;
             }
             if (!this._cache.position.equals(this._position)) {
@@ -52719,7 +52719,10 @@ var BABYLON;
             var camLeft = this._rigCameras[0];
             var camRight = this._rigCameras[1];
             camLeft.beta = camRight.beta = this.beta;
-            camLeft.radius = camRight.radius = this.radius;
+            // This looks like being an issue in rig mode. Should be looked if
+            // further issues are found. but was modifying the view matrix twice
+            // Line below commented in order to fix http://www.html5gamedevs.com/topic/41454-confusion-about-camera-positions/
+            // camLeft.radius = camRight.radius = this.radius;
             switch (this.cameraRigMode) {
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
@@ -66602,68 +66605,81 @@ var BABYLON;
              * Creates a new AxesViewer
              * @param scene defines the hosting scene
              * @param scaleLines defines a number used to scale line length (1 by default)
+             * @param renderingGroupId defines a number used to set the renderingGroupId of the meshes (2 by default)
+             * @param xAxis defines the node hierarchy used to render the x-axis
+             * @param yAxis defines the node hierarchy used to render the y-axis
+             * @param zAxis defines the node hierarchy used to render the z-axis
              */
-            function AxesViewer(scene, scaleLines) {
+            function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                if (renderingGroupId === void 0) { renderingGroupId = 2; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
+                this._instanced = false;
                 /**
                  * Gets or sets a number used to scale line length
                  */
                 this.scaleLines = 1;
                 this.scaleLines = scaleLines;
-                var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                greenColoredMaterial.disableLighting = true;
-                greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
-                var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                redColoredMaterial.disableLighting = true;
-                redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
-                var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                blueColoredMaterial.disableLighting = true;
-                blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
-                this._xmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
-                this._ymesh = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
-                this._zmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
-                this._xmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._xmesh.scaling.scaleInPlace(4);
-                this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
-                this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
-                AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
+                if (!xAxis) {
+                    var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    redColoredMaterial.disableLighting = true;
+                    redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
+                    xAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
+                }
+                if (!yAxis) {
+                    var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    greenColoredMaterial.disableLighting = true;
+                    greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
+                    yAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
+                }
+                if (!zAxis) {
+                    var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    blueColoredMaterial.disableLighting = true;
+                    blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
+                    zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
+                }
+                this._xAxis = xAxis;
+                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis = yAxis;
+                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis = zAxis;
+                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                if (renderingGroupId != null) {
+                    AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._yAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._zAxis, renderingGroupId);
+                }
                 this.scene = scene;
                 this.update(new BABYLON.Vector3(), BABYLON.Vector3.Right(), BABYLON.Vector3.Up(), BABYLON.Vector3.Forward());
             }
-            Object.defineProperty(AxesViewer.prototype, "xAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "xAxis", {
+                /** Gets the node hierarchy used to render x-axis */
                 get: function () {
-                    return this._xmesh;
+                    return this._xAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "yAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "yAxis", {
+                /** Gets the node hierarchy used to render y-axis */
                 get: function () {
-                    return this._ymesh;
+                    return this._yAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "zAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "zAxis", {
+                /** Gets the node hierarchy used to render z-axis */
                 get: function () {
-                    return this._zmesh;
+                    return this._zAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            AxesViewer._recursiveChangeRenderingGroupId = function (mesh, id) {
-                mesh.renderingGroupId = id;
-                mesh.getChildMeshes().forEach(function (m) {
-                    AxesViewer._recursiveChangeRenderingGroupId(m, id);
-                });
-            };
             /**
              * Force the viewer to update
              * @param position defines the position of the viewer
@@ -66672,40 +66688,51 @@ var BABYLON;
              * @param zaxis defines the z axis of the viewer
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
-                if (this._xmesh) {
-                    this._xmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), xaxis);
-                    this._xmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), xaxis));
-                    this._xmesh.rotationQuaternion.normalize();
-                }
-                if (this._ymesh) {
-                    this._ymesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), yaxis);
-                    this._ymesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), yaxis));
-                    this._ymesh.rotationQuaternion.normalize();
-                }
-                if (this._zmesh) {
-                    this._zmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), zaxis);
-                    this._zmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), zaxis));
-                    this._zmesh.rotationQuaternion.normalize();
-                }
+                this._xAxis.position.copyFrom(position);
+                xaxis.scaleToRef(-1, this._tmpVector);
+                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis.position.copyFrom(position);
+                yaxis.scaleToRef(-1, this._tmpVector);
+                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis.position.copyFrom(position);
+                zaxis.scaleToRef(-1, this._tmpVector);
+                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+            };
+            /**
+             * Creates an instance of this axes viewer.
+             * @returns a new axes viewer with instanced meshes
+             */
+            AxesViewer.prototype.createInstance = function () {
+                var xAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._xAxis);
+                var yAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._yAxis);
+                var zAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._zAxis);
+                var axesViewer = new AxesViewer(this.scene, this.scaleLines, null, xAxis, yAxis, zAxis);
+                axesViewer._instanced = true;
+                return axesViewer;
             };
             /** Releases resources */
             AxesViewer.prototype.dispose = function () {
-                if (this._xmesh) {
-                    this._xmesh.dispose();
+                if (this._xAxis) {
+                    this._xAxis.dispose(false, !this._instanced);
+                    delete this._xAxis;
                 }
-                if (this._ymesh) {
-                    this._ymesh.dispose();
+                if (this._yAxis) {
+                    this._yAxis.dispose(false, !this._instanced);
+                    delete this._yAxis;
                 }
-                if (this._zmesh) {
-                    this._zmesh.dispose();
+                if (this._zAxis) {
+                    this._zAxis.dispose(false, !this._instanced);
+                    delete this._zAxis;
                 }
-                this._xmesh = null;
-                this._ymesh = null;
-                this._zmesh = null;
-                this.scene = null;
+                delete this.scene;
+            };
+            AxesViewer._SetRenderingGroupId = function (node, id) {
+                node.getChildMeshes().forEach(function (mesh) {
+                    mesh.renderingGroupId = id;
+                });
             };
             return AxesViewer;
         }());
@@ -67002,7 +67029,7 @@ var BABYLON;
          * @returns true if visible otherwise, false
          */
         DebugLayer.prototype.isVisible = function () {
-            return this.BJSINSPECTOR.Inspector.IsVisible;
+            return this.BJSINSPECTOR && this.BJSINSPECTOR.Inspector.IsVisible;
         };
         /**
          * Hide the inspector and close its window.
@@ -103617,7 +103644,7 @@ var BABYLON;
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
             arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
-            _this._rootMesh.addChild(arrow);
+            arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
             var tmpVector = new BABYLON.Vector3();
             var tmpSnapEvent = { snapDistance: 0 };
@@ -103673,22 +103700,32 @@ var BABYLON;
         }
         /** @hidden */
         AxisDragGizmo._CreateArrow = function (scene, material) {
-            var arrow = new BABYLON.AbstractMesh("", scene);
-            var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
-            var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
-            arrowTail.color = material.emissiveColor;
-            arrow.addChild(arrowMesh);
-            arrow.addChild(arrowTail);
+            var arrow = new BABYLON.TransformNode("arrow", scene);
+            var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
+            var line = BABYLON.MeshBuilder.CreateLines("line", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
+            line.color = material.emissiveColor;
+            cylinder.parent = arrow;
+            line.parent = arrow;
             // Position arrow pointing in its drag axis
-            arrowMesh.scaling.scaleInPlace(0.05);
-            arrowMesh.material = material;
-            arrowMesh.rotation.x = Math.PI / 2;
-            arrowMesh.position.z += 0.3;
-            arrowTail.scaling.scaleInPlace(0.26);
-            arrowTail.rotation.x = Math.PI / 2;
-            arrowTail.material = material;
+            cylinder.scaling.scaleInPlace(0.05);
+            cylinder.material = material;
+            cylinder.rotation.x = Math.PI / 2;
+            cylinder.position.z += 0.3;
+            line.scaling.scaleInPlace(0.26);
+            line.rotation.x = Math.PI / 2;
+            line.material = material;
             return arrow;
         };
+        /** @hidden */
+        AxisDragGizmo._CreateArrowInstance = function (scene, arrow) {
+            var instance = new BABYLON.TransformNode("arrow", scene);
+            for (var _i = 0, _a = arrow.getChildMeshes(); _i < _a.length; _i++) {
+                var mesh = _a[_i];
+                var childInstance = mesh.createInstance(mesh.name);
+                childInstance.parent = instance;
+            }
+            return instance;
+        };
         AxisDragGizmo.prototype._attachedMeshChanged = function (value) {
             if (this.dragBehavior) {
                 this.dragBehavior.enabled = value ? true : false;
@@ -109443,6 +109480,7 @@ var BABYLON;
                 newCamera.minZ = 0;
                 newCamera.parent = this;
                 newCamera.rotationQuaternion = new BABYLON.Quaternion();
+                newCamera.updateUpVectorFromRotation = true;
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -121227,6 +121265,7 @@ var BABYLON;
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
     BABYLON.Scene.prototype.createDefaultEnvironment = function (options) {

+ 124 - 85
dist/preview release/babylon.no-module.max.js

@@ -12920,7 +12920,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.8";
+                return "4.0.0-alpha.10";
             },
             enumerable: true,
             configurable: true
@@ -18885,7 +18885,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19357,6 +19357,7 @@ var BABYLON;
          */
         Node.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) {
             if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
+            this._isDisposed = true;
             if (!doNotRecurse) {
                 var nodes = this.getDescendants(true);
                 for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
@@ -19387,7 +19388,6 @@ var BABYLON;
                 behavior.detach();
             }
             this._behaviors = [];
-            this._isDisposed = true;
         };
         /**
          * Parse animation range data from a serialization object and store them into a given node
@@ -20273,7 +20273,7 @@ var BABYLON;
             if (this._cache.pivotMatrixUpdated) {
                 return false;
             }
-            if (this.infiniteDistance !== this._cache.infiniteDistance) {
+            if (this.infiniteDistance) {
                 return false;
             }
             if (!this._cache.position.equals(this._position)) {
@@ -52686,7 +52686,10 @@ var BABYLON;
             var camLeft = this._rigCameras[0];
             var camRight = this._rigCameras[1];
             camLeft.beta = camRight.beta = this.beta;
-            camLeft.radius = camRight.radius = this.radius;
+            // This looks like being an issue in rig mode. Should be looked if
+            // further issues are found. but was modifying the view matrix twice
+            // Line below commented in order to fix http://www.html5gamedevs.com/topic/41454-confusion-about-camera-positions/
+            // camLeft.radius = camRight.radius = this.radius;
             switch (this.cameraRigMode) {
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
@@ -66569,68 +66572,81 @@ var BABYLON;
              * Creates a new AxesViewer
              * @param scene defines the hosting scene
              * @param scaleLines defines a number used to scale line length (1 by default)
+             * @param renderingGroupId defines a number used to set the renderingGroupId of the meshes (2 by default)
+             * @param xAxis defines the node hierarchy used to render the x-axis
+             * @param yAxis defines the node hierarchy used to render the y-axis
+             * @param zAxis defines the node hierarchy used to render the z-axis
              */
-            function AxesViewer(scene, scaleLines) {
+            function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                if (renderingGroupId === void 0) { renderingGroupId = 2; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
+                this._instanced = false;
                 /**
                  * Gets or sets a number used to scale line length
                  */
                 this.scaleLines = 1;
                 this.scaleLines = scaleLines;
-                var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                greenColoredMaterial.disableLighting = true;
-                greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
-                var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                redColoredMaterial.disableLighting = true;
-                redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
-                var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                blueColoredMaterial.disableLighting = true;
-                blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
-                this._xmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
-                this._ymesh = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
-                this._zmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
-                this._xmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._xmesh.scaling.scaleInPlace(4);
-                this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
-                this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
-                AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
+                if (!xAxis) {
+                    var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    redColoredMaterial.disableLighting = true;
+                    redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
+                    xAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
+                }
+                if (!yAxis) {
+                    var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    greenColoredMaterial.disableLighting = true;
+                    greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
+                    yAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
+                }
+                if (!zAxis) {
+                    var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    blueColoredMaterial.disableLighting = true;
+                    blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
+                    zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
+                }
+                this._xAxis = xAxis;
+                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis = yAxis;
+                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis = zAxis;
+                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                if (renderingGroupId != null) {
+                    AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._yAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._zAxis, renderingGroupId);
+                }
                 this.scene = scene;
                 this.update(new BABYLON.Vector3(), BABYLON.Vector3.Right(), BABYLON.Vector3.Up(), BABYLON.Vector3.Forward());
             }
-            Object.defineProperty(AxesViewer.prototype, "xAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "xAxis", {
+                /** Gets the node hierarchy used to render x-axis */
                 get: function () {
-                    return this._xmesh;
+                    return this._xAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "yAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "yAxis", {
+                /** Gets the node hierarchy used to render y-axis */
                 get: function () {
-                    return this._ymesh;
+                    return this._yAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "zAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "zAxis", {
+                /** Gets the node hierarchy used to render z-axis */
                 get: function () {
-                    return this._zmesh;
+                    return this._zAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            AxesViewer._recursiveChangeRenderingGroupId = function (mesh, id) {
-                mesh.renderingGroupId = id;
-                mesh.getChildMeshes().forEach(function (m) {
-                    AxesViewer._recursiveChangeRenderingGroupId(m, id);
-                });
-            };
             /**
              * Force the viewer to update
              * @param position defines the position of the viewer
@@ -66639,40 +66655,51 @@ var BABYLON;
              * @param zaxis defines the z axis of the viewer
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
-                if (this._xmesh) {
-                    this._xmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), xaxis);
-                    this._xmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), xaxis));
-                    this._xmesh.rotationQuaternion.normalize();
-                }
-                if (this._ymesh) {
-                    this._ymesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), yaxis);
-                    this._ymesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), yaxis));
-                    this._ymesh.rotationQuaternion.normalize();
-                }
-                if (this._zmesh) {
-                    this._zmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), zaxis);
-                    this._zmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), zaxis));
-                    this._zmesh.rotationQuaternion.normalize();
-                }
+                this._xAxis.position.copyFrom(position);
+                xaxis.scaleToRef(-1, this._tmpVector);
+                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis.position.copyFrom(position);
+                yaxis.scaleToRef(-1, this._tmpVector);
+                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis.position.copyFrom(position);
+                zaxis.scaleToRef(-1, this._tmpVector);
+                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+            };
+            /**
+             * Creates an instance of this axes viewer.
+             * @returns a new axes viewer with instanced meshes
+             */
+            AxesViewer.prototype.createInstance = function () {
+                var xAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._xAxis);
+                var yAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._yAxis);
+                var zAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._zAxis);
+                var axesViewer = new AxesViewer(this.scene, this.scaleLines, null, xAxis, yAxis, zAxis);
+                axesViewer._instanced = true;
+                return axesViewer;
             };
             /** Releases resources */
             AxesViewer.prototype.dispose = function () {
-                if (this._xmesh) {
-                    this._xmesh.dispose();
+                if (this._xAxis) {
+                    this._xAxis.dispose(false, !this._instanced);
+                    delete this._xAxis;
                 }
-                if (this._ymesh) {
-                    this._ymesh.dispose();
+                if (this._yAxis) {
+                    this._yAxis.dispose(false, !this._instanced);
+                    delete this._yAxis;
                 }
-                if (this._zmesh) {
-                    this._zmesh.dispose();
+                if (this._zAxis) {
+                    this._zAxis.dispose(false, !this._instanced);
+                    delete this._zAxis;
                 }
-                this._xmesh = null;
-                this._ymesh = null;
-                this._zmesh = null;
-                this.scene = null;
+                delete this.scene;
+            };
+            AxesViewer._SetRenderingGroupId = function (node, id) {
+                node.getChildMeshes().forEach(function (mesh) {
+                    mesh.renderingGroupId = id;
+                });
             };
             return AxesViewer;
         }());
@@ -66969,7 +66996,7 @@ var BABYLON;
          * @returns true if visible otherwise, false
          */
         DebugLayer.prototype.isVisible = function () {
-            return this.BJSINSPECTOR.Inspector.IsVisible;
+            return this.BJSINSPECTOR && this.BJSINSPECTOR.Inspector.IsVisible;
         };
         /**
          * Hide the inspector and close its window.
@@ -103584,7 +103611,7 @@ var BABYLON;
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
             arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
-            _this._rootMesh.addChild(arrow);
+            arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
             var tmpVector = new BABYLON.Vector3();
             var tmpSnapEvent = { snapDistance: 0 };
@@ -103640,22 +103667,32 @@ var BABYLON;
         }
         /** @hidden */
         AxisDragGizmo._CreateArrow = function (scene, material) {
-            var arrow = new BABYLON.AbstractMesh("", scene);
-            var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
-            var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
-            arrowTail.color = material.emissiveColor;
-            arrow.addChild(arrowMesh);
-            arrow.addChild(arrowTail);
+            var arrow = new BABYLON.TransformNode("arrow", scene);
+            var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
+            var line = BABYLON.MeshBuilder.CreateLines("line", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
+            line.color = material.emissiveColor;
+            cylinder.parent = arrow;
+            line.parent = arrow;
             // Position arrow pointing in its drag axis
-            arrowMesh.scaling.scaleInPlace(0.05);
-            arrowMesh.material = material;
-            arrowMesh.rotation.x = Math.PI / 2;
-            arrowMesh.position.z += 0.3;
-            arrowTail.scaling.scaleInPlace(0.26);
-            arrowTail.rotation.x = Math.PI / 2;
-            arrowTail.material = material;
+            cylinder.scaling.scaleInPlace(0.05);
+            cylinder.material = material;
+            cylinder.rotation.x = Math.PI / 2;
+            cylinder.position.z += 0.3;
+            line.scaling.scaleInPlace(0.26);
+            line.rotation.x = Math.PI / 2;
+            line.material = material;
             return arrow;
         };
+        /** @hidden */
+        AxisDragGizmo._CreateArrowInstance = function (scene, arrow) {
+            var instance = new BABYLON.TransformNode("arrow", scene);
+            for (var _i = 0, _a = arrow.getChildMeshes(); _i < _a.length; _i++) {
+                var mesh = _a[_i];
+                var childInstance = mesh.createInstance(mesh.name);
+                childInstance.parent = instance;
+            }
+            return instance;
+        };
         AxisDragGizmo.prototype._attachedMeshChanged = function (value) {
             if (this.dragBehavior) {
                 this.dragBehavior.enabled = value ? true : false;
@@ -109410,6 +109447,7 @@ var BABYLON;
                 newCamera.minZ = 0;
                 newCamera.parent = this;
                 newCamera.rotationQuaternion = new BABYLON.Quaternion();
+                newCamera.updateUpVectorFromRotation = true;
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -121194,6 +121232,7 @@ var BABYLON;
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
     BABYLON.Scene.prototype.createDefaultEnvironment = function (options) {

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.worker.js


+ 124 - 85
dist/preview release/es6.js

@@ -12920,7 +12920,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.8";
+                return "4.0.0-alpha.10";
             },
             enumerable: true,
             configurable: true
@@ -18885,7 +18885,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19357,6 +19357,7 @@ var BABYLON;
          */
         Node.prototype.dispose = function (doNotRecurse, disposeMaterialAndTextures) {
             if (disposeMaterialAndTextures === void 0) { disposeMaterialAndTextures = false; }
+            this._isDisposed = true;
             if (!doNotRecurse) {
                 var nodes = this.getDescendants(true);
                 for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
@@ -19387,7 +19388,6 @@ var BABYLON;
                 behavior.detach();
             }
             this._behaviors = [];
-            this._isDisposed = true;
         };
         /**
          * Parse animation range data from a serialization object and store them into a given node
@@ -20273,7 +20273,7 @@ var BABYLON;
             if (this._cache.pivotMatrixUpdated) {
                 return false;
             }
-            if (this.infiniteDistance !== this._cache.infiniteDistance) {
+            if (this.infiniteDistance) {
                 return false;
             }
             if (!this._cache.position.equals(this._position)) {
@@ -52686,7 +52686,10 @@ var BABYLON;
             var camLeft = this._rigCameras[0];
             var camRight = this._rigCameras[1];
             camLeft.beta = camRight.beta = this.beta;
-            camLeft.radius = camRight.radius = this.radius;
+            // This looks like being an issue in rig mode. Should be looked if
+            // further issues are found. but was modifying the view matrix twice
+            // Line below commented in order to fix http://www.html5gamedevs.com/topic/41454-confusion-about-camera-positions/
+            // camLeft.radius = camRight.radius = this.radius;
             switch (this.cameraRigMode) {
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
@@ -66569,68 +66572,81 @@ var BABYLON;
              * Creates a new AxesViewer
              * @param scene defines the hosting scene
              * @param scaleLines defines a number used to scale line length (1 by default)
+             * @param renderingGroupId defines a number used to set the renderingGroupId of the meshes (2 by default)
+             * @param xAxis defines the node hierarchy used to render the x-axis
+             * @param yAxis defines the node hierarchy used to render the y-axis
+             * @param zAxis defines the node hierarchy used to render the z-axis
              */
-            function AxesViewer(scene, scaleLines) {
+            function AxesViewer(scene, scaleLines, renderingGroupId, xAxis, yAxis, zAxis) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                if (renderingGroupId === void 0) { renderingGroupId = 2; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
+                this._instanced = false;
                 /**
                  * Gets or sets a number used to scale line length
                  */
                 this.scaleLines = 1;
                 this.scaleLines = scaleLines;
-                var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                greenColoredMaterial.disableLighting = true;
-                greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
-                var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                redColoredMaterial.disableLighting = true;
-                redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
-                var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
-                blueColoredMaterial.disableLighting = true;
-                blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
-                this._xmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
-                this._ymesh = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
-                this._zmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
-                this._xmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._xmesh.scaling.scaleInPlace(4);
-                this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
-                this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
-                AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
-                AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
+                if (!xAxis) {
+                    var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    redColoredMaterial.disableLighting = true;
+                    redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
+                    xAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
+                }
+                if (!yAxis) {
+                    var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    greenColoredMaterial.disableLighting = true;
+                    greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
+                    yAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
+                }
+                if (!zAxis) {
+                    var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
+                    blueColoredMaterial.disableLighting = true;
+                    blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
+                    zAxis = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
+                }
+                this._xAxis = xAxis;
+                this._xAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis = yAxis;
+                this._yAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis = zAxis;
+                this._zAxis.rotationQuaternion = new BABYLON.Quaternion();
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                if (renderingGroupId != null) {
+                    AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._yAxis, renderingGroupId);
+                    AxesViewer._SetRenderingGroupId(this._zAxis, renderingGroupId);
+                }
                 this.scene = scene;
                 this.update(new BABYLON.Vector3(), BABYLON.Vector3.Right(), BABYLON.Vector3.Up(), BABYLON.Vector3.Forward());
             }
-            Object.defineProperty(AxesViewer.prototype, "xAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "xAxis", {
+                /** Gets the node hierarchy used to render x-axis */
                 get: function () {
-                    return this._xmesh;
+                    return this._xAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "yAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "yAxis", {
+                /** Gets the node hierarchy used to render y-axis */
                 get: function () {
-                    return this._ymesh;
+                    return this._yAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            Object.defineProperty(AxesViewer.prototype, "zAxisMesh", {
-                /** Gets the mesh used to render x-axis */
+            Object.defineProperty(AxesViewer.prototype, "zAxis", {
+                /** Gets the node hierarchy used to render z-axis */
                 get: function () {
-                    return this._zmesh;
+                    return this._zAxis;
                 },
                 enumerable: true,
                 configurable: true
             });
-            AxesViewer._recursiveChangeRenderingGroupId = function (mesh, id) {
-                mesh.renderingGroupId = id;
-                mesh.getChildMeshes().forEach(function (m) {
-                    AxesViewer._recursiveChangeRenderingGroupId(m, id);
-                });
-            };
             /**
              * Force the viewer to update
              * @param position defines the position of the viewer
@@ -66639,40 +66655,51 @@ var BABYLON;
              * @param zaxis defines the z axis of the viewer
              */
             AxesViewer.prototype.update = function (position, xaxis, yaxis, zaxis) {
-                if (this._xmesh) {
-                    this._xmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), xaxis);
-                    this._xmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), xaxis));
-                    this._xmesh.rotationQuaternion.normalize();
-                }
-                if (this._ymesh) {
-                    this._ymesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), yaxis);
-                    this._ymesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), yaxis));
-                    this._ymesh.rotationQuaternion.normalize();
-                }
-                if (this._zmesh) {
-                    this._zmesh.position.copyFrom(position);
-                    var cross = BABYLON.Vector3.Cross(BABYLON.Vector3.Forward(), zaxis);
-                    this._zmesh.rotationQuaternion.set(cross.x, cross.y, cross.z, 1 + BABYLON.Vector3.Dot(BABYLON.Vector3.Forward(), zaxis));
-                    this._zmesh.rotationQuaternion.normalize();
-                }
+                this._xAxis.position.copyFrom(position);
+                xaxis.scaleToRef(-1, this._tmpVector);
+                this._xAxis.setDirection(this._tmpVector);
+                this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._yAxis.position.copyFrom(position);
+                yaxis.scaleToRef(-1, this._tmpVector);
+                this._yAxis.setDirection(this._tmpVector);
+                this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+                this._zAxis.position.copyFrom(position);
+                zaxis.scaleToRef(-1, this._tmpVector);
+                this._zAxis.setDirection(this._tmpVector);
+                this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+            };
+            /**
+             * Creates an instance of this axes viewer.
+             * @returns a new axes viewer with instanced meshes
+             */
+            AxesViewer.prototype.createInstance = function () {
+                var xAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._xAxis);
+                var yAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._yAxis);
+                var zAxis = BABYLON.AxisDragGizmo._CreateArrowInstance(this.scene, this._zAxis);
+                var axesViewer = new AxesViewer(this.scene, this.scaleLines, null, xAxis, yAxis, zAxis);
+                axesViewer._instanced = true;
+                return axesViewer;
             };
             /** Releases resources */
             AxesViewer.prototype.dispose = function () {
-                if (this._xmesh) {
-                    this._xmesh.dispose();
+                if (this._xAxis) {
+                    this._xAxis.dispose(false, !this._instanced);
+                    delete this._xAxis;
                 }
-                if (this._ymesh) {
-                    this._ymesh.dispose();
+                if (this._yAxis) {
+                    this._yAxis.dispose(false, !this._instanced);
+                    delete this._yAxis;
                 }
-                if (this._zmesh) {
-                    this._zmesh.dispose();
+                if (this._zAxis) {
+                    this._zAxis.dispose(false, !this._instanced);
+                    delete this._zAxis;
                 }
-                this._xmesh = null;
-                this._ymesh = null;
-                this._zmesh = null;
-                this.scene = null;
+                delete this.scene;
+            };
+            AxesViewer._SetRenderingGroupId = function (node, id) {
+                node.getChildMeshes().forEach(function (mesh) {
+                    mesh.renderingGroupId = id;
+                });
             };
             return AxesViewer;
         }());
@@ -66969,7 +66996,7 @@ var BABYLON;
          * @returns true if visible otherwise, false
          */
         DebugLayer.prototype.isVisible = function () {
-            return this.BJSINSPECTOR.Inspector.IsVisible;
+            return this.BJSINSPECTOR && this.BJSINSPECTOR.Inspector.IsVisible;
         };
         /**
          * Hide the inspector and close its window.
@@ -103584,7 +103611,7 @@ var BABYLON;
             var arrow = AxisDragGizmo._CreateArrow(gizmoLayer.utilityLayerScene, coloredMaterial);
             arrow.lookAt(_this._rootMesh.position.subtract(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
-            _this._rootMesh.addChild(arrow);
+            arrow.parent = _this._rootMesh;
             var currentSnapDragDistance = 0;
             var tmpVector = new BABYLON.Vector3();
             var tmpSnapEvent = { snapDistance: 0 };
@@ -103640,22 +103667,32 @@ var BABYLON;
         }
         /** @hidden */
         AxisDragGizmo._CreateArrow = function (scene, material) {
-            var arrow = new BABYLON.AbstractMesh("", scene);
-            var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
-            var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
-            arrowTail.color = material.emissiveColor;
-            arrow.addChild(arrowMesh);
-            arrow.addChild(arrowTail);
+            var arrow = new BABYLON.TransformNode("arrow", scene);
+            var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
+            var line = BABYLON.MeshBuilder.CreateLines("line", { points: [new BABYLON.Vector3(0, 0, 0), new BABYLON.Vector3(0, 1.1, 0)] }, scene);
+            line.color = material.emissiveColor;
+            cylinder.parent = arrow;
+            line.parent = arrow;
             // Position arrow pointing in its drag axis
-            arrowMesh.scaling.scaleInPlace(0.05);
-            arrowMesh.material = material;
-            arrowMesh.rotation.x = Math.PI / 2;
-            arrowMesh.position.z += 0.3;
-            arrowTail.scaling.scaleInPlace(0.26);
-            arrowTail.rotation.x = Math.PI / 2;
-            arrowTail.material = material;
+            cylinder.scaling.scaleInPlace(0.05);
+            cylinder.material = material;
+            cylinder.rotation.x = Math.PI / 2;
+            cylinder.position.z += 0.3;
+            line.scaling.scaleInPlace(0.26);
+            line.rotation.x = Math.PI / 2;
+            line.material = material;
             return arrow;
         };
+        /** @hidden */
+        AxisDragGizmo._CreateArrowInstance = function (scene, arrow) {
+            var instance = new BABYLON.TransformNode("arrow", scene);
+            for (var _i = 0, _a = arrow.getChildMeshes(); _i < _a.length; _i++) {
+                var mesh = _a[_i];
+                var childInstance = mesh.createInstance(mesh.name);
+                childInstance.parent = instance;
+            }
+            return instance;
+        };
         AxisDragGizmo.prototype._attachedMeshChanged = function (value) {
             if (this.dragBehavior) {
                 this.dragBehavior.enabled = value ? true : false;
@@ -109410,6 +109447,7 @@ var BABYLON;
                 newCamera.minZ = 0;
                 newCamera.parent = this;
                 newCamera.rotationQuaternion = new BABYLON.Quaternion();
+                newCamera.updateUpVectorFromRotation = true;
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -121194,6 +121232,7 @@ var BABYLON;
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
     BABYLON.Scene.prototype.createDefaultEnvironment = function (options) {

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

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

+ 69 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -1956,6 +1956,75 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+        * Class used to hold a viewer window and sliders in a grid
+     */
+    export class ScrollViewer extends Rectangle {
+            /** name of ScrollViewer */
+            name?: string | undefined;
+            /**
+                * Adds windowContents to the grid view window
+                * @param windowContents the contents to add the grid view window
+                */
+            addToWindow(windowContents: Control): void;
+            /**
+                * Gets or sets a value indicating the padding to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingLeft: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingLeftInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingRight: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingRightInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingTop: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingTopInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingBottom: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingBottomInPixels: number;
+            /**
+             * Creates a new ScrollViewer
+             * @param name of ScrollViewer
+             */
+            constructor(
+            /** name of ScrollViewer */
+            name?: string | undefined);
+            /** Gets or sets the bar color */
+            barColor: string;
+            /** Gets or sets the bar color */
+            barBorderColor: string;
+            /** Gets or sets the bar background */
+            barBackground: string;
+            /** @hidden */
+            protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
         * Enum that determines the text-wrapping mode to use.
         */
     export enum TextWrapping {

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 143 - 0
dist/preview release/gui/babylon.gui.module.d.ts

@@ -40,6 +40,7 @@ declare module 'babylonjs-gui/2D/controls' {
     export * from "babylonjs-gui/2D/controls/radioButton";
     export * from "babylonjs-gui/2D/controls/stackPanel";
     export * from "babylonjs-gui/2D/controls/selector";
+    export * from "babylonjs-gui/2D/controls/scrollViewer";
     export * from "babylonjs-gui/2D/controls/textBlock";
     export * from "babylonjs-gui/2D/controls/virtualKeyboard";
     export * from "babylonjs-gui/2D/controls/rectangle";
@@ -2102,6 +2103,79 @@ declare module 'babylonjs-gui/2D/controls/selector' {
     }
 }
 
+declare module 'babylonjs-gui/2D/controls/scrollViewer' {
+    import { Measure } from "babylonjs-gui/2D/measure";
+    import { Rectangle } from "babylonjs-gui/2D/controls/rectangle";
+    import { Control } from "babylonjs-gui/2D/controls/control";
+    /**
+        * Class used to hold a viewer window and sliders in a grid
+     */
+    export class ScrollViewer extends Rectangle {
+            /** name of ScrollViewer */
+            name?: string | undefined;
+            /**
+                * Adds windowContents to the grid view window
+                * @param windowContents the contents to add the grid view window
+                */
+            addToWindow(windowContents: Control): void;
+            /**
+                * Gets or sets a value indicating the padding to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingLeft: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingLeftInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingRight: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingRightInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingTop: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingTopInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingBottom: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingBottomInPixels: number;
+            /**
+             * Creates a new ScrollViewer
+             * @param name of ScrollViewer
+             */
+            constructor(
+            /** name of ScrollViewer */
+            name?: string | undefined);
+            /** Gets or sets the bar color */
+            barColor: string;
+            /** Gets or sets the bar color */
+            barBorderColor: string;
+            /** Gets or sets the bar background */
+            barBackground: string;
+            /** @hidden */
+            protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
 declare module 'babylonjs-gui/2D/controls/textBlock' {
     import { Observable } from "babylonjs";
     import { Measure } from "babylonjs-gui/2D/measure";
@@ -5009,6 +5083,75 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+        * Class used to hold a viewer window and sliders in a grid
+     */
+    export class ScrollViewer extends Rectangle {
+            /** name of ScrollViewer */
+            name?: string | undefined;
+            /**
+                * Adds windowContents to the grid view window
+                * @param windowContents the contents to add the grid view window
+                */
+            addToWindow(windowContents: Control): void;
+            /**
+                * Gets or sets a value indicating the padding to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingLeft: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the left of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingLeftInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingRight: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the right of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingRightInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingTop: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the top of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingTopInPixels: number;
+            /**
+                * Gets or sets a value indicating the padding to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            paddingBottom: string | number;
+            /**
+                * Gets a value indicating the padding in pixels to use on the bottom of the viewer window
+                * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+                */
+            readonly paddingBottomInPixels: number;
+            /**
+             * Creates a new ScrollViewer
+             * @param name of ScrollViewer
+             */
+            constructor(
+            /** name of ScrollViewer */
+            name?: string | undefined);
+            /** Gets or sets the bar color */
+            barColor: string;
+            /** Gets or sets the bar color */
+            barBorderColor: string;
+            /** Gets or sets the bar background */
+            barBackground: string;
+            /** @hidden */
+            protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+declare module BABYLON.GUI {
+    /**
         * Enum that determines the text-wrapping mode to use.
         */
     export enum TextWrapping {

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 12 - 12
dist/preview release/inspector/babylon.inspector.bundle.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,10 +28,10 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8",
-        "babylonjs-gui": "4.0.0-alpha.8",
-        "babylonjs-loaders": "4.0.0-alpha.8",
-        "babylonjs-serializers": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10",
+        "babylonjs-gui": "4.0.0-alpha.10",
+        "babylonjs-loaders": "4.0.0-alpha.10",
+        "babylonjs-serializers": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 11 - 6
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2206,13 +2206,18 @@ var BABYLON;
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                var textureURL = null;
-                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
-                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
-                    textureURL = this._uniqueRootUrl + image.uri;
+                var url = null;
+                if (image.uri) {
+                    if (BABYLON.Tools.IsBase64(image.uri)) {
+                        url = image.uri;
+                    }
+                    else if (this.babylonScene.getEngine().textureFormatInUse) {
+                        // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                        url = this._rootUrl + image.uri;
+                    }
                 }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(url, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -2222,7 +2227,7 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
-                if (!textureURL) {
+                if (!url) {
                     promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
                         var name = image.uri || _this._fileName + "#image" + image.index;
                         var dataUrl = "data:" + _this._uniqueRootUrl + name;

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 11 - 6
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -4414,13 +4414,18 @@ var BABYLON;
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                var textureURL = null;
-                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
-                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
-                    textureURL = this._uniqueRootUrl + image.uri;
+                var url = null;
+                if (image.uri) {
+                    if (BABYLON.Tools.IsBase64(image.uri)) {
+                        url = image.uri;
+                    }
+                    else if (this.babylonScene.getEngine().textureFormatInUse) {
+                        // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                        url = this._rootUrl + image.uri;
+                    }
                 }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(url, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -4430,7 +4435,7 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
-                if (!textureURL) {
+                if (!url) {
                     promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
                         var name = image.uri || _this._fileName + "#image" + image.index;
                         var dataUrl = "data:" + _this._uniqueRootUrl + name;

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 11 - 6
dist/preview release/loaders/babylonjs.loaders.js

@@ -5476,13 +5476,18 @@ var BABYLON;
                 var sampler = (texture.sampler == undefined ? GLTFLoader._DefaultSampler : ArrayItem.Get(context + "/sampler", this.gltf.samplers, texture.sampler));
                 var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
-                var textureURL = null;
-                if (image.uri && !BABYLON.Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
-                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
-                    textureURL = this._uniqueRootUrl + image.uri;
+                var url = null;
+                if (image.uri) {
+                    if (BABYLON.Tools.IsBase64(image.uri)) {
+                        url = image.uri;
+                    }
+                    else if (this.babylonScene.getEngine().textureFormatInUse) {
+                        // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                        url = this._rootUrl + image.uri;
+                    }
                 }
                 var deferred = new BABYLON.Deferred();
-                var babylonTexture = new BABYLON.Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(url, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, function () {
                     if (!_this._disposed) {
                         deferred.resolve();
                     }
@@ -5492,7 +5497,7 @@ var BABYLON;
                     }
                 });
                 promises.push(deferred.promise);
-                if (!textureURL) {
+                if (!url) {
                     promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
                         var name = image.uri || _this._fileName + "#image" + image.index;
                         var dataUrl = "data:" + _this._uniqueRootUrl + name;

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

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

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "4.0.0-alpha.8",
+    "version": "4.0.0-alpha.10",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,8 +27,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.8",
-        "babylonjs-gltf2interface": "4.0.0-alpha.8"
+        "babylonjs": "4.0.0-alpha.10",
+        "babylonjs-gltf2interface": "4.0.0-alpha.10"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 3 - 3
dist/preview release/viewer/babylon.viewer.js


文件差異過大導致無法顯示
+ 6 - 6
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -18,6 +18,7 @@
 - GUI:
   - Added new [ImageBasedSlider](http://doc.babylonjs.com/how_to/gui#imagebasedslider) to let users customize sliders using images ([Deltakosh](https://github.com/deltakosh))
   - Added support for clipboard events to let users perform `cut`, `copy` and `paste` events ([Saket Saurabh](https://github.com/ssaket))
+  - Added new [ScrollViewer](https://doc.babylonjs.com/how_to/scrollviewer) for larger containers to be viewed using Sliders ([JohnK](https://github.com/BabylonJSGuide/))
 
 ## Updates
 
@@ -71,6 +72,7 @@
 - Added support for linking a bone to a transform node ([bghgary](https://github.com/bghgary))
 - Factored out `setDirection` function from `lookAt` for transform node ([bghgary](https://github.com/bghgary))
 - Added support for AmmoJS physics plugin ([TrevorDev](https://github.com/TrevorDev))
+- Add support for setting renderingGroupId and creating instances to `AxesViewer` ([bghgary](https://github.com/bghgary))
 
 ### glTF Loader
 
@@ -103,6 +105,7 @@
 - PointerDragBahavior using Mesh as base type, causing type-checking problems with AbstractMesh ([Poolminer](https://github.com/Poolminer/))
 - TransformNode lookAt not working in world space when node's parent has rotation ([TrevorDev](https://github.com/TrevorDev))
 - MakeNotPickableAndWrapInBoundingBox had unexpected behavior when input had scaling of 0 on an axis ([TrevorDev](https://github.com/TrevorDev))
+- Fixed an issue with loading base64 encoded images in the glTF loader ([bghgary](https://github.com/bghgary))
 
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
@@ -116,6 +119,9 @@
 - Added a `DeepImmutable<T>` type to specifiy that a referenced object should be considered recursively immutable, meaning that all its properties are `readonly` and that if a property is a reference to an object, this object is also recursively immutable. ([barroij](https://github.com/barroij))
 - Fixed `VideoTexture` poster property when autoplay is turned off.
 - Fixed position and rotation of plane mesh created by MeshBuilder.CreatePlane when specifying a source plane ([sable](https://github.com/thscott), [bghgary](https://github.com/bghgary))
+- Fixed inspector dynamic loading ([Sebavan](https://github.com/Sebavan))
+- Fixed infiniteDistance not working anymore ([Sebavan](https://github.com/Sebavan))
+- Fixed bug in SolidParticle BoundingSphere update within the SolidParticleSystem ([barroij](https://github.com/barroij))
 
 ### Viewer
 
@@ -151,3 +157,4 @@
   - _Note: The root node is still a `Mesh` object and is still the first in the returned list of meshes_
   - `TransformNode` objects are excluded from the returned list of meshes when importing mesh
   - `TransformNode` objects do not raise `onMeshLoaded` events
+- `xAxisMesh`, `yAxisMesh`, and `zAxisMesh` of `AxesViewer` was renamed to `xAxis`, `yAxis`, and `zAxis` respectively and now return a `TransformNode` to represent the parent node of the cylinder and line of the arrow ([bghgary](https://github.com/bghgary))

+ 1 - 1
gui/src/2D/controls/container.ts

@@ -13,7 +13,7 @@ export class Container extends Control {
     /** @hidden */
     protected _measureForChildren = Measure.Empty();
     /** @hidden */
-    protected _background: string;
+    protected _background = "";
     /** @hidden */
     protected _adaptWidthToChildren = false;
     /** @hidden */

+ 58 - 4
gui/src/2D/controls/control.ts

@@ -107,14 +107,65 @@ export class Control {
     /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
     public clipChildren = true;
 
+    private _shadowOffsetX = 0;
     /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
-    public shadowOffsetX = 0;
+    public get shadowOffsetX() {
+        return this._shadowOffsetX;
+    }
+
+    public set shadowOffsetX(value: number) {
+        if (this._shadowOffsetX === value) {
+            return;
+        }
+
+        this._shadowOffsetX = value;
+        this._markAsDirty();
+    }
+
+    private _shadowOffsetY = 0;
     /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */
-    public shadowOffsetY = 0;
+    public get shadowOffsetY() {
+        return this._shadowOffsetY;
+    }
+
+    public set shadowOffsetY(value: number) {
+        if (this._shadowOffsetY === value) {
+            return;
+        }
+
+        this._shadowOffsetY = value;
+        this._markAsDirty();
+    }
+
+    private _shadowBlur = 0;
     /** Gets or sets a value indicating the amount of blur to use to render the shadow */
-    public shadowBlur = 0;
+    public get shadowBlur() {
+        return this._shadowBlur;
+    }
+
+    public set shadowBlur(value: number) {
+        if (this._shadowBlur === value) {
+            return;
+        }
+
+        this._shadowBlur = value;
+        this._markAsDirty();
+    }
+
+    private _shadowColor = 'black';
     /** Gets or sets a value indicating the color of the shadow (black by default ie. "#000") */
-    public shadowColor = '#000';
+    public get shadowColor() {
+        return this._shadowColor;
+    }
+
+    public set shadowColor(value: string) {
+        if (this._shadowColor === value) {
+            return;
+        }
+
+        this._shadowColor = value;
+        this._markAsDirty();
+    }
 
     /** Gets or sets the cursor to use when the control is hovered */
     public hoverCursor = "";
@@ -396,6 +447,9 @@ export class Control {
 
     /** Gets or set font family */
     public get fontFamily(): string {
+        if (!this._fontSet) {
+            return "";
+        }
         return this._fontFamily;
     }
 

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

@@ -13,6 +13,7 @@ export * from "./multiLine";
 export * from "./radioButton";
 export * from "./stackPanel";
 export * from "./selector";
+export * from "./scrollViewer";
 export * from "./textBlock";
 export * from "./virtualKeyboard";
 export * from "./rectangle";

+ 364 - 0
gui/src/2D/controls/scrollViewer.ts

@@ -0,0 +1,364 @@
+import { Measure } from "../measure";
+import { Rectangle } from "./rectangle";
+import { Grid } from "./grid";
+import { Control } from "./control";
+import { Slider } from "./slider";
+import { ValueAndUnit } from "../valueAndUnit";
+import { Container } from "./container";
+import { TextBlock } from "./textBlock";
+
+/**
+ * Class used to hold a viewer window and sliders in a grid
+*/
+export class ScrollViewer extends Rectangle {
+    private _grid: Grid;
+    private _horizontalBarSpace: Rectangle;
+    private _verticalBarSpace: Rectangle;
+    private _dragSpace: Rectangle;
+    private _horizontalBar: Slider;
+    private _verticalBar: Slider;
+    private _barColor: string = "grey";
+    private _barBorderColor: string = "#444444";
+    private _barBackground: string = "white";
+    private _scrollGridWidth: number = 30;
+    private _scrollGridHeight: number = 30;
+    private _widthScale: number;
+    private _heightScale: number;
+    private _endLeft: number;
+    private _endTop: number;
+    private _window: Container;
+    private _windowContents: Control;
+
+    /**
+     * Adds windowContents to the grid view window
+     * @param windowContents the contents to add the grid view window
+     */
+    public addToWindow(windowContents: Control): void {
+        this._window.removeControl(this._windowContents);
+        this._windowContents.dispose();
+        this._windowContents = windowContents;
+        if (windowContents.typeName === "TextBlock") {
+            this._updateTextBlock(windowContents);
+        }
+        else {
+            this._updateScroller(windowContents);
+        }
+        this._window.addControl(windowContents);
+    }
+
+    /**
+     * Gets or sets a value indicating the padding to use on the left of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingLeft(): string | number {
+        return this._windowContents.paddingLeft;
+    }
+
+    /**
+     * Gets a value indicating the padding in pixels to use on the left of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingLeftInPixels(): number {
+        return this._windowContents.paddingLeftInPixels;
+    }
+
+    public set paddingLeft(value: string | number) {
+        this._windowContents.paddingLeft = value;
+    }
+
+    /**
+     * Gets or sets a value indicating the padding to use on the right of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingRight(): string | number {
+        return this._windowContents.paddingRight;
+    }
+
+    /**
+     * Gets a value indicating the padding in pixels to use on the right of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingRightInPixels(): number {
+        return this._windowContents.paddingRightInPixels;
+    }
+
+    public set paddingRight(value: string | number) {
+        this._windowContents.paddingRight = value;
+    }
+
+    /**
+     * Gets or sets a value indicating the padding to use on the top of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingTop(): string | number {
+        return this._windowContents.paddingTop;
+    }
+
+    /**
+     * Gets a value indicating the padding in pixels to use on the top of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingTopInPixels(): number {
+        return this._windowContents.paddingTopInPixels;
+    }
+
+    public set paddingTop(value: string | number) {
+        this._windowContents.paddingTop = value;
+    }
+
+    /**
+     * Gets or sets a value indicating the padding to use on the bottom of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingBottom(): string | number {
+        return this._windowContents.paddingBottom;
+    }
+
+    /**
+     * Gets a value indicating the padding in pixels to use on the bottom of the viewer window
+     * @see http://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public get paddingBottomInPixels(): number {
+        return this._windowContents.paddingBottomInPixels;
+    }
+
+    public set paddingBottom(value: string | number) {
+        this._windowContents.paddingBottom = value;
+    }
+
+    /**
+    * Creates a new ScrollViewer
+    * @param name of ScrollViewer
+    */
+    constructor(
+        /** name of ScrollViewer */
+        public name?: string) {
+        super(name);
+
+        this.onDirtyObservable.add(() => {
+            this._horizontalBarSpace.color = this.color;
+            this._verticalBarSpace.color = this.color;
+            this._dragSpace.color = this.color;
+            this._updateScroller(this._windowContents);
+            if (this._windowContents.typeName === "TextBlock") {
+                this._updateTextBlock(this._windowContents);
+            }
+        });
+
+        this._grid = new Grid();
+        this._horizontalBar = new Slider();
+        this._verticalBar = new Slider();
+
+        this._window = new Container();
+        this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this._window.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+
+        this._windowContents = new Control();
+        this._window.addControl(this._windowContents);
+
+        this._width = new ValueAndUnit(0.25, ValueAndUnit.UNITMODE_PERCENTAGE, false);
+        this._height = new ValueAndUnit(0.25, ValueAndUnit.UNITMODE_PERCENTAGE, false);
+        this._background = "black";
+
+        this.fontSize = "16px";
+
+        this._grid.addColumnDefinition(1, true);
+        this._grid.addColumnDefinition(this._scrollGridWidth, true);
+        this._grid.addRowDefinition(1, true);
+        this._grid.addRowDefinition(this._scrollGridHeight, true);
+
+        this.addControl(this._grid);
+        this._grid.addControl(this._window, 0, 0);
+
+        this._verticalBar.paddingLeft = 0;
+        this._verticalBar.width = "25px";
+        this._verticalBar.value = 0;
+        this._verticalBar.maximum = 100;
+        this._verticalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        this._verticalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+        this._verticalBar.left = 0.05;
+        this._verticalBar.isThumbClamped = true;
+        this._verticalBar.color = "grey";
+        this._verticalBar.borderColor = "#444444";
+        this._verticalBar.background = "white";
+        this._verticalBar.isVertical = true;
+        this._verticalBar.rotation = Math.PI;
+
+        this._verticalBarSpace = new Rectangle();
+        this._verticalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this._verticalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+        this._verticalBarSpace.color = this.color;
+        this._verticalBarSpace.thickness = 1;
+        this._grid.addControl(this._verticalBarSpace, 0, 1);
+        this._verticalBarSpace.addControl(this._verticalBar);
+
+        this._verticalBar.onValueChangedObservable.add((value) => {
+            this._window.top = value * this._endTop / 100 + "px";
+        });
+
+        this._horizontalBar.paddingLeft = 0;
+        this._horizontalBar.height = "25px";
+        this._horizontalBar.value = 0;
+        this._horizontalBar.maximum = 100;
+        this._horizontalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        this._horizontalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+        this._horizontalBar.left = 0.05;
+        this._horizontalBar.isThumbClamped = true;
+        this._horizontalBar.color = "grey";
+        this._horizontalBar.borderColor = "#444444";
+        this._horizontalBar.background = "white";
+
+        this._horizontalBarSpace = new Rectangle();
+        this._horizontalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
+        this._horizontalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
+        this._horizontalBarSpace.color = this.color;
+        this._horizontalBarSpace.thickness = 1;
+        this._grid.addControl(this._horizontalBarSpace, 1, 0);
+        this._horizontalBarSpace.addControl(this._horizontalBar);
+
+        this._horizontalBar.onValueChangedObservable.add((value) => {
+            this._window.left = value * this._endLeft / 100 + "px";
+        });
+
+        this._dragSpace = new Rectangle();
+        this._dragSpace.color = this.color;
+        this._dragSpace.thickness = 2;
+        this._dragSpace.background = this._barColor;
+        this._grid.addControl(this._dragSpace, 1, 1);
+    }
+
+    /** Gets or sets the bar color */
+    public get barColor(): string {
+        return this._barColor;
+    }
+
+    public set barColor(color: string) {
+        if (this._barColor === color) {
+            return;
+        }
+
+        this._barColor = color;
+        this._horizontalBar.color = color;
+        this._verticalBar.color = color;
+        this._dragSpace.background = color;
+    }
+
+    /** Gets or sets the bar color */
+    public get barBorderColor(): string {
+        return this._barBorderColor;
+    }
+
+    public set barBorderColor(color: string) {
+        if (this._barBorderColor === color) {
+            return;
+        }
+
+        this._barBorderColor = color;
+        this._horizontalBar.borderColor = color;
+        this._verticalBar.borderColor = color;
+    }
+
+    /** Gets or sets the bar background */
+    public get barBackground(): string {
+        return this._barBackground;
+    }
+
+    public set barBackground(color: string) {
+        if (this._barBackground === color) {
+            return;
+        }
+
+        this._barBackground = color;
+        this._horizontalBar.background = color;
+        this._verticalBar.background = color;
+    }
+
+    /** @hidden */
+    protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        super._additionalProcessing(parentMeasure, context);
+
+        let viewerWidth = this._width.getValueInPixel(this._host, parentMeasure.width);
+        let viewerHeight = this._height.getValueInPixel(this._host, parentMeasure.height);
+
+        let innerWidth = viewerWidth - this._scrollGridWidth - 2 * this.thickness;
+        let innerHeight = viewerHeight  - this._scrollGridHeight - 2 * this.thickness;
+        this._horizontalBar.width = (innerWidth * 0.8) + "px";
+        this._verticalBar.height = (innerHeight * 0.8) + "px";
+
+        this._grid.setColumnDefinition(0, innerWidth, true);
+        this._grid.setRowDefinition(0, innerHeight, true);
+    }
+
+    /** @hidden */
+    private _updateScroller(windowContents: Control): void {
+
+        let windowContentsWidth: number  = parseFloat(windowContents.width.toString());
+        if (windowContents._width.unit === 0) {
+            this._widthScale = windowContentsWidth / 100;
+            windowContentsWidth = this._host.getSize().width * this._widthScale;
+            windowContents.width = windowContentsWidth + "px";
+        }
+
+        let windowContentsHeight: number  = parseFloat(windowContents.height.toString());
+        if (windowContents._height.unit === 0) {
+            this._heightScale = windowContentsHeight / 100;
+            windowContentsHeight = this._host.getSize().height * this._heightScale;
+            windowContents.height = this._host.getSize().height * this._heightScale + "px";
+        }
+
+        this._window.width = windowContents.width;
+        this._window.height = windowContents.height;
+        this._windowContents.width = windowContents.width;
+        this._windowContents.height = windowContents.height;
+
+        let viewerWidth = this._width.getValueInPixel(this._host, this._host.getSize().width);
+        let viewerHeight = this._height.getValueInPixel(this._host, this._host.getSize().height);
+
+        let innerWidth = viewerWidth - this._scrollGridWidth - 2 * this.thickness;
+        let innerHeight = viewerHeight  - this._scrollGridHeight - 2 * this.thickness;
+
+        if (windowContentsWidth <= innerWidth) {
+            this._grid.setRowDefinition(0, viewerHeight - 2 * this.thickness , true);
+            this._grid.setRowDefinition(1, 0, true);
+            this._horizontalBar.isVisible = false;
+        }
+        else {
+            this._grid.setRowDefinition(0, innerHeight, true);
+            this._grid.setRowDefinition(1, this._scrollGridHeight, true);
+            this._horizontalBar.isVisible = true;
+        }
+
+        if (windowContentsHeight < innerHeight) {
+            this._grid.setColumnDefinition(0, viewerWidth - 2 * this.thickness, true);
+            this._grid.setColumnDefinition(1, 0, true);
+            this._verticalBar.isVisible = false;
+        }
+        else {
+            this._grid.setColumnDefinition(0, innerWidth, true);
+            this._grid.setColumnDefinition(1, this._scrollGridWidth, true);
+            this._verticalBar.isVisible = true;
+        }
+
+        this._endLeft = innerWidth - windowContentsWidth;
+        this._endTop = innerHeight - windowContentsHeight;
+    }
+
+    /** @hidden */
+    private _updateTextBlock(windowContents: Control): void {
+        let viewerWidth = this._width.getValueInPixel(this._host, this._host.getSize().width);
+        let innerWidth = viewerWidth - this._scrollGridWidth - 2 * this.thickness;
+
+        windowContents.width = innerWidth + "px";
+
+        this._window.width = windowContents.width;
+        this._windowContents.width = windowContents.width;
+
+        (<TextBlock>windowContents).onLinesReadyObservable.add(() => {
+            let windowContentsHeight = (this.fontOffset.height) * (<TextBlock>windowContents).lines.length + windowContents.paddingTopInPixels + windowContents.paddingBottomInPixels;
+            windowContents.height = windowContentsHeight + "px";
+            this._window.height = windowContents.height;
+            this._windowContents.height = windowContents.height;
+            this._updateScroller(windowContents);
+        });
+    }
+}

+ 8 - 0
inspector/src/components/actionTabs/actionTabs.scss

@@ -5,6 +5,10 @@
     bottom: 0px;
 }
 
+#__resizable_base__ {
+    display: none;
+}
+
 #actionTabs {
     background: #333333;
     height: 100%;
@@ -729,6 +733,10 @@
                         display: flex;
                         align-items: center;   
                         margin-right: 5px;
+
+                        select {
+                            width: 115px;
+                        }
                     }                    
                 }                   
 

+ 3 - 2
inspector/src/components/actionTabs/actionTabsComponent.tsx

@@ -17,6 +17,7 @@ interface IActionTabsComponentProps {
     noCommands?: boolean,
     noHeader?: boolean,
     noExpand?: boolean,
+    noClose?: boolean,
     popupMode?: boolean,
     onPopup?: () => void,
     onClose?: () => void,
@@ -101,7 +102,7 @@ export class ActionTabsComponent extends React.Component<IActionTabsComponentPro
                 <div id="actionTabs">
                     {
                         !this.props.noHeader &&
-                        <HeaderComponent title="INSPECTOR" handleBack={true} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                        <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
                     }
                     {this.renderContent()}
                 </div>
@@ -124,7 +125,7 @@ export class ActionTabsComponent extends React.Component<IActionTabsComponentPro
             <Resizable id="actionTabs" minWidth={300} maxWidth={600} size={{ height: "100%" }} minHeight="100%" enable={{ top: false, right: false, bottom: false, left: true, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }}>
                 {
                     !this.props.noHeader &&
-                    <HeaderComponent title="INSPECTOR" handleBack={true} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                    <HeaderComponent title="INSPECTOR" handleBack={true} noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
                 }
                 {this.renderContent()}
             </Resizable>

+ 31 - 6
inspector/src/components/actionTabs/lineContainerComponent.tsx

@@ -9,14 +9,26 @@ interface ILineContainerComponentProps {
 }
 
 export class LineContainerComponent extends React.Component<ILineContainerComponentProps, { isExpanded: boolean }> {
+    private static _InMemoryStorage: {[key: string]: boolean};
+    
     constructor(props: ILineContainerComponentProps) {
         super(props);
 
         let initialState: boolean;
 
-        if (typeof (Storage) !== "undefined" && localStorage.getItem(this.props.title) !== null) {
-            initialState = localStorage.getItem(this.props.title) === "true";
-        } else {
+        try
+        { 
+            if (LineContainerComponent._InMemoryStorage && LineContainerComponent._InMemoryStorage[this.props.title] !== undefined) {
+                initialState = LineContainerComponent._InMemoryStorage[this.props.title];
+            } else if (typeof (Storage) !== "undefined" && localStorage.getItem(this.props.title) !== null) {
+                initialState = localStorage.getItem(this.props.title) === "true";
+            } else {
+                initialState = !this.props.closed;
+            }   
+        }
+        catch (e) {
+            LineContainerComponent._InMemoryStorage = {};
+            LineContainerComponent._InMemoryStorage[this.props.title] = !this.props.closed
             initialState = !this.props.closed;
         }
 
@@ -24,10 +36,23 @@ export class LineContainerComponent extends React.Component<ILineContainerCompon
     }
 
     switchExpandedState(): void {
-        if (typeof (Storage) !== "undefined") {
-            localStorage.setItem(this.props.title, !this.state.isExpanded ? "true" : "false");
+        const newState = !this.state.isExpanded;
+        
+        try
+        { 
+            if (LineContainerComponent._InMemoryStorage) {
+                LineContainerComponent._InMemoryStorage[this.props.title] = newState;
+            } else if (typeof (Storage) !== "undefined") {
+                localStorage.setItem(this.props.title, newState ? "true" : "false");
+            }
+        }
+        catch (e) {
+            LineContainerComponent._InMemoryStorage = {};
+            LineContainerComponent._InMemoryStorage[this.props.title] = newState;
         }
-        this.setState({ isExpanded: !this.state.isExpanded });
+        
+        this.setState({ isExpanded: newState });
+
     }
 
     renderHeader() {

+ 1 - 1
inspector/src/components/actionTabs/lines/optionsLineComponent.tsx

@@ -33,7 +33,7 @@ export class OptionsLineComponent extends React.Component<IOptionsLineComponentP
         }
 
         const newValue = nextProps.target[nextProps.propertyName];
-        if (newValue !== nextState.value) {
+        if (newValue != null && newValue !== nextState.value) {
             nextState.value = newValue;
             return true;
         }

+ 7 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx

@@ -46,7 +46,7 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
                         <TextInputLineComponent lockObject={this.props.lockObject} label="Color" target={control} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                     {
-                        (control as any).background &&
+                        (control as any).background !== undefined &&
                         <TextInputLineComponent lockObject={this.props.lockObject} label="Background" target={control} propertyName="background" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                 </LineContainerComponent>
@@ -77,6 +77,12 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Weight" target={control} propertyName="fontWeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Style" target={control} propertyName="fontStyle" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
+                <LineContainerComponent title="SHADOWS" closed={true}>
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Color" target={control} propertyName="shadowColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Offset X" target={control} propertyName="shadowOffsetX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Offset Y" target={control} propertyName="shadowOffsetY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Blur" target={control} propertyName="shadowBlur" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
             </div>
         );
     }

+ 15 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/textBlockPropertyGridComponent.tsx

@@ -7,6 +7,8 @@ import { LineContainerComponent } from "../../../lineContainerComponent";
 import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
 import { LockObject } from "../lockObject";
 import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
 
 interface ITextBlockPropertyGridComponentProps {
     textBlock: TextBlock,
@@ -34,6 +36,12 @@ export class TextBlockPropertyGridComponent extends React.Component<ITextBlockPr
             { label: "Center", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER },
         ];
 
+        var wrappingOptions = [
+            { label: "Clip", value: BABYLON.GUI.TextWrapping.Clip },
+            { label: "Ellipsis", value: BABYLON.GUI.TextWrapping.Ellipsis },
+            { label: "Word wrap", value: BABYLON.GUI.TextWrapping.WordWrap },
+        ];
+
         return (
             <div className="pane">
                 <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={textBlock} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
@@ -41,6 +49,13 @@ export class TextBlockPropertyGridComponent extends React.Component<ITextBlockPr
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Text" target={textBlock} propertyName="text" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <OptionsLineComponent label="Horizontal text alignment" options={horizontalOptions} target={textBlock} propertyName="textHorizontalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <OptionsLineComponent label="Vertical text alignment" options={verticalOptions} target={textBlock} propertyName="textVerticalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Resize to fit" target={textBlock} propertyName="resizeToFit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <OptionsLineComponent label="Wrapping" options={wrappingOptions} target={textBlock} propertyName="textWrapping" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Line spacing" target={textBlock} propertyName="lineSpacing" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+                <LineContainerComponent title="OUTLINE">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Outline width" target={textBlock} propertyName="outlineWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Outline color" target={textBlock} propertyName="outlineColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
             </div>
         );

+ 8 - 10
inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx

@@ -7,7 +7,6 @@ import { TextLineComponent } from "../../../lines/textLineComponent";
 import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { TextureLineComponent } from "../../../lines/textureLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
-import { AdvancedDynamicTexture } from "babylonjs-gui";
 import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
 import { FileButtonLineComponent } from "../../../lines/fileButtonLineComponent";
 import { LockObject } from "../lockObject";
@@ -47,7 +46,6 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
 
     render() {
         const texture = this.props.texture;
-        const adtTexture = texture instanceof AdvancedDynamicTexture ? texture as AdvancedDynamicTexture : null;
 
         var samplingMode = [
             { label: "Nearest", value: BABYLON.Texture.NEAREST_NEAREST },
@@ -76,14 +74,14 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                     }
                 </LineContainerComponent>
                 {
-                    adtTexture &&
+                    (texture as any).rootContainer &&
                     <LineContainerComponent title="ADVANCED TEXTURE PROPERTIES">
-                        <SliderLineComponent label="Render scale" minimum={0.1} maximum={5} step={0.1} target={adtTexture} propertyName="renderScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <CheckBoxLineComponent label="Premultiply alpha" target={adtTexture} propertyName="premulAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal width" target={adtTexture} propertyName="idealWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal height" target={adtTexture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <CheckBoxLineComponent label="Use smallest ideal" target={adtTexture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <CheckBoxLineComponent label="Render at ideal size" target={adtTexture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <SliderLineComponent label="Render scale" minimum={0.1} maximum={5} step={0.1} target={texture} propertyName="renderScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <CheckBoxLineComponent label="Premultiply alpha" target={texture} propertyName="premulAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal width" target={texture} propertyName="idealWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal height" target={texture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <CheckBoxLineComponent label="Use smallest ideal" target={texture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <CheckBoxLineComponent label="Render at ideal size" target={texture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
                 }
                 <LineContainerComponent title="TRANSFORM">
@@ -92,7 +90,7 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                         <div>
                             <FloatLineComponent lockObject={this.props.lockObject} label="U offset" target={texture} propertyName="uOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <FloatLineComponent lockObject={this.props.lockObject} label="V offset" target={texture} propertyName="vOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent lockObject={this.props.lockObject} label="V scale" target={texture} propertyName="uScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <FloatLineComponent lockObject={this.props.lockObject} label="U scale" target={texture} propertyName="uScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <FloatLineComponent lockObject={this.props.lockObject} label="V scale" target={texture} propertyName="vScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <FloatLineComponent lockObject={this.props.lockObject} label="U angle" target={texture} propertyName="uAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <FloatLineComponent lockObject={this.props.lockObject} label="V angle" target={texture} propertyName="vAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 3 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/axesViewerComponent.tsx

@@ -40,9 +40,9 @@ export class AxesViewerComponent extends React.Component<IAxisViewerComponentPro
         const y = new BABYLON.Vector3(0, 1, 0);
         const z = new BABYLON.Vector3(0, 0, 1);
 
-        viewer.xAxisMesh!.reservedDataStore = { hidden: true };
-        viewer.yAxisMesh!.reservedDataStore = { hidden: true };
-        viewer.zAxisMesh!.reservedDataStore = { hidden: true };
+        viewer.xAxis.reservedDataStore = { hidden: true };
+        viewer.yAxis.reservedDataStore = { hidden: true };
+        viewer.zAxis.reservedDataStore = { hidden: true };
 
         node.reservedDataStore.onBeforeRenderObserver = scene.onBeforeRenderObservable.add(() => {
             let matrix = node.getWorldMatrix();

+ 4 - 0
inspector/src/components/embedHost/embedHost.scss

@@ -5,6 +5,10 @@
     bottom: 0px;
 }
 
+#__resizable_base__ {
+    display: none;
+}
+
 #embed {
     background: #333333;
     height: 100%;

+ 4 - 2
inspector/src/components/embedHost/embedHostComponent.tsx

@@ -14,6 +14,8 @@ interface IEmbedHostComponentProps {
     scene: Scene,
     globalState: GlobalState,
     popupMode: boolean,
+    noClose?: boolean,
+    noExpand?: boolean,
     onClose: () => void,
     onPopup: () => void
 }
@@ -80,7 +82,7 @@ export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps
         if (this.props.popupMode) {
             return (
                 <div id="embed">
-                    <HeaderComponent title="INSPECTOR" handleBack={true} onClose={() => this.props.onClose()} onPopup={() => this.props.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                    <HeaderComponent title="INSPECTOR" noClose={this.props.noClose} noExpand={this.props.noExpand} handleBack={true} onClose={() => this.props.onClose()} onPopup={() => this.props.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
                     {this.renderContent()}
                 </div>
             );
@@ -100,7 +102,7 @@ export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps
 
         return (
             <Resizable id="embed" minWidth={300} maxWidth={600} size={{ height: "100%" }} minHeight="100%" enable={{ top: false, right: false, bottom: false, left: true, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }}>
-                <HeaderComponent title="INSPECTOR" handleBack={true} onClose={() => this.props.onClose()} onPopup={() => this.props.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
+                <HeaderComponent title="INSPECTOR" noClose={this.props.noClose} noExpand={this.props.noExpand} handleBack={true} onClose={() => this.props.onClose()} onPopup={() => this.props.onPopup()} onSelectionChangedObservable={this.props.globalState.onSelectionChangedObservable} />
                 {this.renderContent()}
             </Resizable>
         );

+ 2 - 1
inspector/src/components/headerComponent.tsx

@@ -7,6 +7,7 @@ export interface IHeaderComponentProps {
     title: string,
     handleBack?: boolean,
     noExpand?: boolean,
+    noClose?: boolean,
     noCommands?: boolean,
     onPopup: () => void,
     onClose: () => void,
@@ -89,7 +90,7 @@ export class HeaderComponent extends React.Component<IHeaderComponentProps, { is
                         </div>
                     }
                     {
-                        !this.props.noCommands &&
+                        !this.props.noCommands && !this.props.noClose &&
                         <div className="close" onClick={() => this.props.onClose()}>
                             <FontAwesomeIcon icon={faTimes} />
                         </div>

+ 4 - 0
inspector/src/components/sceneExplorer/sceneExplorer.scss

@@ -9,6 +9,10 @@
     }
 }
 
+#__resizable_base__ {
+    display: none;
+}
+
 #sceneExplorer {
     background: #333333;
     height: 100%;

+ 3 - 2
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -33,6 +33,7 @@ interface ISceneExplorerComponentProps {
     noCommands?: boolean,
     noHeader?: boolean,
     noExpand?: boolean,
+    noClose?: boolean,
     extensibilityGroups?: IExplorerExtensibilityGroup[],
     globalState: GlobalState,
     popupMode?: boolean,
@@ -234,7 +235,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                 <div id="sceneExplorer">
                     {
                         !this.props.noHeader &&
-                        <HeaderComponent title="SCENE EXPLORER" noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} />
+                        <HeaderComponent title="SCENE EXPLORER" noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} />
                     }
                     {this.renderContent()}
                 </div>
@@ -273,7 +274,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
             <Resizable tabIndex={-1} id="sceneExplorer" ref="sceneExplorer" size={{ height: "100%" }} minWidth={300} maxWidth={600} minHeight="100%" enable={{ top: false, right: true, bottom: false, left: false, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }} onKeyDown={keyEvent => this.processKeys(keyEvent)}>
                 {
                     !this.props.noHeader &&
-                    <HeaderComponent title="SCENE EXPLORER" noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} />
+                    <HeaderComponent title="SCENE EXPLORER" noClose={this.props.noClose} noExpand={this.props.noExpand} noCommands={this.props.noCommands} onClose={() => this.onClose()} onPopup={() => this.onPopup()} />
                 }
                 {this.renderContent()}
             </Resizable>

+ 10 - 2
inspector/src/inspector.ts

@@ -69,6 +69,7 @@ export class Inspector {
                 embedMode: options.embedMode,
                 handleResize: options.handleResize,
                 enablePopup: options.enablePopup,
+                enableClose: options.enablePopup,
                 explorerExtensibility: options.explorerExtensibility
             };
         }
@@ -98,6 +99,7 @@ export class Inspector {
             const sceneExplorerElement = React.createElement(SceneExplorerComponent, {
                 scene, globalState: this._GlobalState,
                 extensibilityGroups: options.explorerExtensibility,
+                noClose: !options.enableClose,
                 noExpand: !options.enablePopup, popupMode: options.popup, onPopup: () => {
                     ReactDOM.unmountComponentAtNode(this._SceneExplorerHost!);
 
@@ -152,7 +154,9 @@ export class Inspector {
         if (this._ActionTabsHost) {
             this._OpenedPane++;
             const actionTabsElement = React.createElement(ActionTabsComponent, {
-                globalState: this._GlobalState, scene: scene, noExpand: !options.enablePopup, popupMode: options.popup, onPopup: () => {
+                globalState: this._GlobalState, scene: scene,
+                noClose: !options.enableClose,
+                noExpand: !options.enablePopup, popupMode: options.popup, onPopup: () => {
                     ReactDOM.unmountComponentAtNode(this._ActionTabsHost!);
 
                     this._RemoveElementFromDOM(this._ActionTabsHost);
@@ -205,7 +209,10 @@ export class Inspector {
         if (this._EmbedHost) {
             this._OpenedPane++;
             const embedHostElement = React.createElement(EmbedHostComponent, {
-                globalState: this._GlobalState, scene: scene, popupMode: options.popup, onPopup: () => {
+                globalState: this._GlobalState, scene: scene,
+                    noExpand: !options.enablePopup,
+                    noClose: !options.enableClose,
+                    popupMode: options.popup, onPopup: () => {
                     ReactDOM.unmountComponentAtNode(this._EmbedHost!);
 
                     if (options.popup) {
@@ -300,6 +307,7 @@ export class Inspector {
             showExplorer: true,
             showInspector: true,
             embedMode: false,
+            enableClose: true,
             handleResize: true,
             enablePopup: true,
             ...userOptions

+ 11 - 6
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1702,14 +1702,19 @@ module BABYLON.GLTF2 {
             const samplerData = this._loadSampler(`/samplers/${sampler.index}`, sampler);
 
             const image = ArrayItem.Get(`${context}/source`, this.gltf.images, texture.source);
-            let textureURL: Nullable<string> = null;
-            if (image.uri && !Tools.IsBase64(image.uri) && this.babylonScene.getEngine().textureFormatInUse) {
-                // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
-                textureURL = this._uniqueRootUrl + image.uri;
+            let url: Nullable<string> = null;
+            if (image.uri) {
+                if (Tools.IsBase64(image.uri)) {
+                    url = image.uri;
+                }
+                else if (this.babylonScene.getEngine().textureFormatInUse) {
+                    // If an image uri and a texture format is set like (eg. KTX) load from url instead of blob to support texture format and fallback
+                    url = this._rootUrl + image.uri;
+                }
             }
 
             const deferred = new Deferred<void>();
-            const babylonTexture = new Texture(textureURL, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, () => {
+            const babylonTexture = new Texture(url, this.babylonScene, samplerData.noMipMaps, false, samplerData.samplingMode, () => {
                 if (!this._disposed) {
                     deferred.resolve();
                 }
@@ -1720,7 +1725,7 @@ module BABYLON.GLTF2 {
             });
             promises.push(deferred.promise);
 
-            if (!textureURL) {
+            if (!url) {
                 promises.push(this.loadImageAsync(`/images/${image.index}`, image).then((data) => {
                     const name = image.uri || `${this._fileName}#image${image.index}`;
                     const dataUrl = `data:${this._uniqueRootUrl}${name}`;

+ 1 - 1
package.json

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

+ 3 - 1
readme.md

@@ -2,9 +2,11 @@
 
 Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
 
+[![npm version](https://badge.fury.io/js/babylonjs.svg)](https://badge.fury.io/js/babylonjs)
 [![Build Status](https://travis-ci.com/BabylonJS/Babylon.js.svg?branch=master)](https://travis-ci.com/BabylonJS/Babylon.js)
-[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/babylonJS/babylon.js.svg)](https://isitmaintained.com/project/babylonJS/babylon.js "Average time to resolve an issue")
+[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/BabylonJS/Babylon.js.svg)](http://isitmaintained.com/project/BabylonJS/Babylon.js "Average time to resolve an issue")
 [![Percentage of issues still open](https://isitmaintained.com/badge/open/babylonJS/babylon.js.svg)](https://isitmaintained.com/project/babylonJS/babylon.js "Percentage of issues still open")
+[![Build Size](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)](https://img.badgesize.io/BabylonJS/Babylon.js/master/dist/preview%20release/babylon.js.svg?compression=gzip)
 
 **Any questions?** Here is our official [forum](http://www.html5gamedevs.com/forum/16-babylonjs/) on www.html5gamedevs.com.
 

+ 1 - 0
src/Cameras/XR/babylon.webXRCamera.ts

@@ -28,6 +28,7 @@ module BABYLON {
                 newCamera.minZ = 0;
                 newCamera.parent = this;
                 newCamera.rotationQuaternion = new BABYLON.Quaternion();
+                newCamera.updateUpVectorFromRotation = true;
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {

+ 0 - 1
src/Cameras/babylon.arcRotateCamera.ts

@@ -1054,7 +1054,6 @@ module BABYLON {
             var camRight = <ArcRotateCamera>this._rigCameras[1];
 
             camLeft.beta = camRight.beta = this.beta;
-            camLeft.radius = camRight.radius = this.radius;
 
             switch (this.cameraRigMode) {
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:

+ 97 - 78
src/Debug/babylon.axesViewer.ts

@@ -7,78 +7,89 @@ module BABYLON.Debug {
      * The Axes viewer will show 3 axes in a specific point in space
      */
     export class AxesViewer {
-        private _xmesh: Nullable<AbstractMesh>;
-        private _ymesh: Nullable<AbstractMesh>;
-        private _zmesh: Nullable<AbstractMesh>;
+        private _xAxis: TransformNode;
+        private _yAxis: TransformNode;
+        private _zAxis: TransformNode;
+        private _tmpVector = new Vector3();
+        private _scaleLinesFactor = 4;
+        private _instanced = false;
 
         /**
          * Gets the hosting scene
          */
-        public scene: Nullable<Scene>;
+        public scene: Scene;
+
         /**
          * Gets or sets a number used to scale line length
          */
         public scaleLines = 1;
 
-        /** Gets the mesh used to render x-axis */
-        public get xAxisMesh(): Nullable<AbstractMesh> {
-            return this._xmesh;
-        }
-
-        /** Gets the mesh used to render x-axis */
-        public get yAxisMesh(): Nullable<AbstractMesh> {
-            return this._ymesh;
+        /** Gets the node hierarchy used to render x-axis */
+        public get xAxis(): TransformNode {
+            return this._xAxis;
         }
 
-        /** Gets the mesh used to render x-axis */
-        public get zAxisMesh(): Nullable<AbstractMesh> {
-            return this._zmesh;
+        /** Gets the node hierarchy used to render y-axis */
+        public get yAxis(): TransformNode {
+            return this._yAxis;
         }
 
-        private static _recursiveChangeRenderingGroupId(mesh: AbstractMesh, id: number) {
-            mesh.renderingGroupId = id;
-            mesh.getChildMeshes().forEach((m) => {
-                AxesViewer._recursiveChangeRenderingGroupId(m, id);
-            });
+        /** Gets the node hierarchy used to render z-axis */
+        public get zAxis(): TransformNode {
+            return this._zAxis;
         }
 
         /**
          * Creates a new AxesViewer
          * @param scene defines the hosting scene
          * @param scaleLines defines a number used to scale line length (1 by default)
+         * @param renderingGroupId defines a number used to set the renderingGroupId of the meshes (2 by default)
+         * @param xAxis defines the node hierarchy used to render the x-axis
+         * @param yAxis defines the node hierarchy used to render the y-axis
+         * @param zAxis defines the node hierarchy used to render the z-axis
          */
-        constructor(scene: Scene, scaleLines = 1) {
+        constructor(scene: Scene, scaleLines = 1, renderingGroupId: Nullable<number> = 2, xAxis?: TransformNode, yAxis?: TransformNode, zAxis?: TransformNode) {
             this.scaleLines = scaleLines;
 
-            var greenColoredMaterial = new BABYLON.StandardMaterial("", scene);
-            greenColoredMaterial.disableLighting = true;
-            greenColoredMaterial.emissiveColor = BABYLON.Color3.Green().scale(0.5);
-
-            var redColoredMaterial = new BABYLON.StandardMaterial("", scene);
-            redColoredMaterial.disableLighting = true;
-            redColoredMaterial.emissiveColor = BABYLON.Color3.Red().scale(0.5);
-
-            var blueColoredMaterial = new BABYLON.StandardMaterial("", scene);
-            blueColoredMaterial.disableLighting = true;
-            blueColoredMaterial.emissiveColor = BABYLON.Color3.Blue().scale(0.5);
+            if (!xAxis) {
+                var redColoredMaterial = new StandardMaterial("", scene);
+                redColoredMaterial.disableLighting = true;
+                redColoredMaterial.emissiveColor = Color3.Red().scale(0.5);
+                xAxis = AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
+            }
 
-            this._xmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, redColoredMaterial);
-            this._ymesh = BABYLON.AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
-            this._zmesh = BABYLON.AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
+            if (!yAxis) {
+                var greenColoredMaterial = new StandardMaterial("", scene);
+                greenColoredMaterial.disableLighting = true;
+                greenColoredMaterial.emissiveColor = Color3.Green().scale(0.5);
+                yAxis = AxisDragGizmo._CreateArrow(scene, greenColoredMaterial);
+            }
 
-            this._xmesh.rotationQuaternion = new BABYLON.Quaternion();
-            this._xmesh.scaling.scaleInPlace(4);
-            this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-            this._ymesh.scaling.scaleInPlace(4);
-            this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-            this._zmesh.scaling.scaleInPlace(4);
+            if (!zAxis) {
+                var blueColoredMaterial = new StandardMaterial("", scene);
+                blueColoredMaterial.disableLighting = true;
+                blueColoredMaterial.emissiveColor = Color3.Blue().scale(0.5);
+                zAxis = AxisDragGizmo._CreateArrow(scene, blueColoredMaterial);
+            }
 
-            AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
-            AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
-            AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
+            this._xAxis = xAxis;
+            this._xAxis.rotationQuaternion = new Quaternion();
+            this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+            this._yAxis = yAxis;
+            this._yAxis.rotationQuaternion = new Quaternion();
+            this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+            this._zAxis = zAxis;
+            this._zAxis.rotationQuaternion = new Quaternion();
+            this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+
+            if (renderingGroupId != null) {
+                AxesViewer._SetRenderingGroupId(this._xAxis, renderingGroupId);
+                AxesViewer._SetRenderingGroupId(this._yAxis, renderingGroupId);
+                AxesViewer._SetRenderingGroupId(this._zAxis, renderingGroupId);
+            }
 
             this.scene = scene;
-            this.update(new BABYLON.Vector3(), Vector3.Right(), Vector3.Up(), Vector3.Forward());
+            this.update(new Vector3(), Vector3.Right(), Vector3.Up(), Vector3.Forward());
         }
 
         /**
@@ -89,51 +100,59 @@ module BABYLON.Debug {
          * @param zaxis defines the z axis of the viewer
          */
         public update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void {
-            if (this._xmesh) {
-                this._xmesh.position.copyFrom(position);
-
-                var cross = Vector3.Cross(Vector3.Forward(), xaxis);
-                this._xmesh.rotationQuaternion!.set(cross.x, cross.y, cross.z, 1 + Vector3.Dot(Vector3.Forward(), xaxis));
-                this._xmesh.rotationQuaternion!.normalize();
-            }
-            if (this._ymesh) {
-                this._ymesh.position.copyFrom(position);
-
-                var cross = Vector3.Cross(Vector3.Forward(), yaxis);
-                this._ymesh.rotationQuaternion!.set(cross.x, cross.y, cross.z, 1 + Vector3.Dot(Vector3.Forward(), yaxis));
-                this._ymesh.rotationQuaternion!.normalize();
-            }
-            if (this._zmesh) {
-                this._zmesh.position.copyFrom(position);
-
-                var cross = Vector3.Cross(Vector3.Forward(), zaxis);
-                this._zmesh.rotationQuaternion!.set(cross.x, cross.y, cross.z, 1 + Vector3.Dot(Vector3.Forward(), zaxis));
-                this._zmesh.rotationQuaternion!.normalize();
-            }
+            this._xAxis.position.copyFrom(position);
+            xaxis.scaleToRef(-1, this._tmpVector);
+            this._xAxis.setDirection(this._tmpVector);
+            this._xAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+
+            this._yAxis.position.copyFrom(position);
+            yaxis.scaleToRef(-1, this._tmpVector);
+            this._yAxis.setDirection(this._tmpVector);
+            this._yAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+
+            this._zAxis.position.copyFrom(position);
+            zaxis.scaleToRef(-1, this._tmpVector);
+            this._zAxis.setDirection(this._tmpVector);
+            this._zAxis.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
+        }
 
+        /**
+         * Creates an instance of this axes viewer.
+         * @returns a new axes viewer with instanced meshes
+         */
+        public createInstance(): AxesViewer {
+            const xAxis = AxisDragGizmo._CreateArrowInstance(this.scene, this._xAxis);
+            const yAxis = AxisDragGizmo._CreateArrowInstance(this.scene, this._yAxis);
+            const zAxis = AxisDragGizmo._CreateArrowInstance(this.scene, this._zAxis);
+            const axesViewer = new AxesViewer(this.scene, this.scaleLines, null, xAxis, yAxis, zAxis);
+            axesViewer._instanced = true;
+            return axesViewer;
         }
 
         /** Releases resources */
         public dispose() {
-
-            if (this._xmesh) {
-                this._xmesh.dispose();
+            if (this._xAxis) {
+                this._xAxis.dispose(false, !this._instanced);
+                delete this._xAxis;
             }
 
-            if (this._ymesh) {
-                this._ymesh.dispose();
+            if (this._yAxis) {
+                this._yAxis.dispose(false, !this._instanced);
+                delete this._yAxis;
             }
 
-            if (this._zmesh) {
-                this._zmesh.dispose();
+            if (this._zAxis) {
+                this._zAxis.dispose(false, !this._instanced);
+                delete this._zAxis;
             }
 
-            this._xmesh = null;
-            this._ymesh = null;
-            this._zmesh = null;
-
-            this.scene = null;
+            delete this.scene;
         }
 
+        private static _SetRenderingGroupId(node: TransformNode, id: number) {
+            node.getChildMeshes().forEach((mesh) => {
+                mesh.renderingGroupId = id;
+            });
+        }
     }
 }

+ 5 - 1
src/Debug/babylon.debugLayer.ts

@@ -65,6 +65,10 @@ module BABYLON {
          */
         enablePopup?: boolean;
         /**
+         * Allow the panes to be closed by users (default: true)
+         */
+        enableClose?: boolean;
+        /**
          * Optional list of extensibility entries
          */
         explorerExtensibility?: IExplorerExtensibilityGroup[];
@@ -160,7 +164,7 @@ module BABYLON {
          * @returns true if visible otherwise, false
          */
         public isVisible(): boolean {
-            return this.BJSINSPECTOR.Inspector.IsVisible;
+            return this.BJSINSPECTOR && this.BJSINSPECTOR.Inspector.IsVisible;
         }
 
         /**

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

@@ -481,7 +481,7 @@ module BABYLON {
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "4.0.0-alpha.8";
+            return "4.0.0-alpha.10";
         }
 
         /**

+ 30 - 21
src/Gizmos/babylon.axisDragGizmo.ts

@@ -16,28 +16,38 @@ module BABYLON {
          * Event that fires each time the gizmo snaps to a new location.
          * * snapDistance is the the change in distance
          */
-        public onSnapObservable = new Observable<{snapDistance: number}>();
+        public onSnapObservable = new Observable<{ snapDistance: number }>();
 
         /** @hidden */
-        public static _CreateArrow(scene: Scene, material: StandardMaterial) {
-            var arrow = new BABYLON.AbstractMesh("", scene);
-            var arrowMesh = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", {diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96}, scene);
-            var arrowTail = BABYLON.MeshBuilder.CreateLines("yPosMesh", {points: [new Vector3(0, 0, 0), new Vector3(0, 1.1, 0)]}, scene);
-            arrowTail.color = material.emissiveColor;
-            arrow.addChild(arrowMesh);
-            arrow.addChild(arrowTail);
+        public static _CreateArrow(scene: Scene, material: StandardMaterial): TransformNode {
+            var arrow = new BABYLON.TransformNode("arrow", scene);
+            var cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", { diameterTop: 0, height: 1.5, diameterBottom: 0.75, tessellation: 96 }, scene);
+            var line = BABYLON.MeshBuilder.CreateLines("line", { points: [new Vector3(0, 0, 0), new Vector3(0, 1.1, 0)] }, scene);
+            line.color = material.emissiveColor;
+            cylinder.parent = arrow;
+            line.parent = arrow;
 
             // Position arrow pointing in its drag axis
-            arrowMesh.scaling.scaleInPlace(0.05);
-            arrowMesh.material = material;
-            arrowMesh.rotation.x = Math.PI / 2;
-            arrowMesh.position.z += 0.3;
-            arrowTail.scaling.scaleInPlace(0.26);
-            arrowTail.rotation.x = Math.PI / 2;
-            arrowTail.material = material;
+            cylinder.scaling.scaleInPlace(0.05);
+            cylinder.material = material;
+            cylinder.rotation.x = Math.PI / 2;
+            cylinder.position.z += 0.3;
+            line.scaling.scaleInPlace(0.26);
+            line.rotation.x = Math.PI / 2;
+            line.material = material;
             return arrow;
         }
 
+        /** @hidden */
+        public static _CreateArrowInstance(scene: Scene, arrow: TransformNode): TransformNode {
+            const instance = new BABYLON.TransformNode("arrow", scene);
+            for (const mesh of arrow.getChildMeshes()) {
+                const childInstance = (mesh as Mesh).createInstance(mesh.name);
+                childInstance.parent = instance;
+            }
+            return instance;
+        }
+
         /**
          * Creates an AxisDragGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -61,14 +71,13 @@ module BABYLON {
 
             arrow.lookAt(this._rootMesh.position.subtract(dragAxis));
             arrow.scaling.scaleInPlace(1 / 3);
-
-            this._rootMesh.addChild(arrow);
+            arrow.parent = this._rootMesh;
 
             var currentSnapDragDistance = 0;
             var tmpVector = new Vector3();
-            var tmpSnapEvent = {snapDistance: 0};
+            var tmpSnapEvent = { snapDistance: 0 };
             // Add drag behavior to handle events when the gizmo is dragged
-            this.dragBehavior = new PointerDragBehavior({dragAxis: dragAxis});
+            this.dragBehavior = new PointerDragBehavior({ dragAxis: dragAxis });
             this.dragBehavior.moveAttached = false;
             this._rootMesh.addBehavior(this.dragBehavior);
 
@@ -81,13 +90,13 @@ module BABYLON {
                         this.attachedMesh.parent.computeWorldMatrix().invertToRef(tmpMatrix);
                         tmpMatrix.setTranslationFromFloats(0, 0, 0);
                         Vector3.TransformCoordinatesToRef(event.delta, tmpMatrix, localDelta);
-                    }else {
+                    } else {
                         localDelta.copyFrom(event.delta);
                     }
                     // Snapping logic
                     if (this.snapDistance == 0) {
                         this.attachedMesh.position.addInPlace(localDelta);
-                    }else {
+                    } else {
                         currentSnapDragDistance += event.dragDistance;
                         if (Math.abs(currentSnapDragDistance) > this.snapDistance) {
                             var dragSteps = Math.floor(Math.abs(currentSnapDragDistance) / this.snapDistance);

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

@@ -166,7 +166,7 @@ module BABYLON {
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
-
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
 

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

@@ -233,7 +233,7 @@ module BABYLON {
                 return false;
             }
 
-            if (this.infiniteDistance !== this._cache.infiniteDistance) {
+            if (this.infiniteDistance) {
                 return false;
             }
 

+ 1 - 1
src/Particles/babylon.solidParticleSystem.ts

@@ -898,7 +898,7 @@ module BABYLON {
                     const minBbox = modelBoundingInfo.minimum.multiplyToRef(particleScaling, tempVectors[1]);
                     const maxBbox = modelBoundingInfo.maximum.multiplyToRef(particleScaling, tempVectors[2]);
 
-                    const bSphereCenter = maxBbox.addToRef(minBbox, tempVectors[3]).scaleInPlace(0.5);
+                    const bSphereCenter = maxBbox.addToRef(minBbox, tempVectors[3]).scaleInPlace(0.5).addInPlace(particleGlobalPosition);
                     const halfDiag = maxBbox.subtractToRef(minBbox, tempVectors[4]).scaleInPlace(0.5 * this._bSphereRadiusFactor);
                     const bSphereMinBbox = bSphereCenter.subtractToRef(halfDiag, tempVectors[1]);
                     const bSphereMaxBbox = bSphereCenter.addToRef(halfDiag, tempVectors[2]);

+ 3 - 2
src/babylon.node.ts

@@ -143,7 +143,7 @@ module BABYLON {
                     this._parentNode._children.splice(index, 1);
                 }
 
-                if (!parent) {
+                if (!parent && !this._isDisposed) {
                     this.addToSceneRootNodes();
                 }
             }
@@ -693,6 +693,8 @@ module BABYLON {
          * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
         public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
+            this._isDisposed = true;
+
             if (!doNotRecurse) {
                 const nodes = this.getDescendants(true);
                 for (const node of nodes) {
@@ -722,7 +724,6 @@ module BABYLON {
             }
 
             this._behaviors = [];
-            this._isDisposed = true;
         }
 
         /**

+ 5 - 0
tests/validation/config.json

@@ -2,6 +2,11 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [
     {
+      "title": "Camera rig",
+      "playgroundId": "#ATL1CS#9",
+      "referenceImage": "cameraRig.png"
+    },
+    {
       "title": "XR camera container rotation",
       "playgroundId": "#JV98QW#5",
       "referenceImage": "xrCameraContainerRotation.png",