瀏覽代碼

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

Guide 6 年之前
父節點
當前提交
17744fe2fd
共有 100 個文件被更改,包括 15979 次插入14570 次删除
  1. 6821 6768
      Playground/babylon.d.txt
  2. 21 15
      Tools/Gulp/gulpfile.js
  3. 6820 6767
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 264 151
      dist/preview release/babylon.max.js
  6. 264 151
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 264 151
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/glTF2Interface/package.json
  10. 1 1
      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. 2 2
      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. 1 1
      dist/preview release/inspector/babylon.inspector.d.ts
  19. 2 2
      dist/preview release/inspector/babylon.inspector.module.d.ts
  20. 5 5
      dist/preview release/inspector/package.json
  21. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  22. 38 48
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  23. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  24. 38 48
      dist/preview release/loaders/babylon.glTFFileLoader.js
  25. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  26. 38 48
      dist/preview release/loaders/babylonjs.loaders.js
  27. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  28. 3 3
      dist/preview release/loaders/package.json
  29. 2 2
      dist/preview release/materialsLibrary/package.json
  30. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  31. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  32. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  33. 2 2
      dist/preview release/postProcessesLibrary/package.json
  34. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  35. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  36. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  37. 3 3
      dist/preview release/serializers/package.json
  38. 199 21
      dist/preview release/viewer/babylon.viewer.d.ts
  39. 3 3
      dist/preview release/viewer/babylon.viewer.js
  40. 8 8
      dist/preview release/viewer/babylon.viewer.max.js
  41. 204 26
      dist/preview release/viewer/babylon.viewer.module.d.ts
  42. 12 0
      dist/preview release/what's new.md
  43. 1 1
      gui/src/2D/controls/checkbox.ts
  44. 2 2
      gui/src/2D/controls/container.ts
  45. 60 4
      gui/src/2D/controls/control.ts
  46. 9 1
      inspector/src/components/actionTabs/actionTabs.scss
  47. 3 2
      inspector/src/components/actionTabs/actionTabsComponent.tsx
  48. 38 2
      inspector/src/components/actionTabs/lineContainerComponent.tsx
  49. 2 2
      inspector/src/components/actionTabs/lines/color3LineComponent.tsx
  50. 33 5
      inspector/src/components/actionTabs/lines/floatLineComponent.tsx
  51. 2 4
      inspector/src/components/actionTabs/lines/optionsLineComponent.tsx
  52. 1 0
      inspector/src/components/actionTabs/lines/radioLineComponent.tsx
  53. 25 8
      inspector/src/components/actionTabs/lines/textInputLineComponent.tsx
  54. 4 0
      inspector/src/components/actionTabs/lines/textureLineComponent.tsx
  55. 12 12
      inspector/src/components/actionTabs/lines/textureLinkLineComponent.tsx
  56. 15 15
      inspector/src/components/actionTabs/tabs/debugTabComponent.tsx
  57. 109 11
      inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx
  58. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx
  59. 16 14
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/arcRotateCameraPropertyGridComponent.tsx
  60. 8 6
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/commonCameraPropertyGridComponent.tsx
  61. 5 3
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/freeCameraPropertyGridComponent.tsx
  62. 0 102
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/propertyGridTabComponent.tsx
  63. 5 3
      inspector/src/components/actionTabs/tabs/propertyGrids/fogPropertyGridComponent.tsx
  64. 4 4
      inspector/src/components/actionTabs/tabs/propertyGrids/gridPropertyGridComponent.tsx
  65. 35 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/checkboxPropertyGridComponent.tsx
  66. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/colorPickerPropertyGridComponent.tsx
  67. 49 18
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx
  68. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/controlPropertyGridComponent.tsx
  69. 33 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/ellipsePropertyGridComponent.tsx
  70. 42 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/imageBasedSliderPropertyGridComponent.tsx
  71. 52 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/imagePropertyGridComponent.tsx
  72. 13 11
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/inputTextPropertyGridComponent.tsx
  73. 55 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/linePropertyGridComponent.tsx
  74. 38 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/radioButtonPropertyGridComponent.tsx
  75. 34 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/rectanglePropertyGridComponent.tsx
  76. 44 0
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/sliderPropertyGridComponent.tsx
  77. 34 2
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/textBlockPropertyGridComponent.tsx
  78. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonLightPropertyGridComponent.tsx
  79. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonShadowLightPropertyGridComponent.tsx
  80. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/directionalLightPropertyGridComponent.tsx
  81. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/hemisphericLightPropertyGridComponent.tsx
  82. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/pointLightPropertyGridComponent.tsx
  83. 6 4
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/spotLightPropertyGridComponent.tsx
  84. 9 0
      inspector/src/components/actionTabs/tabs/propertyGrids/lockObject.ts
  85. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx
  86. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx
  87. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/materialPropertyGridComponent.tsx
  88. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  89. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx
  90. 16 16
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  91. 13 13
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/axesViewerComponent.tsx
  92. 20 18
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  93. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/transformNodePropertyGridComponent.tsx
  94. 23 6
      inspector/src/components/actionTabs/tabs/propertyGrids/scenePropertyGridComponent.tsx
  95. 2 2
      inspector/src/components/actionTabs/tabs/tools/gltfComponent.tsx
  96. 4 0
      inspector/src/components/embedHost/embedHost.scss
  97. 4 2
      inspector/src/components/embedHost/embedHostComponent.tsx
  98. 2 1
      inspector/src/components/headerComponent.tsx
  99. 7 3
      inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx
  100. 0 0
      inspector/src/components/sceneExplorer/entities/meshTreeItemComponent.tsx

File diff suppressed because it is too large
+ 6821 - 6768
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())
+                    }));
+                }
             }
         });
     });

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


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


+ 264 - 151
dist/preview release/babylon.max.js

@@ -4134,6 +4134,14 @@ var BABYLON;
             return this;
         };
         /**
+         * Determines equality between Color4 objects
+         * @param otherColor defines the second operand
+         * @returns true if the rgba values are equal to the given ones
+         */
+        Color4.prototype.equals = function (otherColor) {
+            return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b && this.a === otherColor.a;
+        };
+        /**
          * Creates a new Color4 set with the added values of the current Color4 and of the given one
          * @param right defines the second operand
          * @returns a new Color4 object
@@ -12945,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.9";
             },
             enumerable: true,
             configurable: true
@@ -18819,6 +18827,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Gets or sets a boolean used to define if the node must be serialized
              */
             this.doNotSerialize = false;
@@ -18906,7 +18918,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19378,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++) {
@@ -19408,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
@@ -20151,7 +20163,8 @@ var BABYLON;
              * By default the system will update normals to compensate
              */
             _this.ignoreNonUniformScaling = false;
-            _this._localWorld = BABYLON.Matrix.Zero();
+            /** @hidden */
+            _this._localMatrix = BABYLON.Matrix.Zero();
             _this._absolutePosition = BABYLON.Vector3.Zero();
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
@@ -20293,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)) {
@@ -20465,7 +20478,7 @@ var BABYLON;
          */
         TransformNode.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20475,7 +20488,7 @@ var BABYLON;
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
             var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
-            this._localWorld.invertToRef(invLocalWorldMatrix);
+            this._localMatrix.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20485,7 +20498,7 @@ var BABYLON;
          */
         TransformNode.prototype.locallyTranslate = function (vector3) {
             this.computeWorldMatrix(true);
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20505,17 +20518,7 @@ var BABYLON;
             var dv = TransformNode._lookAtVectorCache;
             var pos = space === BABYLON.Space.LOCAL ? this.position : this.getAbsolutePosition();
             targetPoint.subtractToRef(pos, dv);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            if (this.rotationQuaternion) {
-                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
-            }
-            else {
-                this.rotation.x = pitch + pitchCor;
-                this.rotation.y = yaw + yawCor;
-                this.rotation.z = rollCor;
-            }
+            this.setDirection(dv, yawCor, pitchCor, rollCor);
             // Correct for parent's rotation offset
             if (space === BABYLON.Space.WORLD && this.parent) {
                 if (this.rotationQuaternion) {
@@ -20570,6 +20573,31 @@ var BABYLON;
             return this;
         };
         /**
+         * Sets this transform node rotation to the given local axis.
+         * @param localAxis the axis in local space
+         * @param yawCor optional yaw (y-axis) correction in radians
+         * @param pitchCor optional pitch (x-axis) correction in radians
+         * @param rollCor optional roll (z-axis) correction in radians
+         * @returns this TransformNode
+         */
+        TransformNode.prototype.setDirection = function (localAxis, yawCor, pitchCor, rollCor) {
+            if (yawCor === void 0) { yawCor = 0; }
+            if (pitchCor === void 0) { pitchCor = 0; }
+            if (rollCor === void 0) { rollCor = 0; }
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
+            var pitch = Math.atan2(localAxis.y, len);
+            if (this.rotationQuaternion) {
+                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
+            }
+            else {
+                this.rotation.x = pitch + pitchCor;
+                this.rotation.y = yaw + yawCor;
+                this.rotation.z = rollCor;
+            }
+            return this;
+        };
+        /**
          * Sets a new pivot point to the current node
          * @param point defines the new pivot point to use
          * @param space defines if the point is in world or local space (local by default)
@@ -20934,7 +20962,7 @@ var BABYLON;
                 BABYLON.Tmp.Matrix[5].multiplyToRef(this._pivotMatrixInverse, BABYLON.Tmp.Matrix[5]);
             }
             // Local world
-            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localWorld);
+            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localMatrix);
             // Parent
             if (this.parent && this.parent.getWorldMatrix) {
                 if (this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
@@ -20945,24 +20973,24 @@ var BABYLON;
                     else {
                         BABYLON.Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                     }
-                    this._localWorld.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
+                    this._localMatrix.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
                     BABYLON.Vector3.TransformCoordinatesToRef(BABYLON.Tmp.Vector3[5], BABYLON.Tmp.Matrix[5], BABYLON.Tmp.Vector3[5]);
-                    this._worldMatrix.copyFrom(this._localWorld);
+                    this._worldMatrix.copyFrom(this._localMatrix);
                     this._worldMatrix.setTranslation(BABYLON.Tmp.Vector3[5]);
                 }
                 else {
                     if (this._transformToBoneReferal) {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
                         BABYLON.Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
                     }
                     else {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
                     }
                 }
                 this._markSyncedWithParent();
             }
             else {
-                this._worldMatrix.copyFrom(this._localWorld);
+                this._worldMatrix.copyFrom(this._localMatrix);
             }
             // Normal matrix
             if (!this.ignoreNonUniformScaling) {
@@ -22241,13 +22269,14 @@ var BABYLON;
         };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             if (this._boundingInfo) {
-                this._boundingInfo.update(this.worldMatrixFromCache);
+                this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
             }
             else {
-                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, this.worldMatrixFromCache);
+                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
             }
-            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+            this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
             return this;
         };
         /** @hidden */
@@ -24604,6 +24633,7 @@ var BABYLON;
                 this._rigCameras[i].minZ = this.minZ;
                 this._rigCameras[i].maxZ = this.maxZ;
                 this._rigCameras[i].fov = this.fov;
+                this._rigCameras[i].upVector.copyFrom(this.upVector);
             }
             // only update viewport when ANAGLYPH
             if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
@@ -25834,6 +25864,10 @@ var BABYLON;
              */
             _this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            _this.reservedDataStore = null;
+            /**
              * Use this array to add regular expressions used to disable offline support for specific urls
              */
             _this.disableOfflineSupportExceptionRules = new Array();
@@ -31648,6 +31682,10 @@ var BABYLON;
              * Gets or sets an object used to store user defined information.
              */
             this.metadata = null;
+            /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
             this._hasAlpha = false;
             /**
              * Defines if the alpha value should be determined via the rgb values.
@@ -31736,8 +31774,8 @@ var BABYLON;
             this._cachedSize = BABYLON.Size.Zero();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             if (this._scene) {
-                this._scene.addTexture(this);
                 this.uniqueId = this._scene.getUniqueId();
+                this._scene.addTexture(this);
             }
             this._uid = null;
         }
@@ -34267,10 +34305,11 @@ var BABYLON;
             if (!effect) {
                 return this;
             }
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             var sideOrientation = this.overrideMaterialSideOrientation;
             if (sideOrientation == null) {
                 sideOrientation = this._effectiveMaterial.sideOrientation;
-                if (this._getWorldMatrixDeterminant() < 0) {
+                if (effectiveMesh._getWorldMatrixDeterminant() < 0) {
                     sideOrientation = (sideOrientation === BABYLON.Material.ClockWiseSideOrientation ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation);
                 }
             }
@@ -34283,7 +34322,7 @@ var BABYLON;
             if (!hardwareInstancedRendering) { // Binding will be done later because we need to add more info to the VB
                 this._bind(subMesh, effect, fillMode);
             }
-            var world = this.getWorldMatrix();
+            var world = effectiveMesh.getWorldMatrix();
             if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
@@ -36948,6 +36987,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Specifies if the ready state should be checked on each call
              */
             this.checkReadyOnEveryCall = false;
@@ -49044,6 +49087,8 @@ var BABYLON;
             /** @hidden */
             _this._currentTarget = BABYLON.Vector3.Zero();
             /** @hidden */
+            _this._initialFocalDistance = 1;
+            /** @hidden */
             _this._viewMatrix = BABYLON.Matrix.Zero();
             /** @hidden */
             _this._camMatrix = BABYLON.Matrix.Zero();
@@ -49163,6 +49208,7 @@ var BABYLON;
         /** @hidden */
         TargetCamera.prototype.setTarget = function (target) {
             this.upVector.normalize();
+            this._initialFocalDistance = target.subtract(this.position).length();
             if (this.position.z === target.z) {
                 this.position.z += BABYLON.Epsilon;
             }
@@ -49363,10 +49409,8 @@ var BABYLON;
                     //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
                     var leftSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : -1;
                     var rightSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 : 1;
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft.position);
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
-                    camLeft.setTarget(this.getTarget());
-                    camRight.setTarget(this.getTarget());
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft);
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * rightSign, camRight);
                     break;
                 case BABYLON.Camera.RIG_MODE_VR:
                     if (camLeft.rotationQuaternion) {
@@ -49383,13 +49427,17 @@ var BABYLON;
             }
             _super.prototype._updateRigCameras.call(this);
         };
-        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
+        TargetCamera.prototype._getRigCamPositionAndTarget = function (halfSpace, rigCamera) {
             var target = this.getTarget();
-            BABYLON.Matrix.TranslationToRef(-target.x, -target.y, -target.z, TargetCamera._TargetTransformMatrix);
+            target.subtractToRef(this.position, TargetCamera._TargetFocalPoint);
+            TargetCamera._TargetFocalPoint.normalize().scaleInPlace(this._initialFocalDistance);
+            var newFocalTarget = TargetCamera._TargetFocalPoint.addInPlace(this.position);
+            BABYLON.Matrix.TranslationToRef(-newFocalTarget.x, -newFocalTarget.y, -newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._TargetTransformMatrix.multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), TargetCamera._RigCamTransformMatrix);
-            BABYLON.Matrix.TranslationToRef(target.x, target.y, target.z, TargetCamera._TargetTransformMatrix);
+            BABYLON.Matrix.TranslationToRef(newFocalTarget.x, newFocalTarget.y, newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._RigCamTransformMatrix.multiplyToRef(TargetCamera._TargetTransformMatrix, TargetCamera._RigCamTransformMatrix);
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, result);
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, rigCamera.position);
+            rigCamera.setTarget(newFocalTarget);
         };
         /**
          * Gets the current object class name.
@@ -49400,6 +49448,7 @@ var BABYLON;
         };
         TargetCamera._RigCamTransformMatrix = new BABYLON.Matrix();
         TargetCamera._TargetTransformMatrix = new BABYLON.Matrix();
+        TargetCamera._TargetFocalPoint = new BABYLON.Vector3();
         __decorate([
             BABYLON.serializeAsVector3()
         ], TargetCamera.prototype, "rotation", void 0);
@@ -66376,7 +66425,6 @@ var BABYLON;
              * @param scene defines the hosting scene
              * @param autoUpdateBonesMatrices defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)
              * @param renderingGroupId defines the rendering group id to use with the viewer
-             * @param utilityLayerRenderer defines an optional utility layer to render the helper on
              */
             function SkeletonViewer(
             /** defines the skeleton to render */
@@ -66386,21 +66434,21 @@ var BABYLON;
             /** defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)  */
             autoUpdateBonesMatrices, 
             /** defines the rendering group id to use with the viewer */
-            renderingGroupId, 
-            /** defines an optional utility layer to render the helper on */
-            utilityLayerRenderer) {
+            renderingGroupId) {
                 if (autoUpdateBonesMatrices === void 0) { autoUpdateBonesMatrices = true; }
                 if (renderingGroupId === void 0) { renderingGroupId = 1; }
                 this.skeleton = skeleton;
                 this.mesh = mesh;
                 this.autoUpdateBonesMatrices = autoUpdateBonesMatrices;
                 this.renderingGroupId = renderingGroupId;
-                this.utilityLayerRenderer = utilityLayerRenderer;
                 /** Gets or sets the color used to render the skeleton */
                 this.color = BABYLON.Color3.White();
                 this._debugLines = new Array();
                 this._isEnabled = false;
                 this._scene = scene;
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
                 this.update();
                 this._renderFunction = this.update.bind(this);
             }
@@ -66495,6 +66543,9 @@ var BABYLON;
             };
             /** Update the viewer to sync with current skeleton state */
             SkeletonViewer.prototype.update = function () {
+                if (!this._utilityLayer) {
+                    return;
+                }
                 if (this.autoUpdateBonesMatrices) {
                     this.skeleton.computeAbsoluteTransforms();
                 }
@@ -66504,7 +66555,7 @@ var BABYLON;
                 else {
                     this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
                 }
-                var targetScene = this.utilityLayerRenderer ? this.utilityLayerRenderer.utilityLayerScene : this._scene;
+                var targetScene = this._utilityLayer.utilityLayerScene;
                 if (!this._debugMesh) {
                     this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: null }, targetScene);
                     this._debugMesh.renderingGroupId = this.renderingGroupId;
@@ -66517,11 +66568,16 @@ var BABYLON;
             };
             /** Release associated resources */
             SkeletonViewer.prototype.dispose = function () {
+                this.isEnabled = false;
                 if (this._debugMesh) {
                     this.isEnabled = false;
                     this._debugMesh.dispose();
                     this._debugMesh = null;
                 }
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return SkeletonViewer;
         }());
@@ -66549,6 +66605,8 @@ var BABYLON;
              */
             function AxesViewer(scene, scaleLines) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
                 /**
                  * Gets or sets a number used to scale line length
                  */
@@ -66567,11 +66625,11 @@ var BABYLON;
                 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._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
+                this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
+                this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
@@ -66618,21 +66676,21 @@ var BABYLON;
             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();
+                    xaxis.scaleToRef(-1, this._tmpVector);
+                    this._xmesh.setDirection(this._tmpVector);
+                    this._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    yaxis.scaleToRef(-1, this._tmpVector);
+                    this._ymesh.setDirection(this._tmpVector);
+                    this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    zaxis.scaleToRef(-1, this._tmpVector);
+                    this._zmesh.setDirection(this._tmpVector);
+                    this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
             };
             /** Releases resources */
@@ -66946,7 +67004,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.
@@ -67005,6 +67063,9 @@ var BABYLON;
                 if (physicEngine) {
                     this._physicsEnginePlugin = physicEngine.getPhysicsPlugin();
                 }
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
             }
             /** @hidden */
             PhysicsViewer.prototype._updateDebugMeshes = function () {
@@ -67039,7 +67100,7 @@ var BABYLON;
                         return null;
                     }
                 }
-                var debugMesh = this._getDebugMesh(impostor, this._scene);
+                var debugMesh = this._getDebugMesh(impostor);
                 if (debugMesh) {
                     this._impostors[this._numMeshes] = impostor;
                     this._meshes[this._numMeshes] = debugMesh;
@@ -67056,17 +67117,18 @@ var BABYLON;
              * @param impostor defines the impostor to hide
              */
             PhysicsViewer.prototype.hideImpostor = function (impostor) {
-                if (!impostor || !this._scene) {
+                if (!impostor || !this._scene || !this._utilityLayer) {
                     return;
                 }
                 var removed = false;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 for (var i = 0; i < this._numMeshes; i++) {
                     if (this._impostors[i] == impostor) {
                         var mesh = this._meshes[i];
                         if (!mesh) {
                             continue;
                         }
-                        this._scene.removeMesh(mesh);
+                        utilityLayerScene.removeMesh(mesh);
                         mesh.dispose();
                         this._numMeshes--;
                         if (this._numMeshes > 0) {
@@ -67091,37 +67153,39 @@ var BABYLON;
                 if (!this._debugMaterial) {
                     this._debugMaterial = new BABYLON.StandardMaterial('', scene);
                     this._debugMaterial.wireframe = true;
+                    this._debugMaterial.emissiveColor = BABYLON.Color3.White();
+                    this._debugMaterial.disableLighting = true;
                 }
                 return this._debugMaterial;
             };
             PhysicsViewer.prototype._getDebugBoxMesh = function (scene) {
                 if (!this._debugBoxMesh) {
                     this._debugBoxMesh = BABYLON.MeshBuilder.CreateBox('physicsBodyBoxViewMesh', { size: 1 }, scene);
-                    this._debugBoxMesh.renderingGroupId = 1;
                     this._debugBoxMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugBoxMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugBoxMesh);
                 }
                 return this._debugBoxMesh.createInstance('physicsBodyBoxViewInstance');
             };
             PhysicsViewer.prototype._getDebugSphereMesh = function (scene) {
                 if (!this._debugSphereMesh) {
                     this._debugSphereMesh = BABYLON.MeshBuilder.CreateSphere('physicsBodySphereViewMesh', { diameter: 1 }, scene);
-                    this._debugSphereMesh.renderingGroupId = 1;
                     this._debugSphereMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugSphereMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugSphereMesh);
                 }
                 return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
             };
-            PhysicsViewer.prototype._getDebugMesh = function (impostor, scene) {
+            PhysicsViewer.prototype._getDebugMesh = function (impostor) {
+                if (!this._utilityLayer) {
+                    return null;
+                }
                 var mesh = null;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 if (impostor.type == BABYLON.PhysicsImpostor.BoxImpostor) {
-                    mesh = this._getDebugBoxMesh(scene);
+                    mesh = this._getDebugBoxMesh(utilityLayerScene);
                     impostor.getBoxSizeToRef(mesh.scaling);
                 }
                 else if (impostor.type == BABYLON.PhysicsImpostor.SphereImpostor) {
-                    mesh = this._getDebugSphereMesh(scene);
+                    mesh = this._getDebugSphereMesh(utilityLayerScene);
                     var radius = impostor.getRadius();
                     mesh.scaling.x = radius * 2;
                     mesh.scaling.y = radius * 2;
@@ -67146,6 +67210,10 @@ var BABYLON;
                 this._impostors.length = 0;
                 this._scene = null;
                 this._physicsEnginePlugin = null;
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return PhysicsViewer;
         }());
@@ -70632,9 +70700,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
-                var flip = dot >= 0;
-                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
+                plane.setDirection(options.sourcePlane.normal);
             }
             return plane;
         };
@@ -79883,9 +79949,11 @@ var BABYLON;
                 }
                 // Environment texture
                 if (parsedData.environmentTexture !== undefined && parsedData.environmentTexture !== null) {
+                    // PBR needed for both HDR texture (gamma space) & a sky box
+                    var isPBR = parsedData.isPBR !== undefined ? parsedData.isPBR : true;
                     if (parsedData.environmentTextureType && parsedData.environmentTextureType === "BABYLON.HDRCubeTexture") {
                         var hdrSize = (parsedData.environmentTextureSize) ? parsedData.environmentTextureSize : 128;
-                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize);
+                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize, true, !isPBR);
                         if (parsedData.environmentTextureRotationY) {
                             hdrTexture.rotationY = parsedData.environmentTextureRotationY;
                         }
@@ -79901,8 +79969,7 @@ var BABYLON;
                     if (parsedData.createDefaultSkybox === true) {
                         var skyboxScale = (scene.activeCamera !== undefined && scene.activeCamera !== null) ? (scene.activeCamera.maxZ - scene.activeCamera.minZ) / 2 : 1000;
                         var skyboxBlurLevel = parsedData.skyboxBlurLevel || 0;
-                        var skyboxIsPBR = parsedData.skyboxIsPBR !== undefined ? parsedData.skyboxIsPBR : true;
-                        scene.createDefaultSkybox(scene.environmentTexture, skyboxIsPBR, skyboxScale, skyboxBlurLevel);
+                        scene.createDefaultSkybox(scene.environmentTexture, isPBR, skyboxScale, skyboxBlurLevel);
                     }
                 }
                 // Finish
@@ -90568,6 +90635,9 @@ var BABYLON;
                 case ImageProcessingConfiguration.TONEMAPPING_ACES:
                     defines.TONEMAPPING_ACES = true;
                     break;
+                default:
+                    defines.TONEMAPPING_ACES = false;
+                    break;
             }
             defines.CONTRAST = (this.contrast !== 1.0);
             defines.EXPOSURE = (this.exposure !== 1.0);
@@ -92902,6 +92972,8 @@ var BABYLON;
             _this._worldTransform = new BABYLON.Matrix();
             _this._needToDecompose = true;
             _this._needToCompose = false;
+            /** @hidden */
+            _this._linkedTransformNode = null;
             _this._skeleton = skeleton;
             _this._localMatrix = localMatrix ? localMatrix.clone() : BABYLON.Matrix.Identity();
             _this._restPose = restPose ? restPose : _this._localMatrix.clone();
@@ -93017,6 +93089,20 @@ var BABYLON;
         Bone.prototype.getAbsoluteTransform = function () {
             return this._absoluteTransform;
         };
+        /**
+         * Links with the given transform node.
+         * The local matrix of this bone is copied from the transform node every frame.
+         * @param transformNode defines the transform node to link to
+         */
+        Bone.prototype.linkTransformNode = function (transformNode) {
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode--;
+            }
+            this._linkedTransformNode = transformNode;
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode++;
+            }
+        };
         Object.defineProperty(Bone.prototype, "position", {
             // Properties (matches AbstractMesh properties)
             /** Gets or sets current position (in local space) */
@@ -94562,19 +94648,25 @@ var BABYLON;
             this.name = name;
             this.id = id;
             /**
-             * Gets the list of child bones
+             * Defines the list of child bones
              */
             this.bones = new Array();
             /**
-             * Gets a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
+             * Defines a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
              */
             this.needInitialSkinMatrix = false;
+            /**
+             * Defines a mesh that override the matrix used to get the world matrix (null by default).
+             */
+            this.overrideMesh = null;
             this._isDirty = true;
             this._meshesWithPoseMatrix = new Array();
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
             this._canUseTextureForBones = false;
+            /** @hidden */
+            this._numBonesWithLinkedTransformNode = 0;
             /**
              * Specifies if the skeleton should be serialized
              */
@@ -94865,6 +94957,18 @@ var BABYLON;
          * Build all resources required to render a skeleton
          */
         Skeleton.prototype.prepare = function () {
+            // Update the local matrix of bones with linked transform nodes.
+            if (this._numBonesWithLinkedTransformNode > 0) {
+                for (var _i = 0, _a = this.bones; _i < _a.length; _i++) {
+                    var bone_1 = _a[_i];
+                    if (bone_1._linkedTransformNode) {
+                        // Computing the world matrix also computes the local matrix.
+                        bone_1._linkedTransformNode.computeWorldMatrix();
+                        bone_1._matrix = bone_1._linkedTransformNode._localMatrix;
+                        bone_1.markAsDirty();
+                    }
+                }
+            }
             if (!this._isDirty) {
                 return;
             }
@@ -98926,6 +99030,7 @@ var BABYLON;
                 this._originDirection = this._origin.subtract(this._originTop).normalize();
             }
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the updraft event (cylinder).
@@ -98957,6 +99062,9 @@ var BABYLON;
         PhysicsUpdraftEvent.prototype.dispose = function (force) {
             var _this = this;
             if (force === void 0) { force = true; }
+            if (!this._cylinder) {
+                return;
+            }
             if (force) {
                 this._cylinder.dispose();
             }
@@ -99008,7 +99116,6 @@ var BABYLON;
         };
         PhysicsUpdraftEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -99043,6 +99150,7 @@ var BABYLON;
             this._origin.addToRef(new BABYLON.Vector3(0, this._height / 2, 0), this._cylinderPosition);
             this._origin.addToRef(new BABYLON.Vector3(0, this._height, 0), this._originTop);
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the vortex event (cylinder).
@@ -99147,7 +99255,6 @@ var BABYLON;
         };
         PhysicsVortexEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -102136,10 +102243,12 @@ var BABYLON;
         /**
          * Instantiates a UtilityLayerRenderer
          * @param originalScene the original scene that will be rendered on top of
+         * @param handleEvents boolean indicating if the utility layer should handle events
          */
         function UtilityLayerRenderer(
         /** the original scene that will be rendered on top of */
-        originalScene) {
+        originalScene, handleEvents) {
+            if (handleEvents === void 0) { handleEvents = true; }
             var _this = this;
             this.originalScene = originalScene;
             this._pointerCaptures = {};
@@ -102171,92 +102280,94 @@ var BABYLON;
             originalScene.getEngine().scenes.pop();
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority
             this.utilityLayerScene.detachControl();
-            this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
-                if (!_this.processAllEvents) {
-                    if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                        return;
-                    }
-                }
-                var pointerEvent = (prePointerInfo.event);
-                if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
-                    _this._pointerCaptures[pointerEvent.pointerId] = false;
-                    return;
-                }
-                var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
-                if (!prePointerInfo.ray && utilityScenePick) {
-                    prePointerInfo.ray = utilityScenePick.ray;
-                }
-                // always fire the prepointer oversvable
-                _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
-                // allow every non pointer down event to flow to the utility layer
-                if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
-                    if (!prePointerInfo.skipOnPointerObservable) {
-                        _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
+            if (handleEvents) {
+                this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
+                    if (!_this.processAllEvents) {
+                        if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                            return;
+                        }
                     }
-                    if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                    var pointerEvent = (prePointerInfo.event);
+                    if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
                         _this._pointerCaptures[pointerEvent.pointerId] = false;
+                        return;
                     }
-                    return;
-                }
-                if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
-                    // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
-                    if (utilityScenePick && utilityScenePick.hit) {
+                    var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
+                    if (!prePointerInfo.ray && utilityScenePick) {
+                        prePointerInfo.ray = utilityScenePick.ray;
+                    }
+                    // always fire the prepointer oversvable
+                    _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
+                    // allow every non pointer down event to flow to the utility layer
+                    if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
                         if (!prePointerInfo.skipOnPointerObservable) {
                             _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                         }
-                        prePointerInfo.skipOnPointerObservable = true;
-                    }
-                }
-                else {
-                    var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
-                    var pointerEvent_1 = (prePointerInfo.event);
-                    // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
-                    if (originalScenePick && utilityScenePick) {
-                        // No pick in utility scene
-                        if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                // We touched an utility mesh present in the main scene
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
-                            }
-                            else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                                _this._pointerCaptures[pointerEvent_1.pointerId] = true;
-                            }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
-                            }
+                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                            _this._pointerCaptures[pointerEvent.pointerId] = false;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
-                            // We pick something in utility scene or the pick in utility is closer than the one in main scene
-                            _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
-                            // If a previous utility layer set this, do not unset this
+                        return;
+                    }
+                    if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
+                        // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
+                        if (utilityScenePick && utilityScenePick.hit) {
                             if (!prePointerInfo.skipOnPointerObservable) {
-                                prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                             }
+                            prePointerInfo.skipOnPointerObservable = true;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
-                            // We have a pick in both scenes but main is closer than utility
-                            // We touched an utility mesh present in the main scene
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
+                    }
+                    else {
+                        var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
+                        var pointerEvent_1 = (prePointerInfo.event);
+                        // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
+                        if (originalScenePick && utilityScenePick) {
+                            // No pick in utility scene
+                            if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    // We touched an utility mesh present in the main scene
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                                    _this._pointerCaptures[pointerEvent_1.pointerId] = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
                             }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
+                                // We pick something in utility scene or the pick in utility is closer than the one in main scene
+                                _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
+                                // If a previous utility layer set this, do not unset this
+                                if (!prePointerInfo.skipOnPointerObservable) {
+                                    prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                }
+                            }
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
+                                // We have a pick in both scenes but main is closer than utility
+                                // We touched an utility mesh present in the main scene
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
+                            }
+                            if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
+                                _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                             }
-                        }
-                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
-                            _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                         }
                     }
-                }
-            });
+                });
+            }
             // Render directly on top of existing scene without clearing
             this.utilityLayerScene.autoClear = false;
             this._afterRenderObserver = this.originalScene.onAfterRenderObservable.add(function () {
@@ -109334,6 +109445,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) {
@@ -121118,6 +121230,7 @@ var BABYLON;
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
     BABYLON.Scene.prototype.createDefaultEnvironment = function (options) {

+ 264 - 151
dist/preview release/babylon.no-module.max.js

@@ -4101,6 +4101,14 @@ var BABYLON;
             return this;
         };
         /**
+         * Determines equality between Color4 objects
+         * @param otherColor defines the second operand
+         * @returns true if the rgba values are equal to the given ones
+         */
+        Color4.prototype.equals = function (otherColor) {
+            return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b && this.a === otherColor.a;
+        };
+        /**
          * Creates a new Color4 set with the added values of the current Color4 and of the given one
          * @param right defines the second operand
          * @returns a new Color4 object
@@ -12912,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.9";
             },
             enumerable: true,
             configurable: true
@@ -18786,6 +18794,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Gets or sets a boolean used to define if the node must be serialized
              */
             this.doNotSerialize = false;
@@ -18873,7 +18885,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19345,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++) {
@@ -19375,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
@@ -20118,7 +20130,8 @@ var BABYLON;
              * By default the system will update normals to compensate
              */
             _this.ignoreNonUniformScaling = false;
-            _this._localWorld = BABYLON.Matrix.Zero();
+            /** @hidden */
+            _this._localMatrix = BABYLON.Matrix.Zero();
             _this._absolutePosition = BABYLON.Vector3.Zero();
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
@@ -20260,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)) {
@@ -20432,7 +20445,7 @@ var BABYLON;
          */
         TransformNode.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20442,7 +20455,7 @@ var BABYLON;
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
             var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
-            this._localWorld.invertToRef(invLocalWorldMatrix);
+            this._localMatrix.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20452,7 +20465,7 @@ var BABYLON;
          */
         TransformNode.prototype.locallyTranslate = function (vector3) {
             this.computeWorldMatrix(true);
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20472,17 +20485,7 @@ var BABYLON;
             var dv = TransformNode._lookAtVectorCache;
             var pos = space === BABYLON.Space.LOCAL ? this.position : this.getAbsolutePosition();
             targetPoint.subtractToRef(pos, dv);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            if (this.rotationQuaternion) {
-                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
-            }
-            else {
-                this.rotation.x = pitch + pitchCor;
-                this.rotation.y = yaw + yawCor;
-                this.rotation.z = rollCor;
-            }
+            this.setDirection(dv, yawCor, pitchCor, rollCor);
             // Correct for parent's rotation offset
             if (space === BABYLON.Space.WORLD && this.parent) {
                 if (this.rotationQuaternion) {
@@ -20537,6 +20540,31 @@ var BABYLON;
             return this;
         };
         /**
+         * Sets this transform node rotation to the given local axis.
+         * @param localAxis the axis in local space
+         * @param yawCor optional yaw (y-axis) correction in radians
+         * @param pitchCor optional pitch (x-axis) correction in radians
+         * @param rollCor optional roll (z-axis) correction in radians
+         * @returns this TransformNode
+         */
+        TransformNode.prototype.setDirection = function (localAxis, yawCor, pitchCor, rollCor) {
+            if (yawCor === void 0) { yawCor = 0; }
+            if (pitchCor === void 0) { pitchCor = 0; }
+            if (rollCor === void 0) { rollCor = 0; }
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
+            var pitch = Math.atan2(localAxis.y, len);
+            if (this.rotationQuaternion) {
+                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
+            }
+            else {
+                this.rotation.x = pitch + pitchCor;
+                this.rotation.y = yaw + yawCor;
+                this.rotation.z = rollCor;
+            }
+            return this;
+        };
+        /**
          * Sets a new pivot point to the current node
          * @param point defines the new pivot point to use
          * @param space defines if the point is in world or local space (local by default)
@@ -20901,7 +20929,7 @@ var BABYLON;
                 BABYLON.Tmp.Matrix[5].multiplyToRef(this._pivotMatrixInverse, BABYLON.Tmp.Matrix[5]);
             }
             // Local world
-            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localWorld);
+            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localMatrix);
             // Parent
             if (this.parent && this.parent.getWorldMatrix) {
                 if (this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
@@ -20912,24 +20940,24 @@ var BABYLON;
                     else {
                         BABYLON.Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                     }
-                    this._localWorld.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
+                    this._localMatrix.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
                     BABYLON.Vector3.TransformCoordinatesToRef(BABYLON.Tmp.Vector3[5], BABYLON.Tmp.Matrix[5], BABYLON.Tmp.Vector3[5]);
-                    this._worldMatrix.copyFrom(this._localWorld);
+                    this._worldMatrix.copyFrom(this._localMatrix);
                     this._worldMatrix.setTranslation(BABYLON.Tmp.Vector3[5]);
                 }
                 else {
                     if (this._transformToBoneReferal) {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
                         BABYLON.Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
                     }
                     else {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
                     }
                 }
                 this._markSyncedWithParent();
             }
             else {
-                this._worldMatrix.copyFrom(this._localWorld);
+                this._worldMatrix.copyFrom(this._localMatrix);
             }
             // Normal matrix
             if (!this.ignoreNonUniformScaling) {
@@ -22208,13 +22236,14 @@ var BABYLON;
         };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             if (this._boundingInfo) {
-                this._boundingInfo.update(this.worldMatrixFromCache);
+                this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
             }
             else {
-                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, this.worldMatrixFromCache);
+                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
             }
-            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+            this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
             return this;
         };
         /** @hidden */
@@ -24571,6 +24600,7 @@ var BABYLON;
                 this._rigCameras[i].minZ = this.minZ;
                 this._rigCameras[i].maxZ = this.maxZ;
                 this._rigCameras[i].fov = this.fov;
+                this._rigCameras[i].upVector.copyFrom(this.upVector);
             }
             // only update viewport when ANAGLYPH
             if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
@@ -25801,6 +25831,10 @@ var BABYLON;
              */
             _this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            _this.reservedDataStore = null;
+            /**
              * Use this array to add regular expressions used to disable offline support for specific urls
              */
             _this.disableOfflineSupportExceptionRules = new Array();
@@ -31615,6 +31649,10 @@ var BABYLON;
              * Gets or sets an object used to store user defined information.
              */
             this.metadata = null;
+            /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
             this._hasAlpha = false;
             /**
              * Defines if the alpha value should be determined via the rgb values.
@@ -31703,8 +31741,8 @@ var BABYLON;
             this._cachedSize = BABYLON.Size.Zero();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             if (this._scene) {
-                this._scene.addTexture(this);
                 this.uniqueId = this._scene.getUniqueId();
+                this._scene.addTexture(this);
             }
             this._uid = null;
         }
@@ -34234,10 +34272,11 @@ var BABYLON;
             if (!effect) {
                 return this;
             }
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             var sideOrientation = this.overrideMaterialSideOrientation;
             if (sideOrientation == null) {
                 sideOrientation = this._effectiveMaterial.sideOrientation;
-                if (this._getWorldMatrixDeterminant() < 0) {
+                if (effectiveMesh._getWorldMatrixDeterminant() < 0) {
                     sideOrientation = (sideOrientation === BABYLON.Material.ClockWiseSideOrientation ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation);
                 }
             }
@@ -34250,7 +34289,7 @@ var BABYLON;
             if (!hardwareInstancedRendering) { // Binding will be done later because we need to add more info to the VB
                 this._bind(subMesh, effect, fillMode);
             }
-            var world = this.getWorldMatrix();
+            var world = effectiveMesh.getWorldMatrix();
             if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
@@ -36915,6 +36954,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Specifies if the ready state should be checked on each call
              */
             this.checkReadyOnEveryCall = false;
@@ -49011,6 +49054,8 @@ var BABYLON;
             /** @hidden */
             _this._currentTarget = BABYLON.Vector3.Zero();
             /** @hidden */
+            _this._initialFocalDistance = 1;
+            /** @hidden */
             _this._viewMatrix = BABYLON.Matrix.Zero();
             /** @hidden */
             _this._camMatrix = BABYLON.Matrix.Zero();
@@ -49130,6 +49175,7 @@ var BABYLON;
         /** @hidden */
         TargetCamera.prototype.setTarget = function (target) {
             this.upVector.normalize();
+            this._initialFocalDistance = target.subtract(this.position).length();
             if (this.position.z === target.z) {
                 this.position.z += BABYLON.Epsilon;
             }
@@ -49330,10 +49376,8 @@ var BABYLON;
                     //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
                     var leftSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : -1;
                     var rightSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 : 1;
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft.position);
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
-                    camLeft.setTarget(this.getTarget());
-                    camRight.setTarget(this.getTarget());
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft);
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * rightSign, camRight);
                     break;
                 case BABYLON.Camera.RIG_MODE_VR:
                     if (camLeft.rotationQuaternion) {
@@ -49350,13 +49394,17 @@ var BABYLON;
             }
             _super.prototype._updateRigCameras.call(this);
         };
-        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
+        TargetCamera.prototype._getRigCamPositionAndTarget = function (halfSpace, rigCamera) {
             var target = this.getTarget();
-            BABYLON.Matrix.TranslationToRef(-target.x, -target.y, -target.z, TargetCamera._TargetTransformMatrix);
+            target.subtractToRef(this.position, TargetCamera._TargetFocalPoint);
+            TargetCamera._TargetFocalPoint.normalize().scaleInPlace(this._initialFocalDistance);
+            var newFocalTarget = TargetCamera._TargetFocalPoint.addInPlace(this.position);
+            BABYLON.Matrix.TranslationToRef(-newFocalTarget.x, -newFocalTarget.y, -newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._TargetTransformMatrix.multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), TargetCamera._RigCamTransformMatrix);
-            BABYLON.Matrix.TranslationToRef(target.x, target.y, target.z, TargetCamera._TargetTransformMatrix);
+            BABYLON.Matrix.TranslationToRef(newFocalTarget.x, newFocalTarget.y, newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._RigCamTransformMatrix.multiplyToRef(TargetCamera._TargetTransformMatrix, TargetCamera._RigCamTransformMatrix);
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, result);
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, rigCamera.position);
+            rigCamera.setTarget(newFocalTarget);
         };
         /**
          * Gets the current object class name.
@@ -49367,6 +49415,7 @@ var BABYLON;
         };
         TargetCamera._RigCamTransformMatrix = new BABYLON.Matrix();
         TargetCamera._TargetTransformMatrix = new BABYLON.Matrix();
+        TargetCamera._TargetFocalPoint = new BABYLON.Vector3();
         __decorate([
             BABYLON.serializeAsVector3()
         ], TargetCamera.prototype, "rotation", void 0);
@@ -66343,7 +66392,6 @@ var BABYLON;
              * @param scene defines the hosting scene
              * @param autoUpdateBonesMatrices defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)
              * @param renderingGroupId defines the rendering group id to use with the viewer
-             * @param utilityLayerRenderer defines an optional utility layer to render the helper on
              */
             function SkeletonViewer(
             /** defines the skeleton to render */
@@ -66353,21 +66401,21 @@ var BABYLON;
             /** defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)  */
             autoUpdateBonesMatrices, 
             /** defines the rendering group id to use with the viewer */
-            renderingGroupId, 
-            /** defines an optional utility layer to render the helper on */
-            utilityLayerRenderer) {
+            renderingGroupId) {
                 if (autoUpdateBonesMatrices === void 0) { autoUpdateBonesMatrices = true; }
                 if (renderingGroupId === void 0) { renderingGroupId = 1; }
                 this.skeleton = skeleton;
                 this.mesh = mesh;
                 this.autoUpdateBonesMatrices = autoUpdateBonesMatrices;
                 this.renderingGroupId = renderingGroupId;
-                this.utilityLayerRenderer = utilityLayerRenderer;
                 /** Gets or sets the color used to render the skeleton */
                 this.color = BABYLON.Color3.White();
                 this._debugLines = new Array();
                 this._isEnabled = false;
                 this._scene = scene;
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
                 this.update();
                 this._renderFunction = this.update.bind(this);
             }
@@ -66462,6 +66510,9 @@ var BABYLON;
             };
             /** Update the viewer to sync with current skeleton state */
             SkeletonViewer.prototype.update = function () {
+                if (!this._utilityLayer) {
+                    return;
+                }
                 if (this.autoUpdateBonesMatrices) {
                     this.skeleton.computeAbsoluteTransforms();
                 }
@@ -66471,7 +66522,7 @@ var BABYLON;
                 else {
                     this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
                 }
-                var targetScene = this.utilityLayerRenderer ? this.utilityLayerRenderer.utilityLayerScene : this._scene;
+                var targetScene = this._utilityLayer.utilityLayerScene;
                 if (!this._debugMesh) {
                     this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: null }, targetScene);
                     this._debugMesh.renderingGroupId = this.renderingGroupId;
@@ -66484,11 +66535,16 @@ var BABYLON;
             };
             /** Release associated resources */
             SkeletonViewer.prototype.dispose = function () {
+                this.isEnabled = false;
                 if (this._debugMesh) {
                     this.isEnabled = false;
                     this._debugMesh.dispose();
                     this._debugMesh = null;
                 }
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return SkeletonViewer;
         }());
@@ -66516,6 +66572,8 @@ var BABYLON;
              */
             function AxesViewer(scene, scaleLines) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
                 /**
                  * Gets or sets a number used to scale line length
                  */
@@ -66534,11 +66592,11 @@ var BABYLON;
                 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._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
+                this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
+                this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
@@ -66585,21 +66643,21 @@ var BABYLON;
             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();
+                    xaxis.scaleToRef(-1, this._tmpVector);
+                    this._xmesh.setDirection(this._tmpVector);
+                    this._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    yaxis.scaleToRef(-1, this._tmpVector);
+                    this._ymesh.setDirection(this._tmpVector);
+                    this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    zaxis.scaleToRef(-1, this._tmpVector);
+                    this._zmesh.setDirection(this._tmpVector);
+                    this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
             };
             /** Releases resources */
@@ -66913,7 +66971,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.
@@ -66972,6 +67030,9 @@ var BABYLON;
                 if (physicEngine) {
                     this._physicsEnginePlugin = physicEngine.getPhysicsPlugin();
                 }
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
             }
             /** @hidden */
             PhysicsViewer.prototype._updateDebugMeshes = function () {
@@ -67006,7 +67067,7 @@ var BABYLON;
                         return null;
                     }
                 }
-                var debugMesh = this._getDebugMesh(impostor, this._scene);
+                var debugMesh = this._getDebugMesh(impostor);
                 if (debugMesh) {
                     this._impostors[this._numMeshes] = impostor;
                     this._meshes[this._numMeshes] = debugMesh;
@@ -67023,17 +67084,18 @@ var BABYLON;
              * @param impostor defines the impostor to hide
              */
             PhysicsViewer.prototype.hideImpostor = function (impostor) {
-                if (!impostor || !this._scene) {
+                if (!impostor || !this._scene || !this._utilityLayer) {
                     return;
                 }
                 var removed = false;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 for (var i = 0; i < this._numMeshes; i++) {
                     if (this._impostors[i] == impostor) {
                         var mesh = this._meshes[i];
                         if (!mesh) {
                             continue;
                         }
-                        this._scene.removeMesh(mesh);
+                        utilityLayerScene.removeMesh(mesh);
                         mesh.dispose();
                         this._numMeshes--;
                         if (this._numMeshes > 0) {
@@ -67058,37 +67120,39 @@ var BABYLON;
                 if (!this._debugMaterial) {
                     this._debugMaterial = new BABYLON.StandardMaterial('', scene);
                     this._debugMaterial.wireframe = true;
+                    this._debugMaterial.emissiveColor = BABYLON.Color3.White();
+                    this._debugMaterial.disableLighting = true;
                 }
                 return this._debugMaterial;
             };
             PhysicsViewer.prototype._getDebugBoxMesh = function (scene) {
                 if (!this._debugBoxMesh) {
                     this._debugBoxMesh = BABYLON.MeshBuilder.CreateBox('physicsBodyBoxViewMesh', { size: 1 }, scene);
-                    this._debugBoxMesh.renderingGroupId = 1;
                     this._debugBoxMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugBoxMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugBoxMesh);
                 }
                 return this._debugBoxMesh.createInstance('physicsBodyBoxViewInstance');
             };
             PhysicsViewer.prototype._getDebugSphereMesh = function (scene) {
                 if (!this._debugSphereMesh) {
                     this._debugSphereMesh = BABYLON.MeshBuilder.CreateSphere('physicsBodySphereViewMesh', { diameter: 1 }, scene);
-                    this._debugSphereMesh.renderingGroupId = 1;
                     this._debugSphereMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugSphereMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugSphereMesh);
                 }
                 return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
             };
-            PhysicsViewer.prototype._getDebugMesh = function (impostor, scene) {
+            PhysicsViewer.prototype._getDebugMesh = function (impostor) {
+                if (!this._utilityLayer) {
+                    return null;
+                }
                 var mesh = null;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 if (impostor.type == BABYLON.PhysicsImpostor.BoxImpostor) {
-                    mesh = this._getDebugBoxMesh(scene);
+                    mesh = this._getDebugBoxMesh(utilityLayerScene);
                     impostor.getBoxSizeToRef(mesh.scaling);
                 }
                 else if (impostor.type == BABYLON.PhysicsImpostor.SphereImpostor) {
-                    mesh = this._getDebugSphereMesh(scene);
+                    mesh = this._getDebugSphereMesh(utilityLayerScene);
                     var radius = impostor.getRadius();
                     mesh.scaling.x = radius * 2;
                     mesh.scaling.y = radius * 2;
@@ -67113,6 +67177,10 @@ var BABYLON;
                 this._impostors.length = 0;
                 this._scene = null;
                 this._physicsEnginePlugin = null;
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return PhysicsViewer;
         }());
@@ -70599,9 +70667,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
-                var flip = dot >= 0;
-                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
+                plane.setDirection(options.sourcePlane.normal);
             }
             return plane;
         };
@@ -79850,9 +79916,11 @@ var BABYLON;
                 }
                 // Environment texture
                 if (parsedData.environmentTexture !== undefined && parsedData.environmentTexture !== null) {
+                    // PBR needed for both HDR texture (gamma space) & a sky box
+                    var isPBR = parsedData.isPBR !== undefined ? parsedData.isPBR : true;
                     if (parsedData.environmentTextureType && parsedData.environmentTextureType === "BABYLON.HDRCubeTexture") {
                         var hdrSize = (parsedData.environmentTextureSize) ? parsedData.environmentTextureSize : 128;
-                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize);
+                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize, true, !isPBR);
                         if (parsedData.environmentTextureRotationY) {
                             hdrTexture.rotationY = parsedData.environmentTextureRotationY;
                         }
@@ -79868,8 +79936,7 @@ var BABYLON;
                     if (parsedData.createDefaultSkybox === true) {
                         var skyboxScale = (scene.activeCamera !== undefined && scene.activeCamera !== null) ? (scene.activeCamera.maxZ - scene.activeCamera.minZ) / 2 : 1000;
                         var skyboxBlurLevel = parsedData.skyboxBlurLevel || 0;
-                        var skyboxIsPBR = parsedData.skyboxIsPBR !== undefined ? parsedData.skyboxIsPBR : true;
-                        scene.createDefaultSkybox(scene.environmentTexture, skyboxIsPBR, skyboxScale, skyboxBlurLevel);
+                        scene.createDefaultSkybox(scene.environmentTexture, isPBR, skyboxScale, skyboxBlurLevel);
                     }
                 }
                 // Finish
@@ -90535,6 +90602,9 @@ var BABYLON;
                 case ImageProcessingConfiguration.TONEMAPPING_ACES:
                     defines.TONEMAPPING_ACES = true;
                     break;
+                default:
+                    defines.TONEMAPPING_ACES = false;
+                    break;
             }
             defines.CONTRAST = (this.contrast !== 1.0);
             defines.EXPOSURE = (this.exposure !== 1.0);
@@ -92869,6 +92939,8 @@ var BABYLON;
             _this._worldTransform = new BABYLON.Matrix();
             _this._needToDecompose = true;
             _this._needToCompose = false;
+            /** @hidden */
+            _this._linkedTransformNode = null;
             _this._skeleton = skeleton;
             _this._localMatrix = localMatrix ? localMatrix.clone() : BABYLON.Matrix.Identity();
             _this._restPose = restPose ? restPose : _this._localMatrix.clone();
@@ -92984,6 +93056,20 @@ var BABYLON;
         Bone.prototype.getAbsoluteTransform = function () {
             return this._absoluteTransform;
         };
+        /**
+         * Links with the given transform node.
+         * The local matrix of this bone is copied from the transform node every frame.
+         * @param transformNode defines the transform node to link to
+         */
+        Bone.prototype.linkTransformNode = function (transformNode) {
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode--;
+            }
+            this._linkedTransformNode = transformNode;
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode++;
+            }
+        };
         Object.defineProperty(Bone.prototype, "position", {
             // Properties (matches AbstractMesh properties)
             /** Gets or sets current position (in local space) */
@@ -94529,19 +94615,25 @@ var BABYLON;
             this.name = name;
             this.id = id;
             /**
-             * Gets the list of child bones
+             * Defines the list of child bones
              */
             this.bones = new Array();
             /**
-             * Gets a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
+             * Defines a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
              */
             this.needInitialSkinMatrix = false;
+            /**
+             * Defines a mesh that override the matrix used to get the world matrix (null by default).
+             */
+            this.overrideMesh = null;
             this._isDirty = true;
             this._meshesWithPoseMatrix = new Array();
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
             this._canUseTextureForBones = false;
+            /** @hidden */
+            this._numBonesWithLinkedTransformNode = 0;
             /**
              * Specifies if the skeleton should be serialized
              */
@@ -94832,6 +94924,18 @@ var BABYLON;
          * Build all resources required to render a skeleton
          */
         Skeleton.prototype.prepare = function () {
+            // Update the local matrix of bones with linked transform nodes.
+            if (this._numBonesWithLinkedTransformNode > 0) {
+                for (var _i = 0, _a = this.bones; _i < _a.length; _i++) {
+                    var bone_1 = _a[_i];
+                    if (bone_1._linkedTransformNode) {
+                        // Computing the world matrix also computes the local matrix.
+                        bone_1._linkedTransformNode.computeWorldMatrix();
+                        bone_1._matrix = bone_1._linkedTransformNode._localMatrix;
+                        bone_1.markAsDirty();
+                    }
+                }
+            }
             if (!this._isDirty) {
                 return;
             }
@@ -98893,6 +98997,7 @@ var BABYLON;
                 this._originDirection = this._origin.subtract(this._originTop).normalize();
             }
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the updraft event (cylinder).
@@ -98924,6 +99029,9 @@ var BABYLON;
         PhysicsUpdraftEvent.prototype.dispose = function (force) {
             var _this = this;
             if (force === void 0) { force = true; }
+            if (!this._cylinder) {
+                return;
+            }
             if (force) {
                 this._cylinder.dispose();
             }
@@ -98975,7 +99083,6 @@ var BABYLON;
         };
         PhysicsUpdraftEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -99010,6 +99117,7 @@ var BABYLON;
             this._origin.addToRef(new BABYLON.Vector3(0, this._height / 2, 0), this._cylinderPosition);
             this._origin.addToRef(new BABYLON.Vector3(0, this._height, 0), this._originTop);
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the vortex event (cylinder).
@@ -99114,7 +99222,6 @@ var BABYLON;
         };
         PhysicsVortexEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -102103,10 +102210,12 @@ var BABYLON;
         /**
          * Instantiates a UtilityLayerRenderer
          * @param originalScene the original scene that will be rendered on top of
+         * @param handleEvents boolean indicating if the utility layer should handle events
          */
         function UtilityLayerRenderer(
         /** the original scene that will be rendered on top of */
-        originalScene) {
+        originalScene, handleEvents) {
+            if (handleEvents === void 0) { handleEvents = true; }
             var _this = this;
             this.originalScene = originalScene;
             this._pointerCaptures = {};
@@ -102138,92 +102247,94 @@ var BABYLON;
             originalScene.getEngine().scenes.pop();
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority
             this.utilityLayerScene.detachControl();
-            this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
-                if (!_this.processAllEvents) {
-                    if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                        return;
-                    }
-                }
-                var pointerEvent = (prePointerInfo.event);
-                if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
-                    _this._pointerCaptures[pointerEvent.pointerId] = false;
-                    return;
-                }
-                var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
-                if (!prePointerInfo.ray && utilityScenePick) {
-                    prePointerInfo.ray = utilityScenePick.ray;
-                }
-                // always fire the prepointer oversvable
-                _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
-                // allow every non pointer down event to flow to the utility layer
-                if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
-                    if (!prePointerInfo.skipOnPointerObservable) {
-                        _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
+            if (handleEvents) {
+                this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
+                    if (!_this.processAllEvents) {
+                        if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                            return;
+                        }
                     }
-                    if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                    var pointerEvent = (prePointerInfo.event);
+                    if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
                         _this._pointerCaptures[pointerEvent.pointerId] = false;
+                        return;
                     }
-                    return;
-                }
-                if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
-                    // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
-                    if (utilityScenePick && utilityScenePick.hit) {
+                    var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
+                    if (!prePointerInfo.ray && utilityScenePick) {
+                        prePointerInfo.ray = utilityScenePick.ray;
+                    }
+                    // always fire the prepointer oversvable
+                    _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
+                    // allow every non pointer down event to flow to the utility layer
+                    if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
                         if (!prePointerInfo.skipOnPointerObservable) {
                             _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                         }
-                        prePointerInfo.skipOnPointerObservable = true;
-                    }
-                }
-                else {
-                    var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
-                    var pointerEvent_1 = (prePointerInfo.event);
-                    // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
-                    if (originalScenePick && utilityScenePick) {
-                        // No pick in utility scene
-                        if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                // We touched an utility mesh present in the main scene
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
-                            }
-                            else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                                _this._pointerCaptures[pointerEvent_1.pointerId] = true;
-                            }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
-                            }
+                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                            _this._pointerCaptures[pointerEvent.pointerId] = false;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
-                            // We pick something in utility scene or the pick in utility is closer than the one in main scene
-                            _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
-                            // If a previous utility layer set this, do not unset this
+                        return;
+                    }
+                    if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
+                        // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
+                        if (utilityScenePick && utilityScenePick.hit) {
                             if (!prePointerInfo.skipOnPointerObservable) {
-                                prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                             }
+                            prePointerInfo.skipOnPointerObservable = true;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
-                            // We have a pick in both scenes but main is closer than utility
-                            // We touched an utility mesh present in the main scene
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
+                    }
+                    else {
+                        var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
+                        var pointerEvent_1 = (prePointerInfo.event);
+                        // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
+                        if (originalScenePick && utilityScenePick) {
+                            // No pick in utility scene
+                            if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    // We touched an utility mesh present in the main scene
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                                    _this._pointerCaptures[pointerEvent_1.pointerId] = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
                             }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
+                                // We pick something in utility scene or the pick in utility is closer than the one in main scene
+                                _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
+                                // If a previous utility layer set this, do not unset this
+                                if (!prePointerInfo.skipOnPointerObservable) {
+                                    prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                }
+                            }
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
+                                // We have a pick in both scenes but main is closer than utility
+                                // We touched an utility mesh present in the main scene
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
+                            }
+                            if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
+                                _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                             }
-                        }
-                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
-                            _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                         }
                     }
-                }
-            });
+                });
+            }
             // Render directly on top of existing scene without clearing
             this.utilityLayerScene.autoClear = false;
             this._afterRenderObserver = this.originalScene.onAfterRenderObservable.add(function () {
@@ -109301,6 +109412,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) {
@@ -121085,6 +121197,7 @@ var BABYLON;
             hdrSkybox.infiniteDistance = true;
             hdrSkybox.material = skyboxMaterial;
         }
+        hdrSkybox.isPickable = false;
         return hdrSkybox;
     };
     BABYLON.Scene.prototype.createDefaultEnvironment = function (options) {

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


+ 264 - 151
dist/preview release/es6.js

@@ -4101,6 +4101,14 @@ var BABYLON;
             return this;
         };
         /**
+         * Determines equality between Color4 objects
+         * @param otherColor defines the second operand
+         * @returns true if the rgba values are equal to the given ones
+         */
+        Color4.prototype.equals = function (otherColor) {
+            return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b && this.a === otherColor.a;
+        };
+        /**
          * Creates a new Color4 set with the added values of the current Color4 and of the given one
          * @param right defines the second operand
          * @returns a new Color4 object
@@ -12912,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.9";
             },
             enumerable: true,
             configurable: true
@@ -18786,6 +18794,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Gets or sets a boolean used to define if the node must be serialized
              */
             this.doNotSerialize = false;
@@ -18873,7 +18885,7 @@ var BABYLON;
                     if (index !== -1) {
                         this._parentNode._children.splice(index, 1);
                     }
-                    if (!parent) {
+                    if (!parent && !this._isDisposed) {
                         this.addToSceneRootNodes();
                     }
                 }
@@ -19345,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++) {
@@ -19375,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
@@ -20118,7 +20130,8 @@ var BABYLON;
              * By default the system will update normals to compensate
              */
             _this.ignoreNonUniformScaling = false;
-            _this._localWorld = BABYLON.Matrix.Zero();
+            /** @hidden */
+            _this._localMatrix = BABYLON.Matrix.Zero();
             _this._absolutePosition = BABYLON.Vector3.Zero();
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
@@ -20260,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)) {
@@ -20432,7 +20445,7 @@ var BABYLON;
          */
         TransformNode.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
-            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformNormal(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20442,7 +20455,7 @@ var BABYLON;
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
             var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
-            this._localWorld.invertToRef(invLocalWorldMatrix);
+            this._localMatrix.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20452,7 +20465,7 @@ var BABYLON;
          */
         TransformNode.prototype.locallyTranslate = function (vector3) {
             this.computeWorldMatrix(true);
-            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localWorld);
+            this.position = BABYLON.Vector3.TransformCoordinates(vector3, this._localMatrix);
             return this;
         };
         /**
@@ -20472,17 +20485,7 @@ var BABYLON;
             var dv = TransformNode._lookAtVectorCache;
             var pos = space === BABYLON.Space.LOCAL ? this.position : this.getAbsolutePosition();
             targetPoint.subtractToRef(pos, dv);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            if (this.rotationQuaternion) {
-                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
-            }
-            else {
-                this.rotation.x = pitch + pitchCor;
-                this.rotation.y = yaw + yawCor;
-                this.rotation.z = rollCor;
-            }
+            this.setDirection(dv, yawCor, pitchCor, rollCor);
             // Correct for parent's rotation offset
             if (space === BABYLON.Space.WORLD && this.parent) {
                 if (this.rotationQuaternion) {
@@ -20537,6 +20540,31 @@ var BABYLON;
             return this;
         };
         /**
+         * Sets this transform node rotation to the given local axis.
+         * @param localAxis the axis in local space
+         * @param yawCor optional yaw (y-axis) correction in radians
+         * @param pitchCor optional pitch (x-axis) correction in radians
+         * @param rollCor optional roll (z-axis) correction in radians
+         * @returns this TransformNode
+         */
+        TransformNode.prototype.setDirection = function (localAxis, yawCor, pitchCor, rollCor) {
+            if (yawCor === void 0) { yawCor = 0; }
+            if (pitchCor === void 0) { pitchCor = 0; }
+            if (rollCor === void 0) { rollCor = 0; }
+            var yaw = -Math.atan2(localAxis.z, localAxis.x) - Math.PI / 2;
+            var len = Math.sqrt(localAxis.x * localAxis.x + localAxis.z * localAxis.z);
+            var pitch = Math.atan2(localAxis.y, len);
+            if (this.rotationQuaternion) {
+                BABYLON.Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
+            }
+            else {
+                this.rotation.x = pitch + pitchCor;
+                this.rotation.y = yaw + yawCor;
+                this.rotation.z = rollCor;
+            }
+            return this;
+        };
+        /**
          * Sets a new pivot point to the current node
          * @param point defines the new pivot point to use
          * @param space defines if the point is in world or local space (local by default)
@@ -20901,7 +20929,7 @@ var BABYLON;
                 BABYLON.Tmp.Matrix[5].multiplyToRef(this._pivotMatrixInverse, BABYLON.Tmp.Matrix[5]);
             }
             // Local world
-            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localWorld);
+            BABYLON.Tmp.Matrix[5].multiplyToRef(BABYLON.Tmp.Matrix[2], this._localMatrix);
             // Parent
             if (this.parent && this.parent.getWorldMatrix) {
                 if (this.billboardMode !== TransformNode.BILLBOARDMODE_NONE) {
@@ -20912,24 +20940,24 @@ var BABYLON;
                     else {
                         BABYLON.Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                     }
-                    this._localWorld.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
+                    this._localMatrix.getTranslationToRef(BABYLON.Tmp.Vector3[5]);
                     BABYLON.Vector3.TransformCoordinatesToRef(BABYLON.Tmp.Vector3[5], BABYLON.Tmp.Matrix[5], BABYLON.Tmp.Vector3[5]);
-                    this._worldMatrix.copyFrom(this._localWorld);
+                    this._worldMatrix.copyFrom(this._localMatrix);
                     this._worldMatrix.setTranslation(BABYLON.Tmp.Vector3[5]);
                 }
                 else {
                     if (this._transformToBoneReferal) {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), BABYLON.Tmp.Matrix[6]);
                         BABYLON.Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
                     }
                     else {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
                     }
                 }
                 this._markSyncedWithParent();
             }
             else {
-                this._worldMatrix.copyFrom(this._localWorld);
+                this._worldMatrix.copyFrom(this._localMatrix);
             }
             // Normal matrix
             if (!this.ignoreNonUniformScaling) {
@@ -22208,13 +22236,14 @@ var BABYLON;
         };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             if (this._boundingInfo) {
-                this._boundingInfo.update(this.worldMatrixFromCache);
+                this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
             }
             else {
-                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, this.worldMatrixFromCache);
+                this._boundingInfo = new BABYLON.BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
             }
-            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+            this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
             return this;
         };
         /** @hidden */
@@ -24571,6 +24600,7 @@ var BABYLON;
                 this._rigCameras[i].minZ = this.minZ;
                 this._rigCameras[i].maxZ = this.maxZ;
                 this._rigCameras[i].fov = this.fov;
+                this._rigCameras[i].upVector.copyFrom(this.upVector);
             }
             // only update viewport when ANAGLYPH
             if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
@@ -25801,6 +25831,10 @@ var BABYLON;
              */
             _this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            _this.reservedDataStore = null;
+            /**
              * Use this array to add regular expressions used to disable offline support for specific urls
              */
             _this.disableOfflineSupportExceptionRules = new Array();
@@ -31615,6 +31649,10 @@ var BABYLON;
              * Gets or sets an object used to store user defined information.
              */
             this.metadata = null;
+            /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
             this._hasAlpha = false;
             /**
              * Defines if the alpha value should be determined via the rgb values.
@@ -31703,8 +31741,8 @@ var BABYLON;
             this._cachedSize = BABYLON.Size.Zero();
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             if (this._scene) {
-                this._scene.addTexture(this);
                 this.uniqueId = this._scene.getUniqueId();
+                this._scene.addTexture(this);
             }
             this._uid = null;
         }
@@ -34234,10 +34272,11 @@ var BABYLON;
             if (!effect) {
                 return this;
             }
+            var effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             var sideOrientation = this.overrideMaterialSideOrientation;
             if (sideOrientation == null) {
                 sideOrientation = this._effectiveMaterial.sideOrientation;
-                if (this._getWorldMatrixDeterminant() < 0) {
+                if (effectiveMesh._getWorldMatrixDeterminant() < 0) {
                     sideOrientation = (sideOrientation === BABYLON.Material.ClockWiseSideOrientation ? BABYLON.Material.CounterClockWiseSideOrientation : BABYLON.Material.ClockWiseSideOrientation);
                 }
             }
@@ -34250,7 +34289,7 @@ var BABYLON;
             if (!hardwareInstancedRendering) { // Binding will be done later because we need to add more info to the VB
                 this._bind(subMesh, effect, fillMode);
             }
-            var world = this.getWorldMatrix();
+            var world = effectiveMesh.getWorldMatrix();
             if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
@@ -36915,6 +36954,10 @@ var BABYLON;
              */
             this.metadata = null;
             /**
+             * For internal use only. Please do not use.
+             */
+            this.reservedDataStore = null;
+            /**
              * Specifies if the ready state should be checked on each call
              */
             this.checkReadyOnEveryCall = false;
@@ -49011,6 +49054,8 @@ var BABYLON;
             /** @hidden */
             _this._currentTarget = BABYLON.Vector3.Zero();
             /** @hidden */
+            _this._initialFocalDistance = 1;
+            /** @hidden */
             _this._viewMatrix = BABYLON.Matrix.Zero();
             /** @hidden */
             _this._camMatrix = BABYLON.Matrix.Zero();
@@ -49130,6 +49175,7 @@ var BABYLON;
         /** @hidden */
         TargetCamera.prototype.setTarget = function (target) {
             this.upVector.normalize();
+            this._initialFocalDistance = target.subtract(this.position).length();
             if (this.position.z === target.z) {
                 this.position.z += BABYLON.Epsilon;
             }
@@ -49330,10 +49376,8 @@ var BABYLON;
                     //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
                     var leftSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : -1;
                     var rightSign = (this.cameraRigMode === BABYLON.Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 : 1;
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft.position);
-                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
-                    camLeft.setTarget(this.getTarget());
-                    camRight.setTarget(this.getTarget());
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * leftSign, camLeft);
+                    this._getRigCamPositionAndTarget(this._cameraRigParams.stereoHalfAngle * rightSign, camRight);
                     break;
                 case BABYLON.Camera.RIG_MODE_VR:
                     if (camLeft.rotationQuaternion) {
@@ -49350,13 +49394,17 @@ var BABYLON;
             }
             _super.prototype._updateRigCameras.call(this);
         };
-        TargetCamera.prototype._getRigCamPosition = function (halfSpace, result) {
+        TargetCamera.prototype._getRigCamPositionAndTarget = function (halfSpace, rigCamera) {
             var target = this.getTarget();
-            BABYLON.Matrix.TranslationToRef(-target.x, -target.y, -target.z, TargetCamera._TargetTransformMatrix);
+            target.subtractToRef(this.position, TargetCamera._TargetFocalPoint);
+            TargetCamera._TargetFocalPoint.normalize().scaleInPlace(this._initialFocalDistance);
+            var newFocalTarget = TargetCamera._TargetFocalPoint.addInPlace(this.position);
+            BABYLON.Matrix.TranslationToRef(-newFocalTarget.x, -newFocalTarget.y, -newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._TargetTransformMatrix.multiplyToRef(BABYLON.Matrix.RotationY(halfSpace), TargetCamera._RigCamTransformMatrix);
-            BABYLON.Matrix.TranslationToRef(target.x, target.y, target.z, TargetCamera._TargetTransformMatrix);
+            BABYLON.Matrix.TranslationToRef(newFocalTarget.x, newFocalTarget.y, newFocalTarget.z, TargetCamera._TargetTransformMatrix);
             TargetCamera._RigCamTransformMatrix.multiplyToRef(TargetCamera._TargetTransformMatrix, TargetCamera._RigCamTransformMatrix);
-            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, result);
+            BABYLON.Vector3.TransformCoordinatesToRef(this.position, TargetCamera._RigCamTransformMatrix, rigCamera.position);
+            rigCamera.setTarget(newFocalTarget);
         };
         /**
          * Gets the current object class name.
@@ -49367,6 +49415,7 @@ var BABYLON;
         };
         TargetCamera._RigCamTransformMatrix = new BABYLON.Matrix();
         TargetCamera._TargetTransformMatrix = new BABYLON.Matrix();
+        TargetCamera._TargetFocalPoint = new BABYLON.Vector3();
         __decorate([
             BABYLON.serializeAsVector3()
         ], TargetCamera.prototype, "rotation", void 0);
@@ -66343,7 +66392,6 @@ var BABYLON;
              * @param scene defines the hosting scene
              * @param autoUpdateBonesMatrices defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)
              * @param renderingGroupId defines the rendering group id to use with the viewer
-             * @param utilityLayerRenderer defines an optional utility layer to render the helper on
              */
             function SkeletonViewer(
             /** defines the skeleton to render */
@@ -66353,21 +66401,21 @@ var BABYLON;
             /** defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)  */
             autoUpdateBonesMatrices, 
             /** defines the rendering group id to use with the viewer */
-            renderingGroupId, 
-            /** defines an optional utility layer to render the helper on */
-            utilityLayerRenderer) {
+            renderingGroupId) {
                 if (autoUpdateBonesMatrices === void 0) { autoUpdateBonesMatrices = true; }
                 if (renderingGroupId === void 0) { renderingGroupId = 1; }
                 this.skeleton = skeleton;
                 this.mesh = mesh;
                 this.autoUpdateBonesMatrices = autoUpdateBonesMatrices;
                 this.renderingGroupId = renderingGroupId;
-                this.utilityLayerRenderer = utilityLayerRenderer;
                 /** Gets or sets the color used to render the skeleton */
                 this.color = BABYLON.Color3.White();
                 this._debugLines = new Array();
                 this._isEnabled = false;
                 this._scene = scene;
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
                 this.update();
                 this._renderFunction = this.update.bind(this);
             }
@@ -66462,6 +66510,9 @@ var BABYLON;
             };
             /** Update the viewer to sync with current skeleton state */
             SkeletonViewer.prototype.update = function () {
+                if (!this._utilityLayer) {
+                    return;
+                }
                 if (this.autoUpdateBonesMatrices) {
                     this.skeleton.computeAbsoluteTransforms();
                 }
@@ -66471,7 +66522,7 @@ var BABYLON;
                 else {
                     this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
                 }
-                var targetScene = this.utilityLayerRenderer ? this.utilityLayerRenderer.utilityLayerScene : this._scene;
+                var targetScene = this._utilityLayer.utilityLayerScene;
                 if (!this._debugMesh) {
                     this._debugMesh = BABYLON.MeshBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: null }, targetScene);
                     this._debugMesh.renderingGroupId = this.renderingGroupId;
@@ -66484,11 +66535,16 @@ var BABYLON;
             };
             /** Release associated resources */
             SkeletonViewer.prototype.dispose = function () {
+                this.isEnabled = false;
                 if (this._debugMesh) {
                     this.isEnabled = false;
                     this._debugMesh.dispose();
                     this._debugMesh = null;
                 }
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return SkeletonViewer;
         }());
@@ -66516,6 +66572,8 @@ var BABYLON;
              */
             function AxesViewer(scene, scaleLines) {
                 if (scaleLines === void 0) { scaleLines = 1; }
+                this._tmpVector = new BABYLON.Vector3();
+                this._scaleLinesFactor = 4;
                 /**
                  * Gets or sets a number used to scale line length
                  */
@@ -66534,11 +66592,11 @@ var BABYLON;
                 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._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._ymesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._ymesh.scaling.scaleInPlace(4);
+                this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 this._zmesh.rotationQuaternion = new BABYLON.Quaternion();
-                this._zmesh.scaling.scaleInPlace(4);
+                this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 AxesViewer._recursiveChangeRenderingGroupId(this._xmesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._ymesh, 2);
                 AxesViewer._recursiveChangeRenderingGroupId(this._zmesh, 2);
@@ -66585,21 +66643,21 @@ var BABYLON;
             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();
+                    xaxis.scaleToRef(-1, this._tmpVector);
+                    this._xmesh.setDirection(this._tmpVector);
+                    this._xmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    yaxis.scaleToRef(-1, this._tmpVector);
+                    this._ymesh.setDirection(this._tmpVector);
+                    this._ymesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
                 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();
+                    zaxis.scaleToRef(-1, this._tmpVector);
+                    this._zmesh.setDirection(this._tmpVector);
+                    this._zmesh.scaling.setAll(this.scaleLines * this._scaleLinesFactor);
                 }
             };
             /** Releases resources */
@@ -66913,7 +66971,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.
@@ -66972,6 +67030,9 @@ var BABYLON;
                 if (physicEngine) {
                     this._physicsEnginePlugin = physicEngine.getPhysicsPlugin();
                 }
+                this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene, false);
+                this._utilityLayer.pickUtilitySceneFirst = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
             }
             /** @hidden */
             PhysicsViewer.prototype._updateDebugMeshes = function () {
@@ -67006,7 +67067,7 @@ var BABYLON;
                         return null;
                     }
                 }
-                var debugMesh = this._getDebugMesh(impostor, this._scene);
+                var debugMesh = this._getDebugMesh(impostor);
                 if (debugMesh) {
                     this._impostors[this._numMeshes] = impostor;
                     this._meshes[this._numMeshes] = debugMesh;
@@ -67023,17 +67084,18 @@ var BABYLON;
              * @param impostor defines the impostor to hide
              */
             PhysicsViewer.prototype.hideImpostor = function (impostor) {
-                if (!impostor || !this._scene) {
+                if (!impostor || !this._scene || !this._utilityLayer) {
                     return;
                 }
                 var removed = false;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 for (var i = 0; i < this._numMeshes; i++) {
                     if (this._impostors[i] == impostor) {
                         var mesh = this._meshes[i];
                         if (!mesh) {
                             continue;
                         }
-                        this._scene.removeMesh(mesh);
+                        utilityLayerScene.removeMesh(mesh);
                         mesh.dispose();
                         this._numMeshes--;
                         if (this._numMeshes > 0) {
@@ -67058,37 +67120,39 @@ var BABYLON;
                 if (!this._debugMaterial) {
                     this._debugMaterial = new BABYLON.StandardMaterial('', scene);
                     this._debugMaterial.wireframe = true;
+                    this._debugMaterial.emissiveColor = BABYLON.Color3.White();
+                    this._debugMaterial.disableLighting = true;
                 }
                 return this._debugMaterial;
             };
             PhysicsViewer.prototype._getDebugBoxMesh = function (scene) {
                 if (!this._debugBoxMesh) {
                     this._debugBoxMesh = BABYLON.MeshBuilder.CreateBox('physicsBodyBoxViewMesh', { size: 1 }, scene);
-                    this._debugBoxMesh.renderingGroupId = 1;
                     this._debugBoxMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugBoxMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugBoxMesh);
                 }
                 return this._debugBoxMesh.createInstance('physicsBodyBoxViewInstance');
             };
             PhysicsViewer.prototype._getDebugSphereMesh = function (scene) {
                 if (!this._debugSphereMesh) {
                     this._debugSphereMesh = BABYLON.MeshBuilder.CreateSphere('physicsBodySphereViewMesh', { diameter: 1 }, scene);
-                    this._debugSphereMesh.renderingGroupId = 1;
                     this._debugSphereMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
                     this._debugSphereMesh.material = this._getDebugMaterial(scene);
-                    scene.removeMesh(this._debugSphereMesh);
                 }
                 return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
             };
-            PhysicsViewer.prototype._getDebugMesh = function (impostor, scene) {
+            PhysicsViewer.prototype._getDebugMesh = function (impostor) {
+                if (!this._utilityLayer) {
+                    return null;
+                }
                 var mesh = null;
+                var utilityLayerScene = this._utilityLayer.utilityLayerScene;
                 if (impostor.type == BABYLON.PhysicsImpostor.BoxImpostor) {
-                    mesh = this._getDebugBoxMesh(scene);
+                    mesh = this._getDebugBoxMesh(utilityLayerScene);
                     impostor.getBoxSizeToRef(mesh.scaling);
                 }
                 else if (impostor.type == BABYLON.PhysicsImpostor.SphereImpostor) {
-                    mesh = this._getDebugSphereMesh(scene);
+                    mesh = this._getDebugSphereMesh(utilityLayerScene);
                     var radius = impostor.getRadius();
                     mesh.scaling.x = radius * 2;
                     mesh.scaling.y = radius * 2;
@@ -67113,6 +67177,10 @@ var BABYLON;
                 this._impostors.length = 0;
                 this._scene = null;
                 this._physicsEnginePlugin = null;
+                if (this._utilityLayer) {
+                    this._utilityLayer.dispose();
+                    this._utilityLayer = null;
+                }
             };
             return PhysicsViewer;
         }());
@@ -70599,9 +70667,7 @@ var BABYLON;
             vertexData.applyToMesh(plane, options.updatable);
             if (options.sourcePlane) {
                 plane.translate(options.sourcePlane.normal, -options.sourcePlane.d);
-                var dot = BABYLON.Vector3.Dot(plane.position, options.sourcePlane.normal);
-                var flip = dot >= 0;
-                plane.lookAt(BABYLON.Vector3.Zero(), 0, flip ? Math.PI : 0, 0);
+                plane.setDirection(options.sourcePlane.normal);
             }
             return plane;
         };
@@ -79850,9 +79916,11 @@ var BABYLON;
                 }
                 // Environment texture
                 if (parsedData.environmentTexture !== undefined && parsedData.environmentTexture !== null) {
+                    // PBR needed for both HDR texture (gamma space) & a sky box
+                    var isPBR = parsedData.isPBR !== undefined ? parsedData.isPBR : true;
                     if (parsedData.environmentTextureType && parsedData.environmentTextureType === "BABYLON.HDRCubeTexture") {
                         var hdrSize = (parsedData.environmentTextureSize) ? parsedData.environmentTextureSize : 128;
-                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize);
+                        var hdrTexture = new BABYLON.HDRCubeTexture(rootUrl + parsedData.environmentTexture, scene, hdrSize, true, !isPBR);
                         if (parsedData.environmentTextureRotationY) {
                             hdrTexture.rotationY = parsedData.environmentTextureRotationY;
                         }
@@ -79868,8 +79936,7 @@ var BABYLON;
                     if (parsedData.createDefaultSkybox === true) {
                         var skyboxScale = (scene.activeCamera !== undefined && scene.activeCamera !== null) ? (scene.activeCamera.maxZ - scene.activeCamera.minZ) / 2 : 1000;
                         var skyboxBlurLevel = parsedData.skyboxBlurLevel || 0;
-                        var skyboxIsPBR = parsedData.skyboxIsPBR !== undefined ? parsedData.skyboxIsPBR : true;
-                        scene.createDefaultSkybox(scene.environmentTexture, skyboxIsPBR, skyboxScale, skyboxBlurLevel);
+                        scene.createDefaultSkybox(scene.environmentTexture, isPBR, skyboxScale, skyboxBlurLevel);
                     }
                 }
                 // Finish
@@ -90535,6 +90602,9 @@ var BABYLON;
                 case ImageProcessingConfiguration.TONEMAPPING_ACES:
                     defines.TONEMAPPING_ACES = true;
                     break;
+                default:
+                    defines.TONEMAPPING_ACES = false;
+                    break;
             }
             defines.CONTRAST = (this.contrast !== 1.0);
             defines.EXPOSURE = (this.exposure !== 1.0);
@@ -92869,6 +92939,8 @@ var BABYLON;
             _this._worldTransform = new BABYLON.Matrix();
             _this._needToDecompose = true;
             _this._needToCompose = false;
+            /** @hidden */
+            _this._linkedTransformNode = null;
             _this._skeleton = skeleton;
             _this._localMatrix = localMatrix ? localMatrix.clone() : BABYLON.Matrix.Identity();
             _this._restPose = restPose ? restPose : _this._localMatrix.clone();
@@ -92984,6 +93056,20 @@ var BABYLON;
         Bone.prototype.getAbsoluteTransform = function () {
             return this._absoluteTransform;
         };
+        /**
+         * Links with the given transform node.
+         * The local matrix of this bone is copied from the transform node every frame.
+         * @param transformNode defines the transform node to link to
+         */
+        Bone.prototype.linkTransformNode = function (transformNode) {
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode--;
+            }
+            this._linkedTransformNode = transformNode;
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode++;
+            }
+        };
         Object.defineProperty(Bone.prototype, "position", {
             // Properties (matches AbstractMesh properties)
             /** Gets or sets current position (in local space) */
@@ -94529,19 +94615,25 @@ var BABYLON;
             this.name = name;
             this.id = id;
             /**
-             * Gets the list of child bones
+             * Defines the list of child bones
              */
             this.bones = new Array();
             /**
-             * Gets a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
+             * Defines a boolean indicating if the root matrix is provided by meshes or by the current skeleton (this is the default value)
              */
             this.needInitialSkinMatrix = false;
+            /**
+             * Defines a mesh that override the matrix used to get the world matrix (null by default).
+             */
+            this.overrideMesh = null;
             this._isDirty = true;
             this._meshesWithPoseMatrix = new Array();
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
             this._canUseTextureForBones = false;
+            /** @hidden */
+            this._numBonesWithLinkedTransformNode = 0;
             /**
              * Specifies if the skeleton should be serialized
              */
@@ -94832,6 +94924,18 @@ var BABYLON;
          * Build all resources required to render a skeleton
          */
         Skeleton.prototype.prepare = function () {
+            // Update the local matrix of bones with linked transform nodes.
+            if (this._numBonesWithLinkedTransformNode > 0) {
+                for (var _i = 0, _a = this.bones; _i < _a.length; _i++) {
+                    var bone_1 = _a[_i];
+                    if (bone_1._linkedTransformNode) {
+                        // Computing the world matrix also computes the local matrix.
+                        bone_1._linkedTransformNode.computeWorldMatrix();
+                        bone_1._matrix = bone_1._linkedTransformNode._localMatrix;
+                        bone_1.markAsDirty();
+                    }
+                }
+            }
             if (!this._isDirty) {
                 return;
             }
@@ -98893,6 +98997,7 @@ var BABYLON;
                 this._originDirection = this._origin.subtract(this._originTop).normalize();
             }
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the updraft event (cylinder).
@@ -98924,6 +99029,9 @@ var BABYLON;
         PhysicsUpdraftEvent.prototype.dispose = function (force) {
             var _this = this;
             if (force === void 0) { force = true; }
+            if (!this._cylinder) {
+                return;
+            }
             if (force) {
                 this._cylinder.dispose();
             }
@@ -98975,7 +99083,6 @@ var BABYLON;
         };
         PhysicsUpdraftEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -99010,6 +99117,7 @@ var BABYLON;
             this._origin.addToRef(new BABYLON.Vector3(0, this._height / 2, 0), this._cylinderPosition);
             this._origin.addToRef(new BABYLON.Vector3(0, this._height, 0), this._originTop);
             this._tickCallback = this._tick.bind(this);
+            this._prepareCylinder();
         }
         /**
          * Returns the data related to the vortex event (cylinder).
@@ -99114,7 +99222,6 @@ var BABYLON;
         };
         PhysicsVortexEvent.prototype._intersectsWithCylinder = function (impostor) {
             var impostorObject = impostor.object;
-            this._prepareCylinder();
             this._cylinder.position = this._cylinderPosition;
             return this._cylinder.intersectsMesh(impostorObject, true);
         };
@@ -102103,10 +102210,12 @@ var BABYLON;
         /**
          * Instantiates a UtilityLayerRenderer
          * @param originalScene the original scene that will be rendered on top of
+         * @param handleEvents boolean indicating if the utility layer should handle events
          */
         function UtilityLayerRenderer(
         /** the original scene that will be rendered on top of */
-        originalScene) {
+        originalScene, handleEvents) {
+            if (handleEvents === void 0) { handleEvents = true; }
             var _this = this;
             this.originalScene = originalScene;
             this._pointerCaptures = {};
@@ -102138,92 +102247,94 @@ var BABYLON;
             originalScene.getEngine().scenes.pop();
             // Detach controls on utility scene, events will be fired by logic below to handle picking priority
             this.utilityLayerScene.detachControl();
-            this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
-                if (!_this.processAllEvents) {
-                    if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
-                        && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                        return;
-                    }
-                }
-                var pointerEvent = (prePointerInfo.event);
-                if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
-                    _this._pointerCaptures[pointerEvent.pointerId] = false;
-                    return;
-                }
-                var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
-                if (!prePointerInfo.ray && utilityScenePick) {
-                    prePointerInfo.ray = utilityScenePick.ray;
-                }
-                // always fire the prepointer oversvable
-                _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
-                // allow every non pointer down event to flow to the utility layer
-                if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
-                    if (!prePointerInfo.skipOnPointerObservable) {
-                        _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
+            if (handleEvents) {
+                this._originalPointerObserver = originalScene.onPrePointerObservable.add(function (prePointerInfo, eventState) {
+                    if (!_this.processAllEvents) {
+                        if (prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERUP
+                            && prePointerInfo.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                            return;
+                        }
                     }
-                    if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                    var pointerEvent = (prePointerInfo.event);
+                    if (originalScene.isPointerCaptured(pointerEvent.pointerId)) {
                         _this._pointerCaptures[pointerEvent.pointerId] = false;
+                        return;
                     }
-                    return;
-                }
-                if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
-                    // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
-                    if (utilityScenePick && utilityScenePick.hit) {
+                    var utilityScenePick = prePointerInfo.ray ? _this.utilityLayerScene.pickWithRay(prePointerInfo.ray) : _this.utilityLayerScene.pick(originalScene.pointerX, originalScene.pointerY);
+                    if (!prePointerInfo.ray && utilityScenePick) {
+                        prePointerInfo.ray = utilityScenePick.ray;
+                    }
+                    // always fire the prepointer oversvable
+                    _this.utilityLayerScene.onPrePointerObservable.notifyObservers(prePointerInfo);
+                    // allow every non pointer down event to flow to the utility layer
+                    if (_this.onlyCheckPointerDownEvents && prePointerInfo.type != BABYLON.PointerEventTypes.POINTERDOWN) {
                         if (!prePointerInfo.skipOnPointerObservable) {
                             _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                         }
-                        prePointerInfo.skipOnPointerObservable = true;
-                    }
-                }
-                else {
-                    var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
-                    var pointerEvent_1 = (prePointerInfo.event);
-                    // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
-                    if (originalScenePick && utilityScenePick) {
-                        // No pick in utility scene
-                        if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                // We touched an utility mesh present in the main scene
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
-                            }
-                            else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                                _this._pointerCaptures[pointerEvent_1.pointerId] = true;
-                            }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
-                            }
+                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent.pointerId]) {
+                            _this._pointerCaptures[pointerEvent.pointerId] = false;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
-                            // We pick something in utility scene or the pick in utility is closer than the one in main scene
-                            _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
-                            // If a previous utility layer set this, do not unset this
+                        return;
+                    }
+                    if (_this.utilityLayerScene.autoClearDepthAndStencil || _this.pickUtilitySceneFirst) {
+                        // If this layer is an overlay, check if this layer was hit and if so, skip pointer events for the main scene
+                        if (utilityScenePick && utilityScenePick.hit) {
                             if (!prePointerInfo.skipOnPointerObservable) {
-                                prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                _this.utilityLayerScene.onPointerObservable.notifyObservers(new BABYLON.PointerInfo(prePointerInfo.type, prePointerInfo.event, utilityScenePick));
                             }
+                            prePointerInfo.skipOnPointerObservable = true;
                         }
-                        else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
-                            // We have a pick in both scenes but main is closer than utility
-                            // We touched an utility mesh present in the main scene
-                            if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
-                                _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
-                                prePointerInfo.skipOnPointerObservable = true;
+                    }
+                    else {
+                        var originalScenePick = prePointerInfo.ray ? originalScene.pickWithRay(prePointerInfo.ray) : originalScene.pick(originalScene.pointerX, originalScene.pointerY);
+                        var pointerEvent_1 = (prePointerInfo.event);
+                        // If the layer can be occluded by the original scene, only fire pointer events to the first layer that hit they ray
+                        if (originalScenePick && utilityScenePick) {
+                            // No pick in utility scene
+                            if (utilityScenePick.distance === 0 && originalScenePick.pickedMesh) {
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    // We touched an utility mesh present in the main scene
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                                    _this._pointerCaptures[pointerEvent_1.pointerId] = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
                             }
-                            else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
-                                // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
-                                _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
-                                delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance < originalScenePick.distance || originalScenePick.distance === 0)) {
+                                // We pick something in utility scene or the pick in utility is closer than the one in main scene
+                                _this._notifyObservers(prePointerInfo, utilityScenePick, pointerEvent_1);
+                                // If a previous utility layer set this, do not unset this
+                                if (!prePointerInfo.skipOnPointerObservable) {
+                                    prePointerInfo.skipOnPointerObservable = utilityScenePick.distance > 0;
+                                }
+                            }
+                            else if (!_this._pointerCaptures[pointerEvent_1.pointerId] && (utilityScenePick.distance > originalScenePick.distance)) {
+                                // We have a pick in both scenes but main is closer than utility
+                                // We touched an utility mesh present in the main scene
+                                if (_this.mainSceneTrackerPredicate && _this.mainSceneTrackerPredicate(originalScenePick.pickedMesh)) {
+                                    _this._notifyObservers(prePointerInfo, originalScenePick, pointerEvent_1);
+                                    prePointerInfo.skipOnPointerObservable = true;
+                                }
+                                else if (_this._lastPointerEvents[pointerEvent_1.pointerId]) {
+                                    // We need to send a last pointerup to the utilityLayerScene to make sure animations can complete
+                                    _this.onPointerOutObservable.notifyObservers(pointerEvent_1.pointerId);
+                                    delete _this._lastPointerEvents[pointerEvent_1.pointerId];
+                                }
+                            }
+                            if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
+                                _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                             }
-                        }
-                        if (prePointerInfo.type === BABYLON.PointerEventTypes.POINTERUP && _this._pointerCaptures[pointerEvent_1.pointerId]) {
-                            _this._pointerCaptures[pointerEvent_1.pointerId] = false;
                         }
                     }
-                }
-            });
+                });
+            }
             // Render directly on top of existing scene without clearing
             this.utilityLayerScene.autoClear = false;
             this._afterRenderObserver = this.originalScene.onAfterRenderObservable.add(function () {
@@ -109301,6 +109412,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) {
@@ -121085,6 +121197,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.9",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,6 +1,6 @@
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {

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


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


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


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

@@ -1,6 +1,6 @@
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 
 declare module 'babylonjs-gui' {
     export * from "babylonjs-gui/2D";
@@ -3053,7 +3053,7 @@ declare module 'babylonjs-gui/3D/materials/fluentMaterial' {
 
 /*Babylon.js GUI*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {

+ 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.9",
     "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.9"
     },
     "engines": {
         "node": "*"

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


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


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

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

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

@@ -1,6 +1,6 @@
 /*Babylon.js Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 
 declare module 'babylonjs-inspector' {
     export * from "babylonjs-inspector/inspector";
@@ -31,7 +31,7 @@ declare module 'babylonjs-inspector/components/propertyChangedEvent' {
 
 /*Babylon.js Inspector*/
 // Dependencies for this module:
-//   ../../../../Tools/gulp/babylonjs
+//   ../../../../Tools/Gulp/babylonjs
 declare module INSPECTOR {
 }
 declare module INSPECTOR {

+ 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.9",
     "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.9",
+        "babylonjs-gui": "4.0.0-alpha.9",
+        "babylonjs-loaders": "4.0.0-alpha.9",
+        "babylonjs-serializers": "4.0.0-alpha.9"
     },
     "engines": {
         "node": "*"

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


+ 38 - 48
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1114,6 +1114,19 @@ var BABYLON;
                         }));
                     }
                 }
+                // Link all Babylon bones for each glTF node with the corresponding Babylon transform node.
+                // A glTF joint is a pointer to a glTF node in the glTF node hierarchy similar to Unity3D.
+                if (this.gltf.nodes) {
+                    for (var _b = 0, _c = this.gltf.nodes; _b < _c.length; _b++) {
+                        var node = _c[_b];
+                        if (node._babylonTransformNode && node._babylonBones) {
+                            for (var _d = 0, _e = node._babylonBones; _d < _e.length; _d++) {
+                                var babylonBone = _e[_d];
+                                babylonBone.linkTransformNode(node._babylonTransformNode);
+                            }
+                        }
+                    }
+                }
                 promises.push(this._loadAnimationsAsync());
                 this.logClose();
                 return Promise.all(promises).then(function () { });
@@ -1125,9 +1138,6 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
-                    callback(node._babylonTransformNode);
-                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -1226,20 +1236,12 @@ var BABYLON;
                         }));
                     }
                     if (node.children) {
-                        var _loop_1 = function (index) {
+                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                            var index = _a[_i];
                             var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
                             promises.push(_this.loadNodeAsync("/nodes/" + childNode.index, childNode, function (childBabylonMesh) {
-                                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                                if (childNode.skin != undefined) {
-                                    childBabylonMesh.parent = _this._rootBabylonMesh;
-                                    return;
-                                }
                                 childBabylonMesh.parent = babylonTransformNode;
                             }));
-                        };
-                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                            var index = _a[_i];
-                            _loop_1(index);
                         }
                     }
                     assign(babylonTransformNode);
@@ -1276,16 +1278,16 @@ var BABYLON;
                     var primitive = mesh.primitives[0];
                     promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name, node, mesh, primitive, function (babylonMesh) {
                         node._babylonTransformNode = babylonMesh;
+                        node._primitiveBabylonMeshes = [babylonMesh];
                     }));
                 }
                 else {
-                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
-                    node._babylonTransformNode = babylonTransformNode_1;
+                    node._babylonTransformNode = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._primitiveBabylonMeshes = [];
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name + "_primitive" + primitive.index, node, mesh, primitive, function (babylonMesh) {
-                            babylonMesh.parent = babylonTransformNode_1;
-                            node._primitiveBabylonMeshes = node._primitiveBabylonMeshes || [];
+                            babylonMesh.parent = node._babylonTransformNode;
                             node._primitiveBabylonMeshes.push(babylonMesh);
                         }));
                     }
@@ -1513,13 +1515,13 @@ var BABYLON;
                     });
                 };
                 if (skin._data) {
-                    var data_1 = skin._data;
-                    return data_1.promise.then(function () {
-                        assignSkeleton(data_1.babylonSkeleton);
-                    });
+                    assignSkeleton(skin._data.babylonSkeleton);
+                    return skin._data.promise;
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                babylonSkeleton.overrideMesh = this._rootBabylonMesh;
                 this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
                 var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -1684,11 +1686,6 @@ var BABYLON;
                     (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
-                // Ignore animations targeting TRS of skinned nodes.
-                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
-                    return Promise.resolve();
-                }
                 var sampler = ArrayItem.Get(context + "/sampler", animation.samplers, channel.sampler);
                 return this._loadAnimationSamplerAsync(animationContext + "/samplers/" + channel.sampler, sampler).then(function (data) {
                     var targetPath;
@@ -1788,7 +1785,7 @@ var BABYLON;
                         keys[frameIndex] = getNextKey(frameIndex);
                     }
                     if (targetPath === "influence") {
-                        var _loop_2 = function (targetIndex) {
+                        var _loop_1 = function (targetIndex) {
                             var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
@@ -1805,27 +1802,15 @@ var BABYLON;
                             });
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
-                            _loop_2(targetIndex);
+                            _loop_1(targetIndex);
                         }
                     }
                     else {
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        var babylonTransformNode = targetNode._babylonTransformNode;
-                        var babylonBones = targetNode._babylonBones;
-                        if (babylonBones) {
-                            var babylonAnimationTargets = [babylonTransformNode].concat(babylonBones);
-                            for (var _i = 0, babylonAnimationTargets_1 = babylonAnimationTargets; _i < babylonAnimationTargets_1.length; _i++) {
-                                var babylonAnimationTarget = babylonAnimationTargets_1[_i];
-                                babylonAnimationTarget.animations.push(babylonAnimation);
-                            }
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
-                        }
-                        else {
-                            babylonTransformNode.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
-                        }
+                        targetNode._babylonTransformNode.animations.push(babylonAnimation);
+                        babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonTransformNode);
                     }
                 });
             };
@@ -2221,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();
                     }
@@ -2237,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;

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


+ 38 - 48
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3322,6 +3322,19 @@ var BABYLON;
                         }));
                     }
                 }
+                // Link all Babylon bones for each glTF node with the corresponding Babylon transform node.
+                // A glTF joint is a pointer to a glTF node in the glTF node hierarchy similar to Unity3D.
+                if (this.gltf.nodes) {
+                    for (var _b = 0, _c = this.gltf.nodes; _b < _c.length; _b++) {
+                        var node = _c[_b];
+                        if (node._babylonTransformNode && node._babylonBones) {
+                            for (var _d = 0, _e = node._babylonBones; _d < _e.length; _d++) {
+                                var babylonBone = _e[_d];
+                                babylonBone.linkTransformNode(node._babylonTransformNode);
+                            }
+                        }
+                    }
+                }
                 promises.push(this._loadAnimationsAsync());
                 this.logClose();
                 return Promise.all(promises).then(function () { });
@@ -3333,9 +3346,6 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
-                    callback(node._babylonTransformNode);
-                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -3434,20 +3444,12 @@ var BABYLON;
                         }));
                     }
                     if (node.children) {
-                        var _loop_1 = function (index) {
+                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                            var index = _a[_i];
                             var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
                             promises.push(_this.loadNodeAsync("/nodes/" + childNode.index, childNode, function (childBabylonMesh) {
-                                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                                if (childNode.skin != undefined) {
-                                    childBabylonMesh.parent = _this._rootBabylonMesh;
-                                    return;
-                                }
                                 childBabylonMesh.parent = babylonTransformNode;
                             }));
-                        };
-                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                            var index = _a[_i];
-                            _loop_1(index);
                         }
                     }
                     assign(babylonTransformNode);
@@ -3484,16 +3486,16 @@ var BABYLON;
                     var primitive = mesh.primitives[0];
                     promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name, node, mesh, primitive, function (babylonMesh) {
                         node._babylonTransformNode = babylonMesh;
+                        node._primitiveBabylonMeshes = [babylonMesh];
                     }));
                 }
                 else {
-                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
-                    node._babylonTransformNode = babylonTransformNode_1;
+                    node._babylonTransformNode = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._primitiveBabylonMeshes = [];
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name + "_primitive" + primitive.index, node, mesh, primitive, function (babylonMesh) {
-                            babylonMesh.parent = babylonTransformNode_1;
-                            node._primitiveBabylonMeshes = node._primitiveBabylonMeshes || [];
+                            babylonMesh.parent = node._babylonTransformNode;
                             node._primitiveBabylonMeshes.push(babylonMesh);
                         }));
                     }
@@ -3721,13 +3723,13 @@ var BABYLON;
                     });
                 };
                 if (skin._data) {
-                    var data_1 = skin._data;
-                    return data_1.promise.then(function () {
-                        assignSkeleton(data_1.babylonSkeleton);
-                    });
+                    assignSkeleton(skin._data.babylonSkeleton);
+                    return skin._data.promise;
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                babylonSkeleton.overrideMesh = this._rootBabylonMesh;
                 this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
                 var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -3892,11 +3894,6 @@ var BABYLON;
                     (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
-                // Ignore animations targeting TRS of skinned nodes.
-                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
-                    return Promise.resolve();
-                }
                 var sampler = ArrayItem.Get(context + "/sampler", animation.samplers, channel.sampler);
                 return this._loadAnimationSamplerAsync(animationContext + "/samplers/" + channel.sampler, sampler).then(function (data) {
                     var targetPath;
@@ -3996,7 +3993,7 @@ var BABYLON;
                         keys[frameIndex] = getNextKey(frameIndex);
                     }
                     if (targetPath === "influence") {
-                        var _loop_2 = function (targetIndex) {
+                        var _loop_1 = function (targetIndex) {
                             var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
@@ -4013,27 +4010,15 @@ var BABYLON;
                             });
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
-                            _loop_2(targetIndex);
+                            _loop_1(targetIndex);
                         }
                     }
                     else {
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        var babylonTransformNode = targetNode._babylonTransformNode;
-                        var babylonBones = targetNode._babylonBones;
-                        if (babylonBones) {
-                            var babylonAnimationTargets = [babylonTransformNode].concat(babylonBones);
-                            for (var _i = 0, babylonAnimationTargets_1 = babylonAnimationTargets; _i < babylonAnimationTargets_1.length; _i++) {
-                                var babylonAnimationTarget = babylonAnimationTargets_1[_i];
-                                babylonAnimationTarget.animations.push(babylonAnimation);
-                            }
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
-                        }
-                        else {
-                            babylonTransformNode.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
-                        }
+                        targetNode._babylonTransformNode.animations.push(babylonAnimation);
+                        babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonTransformNode);
                     }
                 });
             };
@@ -4429,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();
                     }
@@ -4445,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;

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


+ 38 - 48
dist/preview release/loaders/babylonjs.loaders.js

@@ -4384,6 +4384,19 @@ var BABYLON;
                         }));
                     }
                 }
+                // Link all Babylon bones for each glTF node with the corresponding Babylon transform node.
+                // A glTF joint is a pointer to a glTF node in the glTF node hierarchy similar to Unity3D.
+                if (this.gltf.nodes) {
+                    for (var _b = 0, _c = this.gltf.nodes; _b < _c.length; _b++) {
+                        var node = _c[_b];
+                        if (node._babylonTransformNode && node._babylonBones) {
+                            for (var _d = 0, _e = node._babylonBones; _d < _e.length; _d++) {
+                                var babylonBone = _e[_d];
+                                babylonBone.linkTransformNode(node._babylonTransformNode);
+                            }
+                        }
+                    }
+                }
                 promises.push(this._loadAnimationsAsync());
                 this.logClose();
                 return Promise.all(promises).then(function () { });
@@ -4395,9 +4408,6 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
-                    callback(node._babylonTransformNode);
-                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -4496,20 +4506,12 @@ var BABYLON;
                         }));
                     }
                     if (node.children) {
-                        var _loop_1 = function (index) {
+                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
+                            var index = _a[_i];
                             var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
                             promises.push(_this.loadNodeAsync("/nodes/" + childNode.index, childNode, function (childBabylonMesh) {
-                                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                                if (childNode.skin != undefined) {
-                                    childBabylonMesh.parent = _this._rootBabylonMesh;
-                                    return;
-                                }
                                 childBabylonMesh.parent = babylonTransformNode;
                             }));
-                        };
-                        for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                            var index = _a[_i];
-                            _loop_1(index);
                         }
                     }
                     assign(babylonTransformNode);
@@ -4546,16 +4548,16 @@ var BABYLON;
                     var primitive = mesh.primitives[0];
                     promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name, node, mesh, primitive, function (babylonMesh) {
                         node._babylonTransformNode = babylonMesh;
+                        node._primitiveBabylonMeshes = [babylonMesh];
                     }));
                 }
                 else {
-                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
-                    node._babylonTransformNode = babylonTransformNode_1;
+                    node._babylonTransformNode = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._primitiveBabylonMeshes = [];
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, name + "_primitive" + primitive.index, node, mesh, primitive, function (babylonMesh) {
-                            babylonMesh.parent = babylonTransformNode_1;
-                            node._primitiveBabylonMeshes = node._primitiveBabylonMeshes || [];
+                            babylonMesh.parent = node._babylonTransformNode;
                             node._primitiveBabylonMeshes.push(babylonMesh);
                         }));
                     }
@@ -4783,13 +4785,13 @@ var BABYLON;
                     });
                 };
                 if (skin._data) {
-                    var data_1 = skin._data;
-                    return data_1.promise.then(function () {
-                        assignSkeleton(data_1.babylonSkeleton);
-                    });
+                    assignSkeleton(skin._data.babylonSkeleton);
+                    return skin._data.promise;
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                babylonSkeleton.overrideMesh = this._rootBabylonMesh;
                 this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
                 var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -4954,11 +4956,6 @@ var BABYLON;
                     (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
-                // Ignore animations targeting TRS of skinned nodes.
-                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
-                    return Promise.resolve();
-                }
                 var sampler = ArrayItem.Get(context + "/sampler", animation.samplers, channel.sampler);
                 return this._loadAnimationSamplerAsync(animationContext + "/samplers/" + channel.sampler, sampler).then(function (data) {
                     var targetPath;
@@ -5058,7 +5055,7 @@ var BABYLON;
                         keys[frameIndex] = getNextKey(frameIndex);
                     }
                     if (targetPath === "influence") {
-                        var _loop_2 = function (targetIndex) {
+                        var _loop_1 = function (targetIndex) {
                             var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                             var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                             babylonAnimation.setKeys(keys.map(function (key) { return ({
@@ -5075,27 +5072,15 @@ var BABYLON;
                             });
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
-                            _loop_2(targetIndex);
+                            _loop_1(targetIndex);
                         }
                     }
                     else {
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        var babylonTransformNode = targetNode._babylonTransformNode;
-                        var babylonBones = targetNode._babylonBones;
-                        if (babylonBones) {
-                            var babylonAnimationTargets = [babylonTransformNode].concat(babylonBones);
-                            for (var _i = 0, babylonAnimationTargets_1 = babylonAnimationTargets; _i < babylonAnimationTargets_1.length; _i++) {
-                                var babylonAnimationTarget = babylonAnimationTargets_1[_i];
-                                babylonAnimationTarget.animations.push(babylonAnimation);
-                            }
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
-                        }
-                        else {
-                            babylonTransformNode.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
-                        }
+                        targetNode._babylonTransformNode.animations.push(babylonAnimation);
+                        babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonTransformNode);
                     }
                 });
             };
@@ -5491,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();
                     }
@@ -5507,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;

File diff suppressed because it is too large
+ 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.9",
     "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.9",
+        "babylonjs": "4.0.0-alpha.9"
     },
     "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.9",
     "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.9"
     },
     "engines": {
         "node": "*"

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


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


File diff suppressed because it is too large
+ 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.9",
     "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.9"
     },
     "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.9",
     "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.9"
     },
     "engines": {
         "node": "*"

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


File diff suppressed because it is too large
+ 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.9",
     "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.9",
+        "babylonjs-gltf2interface": "4.0.0-alpha.9"
     },
     "engines": {
         "node": "*"

+ 199 - 21
dist/preview release/viewer/babylon.viewer.d.ts

@@ -2,14 +2,10 @@
 /// <reference path="./babylon.glTF2Interface.d.ts"/>
 /// <reference path="./babylonjs.loaders.d.ts"/>
 declare module "babylonjs-loaders"{ export=BABYLON;}
-/// <reference path="./babylon.d.ts"/>
-/// <reference path="./babylon.glTF2Interface.d.ts"/>
-/// <reference path="./babylonjs.loaders.d.ts"/>
-declare module "babylonjs-loaders"{ export=BABYLON;}
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/gulp/babylonjs
-//   ../../../../../Tools/gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 declare module BabylonViewer {
     /**
         * BabylonJS Viewer
@@ -928,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1042,6 +1038,169 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    /**
+        * The object sent when an event is triggered
+        */
+    export interface EventCallback {
+            event: Event;
+            template: Template;
+            selector: string;
+            payload?: any;
+    }
+    /**
+        * The template manager, a member of the viewer class, will manage the viewer's templates and generate the HTML.
+        * The template manager managers a single viewer and can be seen as the collection of all sub-templates of the viewer.
+        */
+    export class TemplateManager {
+            containerElement: Element;
+            /**
+                * Will be triggered when any template is initialized
+                */
+            onTemplateInit: BABYLON.Observable<Template>;
+            /**
+                * Will be triggered when any template is fully loaded
+                */
+            onTemplateLoaded: BABYLON.Observable<Template>;
+            /**
+                * Will be triggered when a template state changes
+                */
+            onTemplateStateChange: BABYLON.Observable<Template>;
+            /**
+                * Will be triggered when all templates finished loading
+                */
+            onAllLoaded: BABYLON.Observable<TemplateManager>;
+            /**
+                * Will be triggered when any event on any template is triggered.
+                */
+            onEventTriggered: BABYLON.Observable<EventCallback>;
+            /**
+                * This template manager's event manager. In charge of callback registrations to native event types
+                */
+            eventManager: EventManager;
+            constructor(containerElement: Element);
+            /**
+                * Initialize the template(s) for the viewer. Called bay the Viewer class
+                * @param templates the templates to be used to initialize the main template
+                */
+            initTemplate(templates: {
+                    [key: string]: ITemplateConfiguration;
+            }): Promise<void>;
+            /**
+                * Get the canvas in the template tree.
+                * There must be one and only one canvas inthe template.
+                */
+            getCanvas(): HTMLCanvasElement | null;
+            /**
+                * Get a specific template from the template tree
+                * @param name the name of the template to load
+                */
+            getTemplate(name: string): Template | undefined;
+            /**
+                * Dispose the template manager
+                */
+            dispose(): void;
+    }
+    /**
+        * This class represents a single template in the viewer's template tree.
+        * An example for a template is a single canvas, an overlay (containing sub-templates) or the navigation bar.
+        * A template is injected using the template manager in the correct position.
+        * The template is rendered using Handlebars and can use Handlebars' features (such as parameter injection)
+        *
+        * For further information please refer to the documentation page, https://doc.babylonjs.com
+        */
+    export class Template {
+            name: string;
+            /**
+                * Will be triggered when the template is loaded
+                */
+            onLoaded: BABYLON.Observable<Template>;
+            /**
+                * will be triggered when the template is appended to the tree
+                */
+            onAppended: BABYLON.Observable<Template>;
+            /**
+                * Will be triggered when the template's state changed (shown, hidden)
+                */
+            onStateChange: BABYLON.Observable<Template>;
+            /**
+                * Will be triggered when an event is triggered on ths template.
+                * The event is a native browser event (like mouse or pointer events)
+                */
+            onEventTriggered: BABYLON.Observable<EventCallback>;
+            onParamsUpdated: BABYLON.Observable<Template>;
+            onHTMLRendered: BABYLON.Observable<Template>;
+            /**
+                * is the template loaded?
+                */
+            isLoaded: boolean;
+            /**
+                * This is meant to be used to track the show and hide functions.
+                * This is NOT (!!) a flag to check if the element is actually visible to the user.
+                */
+            isShown: boolean;
+            /**
+                * Is this template a part of the HTML tree (the template manager injected it)
+                */
+            isInHtmlTree: boolean;
+            /**
+                * The HTML element containing this template
+                */
+            parent: HTMLElement;
+            /**
+                * A promise that is fulfilled when the template finished loading.
+                */
+            initPromise: Promise<Template>;
+            constructor(name: string, _configuration: ITemplateConfiguration);
+            /**
+                * Some templates have parameters (like background color for example).
+                * The parameters are provided to Handlebars which in turn generates the template.
+                * This function will update the template with the new parameters
+                *
+                * Note that when updating parameters the events will be registered again (after being cleared).
+                *
+                * @param params the new template parameters
+                */
+            updateParams(params: {
+                    [key: string]: string | number | boolean | object;
+            }, append?: boolean): void;
+            redraw(): void;
+            /**
+                * Get the template'S configuration
+                */
+            readonly configuration: ITemplateConfiguration;
+            /**
+                * A template can be a parent element for other templates or HTML elements.
+                * This function will deliver all child HTML elements of this template.
+                */
+            getChildElements(): Array<string>;
+            /**
+                * Appending the template to a parent HTML element.
+                * If a parent is already set and you wish to replace the old HTML with new one, forceRemove should be true.
+                * @param parent the parent to which the template is added
+                * @param forceRemove if the parent already exists, shoud the template be removed from it?
+                */
+            appendTo(parent: HTMLElement, forceRemove?: boolean): void;
+            /**
+                * Show the template using the provided visibilityFunction, or natively using display: flex.
+                * The provided function returns a promise that should be fullfilled when the element is shown.
+                * Since it is a promise async operations are more than possible.
+                * See the default viewer for an opacity example.
+                * @param visibilityFunction The function to execute to show the template.
+                */
+            show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+            /**
+                * Hide the template using the provided visibilityFunction, or natively using display: none.
+                * The provided function returns a promise that should be fullfilled when the element is hidden.
+                * Since it is a promise async operations are more than possible.
+                * See the default viewer for an opacity example.
+                * @param visibilityFunction The function to execute to show the template.
+                */
+            hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+            /**
+                * Dispose this template
+                */
+            dispose(): void;
+    }
 }
 declare module BabylonViewer {
     export class ConfigurationContainer {
@@ -1399,20 +1558,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
@@ -1440,6 +1585,39 @@ declare module BabylonViewer {
 }
 declare module BabylonViewer {
     /**
+        * The EventManager is in charge of registering user interctions with the viewer.
+        * It is used in the TemplateManager
+        */
+    export class EventManager {
+            constructor(_templateManager: TemplateManager);
+            /**
+                * Register a new callback to a specific template.
+                * The best example for the usage can be found in the DefaultViewer
+                *
+                * @param templateName the templateName to register the event to
+                * @param callback The callback to be executed
+                * @param eventType the type of event to register
+                * @param selector an optional selector. if not defined the parent object in the template will be selected
+                */
+            registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
+            /**
+                * This will remove a registered event from the defined template.
+                * Each one of the variables apart from the template name are optional, but one must be provided.
+                *
+                * @param templateName the templateName
+                * @param callback the callback to remove (optional)
+                * @param eventType the event type to remove (optional)
+                * @param selector the selector from which to remove the event (optional)
+                */
+            unregisterCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
+            /**
+                * Dispose the event manager
+                */
+            dispose(): void;
+    }
+}
+declare module BabylonViewer {
+    /**
         * The ViewerLabs class will hold functions that are not (!) backwards compatible.
         * The APIs in all labs-related classes and configuration  might change.
         * Once stable, lab features will be moved to the publis API and configuration object.

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


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


+ 204 - 26
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -3,15 +3,10 @@
 /// <reference path="./babylonjs.loaders.d.ts"/>
 declare module "babylonjs-loaders"{ export=BABYLON;}
 
-/// <reference path="./babylon.d.ts"/>
-/// <reference path="./babylon.glTF2Interface.d.ts"/>
-/// <reference path="./babylonjs.loaders.d.ts"/>
-declare module "babylonjs-loaders"{ export=BABYLON;}
-
 // Generated by dts-bundle v0.7.3
 // Dependencies for this module:
-//   ../../../../../Tools/gulp/babylonjs
-//   ../../../../../Tools/gulp/babylonjs-loaders
+//   ../../../../../Tools/Gulp/babylonjs
+//   ../../../../../Tools/Gulp/babylonjs-loaders
 
 declare module 'babylonjs-viewer' {
     import { mapperManager } from 'babylonjs-viewer/configuration/mappers';
@@ -990,14 +985,13 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1120,7 +1114,172 @@ declare module 'babylonjs-viewer/configuration/configuration' {
 }
 
 declare module 'babylonjs-viewer/templating/templateManager' {
-    
+    import { Observable } from 'babylonjs';
+    import { EventManager } from 'babylonjs-viewer/templating/eventManager';
+    import { ITemplateConfiguration } from 'babylonjs-viewer/configuration/interfaces';
+    /**
+        * The object sent when an event is triggered
+        */
+    export interface EventCallback {
+            event: Event;
+            template: Template;
+            selector: string;
+            payload?: any;
+    }
+    /**
+        * The template manager, a member of the viewer class, will manage the viewer's templates and generate the HTML.
+        * The template manager managers a single viewer and can be seen as the collection of all sub-templates of the viewer.
+        */
+    export class TemplateManager {
+            containerElement: Element;
+            /**
+                * Will be triggered when any template is initialized
+                */
+            onTemplateInit: Observable<Template>;
+            /**
+                * Will be triggered when any template is fully loaded
+                */
+            onTemplateLoaded: Observable<Template>;
+            /**
+                * Will be triggered when a template state changes
+                */
+            onTemplateStateChange: Observable<Template>;
+            /**
+                * Will be triggered when all templates finished loading
+                */
+            onAllLoaded: Observable<TemplateManager>;
+            /**
+                * Will be triggered when any event on any template is triggered.
+                */
+            onEventTriggered: Observable<EventCallback>;
+            /**
+                * This template manager's event manager. In charge of callback registrations to native event types
+                */
+            eventManager: EventManager;
+            constructor(containerElement: Element);
+            /**
+                * Initialize the template(s) for the viewer. Called bay the Viewer class
+                * @param templates the templates to be used to initialize the main template
+                */
+            initTemplate(templates: {
+                    [key: string]: ITemplateConfiguration;
+            }): Promise<void>;
+            /**
+                * Get the canvas in the template tree.
+                * There must be one and only one canvas inthe template.
+                */
+            getCanvas(): HTMLCanvasElement | null;
+            /**
+                * Get a specific template from the template tree
+                * @param name the name of the template to load
+                */
+            getTemplate(name: string): Template | undefined;
+            /**
+                * Dispose the template manager
+                */
+            dispose(): void;
+    }
+    /**
+        * This class represents a single template in the viewer's template tree.
+        * An example for a template is a single canvas, an overlay (containing sub-templates) or the navigation bar.
+        * A template is injected using the template manager in the correct position.
+        * The template is rendered using Handlebars and can use Handlebars' features (such as parameter injection)
+        *
+        * For further information please refer to the documentation page, https://doc.babylonjs.com
+        */
+    export class Template {
+            name: string;
+            /**
+                * Will be triggered when the template is loaded
+                */
+            onLoaded: Observable<Template>;
+            /**
+                * will be triggered when the template is appended to the tree
+                */
+            onAppended: Observable<Template>;
+            /**
+                * Will be triggered when the template's state changed (shown, hidden)
+                */
+            onStateChange: Observable<Template>;
+            /**
+                * Will be triggered when an event is triggered on ths template.
+                * The event is a native browser event (like mouse or pointer events)
+                */
+            onEventTriggered: Observable<EventCallback>;
+            onParamsUpdated: Observable<Template>;
+            onHTMLRendered: Observable<Template>;
+            /**
+                * is the template loaded?
+                */
+            isLoaded: boolean;
+            /**
+                * This is meant to be used to track the show and hide functions.
+                * This is NOT (!!) a flag to check if the element is actually visible to the user.
+                */
+            isShown: boolean;
+            /**
+                * Is this template a part of the HTML tree (the template manager injected it)
+                */
+            isInHtmlTree: boolean;
+            /**
+                * The HTML element containing this template
+                */
+            parent: HTMLElement;
+            /**
+                * A promise that is fulfilled when the template finished loading.
+                */
+            initPromise: Promise<Template>;
+            constructor(name: string, _configuration: ITemplateConfiguration);
+            /**
+                * Some templates have parameters (like background color for example).
+                * The parameters are provided to Handlebars which in turn generates the template.
+                * This function will update the template with the new parameters
+                *
+                * Note that when updating parameters the events will be registered again (after being cleared).
+                *
+                * @param params the new template parameters
+                */
+            updateParams(params: {
+                    [key: string]: string | number | boolean | object;
+            }, append?: boolean): void;
+            redraw(): void;
+            /**
+                * Get the template'S configuration
+                */
+            readonly configuration: ITemplateConfiguration;
+            /**
+                * A template can be a parent element for other templates or HTML elements.
+                * This function will deliver all child HTML elements of this template.
+                */
+            getChildElements(): Array<string>;
+            /**
+                * Appending the template to a parent HTML element.
+                * If a parent is already set and you wish to replace the old HTML with new one, forceRemove should be true.
+                * @param parent the parent to which the template is added
+                * @param forceRemove if the parent already exists, shoud the template be removed from it?
+                */
+            appendTo(parent: HTMLElement, forceRemove?: boolean): void;
+            /**
+                * Show the template using the provided visibilityFunction, or natively using display: flex.
+                * The provided function returns a promise that should be fullfilled when the element is shown.
+                * Since it is a promise async operations are more than possible.
+                * See the default viewer for an opacity example.
+                * @param visibilityFunction The function to execute to show the template.
+                */
+            show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+            /**
+                * Hide the template using the provided visibilityFunction, or natively using display: none.
+                * The provided function returns a promise that should be fullfilled when the element is hidden.
+                * Since it is a promise async operations are more than possible.
+                * See the default viewer for an opacity example.
+                * @param visibilityFunction The function to execute to show the template.
+                */
+            hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+            /**
+                * Dispose this template
+                */
+            dispose(): void;
+    }
 }
 
 declare module 'babylonjs-viewer/configuration/configurationContainer' {
@@ -1503,22 +1662,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
@@ -1562,6 +1705,41 @@ declare module 'babylonjs-viewer/configuration/interfaces/environmentMapConfigur
     }
 }
 
+declare module 'babylonjs-viewer/templating/eventManager' {
+    import { EventCallback, TemplateManager } from "babylonjs-viewer/templating/templateManager";
+    /**
+        * The EventManager is in charge of registering user interctions with the viewer.
+        * It is used in the TemplateManager
+        */
+    export class EventManager {
+            constructor(_templateManager: TemplateManager);
+            /**
+                * Register a new callback to a specific template.
+                * The best example for the usage can be found in the DefaultViewer
+                *
+                * @param templateName the templateName to register the event to
+                * @param callback The callback to be executed
+                * @param eventType the type of event to register
+                * @param selector an optional selector. if not defined the parent object in the template will be selected
+                */
+            registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
+            /**
+                * This will remove a registered event from the defined template.
+                * Each one of the variables apart from the template name are optional, but one must be provided.
+                *
+                * @param templateName the templateName
+                * @param callback the callback to remove (optional)
+                * @param eventType the event type to remove (optional)
+                * @param selector the selector from which to remove the event (optional)
+                */
+            unregisterCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
+            /**
+                * Dispose the event manager
+                */
+            dispose(): void;
+    }
+}
+
 declare module 'babylonjs-viewer/labs/viewerLabs' {
     import { PBREnvironment } from "babylonjs-viewer/labs/environmentSerializer";
     import { ShadowLight, Vector3, Scene } from 'babylonjs';

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

@@ -68,12 +68,19 @@
 - Added `Tools.CustomRequestHeaders`, `Tools.UseCustomRequestHeaders`, `Tools.InjectCustomRequestHeaders` to send Custom Request Headers alongside XMLHttpRequest's i.e. when loading files (Tools.Loadfile) from resources requiring special headers like 'Authorization' ([susares](https://github.com/susares))
 - Added `.serialize` and `.Parse` functions in `ReflectionProbe` to retrieve reflection probes when parsing a previously serialized material ([julien-moreau](https://github.com/julien-moreau))
 - GizmoManager clearGizmoOnEmptyPointerEvent options and onAttachedToMeshObservable event ([TrevorDev](https://github.com/TrevorDev))
+- Added support for overriding the mesh used for the world matrix for a mesh with a skeleton ([bghgary](https://github.com/bghgary))
+- 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))
+
 ### glTF Loader
 
 - Added support for mesh instancing for improved performance when multiple nodes point to the same mesh ([bghgary](https://github.com/bghgary))
 - Create `TransformNode` objects instead of `Mesh` objects for glTF nodes without geometry ([bghgary](https://github.com/bghgary))
 - Added glTF JSON pointers to metadata of nodes, materials, and textures ([bghgary](https://github.com/bghgary))
 - Load KTX textures in the gltf2 loader when textureFormat is set on engine ([TrevorDev](https://github.com/TrevorDev))
+- Skinned meshes now behave as intended by glTF ([bghgary](https://github.com/bghgary))
+  - Skinned meshes now set an override mesh instead of reparenting to the `__root__` transform node
+  - Loaded bones are linked with the transform node created for the corresponding glTF node
 
 ### glTF Serializer
 
@@ -82,6 +89,7 @@
 ### Materials Library
 
 ## Bug fixes
+- Fixed anaglyph mode for Free and Universal cameras ([Deltakosh](https://github.com/deltakosh))
 - Fixed FileLoader's loading of a skybox, & added a parsed value for whether to create with PBR or STDMaterial ([Palmer-JC](https://github.com/Palmer-JC))
 - Removed bones from rootNodes where they should never have been ([Deltakosh](https://github.com/deltakosh))
 - Refocusing on input gui with pointer events ([TrevorDev](https://github.com/TrevorDev))
@@ -95,6 +103,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))
@@ -107,6 +116,9 @@
 - Fixed effect layer compatibility with multi materials ([Sebavan](https://github.com/Sebavan))
 - 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))
 
 ### Viewer
 

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

@@ -88,7 +88,7 @@ export class Checkbox extends Control {
     }
 
     protected _getTypeName(): string {
-        return "CheckBox";
+        return "Checkbox";
     }
 
     /** @hidden */

+ 2 - 2
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 */
@@ -164,7 +164,7 @@ export class Container extends Control {
      * @returns the current container
      */
     public clearControls(): Container {
-        let children = this._children.slice();
+        let children = this.children.slice();
 
         for (var child of children) {
             this.removeControl(child);

+ 60 - 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;
     }
 
@@ -1039,10 +1093,12 @@ export class Control {
             return;
         }
 
+        context.save();
         context.strokeStyle = "#4affff";
         context.lineWidth = 2;
 
         this._renderHighlightSpecific(context);
+        context.restore();
     }
 
     /** @hidden */

+ 9 - 1
inspector/src/components/actionTabs/actionTabs.scss

@@ -5,6 +5,10 @@
     bottom: 0px;
 }
 
+#__resizable_base__ {
+    display: none;
+}
+
 #actionTabs {
     background: #333333;
     height: 100%;
@@ -564,7 +568,7 @@
                     }                    
 
                     .command {
-                        border: 0px;
+                        border: 1px solid transparent;
                         background:transparent;
                         color: white;
                     }
@@ -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>

+ 38 - 2
inspector/src/components/actionTabs/lineContainerComponent.tsx

@@ -9,14 +9,50 @@ interface ILineContainerComponentProps {
 }
 
 export class LineContainerComponent extends React.Component<ILineContainerComponentProps, { isExpanded: boolean }> {
+    private static _InMemoryStorage: {[key: string]: boolean};
+    
     constructor(props: ILineContainerComponentProps) {
         super(props);
 
-        this.state = { isExpanded: !this.props.closed };
+        let initialState: boolean;
+
+        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;
+        }
+
+        this.state = { isExpanded: initialState };
     }
 
     switchExpandedState(): void {
-        this.setState({ isExpanded: !this.state.isExpanded });
+        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: newState });
+
     }
 
     renderHeader() {

+ 2 - 2
inspector/src/components/actionTabs/lines/color3LineComponent.tsx

@@ -14,14 +14,14 @@ export class Color3LineComponent extends React.Component<IColor3LineComponentPro
     constructor(props: IColor3LineComponentProps) {
         super(props);
 
-        this.state = { color: this.props.target[this.props.propertyName] };
+        this.state = { color: this.props.target[this.props.propertyName].clone() };
     }
 
     shouldComponentUpdate(nextProps: IColor3LineComponentProps, nextState: { color: Color3 }) {
         const currentState = nextProps.target[nextProps.propertyName];
 
         if (!currentState.equals(nextState.color) || this._localChange) {
-            nextState.color = currentState;
+            nextState.color = currentState.clone();
             this._localChange = false;
             return true;
         }

+ 33 - 5
inspector/src/components/actionTabs/lines/floatLineComponent.tsx

@@ -1,12 +1,15 @@
 import * as React from "react";
 import { Observable } from "babylonjs";
 import { PropertyChangedEvent } from "../../propertyChangedEvent";
+import { LockObject } from "../tabs/propertyGrids/lockObject";
 
 interface IFloatLineComponentProps {
     label: string,
     target: any,
     propertyName: string,
+    lockObject?: LockObject,
     onChange?: (newValue: number) => void,
+    isInteger?: boolean,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>,
     additionalClass?: string
 }
@@ -19,10 +22,15 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         super(props);
 
         let currentValue = this.props.target[this.props.propertyName];
-        this.state = { value: currentValue ? currentValue.toFixed(3) : "0" }
+        this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(3)) : "0" }
         this._store = currentValue;
     }
 
+
+    componentWillUnmount() {
+        this.unlock();
+    }
+
     shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: { value: string }) {
         if (this._localChange) {
             this._localChange = false;
@@ -30,8 +38,10 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         }
 
         const newValue = nextProps.target[nextProps.propertyName];
-        if (newValue && newValue !== nextState.value) {
-            nextState.value = newValue.toFixed(3);
+        const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(3) : "0";
+
+        if (newValueString !== nextState.value) {
+            nextState.value = newValueString;
             return true;
         }
         return false;
@@ -59,7 +69,13 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
             return;
         }
 
-        let valueAsNumber = parseFloat(valueString);
+        let valueAsNumber: number
+
+        if (this.props.isInteger) {
+            valueAsNumber = parseInt(valueString);
+        } else {
+            valueAsNumber = parseFloat(valueString);
+        }
 
         this._localChange = true;
         this.setState({ value: valueString });
@@ -74,6 +90,18 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         this._store = valueAsNumber;
     }
 
+    lock() {
+        if (this.props.lockObject) {
+            this.props.lockObject.lock = true;
+        }
+    }
+
+    unlock() {
+        if (this.props.lockObject) {
+            this.props.lockObject.lock = false;
+        }
+    }
+
     render() {
         return (
             <div className={this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine"}>
@@ -81,7 +109,7 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
                     {this.props.label}
                 </div>
                 <div className="value">
-                    <input className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
+                    <input className="numeric-input" value={this.state.value} onBlur={() => this.unlock()} onFocus={() => this.lock()} onChange={evt => this.updateValue(evt.target.value)} />
                 </div>
             </div>
         );

+ 2 - 4
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;
         }
@@ -71,8 +71,6 @@ export class OptionsLineComponent extends React.Component<IOptionsLineComponentP
     }
 
     render() {
-        var currentValue = this.props.target[this.props.propertyName];
-
         return (
             <div className="listLine">
                 <div className="label">
@@ -80,7 +78,7 @@ export class OptionsLineComponent extends React.Component<IOptionsLineComponentP
 
                 </div>
                 <div className="options">
-                    <select onChange={evt => this.updateValue(evt.target.value)} defaultValue={currentValue}>
+                    <select onChange={evt => this.updateValue(evt.target.value)} value={this.state.value}>
                         {
                             this.props.options.map(option => {
                                 return (

+ 1 - 0
inspector/src/components/actionTabs/lines/radioLineComponent.tsx

@@ -26,6 +26,7 @@ export class RadioButtonLineComponent extends React.Component<IRadioButtonLineCo
     componentWillUnmount() {
         if (this._onSelectionChangedObserver) {
             this.props.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
+            this._onSelectionChangedObserver = null;
         }
     }
 

+ 25 - 8
inspector/src/components/actionTabs/lines/textInputLineComponent.tsx

@@ -1,11 +1,15 @@
 import * as React from "react";
 import { Observable } from "babylonjs";
 import { PropertyChangedEvent } from "components/propertyChangedEvent";
+import { LockObject } from "../tabs/propertyGrids/lockObject";
 
 interface ITextInputLineComponentProps {
     label: string,
-    target: any,
-    propertyName: string,
+    lockObject: LockObject,
+    target?: any,
+    propertyName?: string,
+    value?: string,
+    onChange?: (value: string) => void,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -15,7 +19,11 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     constructor(props: ITextInputLineComponentProps) {
         super(props);
 
-        this.state = { value: this.props.target[this.props.propertyName] || "" }
+        this.state = { value: this.props.value || this.props.target[this.props.propertyName!] || "" }
+    }
+
+    componentWillUnmount() {
+        this.props.lockObject.lock = false;
     }
 
     shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: { value: string }) {
@@ -24,7 +32,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
             return true;
         }
 
-        const newValue = nextProps.target[nextProps.propertyName];
+        const newValue = nextProps.value || nextProps.target[nextProps.propertyName!];
         if (newValue !== nextState.value) {
             nextState.value = newValue || "";
             return true;
@@ -33,12 +41,18 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     }
 
     raiseOnPropertyChanged(newValue: string, previousValue: string) {
+        if (this.props.onChange) {
+            this.props.onChange(newValue);
+            return;
+        }
+
         if (!this.props.onPropertyChangedObservable) {
             return;
         }
+
         this.props.onPropertyChangedObservable.notifyObservers({
             object: this.props.target,
-            property: this.props.propertyName,
+            property: this.props.propertyName!,
             value: newValue,
             initialValue: previousValue
         });
@@ -47,11 +61,14 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     updateValue(value: string) {
 
         this._localChange = true;
-        const store = this.props.target[this.props.propertyName];
+        const store = this.props.value || this.props.target[this.props.propertyName!];
         this.setState({ value: value });
 
         this.raiseOnPropertyChanged(value, store);
-        this.props.target[this.props.propertyName] = value;
+
+        if (this.props.propertyName) {
+            this.props.target[this.props.propertyName] = value;
+        }
     }
 
     render() {
@@ -61,7 +78,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
                     {this.props.label}
                 </div>
                 <div className="value">
-                    <input value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
+                    <input value={this.state.value} onBlur={() => this.props.lockObject.lock = false} onFocus={() => this.props.lockObject.lock = true} onChange={evt => this.updateValue(evt.target.value)} />
                 </div>
             </div>
         );

+ 4 - 0
inspector/src/components/actionTabs/lines/textureLineComponent.tsx

@@ -20,6 +20,10 @@ export class TextureLineComponent extends React.Component<ITextureLineComponentP
         }
     }
 
+    shouldComponentUpdate(nextProps: ITextureLineComponentProps): boolean {
+        return (nextProps.texture !== this.props.texture);
+    }
+
     componentDidMount() {
         this.updatePreview();
     }

+ 12 - 12
inspector/src/components/actionTabs/lines/textureLinkLineComponent.tsx

@@ -21,7 +21,7 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
         const material = this.props.material;
         const texture = this.props.texture;
 
-        this.state = { isDebugSelected: material && material.metadata && material.metadata.debugTexture === texture };
+        this.state = { isDebugSelected: material && material.reservedDataStore && material.reservedDataStore.debugTexture === texture };
     }
 
 
@@ -51,8 +51,8 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
         }
         const scene = material.getScene();
 
-        if (material.metadata && material.metadata.debugTexture === texture) {
-            const debugMaterial = material.metadata.debugMaterial;
+        if (material.reservedDataStore && material.reservedDataStore.debugTexture === texture) {
+            const debugMaterial = material.reservedDataStore.debugMaterial;
 
             for (var mesh of scene.meshes) {
                 if (mesh.material === debugMaterial) {
@@ -60,8 +60,8 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
                 }
             }
             debugMaterial.dispose();
-            material.metadata.debugTexture = null;
-            material.metadata.debugMaterial = null;
+            material.reservedDataStore.debugTexture = null;
+            material.reservedDataStore.debugMaterial = null;
 
             this.setState({ isDebugSelected: false });
             return;
@@ -69,8 +69,8 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
 
         let checkMaterial = material;
         let needToDisposeCheckMaterial = false;
-        if (material.metadata && material.metadata.debugTexture) {
-            checkMaterial = material.metadata.debugMaterial;
+        if (material.reservedDataStore && material.reservedDataStore.debugTexture) {
+            checkMaterial = material.reservedDataStore.debugMaterial;
             needToDisposeCheckMaterial = true;
         }
 
@@ -79,7 +79,7 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
         debugMaterial.sideOrientation = material.sideOrientation;
         debugMaterial.emissiveTexture = texture!;
         debugMaterial.forceDepthWrite = true;
-        debugMaterial.metadata = { hidden: true };
+        debugMaterial.reservedDataStore = { hidden: true };
 
         for (var mesh of scene.meshes) {
             if (mesh.material === checkMaterial) {
@@ -87,12 +87,12 @@ export class TextureLinkLineComponent extends React.Component<ITextureLinkLineCo
             }
         }
 
-        if (!material.metadata) {
-            material.metadata = {};
+        if (!material.reservedDataStore) {
+            material.reservedDataStore = {};
         }
 
-        material.metadata.debugTexture = texture;
-        material.metadata.debugMaterial = debugMaterial;
+        material.reservedDataStore.debugTexture = texture;
+        material.reservedDataStore.debugMaterial = debugMaterial;
 
         if (this.props.onDebugSelectionChangeObservable) {
             this.props.onDebugSelectionChangeObservable.notifyObservers(texture!);

+ 15 - 15
inspector/src/components/actionTabs/tabs/debugTabComponent.tsx

@@ -20,18 +20,18 @@ export class DebugTabComponent extends PaneComponent {
             return;
         }
 
-        if (!scene.metadata) {
-            scene.metadata = {};
+        if (!scene.reservedDataStore) {
+            scene.reservedDataStore = {};
         }
 
         for (var mesh of scene.meshes) {
-            if (mesh.skeleton && mesh.metadata && mesh.metadata.skeletonViewer) {
-                this._skeletonViewers.push(mesh.metadata.skeletonViewer);
+            if (mesh.skeleton && mesh.reservedDataStore && mesh.reservedDataStore.skeletonViewer) {
+                this._skeletonViewers.push(mesh.reservedDataStore.skeletonViewer);
             }
         }
 
         this._skeletonViewersEnabled = (this._skeletonViewers.length > 0);
-        this._physicsViewersEnabled = scene.metadata.physicsViewer != null;
+        this._physicsViewersEnabled = scene.reservedDataStore.physicsViewer != null;
     }
 
     componentWillUnmount() {
@@ -54,18 +54,18 @@ export class DebugTabComponent extends PaneComponent {
                     if (found) {
                         continue;
                     }
-                    var viewer = new BABYLON.Debug.SkeletonViewer(mesh.skeleton, mesh, scene, true, 0, BABYLON.UtilityLayerRenderer.DefaultUtilityLayer);
+                    var viewer = new BABYLON.Debug.SkeletonViewer(mesh.skeleton, mesh, scene, true, 0);
                     viewer.isEnabled = true;
                     this._skeletonViewers.push(viewer);
-                    if (!mesh.metadata) {
-                        mesh.metadata = {};
+                    if (!mesh.reservedDataStore) {
+                        mesh.reservedDataStore = {};
                     }
-                    mesh.metadata.skeletonViewer = viewer;
+                    mesh.reservedDataStore.skeletonViewer = viewer;
                 }
             }
         } else {
             for (var index = 0; index < this._skeletonViewers.length; index++) {
-                this._skeletonViewers[index].mesh.metadata.skeletonViewer = null;
+                this._skeletonViewers[index].mesh.reservedDataStore.skeletonViewer = null;
                 this._skeletonViewers[index].dispose();
             }
             this._skeletonViewers = [];
@@ -79,21 +79,21 @@ export class DebugTabComponent extends PaneComponent {
 
         if (this._physicsViewersEnabled) {
             const physicsViewer = new BABYLON.Debug.PhysicsViewer(scene);
-            scene.metadata.physicsViewer = physicsViewer;
+            scene.reservedDataStore.physicsViewer = physicsViewer;
 
             for (var mesh of scene.meshes) {
                 if (mesh.physicsImpostor) {
                     let debugMesh = physicsViewer.showImpostor(mesh.physicsImpostor);
 
                     if (debugMesh) {
-                        debugMesh.metadata = { hidden: true };
-                        debugMesh.material!.metadata = { hidden: true };
+                        debugMesh.reservedDataStore = { hidden: true };
+                        debugMesh.material!.reservedDataStore = { hidden: true };
                     }
                 }
             }
         } else {
-            scene.metadata.physicsViewer.dispose();
-            scene.metadata.physicsViewer = null;
+            scene.reservedDataStore.physicsViewer.dispose();
+            scene.reservedDataStore.physicsViewer = null;
         }
     }
 

+ 109 - 11
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -19,19 +19,35 @@ import { TextBlockPropertyGridComponent } from "./propertyGrids/gui/textBlockPro
 import { TextBlock } from "babylonjs-gui/2D/controls/textBlock";
 import { InputText } from "babylonjs-gui/2D/controls/inputText";
 import { InputTextPropertyGridComponent } from "./propertyGrids/gui/inputTextPropertyGridComponent";
-import { ColorPicker } from "babylonjs-gui";
+import { ColorPicker, Image, Slider, ImageBasedSlider, Rectangle, Ellipse, Checkbox, RadioButton, Line } from "babylonjs-gui";
 import { ColorPickerPropertyGridComponent } from "./propertyGrids/gui/colorPickerPropertyGridComponent";
 import { AnimationGroupGridComponent } from "./propertyGrids/animationGroupPropertyGridComponent";
+import { LockObject } from "./propertyGrids/lockObject";
+import { ImagePropertyGridComponent } from "./propertyGrids/gui/imagePropertyGridComponent";
+import { SliderPropertyGridComponent } from "./propertyGrids/gui/sliderPropertyGridComponent";
+import { ImageBasedSliderPropertyGridComponent } from "./propertyGrids/gui/imageBasedSliderPropertyGridComponent";
+import { RectanglePropertyGridComponent } from "./propertyGrids/gui/rectanglePropertyGridComponent";
+import { EllipsePropertyGridComponent } from "./propertyGrids/gui/ellipsePropertyGridComponent";
+import { CheckboxPropertyGridComponent } from "./propertyGrids/gui/checkboxPropertyGridComponent";
+import { RadioButtonPropertyGridComponent } from "./propertyGrids/gui/radioButtonPropertyGridComponent";
+import { LinePropertyGridComponent } from "./propertyGrids/gui/linePropertyGridComponent";
 
 export class PropertyGridTabComponent extends PaneComponent {
     private _timerIntervalId: number;
+    private _lockObject = new LockObject();
 
     constructor(props: IPaneComponentProps) {
         super(props);
     }
 
+    timerRefresh() {
+        if (!this._lockObject.lock) {
+            this.forceUpdate();
+        }
+    }
+
     componentWillMount() {
-        this._timerIntervalId = window.setInterval(() => this.forceUpdate(), 500);
+        this._timerIntervalId = window.setInterval(() => this.timerRefresh(), 500);
     }
 
     componentWillUnmount() {
@@ -56,6 +72,7 @@ export class PropertyGridTabComponent extends PaneComponent {
                 const mesh = entity as Mesh;
                 if (mesh.getTotalVertices() > 0) {
                     return (<MeshPropertyGridComponent mesh={mesh}
+                        lockObject={this._lockObject}
                         onSelectionChangedObservable={this.props.onSelectionChangedObservable}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
                 }
@@ -63,18 +80,23 @@ export class PropertyGridTabComponent extends PaneComponent {
 
             if (className.indexOf("FreeCamera") !== -1) {
                 const freeCamera = entity as FreeCamera;
-                return (<FreeCameraPropertyGridComponent camera={freeCamera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<FreeCameraPropertyGridComponent camera={freeCamera}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className.indexOf("ArcRotateCamera") !== -1) {
                 const arcRotateCamera = entity as ArcRotateCamera;
-                return (<ArcRotateCameraPropertyGridComponent camera={arcRotateCamera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<ArcRotateCameraPropertyGridComponent camera={arcRotateCamera}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className === "HemisphericLight") {
                 const hemisphericLight = entity as HemisphericLight;
                 return (<HemisphericLightPropertyGridComponent
                     light={hemisphericLight}
+                    lockObject={this._lockObject}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
@@ -82,18 +104,22 @@ export class PropertyGridTabComponent extends PaneComponent {
                 const pointLight = entity as PointLight;
                 return (<PointLightPropertyGridComponent
                     light={pointLight}
+                    lockObject={this._lockObject}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className.indexOf("TransformNode") !== -1 || className.indexOf("Mesh") !== -1) {
                 const transformNode = entity as TransformNode;
-                return (<TransformNodePropertyGridComponent transformNode={transformNode} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<TransformNodePropertyGridComponent transformNode={transformNode}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className === "StandardMaterial") {
                 const material = entity as StandardMaterial;
                 return (<StandardMaterialPropertyGridComponent
                     material={material}
+                    lockObject={this._lockObject}
                     onSelectionChangedObservable={this.props.onSelectionChangedObservable}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
@@ -102,6 +128,7 @@ export class PropertyGridTabComponent extends PaneComponent {
                 const material = entity as PBRMaterial;
                 return (<PBRMaterialPropertyGridComponent
                     material={material}
+                    lockObject={this._lockObject}
                     onSelectionChangedObservable={this.props.onSelectionChangedObservable}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
@@ -110,6 +137,7 @@ export class PropertyGridTabComponent extends PaneComponent {
                 const material = entity as BackgroundMaterial;
                 return (<BackgroundMaterialPropertyGridComponent
                     material={material}
+                    lockObject={this._lockObject}
                     onSelectionChangedObservable={this.props.onSelectionChangedObservable}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
@@ -119,41 +147,111 @@ export class PropertyGridTabComponent extends PaneComponent {
                 return (<AnimationGroupGridComponent
                     animationGroup={animationGroup}
                     scene={this.props.scene}
+                    lockObject={this._lockObject}
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className.indexOf("Material") !== -1) {
                 const material = entity as Material;
-                return (<MaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<MaterialPropertyGridComponent material={material}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className.indexOf("Texture") !== -1) {
                 const texture = entity as Texture;
-                return (<TexturePropertyGridComponent texture={texture} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<TexturePropertyGridComponent texture={texture}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className === "TextBlock") {
                 const textBlock = entity as TextBlock;
-                return (<TextBlockPropertyGridComponent textBlock={textBlock} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<TextBlockPropertyGridComponent textBlock={textBlock}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className === "InputText") {
                 const inputText = entity as InputText;
-                return (<InputTextPropertyGridComponent inputText={inputText} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<InputTextPropertyGridComponent inputText={inputText}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (className === "ColorPicker") {
                 const colorPicker = entity as ColorPicker;
-                return (<ColorPickerPropertyGridComponent colorPicker={colorPicker} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<ColorPickerPropertyGridComponent colorPicker={colorPicker}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Image") {
+                const image = entity as Image;
+                return (<ImagePropertyGridComponent image={image}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Slider") {
+                const slider = entity as Slider;
+                return (<SliderPropertyGridComponent slider={slider}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "ImageBasedSlider") {
+                const imageBasedSlider = entity as ImageBasedSlider;
+                return (<ImageBasedSliderPropertyGridComponent imageBasedSlider={imageBasedSlider}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Rectangle") {
+                const rectangle = entity as Rectangle;
+                return (<RectanglePropertyGridComponent rectangle={rectangle}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Ellipse") {
+                const ellipse = entity as Ellipse;
+                return (<EllipsePropertyGridComponent ellipse={ellipse}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Checkbox") {
+                const checkbox = entity as Checkbox;
+                return (<CheckboxPropertyGridComponent checkbox={checkbox}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "RadioButton") {
+                const radioButton = entity as RadioButton;
+                return (<RadioButtonPropertyGridComponent radioButton={radioButton}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
+            if (className === "Line") {
+                const line = entity as Line;
+                return (<LinePropertyGridComponent line={line}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
             if (entity._host) {
                 const control = entity as Control;
-                return (<ControlPropertyGridComponent control={control} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+                return (<ControlPropertyGridComponent control={control}
+                    lockObject={this._lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
         } else if (entity.transformNodes) {
             const scene = entity as Scene;
             return (<ScenePropertyGridComponent scene={scene}
+                lockObject={this._lockObject}
                 onSelectionChangedObservable={this.props.onSelectionChangedObservable}
                 onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
         }

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx

@@ -5,10 +5,12 @@ import { ButtonLineComponent } from "../../lines/buttonLineComponent";
 import { LineContainerComponent } from "../../lineContainerComponent";
 import { TextLineComponent } from "../../lines/textLineComponent";
 import { SliderLineComponent } from "../../lines/sliderLineComponent";
+import { LockObject } from "./lockObject";
 
 interface IAnimationGroupGridComponentProps {
     animationGroup: AnimationGroup,
     scene: Scene,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 

+ 16 - 14
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/arcRotateCameraPropertyGridComponent.tsx

@@ -7,9 +7,11 @@ import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
+import { LockObject } from "../lockObject";
 
 interface IArcRotateCameraPropertyGridComponentProps {
     camera: ArcRotateCamera,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -23,31 +25,31 @@ export class ArcRotateCameraPropertyGridComponent extends React.Component<IArcRo
 
         return (
             <div className="pane">
-                <CommonCameraPropertyGridComponent camera={camera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonCameraPropertyGridComponent lockObject={this.props.lockObject} camera={camera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="TRANSFORMS">
                     <SliderLineComponent label="Alpha" target={camera} propertyName="alpha" minimum={camera.lowerAlphaLimit || 0} maximum={camera.upperAlphaLimit || 2 * Math.PI} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Beta" target={camera} propertyName="beta" minimum={camera.lowerAlphaLimit || 0} maximum={camera.upperBetaLimit || 2 * Math.PI} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Radius" target={camera} propertyName="radius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Radius" target={camera} propertyName="radius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="CONTROLS" closed={true}>
-                    <FloatLineComponent label="Angular sensitivity X" target={camera} propertyName="angularSensibilityX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Angular sensitivity Y" target={camera} propertyName="angularSensibilityY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Panning sensitivity" target={camera} propertyName="panningSensibility" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Pinch delta percentage" target={camera} propertyName="pinchDeltaPercentage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Wheel delta percentage" target={camera} propertyName="wheelDeltaPercentage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Speed" target={camera} propertyName="speed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Angular sensitivity X" target={camera} propertyName="angularSensibilityX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Angular sensitivity Y" target={camera} propertyName="angularSensibilityY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Panning sensitivity" target={camera} propertyName="panningSensibility" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Pinch delta percentage" target={camera} propertyName="pinchDeltaPercentage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Wheel delta percentage" target={camera} propertyName="wheelDeltaPercentage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Speed" target={camera} propertyName="speed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="COLLISIONS" closed={true}>
                     <CheckBoxLineComponent label="Check collisions" target={camera} propertyName="checkCollisions" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Collision radius" target={camera} propertyName="collisionRadius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="LIMITS" closed={true}>
-                    <FloatLineComponent label="Lower alpha limit" target={camera} propertyName="lowerAlphaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Upper alpha limit" target={camera} propertyName="upperAlphaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Lower beta limit" target={camera} propertyName="lowerBetaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Upper beta limit" target={camera} propertyName="upperBetaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Lower radius limit" target={camera} propertyName="lowerRadiusLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Upper radius limit" target={camera} propertyName="upperRadiusLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Lower alpha limit" target={camera} propertyName="lowerAlphaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Upper alpha limit" target={camera} propertyName="upperAlphaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Lower beta limit" target={camera} propertyName="lowerBetaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Upper beta limit" target={camera} propertyName="upperBetaLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Lower radius limit" target={camera} propertyName="lowerRadiusLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Upper radius limit" target={camera} propertyName="upperRadiusLimit" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="BEHAVIORS" closed={true}>
                     <CheckBoxLineComponent label="Auto rotation" target={camera} propertyName="useAutoRotationBehavior" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 8 - 6
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/commonCameraPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { LineContainerComponent } from "../../../lineContainerComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { TextLineComponent } from "../../../lines/textLineComponent";
 import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+import { LockObject } from "../lockObject";
 
 interface ICommonCameraPropertyGridComponentProps {
     camera: Camera,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -32,8 +34,8 @@ export class CommonCameraPropertyGridComponent extends React.Component<ICommonCa
                 <TextLineComponent label="ID" value={camera.id} />
                 <TextLineComponent label="Unique ID" value={camera.uniqueId.toString()} />
                 <TextLineComponent label="Class" value={camera.getClassName()} />
-                <FloatLineComponent label="Near plane" target={camera} propertyName="minZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                <FloatLineComponent label="Far plane" target={camera} propertyName="maxZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent lockObject={this.props.lockObject} label="Near plane" target={camera} propertyName="minZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent lockObject={this.props.lockObject} label="Far plane" target={camera} propertyName="maxZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <SliderLineComponent label="Inertia" target={camera} propertyName="inertia" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <OptionsLineComponent label="Mode" options={modeOptions} target={camera} propertyName="mode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={value => this.setState({ mode: value })} />
                 {
@@ -42,19 +44,19 @@ export class CommonCameraPropertyGridComponent extends React.Component<ICommonCa
                 }
                 {
                     camera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA &&
-                    <FloatLineComponent label="Left" target={camera} propertyName="orthoLeft" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Left" target={camera} propertyName="orthoLeft" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
                 {
                     camera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA &&
-                    <FloatLineComponent label="Top" target={camera} propertyName="orthoTop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Top" target={camera} propertyName="orthoTop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
                 {
                     camera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA &&
-                    <FloatLineComponent label="Right" target={camera} propertyName="orthoRight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Right" target={camera} propertyName="orthoRight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
                 {
                     camera.mode === BABYLON.Camera.ORTHOGRAPHIC_CAMERA &&
-                    <FloatLineComponent label="Bottom" target={camera} propertyName="orthoBottom" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Bottom" target={camera} propertyName="orthoBottom" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
 
             </LineContainerComponent>

+ 5 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/freeCameraPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { LineContainerComponent } from "../../../lineContainerComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IFreeCameraPropertyGridComponentProps {
     camera: FreeCamera,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -22,13 +24,13 @@ export class FreeCameraPropertyGridComponent extends React.Component<IFreeCamera
 
         return (
             <div className="pane">
-                <CommonCameraPropertyGridComponent camera={camera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonCameraPropertyGridComponent lockObject={this.props.lockObject} camera={camera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="TRANSFORMS">
                     <Vector3LineComponent label="Position" target={camera} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="CONTROLS" closed={true}>
-                    <FloatLineComponent label="Angular sensitivity" target={camera} propertyName="angularSensibility" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Speed" target={camera} propertyName="speed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Angular sensitivity" target={camera} propertyName="angularSensibility" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Speed" target={camera} propertyName="speed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="COLLISIONS" closed={true}>
                     <CheckBoxLineComponent label="Check collisions" target={camera} propertyName="checkCollisions" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 0 - 102
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/propertyGridTabComponent.tsx

@@ -1,102 +0,0 @@
-import * as React from "react";
-import { PaneComponent, IPaneComponentProps } from "../../../paneComponent";
-import { Mesh, TransformNode, Material, StandardMaterial, Texture, PBRMaterial, Scene, FreeCamera, ArcRotateCamera, HemisphericLight, PointLight } from "babylonjs";
-import { MaterialPropertyGridComponent } from "../materials/materialPropertyGridComponent";
-import { StandardMaterialPropertyGridComponent } from "../materials/standardMaterialPropertyGridComponent";
-import { TexturePropertyGridComponent } from "../materials/texturePropertyGridComponent";
-import { PBRMaterialPropertyGridComponent } from "../materials/pbrMaterialPropertyGridComponent";
-import { ScenePropertyGridComponent } from "../scenePropertyGridComponent";
-import { HemisphericLightPropertyGridComponent } from "../lights/hemisphericLightPropertyGridComponent";
-import { PointLightPropertyGridComponent } from "../lights/pointLightPropertyGridComponent";
-import { FreeCameraPropertyGridComponent } from "./freeCameraPropertyGridComponent";
-import { ArcRotateCameraPropertyGridComponent } from "./arcRotateCameraPropertyGridComponent";
-import { MeshPropertyGridComponent } from "../meshes/meshPropertyGridComponent";
-import { TransformNodePropertyGridComponent } from "../meshes/transformNodePropertyGridComponent";
-
-export class PropertyGridTabComponent extends PaneComponent {
-    constructor(props: IPaneComponentProps) {
-        super(props);
-    }
-
-    render() {
-        const entity = this.props.selectedEntity;
-
-        if (!entity) {
-            return null;
-        }
-
-        if (entity.getClassName) {
-            const className = entity.getClassName();
-
-            if (className.indexOf("Mesh") !== -1) {
-                const mesh = entity as Mesh;
-                if (mesh.getTotalVertices() > 0) {
-                    return (<MeshPropertyGridComponent mesh={mesh}
-                        onSelectionChangedObservable={this.props.onSelectionChangedObservable}
-                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-                }
-            }
-
-            if (className.indexOf("FreeCamera") !== -1) {
-                const freeCamera = entity as FreeCamera;
-                return (<FreeCameraPropertyGridComponent camera={freeCamera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className.indexOf("ArcRotateCamera") !== -1) {
-                const arcRotateCamera = entity as ArcRotateCamera;
-                return (<ArcRotateCameraPropertyGridComponent camera={arcRotateCamera} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className === "HemisphericLight") {
-                const hemisphericLight = entity as HemisphericLight;
-                return (<HemisphericLightPropertyGridComponent
-                    light={hemisphericLight}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className === "PointLight") {
-                const pointLight = entity as PointLight;
-                return (<PointLightPropertyGridComponent
-                    light={pointLight}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className.indexOf("TransformNode") !== -1 || className.indexOf("Mesh") !== -1) {
-                const transformNode = entity as TransformNode;
-                return (<TransformNodePropertyGridComponent transformNode={transformNode} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className === "StandardMaterial") {
-                const material = entity as StandardMaterial;
-                return (<StandardMaterialPropertyGridComponent
-                    material={material}
-                    onSelectionChangedObservable={this.props.onSelectionChangedObservable}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className === "PBRMaterial") {
-                const material = entity as PBRMaterial;
-                return (<PBRMaterialPropertyGridComponent
-                    material={material}
-                    onSelectionChangedObservable={this.props.onSelectionChangedObservable}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className.indexOf("Material") !== -1) {
-                const material = entity as Material;
-                return (<MaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-            if (className.indexOf("Texture") !== -1) {
-                const texture = entity as Texture;
-                return (<TexturePropertyGridComponent texture={texture} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-            }
-
-        } else if (entity.transformNodes) {
-            const scene = entity as Scene;
-            return (<ScenePropertyGridComponent scene={scene} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
-        }
-
-        return null;
-    }
-}

+ 5 - 3
inspector/src/components/actionTabs/tabs/propertyGrids/fogPropertyGridComponent.tsx

@@ -4,9 +4,11 @@ import { PropertyChangedEvent } from "../../../propertyChangedEvent";
 import { Color3LineComponent } from "../../lines/color3LineComponent";
 import { FloatLineComponent } from "../../lines/floatLineComponent";
 import { OptionsLineComponent } from "../../lines/optionsLineComponent";
+import { LockObject } from "./lockObject";
 
 interface IFogPropertyGridComponentProps {
     scene: Scene,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -36,15 +38,15 @@ export class FogPropertyGridComponent extends React.Component<IFogPropertyGridCo
                 }
                 {
                     (this.state.mode === BABYLON.Scene.FOGMODE_EXP || this.state.mode === BABYLON.Scene.FOGMODE_EXP2) &&
-                    <FloatLineComponent label="Fog density" target={scene} propertyName="fogDensity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Fog density" target={scene} propertyName="fogDensity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
                 {
                     this.state.mode === BABYLON.Scene.FOGMODE_LINEAR &&
-                    <FloatLineComponent label="Fog start" target={scene} propertyName="fogStart" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Fog start" target={scene} propertyName="fogStart" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
                 {
                     this.state.mode === BABYLON.Scene.FOGMODE_LINEAR &&
-                    <FloatLineComponent label="Fog end" target={scene} propertyName="fogEnd" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Fog end" target={scene} propertyName="fogEnd" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 }
             </div>
         );

+ 4 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/gridPropertyGridComponent.tsx

@@ -18,7 +18,7 @@ export class GridPropertyGridComponent extends React.Component<IGridPropertyGrid
         const scene = BABYLON.UtilityLayerRenderer.DefaultKeepDepthUtilityLayer.utilityLayerScene;
 
         for (var mesh of scene.meshes) {
-            if (mesh.metadata && mesh.metadata.isInspectorGrid) {
+            if (mesh.reservedDataStore && mesh.reservedDataStore.isInspectorGrid) {
                 this._gridMesh = mesh;
                 this.setState({ isEnabled: true });
                 return;
@@ -43,12 +43,12 @@ export class GridPropertyGridComponent extends React.Component<IGridPropertyGrid
             var depth = (extend.max.z - extend.min.z) * 5.0;
 
             this._gridMesh = BABYLON.Mesh.CreateGround("grid", 1.0, 1.0, 1, scene);
-            if (!this._gridMesh.metadata) {
-                this._gridMesh.metadata = {};
+            if (!this._gridMesh.reservedDataStore) {
+                this._gridMesh.reservedDataStore = {};
             }
             this._gridMesh.scaling.x = Math.max(width, depth);
             this._gridMesh.scaling.z = this._gridMesh.scaling.x;
-            this._gridMesh.metadata.isInspectorGrid = true;
+            this._gridMesh.reservedDataStore.isInspectorGrid = true;
             this._gridMesh.isPickable = false;
 
             var groundMaterial = new (BABYLON as any).GridMaterial("GridMaterial", scene);

+ 35 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/checkboxPropertyGridComponent.tsx

@@ -0,0 +1,35 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { Checkbox } from "babylonjs-gui";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+
+interface ICheckboxPropertyGridComponentProps {
+    checkbox: Checkbox,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class CheckboxPropertyGridComponent extends React.Component<ICheckboxPropertyGridComponentProps> {
+    constructor(props: ICheckboxPropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const checkbox = this.props.checkbox;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={checkbox} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="CHECKBOX">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Check size ratio" target={checkbox} propertyName="checkSizeRatio" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Checked" target={checkbox} propertyName="isChecked" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/gui/colorPickerPropertyGridComponent.tsx

@@ -5,9 +5,11 @@ import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridC
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { ColorPicker } from "babylonjs-gui/2D/controls/colorpicker";
 import { Color3LineComponent } from "../../../lines/color3LineComponent";
+import { LockObject } from "../lockObject";
 
 interface IColorPickerPropertyGridComponentProps {
     colorPicker: ColorPicker,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -21,7 +23,7 @@ export class ColorPickerPropertyGridComponent extends React.Component<IColorPick
 
         return (
             <div className="pane">
-                <CommonControlPropertyGridComponent control={colorPicker} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={colorPicker} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="COLORPICKER">
                     <Color3LineComponent label="Color" target={colorPicker} propertyName="value" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>

+ 49 - 18
inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx

@@ -7,9 +7,12 @@ import { Control } from "babylonjs-gui/2D/controls/control";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+import { LockObject } from "../lockObject";
+import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
 
 interface ICommonControlPropertyGridComponentProps {
     control: Control,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -21,36 +24,64 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
     render() {
         const control = this.props.control;
 
+        var horizontalOptions = [
+            { label: "Left", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT },
+            { label: "Right", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT },
+            { label: "Center", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER },
+        ];
+
+        var verticalOptions = [
+            { label: "Top", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP },
+            { label: "Bottom", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM },
+            { label: "Center", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER },
+        ];
+
         return (
             <div>
                 <LineContainerComponent title="GENERAL">
                     <TextLineComponent label="Class" value={control.getClassName()} />
                     <SliderLineComponent label="Alpha" target={control} propertyName="alpha" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Color" target={control} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Background" target={control} propertyName="background" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    {
+                        control.color &&
+                        <TextInputLineComponent lockObject={this.props.lockObject} label="Color" target={control} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                    {
+                        (control as any).background !== undefined &&
+                        <TextInputLineComponent lockObject={this.props.lockObject} label="Background" target={control} propertyName="background" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    }
+                </LineContainerComponent>
+                <LineContainerComponent title="ALIGNMENT">
+                    <OptionsLineComponent label="Horizontal" options={horizontalOptions} target={control} propertyName="horizontalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <OptionsLineComponent label="Vertical" options={verticalOptions} target={control} propertyName="verticalAlignment" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="POSITION">
-                    <TextInputLineComponent label="Left" target={control} propertyName="left" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Top" target={control} propertyName="top" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Width" target={control} propertyName="width" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Height" target={control} propertyName="height" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Padding left" target={control} propertyName="paddingLeft" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Padding top" target={control} propertyName="paddingTop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Padding right" target={control} propertyName="paddingRight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Padding bottom" target={control} propertyName="paddingBottom" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Left" target={control} propertyName="left" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Top" target={control} propertyName="top" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Width" target={control} propertyName="width" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Height" target={control} propertyName="height" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Padding left" target={control} propertyName="paddingLeft" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Padding top" target={control} propertyName="paddingTop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Padding right" target={control} propertyName="paddingRight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Padding bottom" target={control} propertyName="paddingBottom" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="TRANSFORMATION" closed={true}>
-                    <FloatLineComponent label="ScaleX" target={control} propertyName="scaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="ScaleY" target={control} propertyName="scaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="ScaleX" target={control} propertyName="scaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="ScaleY" target={control} propertyName="scaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Rotation" target={control} propertyName="rotation" minimum={0} maximum={2 * Math.PI} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Transform center X" target={control} propertyName="transformCenterX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Transform center Y" target={control} propertyName="transformCenterY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Transform center X" target={control} propertyName="transformCenterX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Transform center Y" target={control} propertyName="transformCenterY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent title="FONT" closed={true}>
-                    <TextInputLineComponent label="Family" target={control} propertyName="fontFamily" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Size" target={control} propertyName="fontSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Weight" target={control} propertyName="fontWeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Style" target={control} propertyName="fontStyle" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Family" target={control} propertyName="fontFamily" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Size" target={control} propertyName="fontSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <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>
         );

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/gui/controlPropertyGridComponent.tsx

@@ -3,9 +3,11 @@ import { Observable } from "babylonjs";
 import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
 import { Control } from "babylonjs-gui/2D/controls/control";
 import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
 
 interface IControlPropertyGridComponentProps {
     control: Control,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -19,7 +21,7 @@ export class ControlPropertyGridComponent extends React.Component<IControlProper
 
         return (
             <div className="pane">
-                <CommonControlPropertyGridComponent control={control} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={control} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </div>
         );
     }

+ 33 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/ellipsePropertyGridComponent.tsx

@@ -0,0 +1,33 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { Ellipse } from "babylonjs-gui";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+
+interface IEllipsePropertyGridComponentProps {
+    ellipse: Ellipse,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class EllipsePropertyGridComponent extends React.Component<IEllipsePropertyGridComponentProps> {
+    constructor(props: IEllipsePropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const ellipse = this.props.ellipse;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={ellipse} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="ELLIPSE">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={ellipse} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 42 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/imageBasedSliderPropertyGridComponent.tsx

@@ -0,0 +1,42 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { LockObject } from "../lockObject";
+import { ImageBasedSlider } from "babylonjs-gui";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+
+interface IImageBasedSliderPropertyGridComponentProps {
+    imageBasedSlider: ImageBasedSlider,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class ImageBasedSliderPropertyGridComponent extends React.Component<IImageBasedSliderPropertyGridComponentProps> {
+    constructor(props: IImageBasedSliderPropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const imageBasedSlider = this.props.imageBasedSlider;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={imageBasedSlider} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="IMAGE BASED SLIDER">
+                    <CheckBoxLineComponent label="Display thumb" target={imageBasedSlider} propertyName="displayThumb" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Vertical" target={imageBasedSlider} propertyName="isVertical" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Thumb clamped" target={imageBasedSlider} propertyName="isThumbClamped" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Bar offset" target={imageBasedSlider} propertyName="barOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Thumb width" target={imageBasedSlider} propertyName="thumbWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Minimum" target={imageBasedSlider} propertyName="minimum" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Maximum" target={imageBasedSlider} propertyName="maximum" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Value" target={imageBasedSlider} propertyName="value" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 52 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/imagePropertyGridComponent.tsx

@@ -0,0 +1,52 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { LockObject } from "../lockObject";
+import { Image } from "babylonjs-gui";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+
+interface IImagePropertyGridComponentProps {
+    image: Image,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class ImagePropertyGridComponent extends React.Component<IImagePropertyGridComponentProps> {
+    constructor(props: IImagePropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const image = this.props.image;
+
+        var stretchOptions = [
+            { label: "None", value: BABYLON.GUI.Image.STRETCH_NONE },
+            { label: "Fill", value: BABYLON.GUI.Image.STRETCH_FILL },
+            { label: "Uniform", value: BABYLON.GUI.Image.STRETCH_UNIFORM },
+            { label: "Extend", value: BABYLON.GUI.Image.STRETCH_EXTEND }
+        ];
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={image} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="IMAGE">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Source left" target={image} propertyName="sourceLeft" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Source top" target={image} propertyName="sourceTop" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Source width" target={image} propertyName="sourceWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Source height" target={image} propertyName="sourceHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Autoscale" target={image} propertyName="autoScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <OptionsLineComponent label="Stretch" options={stretchOptions} target={image} propertyName="stretch" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={value => this.setState({ mode: value })} />
+                </LineContainerComponent>
+                <LineContainerComponent title="ANIMATION SHEET">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Cell Id" isInteger={true} target={image} propertyName="cellId" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Cell width" target={image} propertyName="cellWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Cell height" target={image} propertyName="cellHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 13 - 11
inspector/src/components/actionTabs/tabs/propertyGrids/gui/inputTextPropertyGridComponent.tsx

@@ -8,9 +8,11 @@ import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IInputTextPropertyGridComponentProps {
     inputText: InputText,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -24,21 +26,21 @@ export class InputTextPropertyGridComponent extends React.Component<IInputTextPr
 
         return (
             <div className="pane">
-                <CommonControlPropertyGridComponent control={inputText} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={inputText} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="INPUTTEXT">
-                    <TextInputLineComponent label="Text" target={inputText} propertyName="text" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Prompt" target={inputText} propertyName="promptMessage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Max width" target={inputText} propertyName="maxWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Highlight color" target={inputText} propertyName="textHighlightColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Text" target={inputText} propertyName="text" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Prompt" target={inputText} propertyName="promptMessage" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Max width" target={inputText} propertyName="maxWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Highlight color" target={inputText} propertyName="textHighlightColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Highligher opacity" minimum={0} maximum={1} step={0.01} target={inputText} propertyName="highligherOpacity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="On focus select all" target={inputText} propertyName="onFocusSelectAll" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Focused background" target={inputText} propertyName="focusedBackground" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Max width" target={inputText} propertyName="maxWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Margin" target={inputText} propertyName="margin" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Focused background" target={inputText} propertyName="focusedBackground" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Max width" target={inputText} propertyName="maxWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Margin" target={inputText} propertyName="margin" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Auto stretch width" target={inputText} propertyName="autoStretchWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Thickness" target={inputText} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Placeholder text" target={inputText} propertyName="placeholderText" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <TextInputLineComponent label="Placeholder color" target={inputText} propertyName="placeholderColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={inputText} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Placeholder text" target={inputText} propertyName="placeholderText" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Placeholder color" target={inputText} propertyName="placeholderColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
             </div>
         );

+ 55 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/linePropertyGridComponent.tsx

@@ -0,0 +1,55 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { Line } from "babylonjs-gui";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+
+interface ILinePropertyGridComponentProps {
+    line: Line,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class LinePropertyGridComponent extends React.Component<ILinePropertyGridComponentProps> {
+    constructor(props: ILinePropertyGridComponentProps) {
+        super(props);
+    }
+
+    onDashChange(value: string) {
+        const line = this.props.line;
+        const split = value.split(",");
+        line.dash = [];
+
+        split.forEach(v => {
+            const int = parseInt(v);
+
+            if (isNaN(int)) {
+                return;
+            }
+
+            line.dash.push(int);
+        });
+    }
+
+    render() {
+        const line = this.props.line;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={line} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="LINE">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Line width" target={line} propertyName="lineWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="X1" target={line} propertyName="x1" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Y1" target={line} propertyName="y1" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="X2" target={line} propertyName="x2" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Y2" target={line} propertyName="y2" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Dash pattern" target={line} value={line.dash.join(",")} onChange={newValue => this.onDashChange(newValue)} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 38 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/radioButtonPropertyGridComponent.tsx

@@ -0,0 +1,38 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { RadioButton } from "babylonjs-gui";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+
+interface IRadioButtonPropertyGridComponentProps {
+    radioButton: RadioButton,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class RadioButtonPropertyGridComponent extends React.Component<IRadioButtonPropertyGridComponentProps> {
+    constructor(props: IRadioButtonPropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const radioButton = this.props.radioButton;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={radioButton} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="RADIO BUTTON">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={radioButton} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Check size ratio" target={radioButton} propertyName="checkSizeRatio" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Group" target={radioButton} propertyName="group" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Checked" target={radioButton} propertyName="isChecked" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 34 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/rectanglePropertyGridComponent.tsx

@@ -0,0 +1,34 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { Rectangle } from "babylonjs-gui";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+
+interface IRectanglePropertyGridComponentProps {
+    rectangle: Rectangle,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class RectanglePropertyGridComponent extends React.Component<IRectanglePropertyGridComponentProps> {
+    constructor(props: IRectanglePropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const rectangle = this.props.rectangle;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={rectangle} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="RECTANGLE">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Thickness" target={rectangle} propertyName="thickness" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Corner radius" target={rectangle} propertyName="cornerRadius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 44 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/gui/sliderPropertyGridComponent.tsx

@@ -0,0 +1,44 @@
+import * as React from "react";
+import { Observable } from "babylonjs";
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridComponent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { LockObject } from "../lockObject";
+import { Slider } from "babylonjs-gui";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+
+interface ISliderPropertyGridComponentProps {
+    slider: Slider,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class SliderPropertyGridComponent extends React.Component<ISliderPropertyGridComponentProps> {
+    constructor(props: ISliderPropertyGridComponentProps) {
+        super(props);
+    }
+
+    render() {
+        const slider = this.props.slider;
+
+        return (
+            <div className="pane">
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={slider} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent title="SLIDER">
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Border color" target={slider} propertyName="borderColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Display thumb" target={slider} propertyName="displayThumb" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Thumb circle" target={slider} propertyName="isThumbCircle" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Vertical" target={slider} propertyName="isVertical" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Thumb clamped" target={slider} propertyName="isThumbClamped" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Bar offset" target={slider} propertyName="barOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Thumb width" target={slider} propertyName="thumbWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Minimum" target={slider} propertyName="minimum" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Maximum" target={slider} propertyName="maximum" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Value" target={slider} propertyName="value" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 34 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/gui/textBlockPropertyGridComponent.tsx

@@ -5,9 +5,14 @@ import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridC
 import { TextBlock } from "babylonjs-gui";
 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,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -19,11 +24,38 @@ export class TextBlockPropertyGridComponent extends React.Component<ITextBlockPr
     render() {
         const textBlock = this.props.textBlock;
 
+        var horizontalOptions = [
+            { label: "Left", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT },
+            { label: "Right", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT },
+            { label: "Center", value: BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER },
+        ];
+
+        var verticalOptions = [
+            { label: "Top", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP },
+            { label: "Bottom", value: BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM },
+            { 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 control={textBlock} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonControlPropertyGridComponent lockObject={this.props.lockObject} control={textBlock} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="TEXTBLOCK">
-                    <TextInputLineComponent label="Text" target={textBlock} propertyName="text" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <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>
         );

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonLightPropertyGridComponent.tsx

@@ -4,9 +4,11 @@ import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { TextLineComponent } from "../../../lines/textLineComponent";
+import { LockObject } from "../lockObject";
 
 interface ICommonLightPropertyGridComponentProps {
     light: Light,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -23,7 +25,7 @@ export class CommonLightPropertyGridComponent extends React.Component<ICommonLig
                 <TextLineComponent label="ID" value={light.id} />
                 <TextLineComponent label="Unique ID" value={light.uniqueId.toString()} />
                 <TextLineComponent label="Class" value={light.getClassName()} />
-                <FloatLineComponent label="Intensity" target={light} propertyName="intensity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent lockObject={this.props.lockObject} label="Intensity" target={light} propertyName="intensity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </LineContainerComponent>
         );
     }

+ 4 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonShadowLightPropertyGridComponent.tsx

@@ -4,9 +4,11 @@ import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { LockObject } from "../lockObject";
 
 interface ICommonShadowLightPropertyGridComponentProps {
     light: IShadowLight,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -21,8 +23,8 @@ export class CommonShadowLightPropertyGridComponent extends React.Component<ICom
         return (
             <LineContainerComponent title="SHADOWS">
                 <CheckBoxLineComponent label="Shadows enabled" target={light} propertyName="shadowEnabled" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                <FloatLineComponent label="Shadows near plane" target={light} propertyName="shadowMinZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                <FloatLineComponent label="Shadows far plane" target={light} propertyName="shadowMaxZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent lockObject={this.props.lockObject} label="Shadows near plane" target={light} propertyName="shadowMinZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent lockObject={this.props.lockObject} label="Shadows far plane" target={light} propertyName="shadowMaxZ" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </LineContainerComponent>
         );
     }

+ 4 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/lights/directionalLightPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { LineContainerComponent } from "../../../lineContainerComponent";
 import { Color3LineComponent } from "../../../lines/color3LineComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { CommonShadowLightPropertyGridComponent } from "./commonShadowLightPropertyGridComponent";
+import { LockObject } from "../lockObject";
 
 interface IDirectionalLightPropertyGridComponentProps {
     light: DirectionalLight,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -22,14 +24,14 @@ export class DirectionalLightPropertyGridComponent extends React.Component<IDire
 
         return (
             <div className="pane">
-                <CommonLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="SETUP">
                     <Color3LineComponent label="Diffuse" target={light} propertyName="diffuse" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Specular" target={light} propertyName="specular" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Position" target={light} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Direction" target={light} propertyName="direction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                <CommonShadowLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonShadowLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </div>
         );
     }

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/lights/hemisphericLightPropertyGridComponent.tsx

@@ -5,9 +5,11 @@ import { CommonLightPropertyGridComponent } from "./commonLightPropertyGridCompo
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { Color3LineComponent } from "../../../lines/color3LineComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
+import { LockObject } from "../lockObject";
 
 interface IHemisphericLightPropertyGridComponentProps {
     light: HemisphericLight,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -21,7 +23,7 @@ export class HemisphericLightPropertyGridComponent extends React.Component<IHemi
 
         return (
             <div className="pane">
-                <CommonLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="SETUP">
                     <Color3LineComponent label="Diffuse" target={light} propertyName="diffuse" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Ground" target={light} propertyName="groundColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 4 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/lights/pointLightPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { LineContainerComponent } from "../../../lineContainerComponent";
 import { Color3LineComponent } from "../../../lines/color3LineComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { CommonShadowLightPropertyGridComponent } from "./commonShadowLightPropertyGridComponent";
+import { LockObject } from "../lockObject";
 
 interface IPointLightPropertyGridComponentProps {
     light: PointLight,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -22,13 +24,13 @@ export class PointLightPropertyGridComponent extends React.Component<IPointLight
 
         return (
             <div className="pane">
-                <CommonLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="SETUP">
                     <Color3LineComponent label="Diffuse" target={light} propertyName="diffuse" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Specular" target={light} propertyName="specular" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Position" target={light} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                <CommonShadowLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonShadowLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </div>
         );
     }

+ 6 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/lights/spotLightPropertyGridComponent.tsx

@@ -7,9 +7,11 @@ import { Color3LineComponent } from "../../../lines/color3LineComponent";
 import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { CommonShadowLightPropertyGridComponent } from "./commonShadowLightPropertyGridComponent";
+import { LockObject } from "../lockObject";
 
 interface ISpotLightPropertyGridComponentProps {
     light: SpotLight,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -23,16 +25,16 @@ export class SpotLightPropertyGridComponent extends React.Component<ISpotLightPr
 
         return (
             <div className="pane">
-                <CommonLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="SETUP">
                     <Color3LineComponent label="Diffuse" target={light} propertyName="diffuse" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Specular" target={light} propertyName="specular" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Position" target={light} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Direction" target={light} propertyName="direction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Angle" target={light} propertyName="angle" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Exponent" target={light} propertyName="exponent" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Angle" target={light} propertyName="angle" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Exponent" target={light} propertyName="exponent" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                <CommonShadowLightPropertyGridComponent light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonShadowLightPropertyGridComponent lockObject={this.props.lockObject} light={light} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </div>
         );
     }

+ 9 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/lockObject.ts

@@ -0,0 +1,9 @@
+/**
+ * Class used to provide lock mechanism
+ */
+export class LockObject {
+    /**
+     * Gets or set if the lock is engaged
+     */
+    public lock = false;
+}

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx

@@ -7,9 +7,11 @@ import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
 import { TextureLinkLineComponent } from "../../../lines/textureLinkLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IBackgroundMaterialPropertyGridComponentProps {
     material: BackgroundMaterial,
+    lockObject: LockObject,
     onSelectionChangedObservable?: Observable<any>,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
@@ -41,7 +43,7 @@ export class BackgroundMaterialPropertyGridComponent extends React.Component<IBa
 
         return (
             <div className="pane">
-                <CommonMaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonMaterialPropertyGridComponent lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent title="LIGHTING & COLORS">
                     <Color3LineComponent label="Primary" target={material} propertyName="primaryColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Shadow level" target={material} propertyName="primaryColorShadowLevel" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { TextLineComponent } from "../../../lines/textLineComponent";
 import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+import { LockObject } from "../lockObject";
 
 interface ICommonMaterialPropertyGridComponentProps {
     material: Material,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -58,7 +60,7 @@ export class CommonMaterialPropertyGridComponent extends React.Component<ICommon
                     <SliderLineComponent label="Point size" target={material} propertyName="pointSize" minimum={0} maximum={100} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Z-offset" target={material} propertyName="zOffset" minimum={-10} maximum={10} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                <LineContainerComponent title="TRANSPARENCY">                
+                <LineContainerComponent title="TRANSPARENCY">
                     <SliderLineComponent label="Alpha" target={material} propertyName="alpha" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     {
                         (material as any).transparencyMode !== undefined &&

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/materialPropertyGridComponent.tsx

@@ -2,9 +2,11 @@ import * as React from "react";
 import { Material, Observable } from "babylonjs";
 import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
 import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
+import { LockObject } from "../lockObject";
 
 interface IMaterialPropertyGridComponentProps {
     material: Material,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -18,7 +20,7 @@ export class MaterialPropertyGridComponent extends React.Component<IMaterialProp
 
         return (
             <div className="pane">
-                <CommonMaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonMaterialPropertyGridComponent lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
             </div>
         );
     }

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -7,9 +7,11 @@ import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
 import { TextureLinkLineComponent } from "../../../lines/textureLinkLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IPBRMaterialPropertyGridComponentProps {
     material: PBRMaterial,
+    lockObject: LockObject,
     onSelectionChangedObservable?: Observable<any>,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
@@ -49,7 +51,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
 
         return (
             <div className="pane">
-                <CommonMaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonMaterialPropertyGridComponent lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 {this.renderTextures()}
                 <LineContainerComponent title="LIGHTING & COLORS">
                     <Color3LineComponent label="Albedo" target={material} propertyName="albedoColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx

@@ -6,9 +6,11 @@ import { Color3LineComponent } from "../../../lines/color3LineComponent";
 import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
 import { TextureLinkLineComponent } from "../../../lines/textureLinkLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IStandardMaterialPropertyGridComponentProps {
     material: StandardMaterial,
+    lockObject: LockObject,
     onSelectionChangedObservable?: Observable<any>,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
@@ -47,7 +49,7 @@ export class StandardMaterialPropertyGridComponent extends React.Component<IStan
 
         return (
             <div className="pane">
-                <CommonMaterialPropertyGridComponent material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CommonMaterialPropertyGridComponent lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 {this.renderTextures()}
                 <LineContainerComponent title="LIGHTING & COLORS">
                     <Color3LineComponent label="Diffuse" target={material} propertyName="diffuseColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

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

@@ -7,12 +7,13 @@ 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";
 
 interface ITexturePropertyGridComponentProps {
     texture: BaseTexture,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -45,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 },
@@ -74,27 +74,27 @@ 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 label="Ideal width" target={adtTexture} propertyName="idealWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent 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">
                     {
                         !texture.isCube &&
                         <div>
-                            <FloatLineComponent label="U offset" target={texture} propertyName="uOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="V offset" target={texture} propertyName="vOffset" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="V scale" target={texture} propertyName="uScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="V scale" target={texture} propertyName="vScale" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="U angle" target={texture} propertyName="uAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="V angle" target={texture} propertyName="vAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                            <FloatLineComponent label="W angle" target={texture} propertyName="wAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <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="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} />
+                            <FloatLineComponent lockObject={this.props.lockObject} label="W angle" target={texture} propertyName="wAng" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <CheckBoxLineComponent label="Clamp U" isSelected={() => texture.wrapU === BABYLON.Texture.CLAMP_ADDRESSMODE} onSelect={(value) => texture.wrapU = value ? BABYLON.Texture.CLAMP_ADDRESSMODE : BABYLON.Texture.WRAP_ADDRESSMODE} />
                             <CheckBoxLineComponent label="Clamp V" isSelected={() => texture.wrapV === BABYLON.Texture.CLAMP_ADDRESSMODE} onSelect={(value) => texture.wrapV = value ? BABYLON.Texture.CLAMP_ADDRESSMODE : BABYLON.Texture.WRAP_ADDRESSMODE} />
                         </div>

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

@@ -11,23 +11,23 @@ export class AxesViewerComponent extends React.Component<IAxisViewerComponentPro
         super(props);
         const node = this.props.node;
 
-        if (!node.metadata) {
-            node.metadata = {};
+        if (!node.reservedDataStore) {
+            node.reservedDataStore = {};
         }
 
-        this.state = { displayAxis: (node.metadata && node.metadata.axisViewer) ? true : false }
+        this.state = { displayAxis: (node.reservedDataStore && node.reservedDataStore.axisViewer) ? true : false }
     }
 
     displayAxes() {
         const node = this.props.node;
         const scene = node.getScene();
 
-        if (node.metadata.axisViewer) {
-            node.metadata.axisViewer.dispose();
-            node.metadata.axisViewer = null;
+        if (node.reservedDataStore.axisViewer) {
+            node.reservedDataStore.axisViewer.dispose();
+            node.reservedDataStore.axisViewer = null;
 
-            scene.onBeforeRenderObservable.remove(node.metadata.onBeforeRenderObserver);
-            node.metadata.onBeforeRenderObserver = null;
+            scene.onBeforeRenderObservable.remove(node.reservedDataStore.onBeforeRenderObserver);
+            node.reservedDataStore.onBeforeRenderObserver = null;
 
             this.setState({ displayAxis: false });
 
@@ -35,16 +35,16 @@ export class AxesViewerComponent extends React.Component<IAxisViewerComponentPro
         }
 
         const viewer = new BABYLON.Debug.AxesViewer(scene);
-        node.metadata.axisViewer = viewer;
+        node.reservedDataStore.axisViewer = viewer;
         const x = new BABYLON.Vector3(1, 0, 0);
         const y = new BABYLON.Vector3(0, 1, 0);
         const z = new BABYLON.Vector3(0, 0, 1);
 
-        viewer.xAxisMesh!.metadata = { hidden: true };
-        viewer.yAxisMesh!.metadata = { hidden: true };
-        viewer.zAxisMesh!.metadata = { hidden: true };
+        viewer.xAxisMesh!.reservedDataStore = { hidden: true };
+        viewer.yAxisMesh!.reservedDataStore = { hidden: true };
+        viewer.zAxisMesh!.reservedDataStore = { hidden: true };
 
-        node.metadata.onBeforeRenderObserver = scene.onBeforeRenderObservable.add(() => {
+        node.reservedDataStore.onBeforeRenderObserver = scene.onBeforeRenderObservable.add(() => {
             let matrix = node.getWorldMatrix();
             let extend = BABYLON.Tmp.Vector3[0];
             const worldExtend = scene.getWorldExtends();

+ 20 - 18
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -9,9 +9,11 @@ import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent";
 import { AxesViewerComponent } from "./axesViewerComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
+import { LockObject } from "../lockObject";
 
 interface IMeshPropertyGridComponentProps {
     mesh: Mesh,
+    lockObject: LockObject,
     onSelectionChangedObservable?: Observable<any>,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
@@ -21,16 +23,16 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         super(props);
         const mesh = this.props.mesh;
 
-        this.state = { displayNormals: false, renderNormalVectors: mesh.metadata && mesh.metadata.normalLines }
+        this.state = { displayNormals: false, renderNormalVectors: mesh.reservedDataStore && mesh.reservedDataStore.normalLines }
     }
 
     renderNormalVectors() {
         const mesh = this.props.mesh;
         const scene = mesh.getScene();
 
-        if (mesh.metadata && mesh.metadata.normalLines) {
-            mesh.metadata.normalLines.dispose();
-            mesh.metadata.normalLines = null;
+        if (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) {
+            mesh.reservedDataStore.normalLines.dispose();
+            mesh.reservedDataStore.normalLines = null;
 
             this.setState({ renderNormalVectors: false });
             return;
@@ -53,11 +55,11 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         normalLines.color = color;
         normalLines.parent = mesh;
 
-        if (!mesh.metadata) {
-            mesh.metadata = {};
+        if (!mesh.reservedDataStore) {
+            mesh.reservedDataStore = {};
         }
 
-        mesh.metadata.normalLines = normalLines;
+        mesh.reservedDataStore.normalLines = normalLines;
 
         this.setState({ renderNormalVectors: true });
     }
@@ -72,8 +74,8 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         if (mesh.material.getClassName() === "NormalMaterial") {
             mesh.material.dispose();
 
-            mesh.material = mesh.metadata.originalMaterial;
-            mesh.metadata.originalMaterial = null;
+            mesh.material = mesh.reservedDataStore.originalMaterial;
+            mesh.reservedDataStore.originalMaterial = null;
             this.setState({ displayNormals: false });
         } else {
 
@@ -85,15 +87,15 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                 return;
             }
 
-            if (!mesh.metadata) {
-                mesh.metadata = {};
+            if (!mesh.reservedDataStore) {
+                mesh.reservedDataStore = {};
             }
 
-            mesh.metadata.originalMaterial = mesh.material;
+            mesh.reservedDataStore.originalMaterial = mesh.material;
             const normalMaterial = new (BABYLON as any).NormalMaterial("normalMaterial", scene);
             normalMaterial.disableLighting = true;
             normalMaterial.sideOrientation = mesh.material.sideOrientation;
-            normalMaterial.metadata = { hidden: true };
+            normalMaterial.reservedDataStore = { hidden: true };
             mesh.material = normalMaterial;
             this.setState({ displayNormals: true });
         }
@@ -137,7 +139,7 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         const scene = mesh.getScene();
 
         const displayNormals = mesh.material != null && mesh.material.getClassName() === "NormalMaterial";
-        const renderNormalVectors = (mesh.metadata && mesh.metadata.normalLines) ? true : false;
+        const renderNormalVectors = (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) ? true : false;
 
         return (
             <div className="pane">
@@ -170,7 +172,7 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                 </LineContainerComponent>
                 <LineContainerComponent title="DISPLAY" closed={true}>
                     <SliderLineComponent label="Visibility" target={mesh} propertyName="visibility" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent label="Alpha index" target={mesh} propertyName="alphaIndex" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Alpha index" target={mesh} propertyName="alphaIndex" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Receive shadows" target={mesh} propertyName="receiveShadows" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     {
                         mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind) &&
@@ -204,9 +206,9 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                 {
                     mesh.physicsImpostor != null &&
                     <LineContainerComponent title="PHYSICS" closed={true}>
-                        <FloatLineComponent label="Mass" target={mesh.physicsImpostor} propertyName="mass" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent label="Friction" target={mesh.physicsImpostor} propertyName="friction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                        <FloatLineComponent label="Restitution" target={mesh.physicsImpostor} propertyName="restitution" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Mass" target={mesh.physicsImpostor} propertyName="mass" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Friction" target={mesh.physicsImpostor} propertyName="friction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Restitution" target={mesh.physicsImpostor} propertyName="restitution" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <TextLineComponent label="Type" value={this.convertPhysicsTypeToString()} />
                     </LineContainerComponent>
                 }

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/transformNodePropertyGridComponent.tsx

@@ -7,9 +7,11 @@ import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
 import { TextLineComponent } from "../../../lines/textLineComponent";
 import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent";
 import { AxesViewerComponent } from "./axesViewerComponent";
+import { LockObject } from "../lockObject";
 
 interface ITransformNodePropertyGridComponentProps {
     transformNode: TransformNode,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 

+ 23 - 6
inspector/src/components/actionTabs/tabs/propertyGrids/scenePropertyGridComponent.tsx

@@ -10,15 +10,20 @@ import { FileButtonLineComponent } from "../../lines/fileButtonLineComponent";
 import { TextureLinkLineComponent } from "../../lines/textureLinkLineComponent";
 import { Vector3LineComponent } from "../../lines/vector3LineComponent";
 import { FloatLineComponent } from "../../lines/floatLineComponent";
+import { SliderLineComponent } from "../../lines/sliderLineComponent";
+import { OptionsLineComponent } from "../../lines/optionsLineComponent";
+import { LockObject } from "./lockObject";
 
 interface IScenePropertyGridComponentProps {
     scene: Scene,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>,
     onSelectionChangedObservable?: Observable<any>
 }
 
 export class ScenePropertyGridComponent extends React.Component<IScenePropertyGridComponentProps> {
     private _storedEnvironmentTexture: Nullable<BaseTexture>;
+    private _renderingModeGroupObservable = new BABYLON.Observable<RadioButtonLineComponent>();
 
     constructor(props: IScenePropertyGridComponentProps) {
         super(props);
@@ -90,7 +95,6 @@ export class ScenePropertyGridComponent extends React.Component<IScenePropertyGr
     render() {
         const scene = this.props.scene;
 
-        const renderingModeGroupObservable = new BABYLON.Observable<RadioButtonLineComponent>();
 
         const physicsEngine = scene.getPhysicsEngine();
         let dummy: Nullable<{ gravity: Vector3, timeStep: number }> = null;
@@ -102,12 +106,19 @@ export class ScenePropertyGridComponent extends React.Component<IScenePropertyGr
             }
         }
 
+        const imageProcessing = scene.imageProcessingConfiguration;
+
+        var toneMappingOptions = [
+            { label: "Standard", value: BABYLON.ImageProcessingConfiguration.TONEMAPPING_STANDARD },
+            { label: "ACES", value: BABYLON.ImageProcessingConfiguration.TONEMAPPING_ACES }
+        ]
+
         return (
             <div className="pane">
                 <LineContainerComponent title="RENDERING MODE">
-                    <RadioButtonLineComponent onSelectionChangedObservable={renderingModeGroupObservable} label="Point" isSelected={() => scene.forcePointsCloud} onSelect={() => this.setRenderingModes(true, false)} />
-                    <RadioButtonLineComponent onSelectionChangedObservable={renderingModeGroupObservable} label="Wireframe" isSelected={() => scene.forceWireframe} onSelect={() => this.setRenderingModes(false, true)} />
-                    <RadioButtonLineComponent onSelectionChangedObservable={renderingModeGroupObservable} label="Solid" isSelected={() => !scene.forcePointsCloud && !scene.forceWireframe} onSelect={() => this.setRenderingModes(false, false)} />
+                    <RadioButtonLineComponent onSelectionChangedObservable={this._renderingModeGroupObservable} label="Point" isSelected={() => scene.forcePointsCloud} onSelect={() => this.setRenderingModes(true, false)} />
+                    <RadioButtonLineComponent onSelectionChangedObservable={this._renderingModeGroupObservable} label="Wireframe" isSelected={() => scene.forceWireframe} onSelect={() => this.setRenderingModes(false, true)} />
+                    <RadioButtonLineComponent onSelectionChangedObservable={this._renderingModeGroupObservable} label="Solid" isSelected={() => !scene.forcePointsCloud && !scene.forceWireframe} onSelect={() => this.setRenderingModes(false, false)} />
                 </LineContainerComponent>
                 <LineContainerComponent title="ENVIRONMENT">
                     <Color3LineComponent label="Clear color" target={scene} propertyName="clearColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
@@ -119,12 +130,18 @@ export class ScenePropertyGridComponent extends React.Component<IScenePropertyGr
                         <TextureLinkLineComponent label="Env. texture" texture={scene.environmentTexture} onSelectionChangedObservable={this.props.onSelectionChangedObservable} />
                     }
                     <FileButtonLineComponent label="Update environment texture" onClick={(file) => this.updateEnvironmentTexture(file)} accept=".dds, .env" />
-                    <FogPropertyGridComponent scene={scene} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FogPropertyGridComponent lockObject={this.props.lockObject} scene={scene} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>
+                <LineContainerComponent title="IMAGE PROCESSING">
+                    <SliderLineComponent minimum={0} maximum={4} step={0.1} label="Contrast" target={imageProcessing} propertyName="contrast" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <SliderLineComponent minimum={0} maximum={4} step={0.1} label="Exposure" target={imageProcessing} propertyName="exposure" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Tone mapping" target={imageProcessing} propertyName="toneMappingEnabled" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <OptionsLineComponent label="Tone mapping type" options={toneMappingOptions} target={imageProcessing} propertyName="toneMappingType" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={value => this.setState({ mode: value })} />
                 </LineContainerComponent>
                 {
                     dummy !== null &&
                     <LineContainerComponent title="PHYSICS" closed={true}>
-                        <FloatLineComponent label="Time step" target={dummy} propertyName="timeStep" onChange={newValue => this.updateTimeStep(newValue)} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Time step" target={dummy} propertyName="timeStep" onChange={newValue => this.updateTimeStep(newValue)} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <Vector3LineComponent label="Gravity" target={dummy} propertyName="gravity" onChange={newValue => this.updateGravity(newValue)} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
                 }

+ 2 - 2
inspector/src/components/actionTabs/tabs/tools/gltfComponent.tsx

@@ -76,11 +76,11 @@ export class GLTFComponent extends React.Component<IGLTFComponentProps> {
             <LineContainerComponent title="GLTF VALIDATION" closed={!issues.numErrors && !issues.numWarnings}>
                 {
                     issues.numErrors !== 0 &&
-                    <MessageLineComponent text="Your file has some validation issues" icon={faTimesCircle} color="Red"/>
+                    <MessageLineComponent text="Your file has some validation issues" icon={faTimesCircle} color="Red" />
                 }
                 {
                     issues.numErrors === 0 &&
-                    <MessageLineComponent text="Your file is a valid glTF file" icon={faCheck} color="Green"/>
+                    <MessageLineComponent text="Your file is a valid glTF file" icon={faCheck} color="Green" />
                 }
                 <TextLineComponent label="Errors" value={issues.numErrors.toString()} />
                 <TextLineComponent label="Warnings" value={issues.numWarnings.toString()} />

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

+ 7 - 3
inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx

@@ -57,13 +57,17 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
 
     render() {
         const isActiveElement = this.state.isActive ? <FontAwesomeIcon icon={faVideo} /> : <FontAwesomeIcon icon={faVideo} className="isNotActive" />;
+        const scene = this.props.camera.getScene()!;
 
         return (
             <div className="cameraTools">
                 <TreeItemLabelComponent label={this.props.camera.name} onClick={() => this.props.onClick()} icon={faCamera} color="green" />
-                <div className="activeCamera icon" onClick={() => this.setActive()} title="Set as main camera">
-                    {isActiveElement}
-                </div>
+                {
+                    (!scene.activeCameras || scene.activeCameras.length === 0) &&
+                    <div className="activeCamera icon" onClick={() => this.setActive()} title="Set as main camera">
+                        {isActiveElement}
+                    </div>
+                }
                 <ExtensionsComponent target={this.props.camera} extensibilityGroups={this.props.extensibilityGroups} />
             </div>
         )

+ 0 - 0
inspector/src/components/sceneExplorer/entities/meshTreeItemComponent.tsx


Some files were not shown because too many files changed in this diff