Przeglądaj źródła

Merge branch 'master' into pickerdialog

# Conflicts:
#	dist/preview release/inspector/babylon.inspector.bundle.js
#	dist/preview release/inspector/babylon.inspector.bundle.js.map
David Catuhe 6 lat temu
rodzic
commit
1766e3074c
59 zmienionych plików z 16380 dodań i 16190 usunięć
  1. 7881 7866
      Playground/babylon.d.txt
  2. 7875 7860
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 54 17
      dist/preview release/babylon.max.js
  5. 54 17
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 54 17
      dist/preview release/es6.js
  8. 11 11
      dist/preview release/inspector/babylon.inspector.bundle.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  10. 27 42
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  11. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  12. 27 42
      dist/preview release/loaders/babylon.glTFFileLoader.js
  13. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  14. 27 42
      dist/preview release/loaders/babylonjs.loaders.js
  15. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  16. 1 1
      dist/preview release/viewer/babylon.viewer.js
  17. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  18. 6 0
      dist/preview release/what's new.md
  19. 2 2
      inspector/src/components/actionTabs/lines/color3LineComponent.tsx
  20. 20 1
      inspector/src/components/actionTabs/lines/floatLineComponent.tsx
  21. 7 1
      inspector/src/components/actionTabs/lines/textInputLineComponent.tsx
  22. 44 10
      inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx
  23. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx
  24. 16 14
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/arcRotateCameraPropertyGridComponent.tsx
  25. 8 6
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/commonCameraPropertyGridComponent.tsx
  26. 5 3
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/freeCameraPropertyGridComponent.tsx
  27. 0 102
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/propertyGridTabComponent.tsx
  28. 5 3
      inspector/src/components/actionTabs/tabs/propertyGrids/fogPropertyGridComponent.tsx
  29. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/colorPickerPropertyGridComponent.tsx
  30. 20 18
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx
  31. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/controlPropertyGridComponent.tsx
  32. 13 11
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/inputTextPropertyGridComponent.tsx
  33. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/gui/textBlockPropertyGridComponent.tsx
  34. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonLightPropertyGridComponent.tsx
  35. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonShadowLightPropertyGridComponent.tsx
  36. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/directionalLightPropertyGridComponent.tsx
  37. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/hemisphericLightPropertyGridComponent.tsx
  38. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/pointLightPropertyGridComponent.tsx
  39. 6 4
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/spotLightPropertyGridComponent.tsx
  40. 9 0
      inspector/src/components/actionTabs/tabs/propertyGrids/lockObject.ts
  41. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/backgroundMaterialPropertyGridComponent.tsx
  42. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx
  43. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/materialPropertyGridComponent.tsx
  44. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  45. 3 1
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/standardMaterialPropertyGridComponent.tsx
  46. 11 9
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  47. 6 4
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  48. 2 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/transformNodePropertyGridComponent.tsx
  49. 4 2
      inspector/src/components/actionTabs/tabs/propertyGrids/scenePropertyGridComponent.tsx
  50. 2 2
      inspector/src/components/actionTabs/tabs/tools/gltfComponent.tsx
  51. 1 1
      inspector/src/components/sceneExplorer/sceneExplorer.scss
  52. 41 0
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  53. 25 37
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  54. 20 0
      src/Bones/babylon.bone.ts
  55. 22 3
      src/Bones/babylon.skeleton.ts
  56. 5 4
      src/Mesh/babylon.abstractMesh.ts
  57. 4 2
      src/Mesh/babylon.mesh.ts
  58. 1 1
      src/Mesh/babylon.subMesh.ts
  59. 11 10
      src/Mesh/babylon.transformNode.ts

Plik diff jest za duży
+ 7881 - 7866
Playground/babylon.d.txt


Plik diff jest za duży
+ 7875 - 7860
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 1 - 1
dist/preview release/babylon.js


+ 54 - 17
dist/preview release/babylon.max.js

@@ -20159,7 +20159,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;
@@ -20473,7 +20474,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;
         };
         /**
@@ -20483,7 +20484,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);
         };
         /**
@@ -20493,7 +20494,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;
         };
         /**
@@ -20942,7 +20943,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) {
@@ -20953,24 +20954,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) {
@@ -22249,13 +22250,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 */
@@ -34275,10 +34277,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);
                 }
             }
@@ -34291,7 +34294,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);
             }
@@ -92931,6 +92934,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();
@@ -93046,6 +93051,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) */
@@ -94591,19 +94610,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
              */
@@ -94894,6 +94919,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;
             }

+ 54 - 17
dist/preview release/babylon.no-module.max.js

@@ -20126,7 +20126,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;
@@ -20440,7 +20441,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;
         };
         /**
@@ -20450,7 +20451,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);
         };
         /**
@@ -20460,7 +20461,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;
         };
         /**
@@ -20909,7 +20910,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) {
@@ -20920,24 +20921,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) {
@@ -22216,13 +22217,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 */
@@ -34242,10 +34244,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);
                 }
             }
@@ -34258,7 +34261,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);
             }
@@ -92898,6 +92901,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();
@@ -93013,6 +93018,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) */
@@ -94558,19 +94577,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
              */
@@ -94861,6 +94886,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;
             }

Plik diff jest za duży
+ 1 - 1
dist/preview release/babylon.worker.js


+ 54 - 17
dist/preview release/es6.js

@@ -20126,7 +20126,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;
@@ -20440,7 +20441,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;
         };
         /**
@@ -20450,7 +20451,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);
         };
         /**
@@ -20460,7 +20461,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;
         };
         /**
@@ -20909,7 +20910,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) {
@@ -20920,24 +20921,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) {
@@ -22216,13 +22217,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 */
@@ -34242,10 +34244,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);
                 }
             }
@@ -34258,7 +34261,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);
             }
@@ -92898,6 +92901,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();
@@ -93013,6 +93018,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) */
@@ -94558,19 +94577,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
              */
@@ -94861,6 +94886,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;
             }

Plik diff jest za duży
+ 11 - 11
dist/preview release/inspector/babylon.inspector.bundle.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


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

Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


Plik diff jest za duży
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -67,12 +67,18 @@
 - 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))
+
 ### 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
 

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

+ 20 - 1
inspector/src/components/actionTabs/lines/floatLineComponent.tsx

@@ -1,11 +1,13 @@
 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,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>,
     additionalClass?: string
@@ -23,6 +25,11 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
         this._store = currentValue;
     }
 
+
+    componentWillUnmount() {
+        this.unlock();
+    }
+
     shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: { value: string }) {
         if (this._localChange) {
             this._localChange = false;
@@ -74,6 +81,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 +100,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>
         );

+ 7 - 1
inspector/src/components/actionTabs/lines/textInputLineComponent.tsx

@@ -1,10 +1,12 @@
 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,
+    lockObject: LockObject,
     propertyName: string,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
@@ -18,6 +20,10 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
         this.state = { value: this.props.target[this.props.propertyName] || "" }
     }
 
+    componentWillUnmount() {
+        this.props.lockObject.lock = false;
+    }
+
     shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: { value: string }) {
         if (this._localChange) {
             this._localChange = false;
@@ -61,7 +67,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>
         );

+ 44 - 10
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -22,16 +22,24 @@ import { InputTextPropertyGridComponent } from "./propertyGrids/gui/inputTextPro
 import { ColorPicker } from "babylonjs-gui";
 import { ColorPickerPropertyGridComponent } from "./propertyGrids/gui/colorPickerPropertyGridComponent";
 import { AnimationGroupGridComponent } from "./propertyGrids/animationGroupPropertyGridComponent";
+import { LockObject } from "./propertyGrids/lockObject";
 
 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 +64,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 +72,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 +96,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 +120,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 +129,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 +139,55 @@ 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 (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>
         );

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

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

@@ -7,9 +7,11 @@ 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";
 
 interface ICommonControlPropertyGridComponentProps {
     control: Control,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -26,31 +28,31 @@ export class CommonControlPropertyGridComponent extends React.Component<ICommonC
                 <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} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Color" target={control} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Background" target={control} propertyName="background" 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>
             </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>
         );
     }

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

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

@@ -5,9 +5,11 @@ import { CommonControlPropertyGridComponent } from "./commonControlPropertyGridC
 import { TextBlock } from "babylonjs-gui";
 import { LineContainerComponent } from "../../../lineContainerComponent";
 import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+import { LockObject } from "../lockObject";
 
 interface ITextBlockPropertyGridComponentProps {
     textBlock: TextBlock,
+    lockObject: LockObject,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>
 }
 
@@ -21,9 +23,9 @@ export class TextBlockPropertyGridComponent extends React.Component<ITextBlockPr
 
         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} />
                 </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} />

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

@@ -10,9 +10,11 @@ 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>
 }
 
@@ -78,8 +80,8 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                     <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} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal width" target={adtTexture} propertyName="idealWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                        <FloatLineComponent lockObject={this.props.lockObject} label="Ideal height" target={adtTexture} propertyName="idealHeight" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Use smallest ideal" target={adtTexture} propertyName="useSmallestIdeal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Render at ideal size" target={adtTexture} propertyName="renderAtIdealSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
@@ -88,13 +90,13 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                     {
                         !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="V 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>

+ 6 - 4
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>
 }
@@ -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>
 }
 

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

@@ -12,9 +12,11 @@ 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>
 }
@@ -128,7 +130,7 @@ 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} />
@@ -139,7 +141,7 @@ export class ScenePropertyGridComponent extends React.Component<IScenePropertyGr
                 {
                     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()} />

+ 1 - 1
inspector/src/components/sceneExplorer/sceneExplorer.scss

@@ -158,7 +158,7 @@
             .expandAll {                
                 opacity: 0.5;
                 grid-column: 2;
-                margin-right: 5px;  
+                margin-right: 10px;  
             }
         }
         

+ 41 - 0
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -43,12 +43,21 @@ interface ISceneExplorerComponentProps {
 export class SceneExplorerComponent extends React.Component<ISceneExplorerComponentProps, { filter: Nullable<string>, selectedEntity: any, scene: Scene }> {
     private _onSelectionChangeObserver: Nullable<Observer<any>>;
     private _onNewSceneAddedObserver: Nullable<Observer<Scene>>;
+
     private _once = true;
 
+    private sceneMutationFunc: () => void;
+
     constructor(props: ISceneExplorerComponentProps) {
         super(props);
 
         this.state = { filter: null, selectedEntity: null, scene: this.props.scene };
+
+        this.sceneMutationFunc = this.processMutation.bind(this);
+    }
+
+    processMutation() {
+        this.forceUpdate();
     }
 
     componentWillMount() {
@@ -67,6 +76,22 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
         if (this._onNewSceneAddedObserver) {
             BABYLON.Engine.LastCreatedEngine!.onNewSceneAddedObservable.remove(this._onNewSceneAddedObserver);
         }
+
+        const scene = this.state.scene;
+
+        scene.onNewCameraAddedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onNewLightAddedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onNewMaterialAddedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onNewMeshAddedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onNewTextureAddedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onNewTransformNodeAddedObservable.removeCallback(this.sceneMutationFunc);
+
+        scene.onMeshRemovedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onCameraRemovedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onLightRemovedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onMaterialRemovedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onTransformNodeRemovedObservable.removeCallback(this.sceneMutationFunc);
+        scene.onTextureRemovedObservable.removeCallback(this.sceneMutationFunc);
     }
 
     filterContent(filter: string) {
@@ -218,6 +243,22 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
 
         if (this._once) {
             this._once = false;
+            const scene = this.state.scene;
+
+            scene.onNewCameraAddedObservable.add(this.sceneMutationFunc);
+            scene.onNewLightAddedObservable.add(this.sceneMutationFunc);
+            scene.onNewMaterialAddedObservable.add(this.sceneMutationFunc);
+            scene.onNewMeshAddedObservable.add(this.sceneMutationFunc);
+            scene.onNewTextureAddedObservable.add(this.sceneMutationFunc);
+            scene.onNewTransformNodeAddedObservable.add(this.sceneMutationFunc);
+
+            scene.onMeshRemovedObservable.add(this.sceneMutationFunc);
+            scene.onCameraRemovedObservable.add(this.sceneMutationFunc);
+            scene.onLightRemovedObservable.add(this.sceneMutationFunc);
+            scene.onMaterialRemovedObservable.add(this.sceneMutationFunc);
+            scene.onTransformNodeRemovedObservable.add(this.sceneMutationFunc);
+            scene.onTextureRemovedObservable.add(this.sceneMutationFunc);
+
             // A bit hacky but no other way to force the initial width to 300px and not auto
             setTimeout(() => {
                 const element = document.getElementById("sceneExplorer");

+ 25 - 37
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -432,6 +432,18 @@ module BABYLON.GLTF2 {
                 }
             }
 
+            // 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 (const node of this.gltf.nodes) {
+                    if (node._babylonTransformNode && node._babylonBones) {
+                        for (const babylonBone of node._babylonBones) {
+                            babylonBone.linkTransformNode(node._babylonTransformNode);
+                        }
+                    }
+                }
+            }
+
             promises.push(this._loadAnimationsAsync());
 
             this.logClose();
@@ -445,9 +457,6 @@ module BABYLON.GLTF2 {
                     callback(babylonMesh);
                 }
             }
-            else if (node._babylonTransformNode instanceof AbstractMesh) {
-                callback(node._babylonTransformNode);
-            }
         }
 
         private _getMeshes(): AbstractMesh[] {
@@ -561,12 +570,6 @@ module BABYLON.GLTF2 {
                     for (const index of node.children) {
                         const childNode = ArrayItem.Get(`${context}/children/${index}`, this.gltf.nodes, index);
                         promises.push(this.loadNodeAsync(`/nodes/${childNode.index}`, childNode, (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;
                         }));
                     }
@@ -616,16 +619,16 @@ module BABYLON.GLTF2 {
                 const primitive = mesh.primitives[0];
                 promises.push(this._loadMeshPrimitiveAsync(`${context}/primitives/${primitive.index}`, name, node, mesh, primitive, (babylonMesh) => {
                     node._babylonTransformNode = babylonMesh;
+                    node._primitiveBabylonMeshes = [babylonMesh];
                 }));
             }
             else {
-                const babylonTransformNode = new TransformNode(name, this.babylonScene);
-                node._babylonTransformNode = babylonTransformNode;
+                node._babylonTransformNode = new TransformNode(name, this.babylonScene);
+                node._primitiveBabylonMeshes = [];
                 for (const primitive of primitives) {
                     promises.push(this._loadMeshPrimitiveAsync(`${context}/primitives/${primitive.index}`, `${name}_primitive${primitive.index}`, node, mesh, primitive, (babylonMesh) => {
-                        babylonMesh.parent = babylonTransformNode;
-                        node._primitiveBabylonMeshes = node._primitiveBabylonMeshes || [];
-                        node._primitiveBabylonMeshes.push(babylonMesh);
+                        babylonMesh.parent = node._babylonTransformNode!;
+                        node._primitiveBabylonMeshes!.push(babylonMesh);
                     }));
                 }
             }
@@ -893,14 +896,16 @@ module BABYLON.GLTF2 {
             };
 
             if (skin._data) {
-                const data = skin._data;
-                return data.promise.then(() => {
-                    assignSkeleton(data.babylonSkeleton);
-                });
+                assignSkeleton(skin._data.babylonSkeleton);
+                return skin._data.promise;
             }
 
             const skeletonId = `skeleton${skin.index}`;
             const babylonSkeleton = new 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);
 
@@ -1102,12 +1107,6 @@ module BABYLON.GLTF2 {
                 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 !== AnimationChannelTargetPath.WEIGHTS) {
-                return Promise.resolve();
-            }
-
             const sampler = ArrayItem.Get(`${context}/sampler`, animation.samplers, channel.sampler);
             return this._loadAnimationSamplerAsync(`${animationContext}/samplers/${channel.sampler}`, sampler).then((data) => {
                 let targetPath: string;
@@ -1234,19 +1233,8 @@ module BABYLON.GLTF2 {
                     const babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
                     babylonAnimation.setKeys(keys);
 
-                    const babylonTransformNode = targetNode._babylonTransformNode!;
-                    const babylonBones = targetNode._babylonBones;
-                    if (babylonBones) {
-                        const babylonAnimationTargets = [babylonTransformNode, ...babylonBones];
-                        for (const babylonAnimationTarget of babylonAnimationTargets) {
-                            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!);
                 }
             });
         }

+ 20 - 0
src/Bones/babylon.bone.ts

@@ -46,6 +46,9 @@ module BABYLON {
         private _needToCompose = false;
 
         /** @hidden */
+        public _linkedTransformNode: Nullable<TransformNode> = null;
+
+        /** @hidden */
         get _matrix(): Matrix {
             this._compose();
             return this._localMatrix;
@@ -193,6 +196,23 @@ module BABYLON {
             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
+         */
+        public linkTransformNode(transformNode: Nullable<TransformNode>): void {
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode--;
+            }
+
+            this._linkedTransformNode = transformNode;
+
+            if (this._linkedTransformNode) {
+                this._skeleton._numBonesWithLinkedTransformNode++;
+            }
+        }
+
         // Properties (matches AbstractMesh properties)
 
         /** Gets or sets current position (in local space) */

+ 22 - 3
src/Bones/babylon.skeleton.ts

@@ -5,17 +5,21 @@ module BABYLON {
      */
     export class Skeleton implements IAnimatable {
         /**
-         * Gets the list of child bones
+         * Defines the list of child bones
          */
         public bones = new Array<Bone>();
         /**
-         * Gets an estimate of the dimension of the skeleton at rest
+         * Defines an estimate of the dimension of the skeleton at rest
          */
         public dimensionsAtRest: Vector3;
         /**
-         * 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)
          */
         public needInitialSkinMatrix = false;
+        /**
+         * Defines a mesh that override the matrix used to get the world matrix (null by default).
+         */
+        public overrideMesh: Nullable<AbstractMesh> = null;
 
         /**
          * Gets the list of animations attached to this skeleton
@@ -37,6 +41,9 @@ module BABYLON {
 
         private _canUseTextureForBones = false;
 
+        /** @hidden */
+        public _numBonesWithLinkedTransformNode = 0;
+
         /**
          * Specifies if the skeleton should be serialized
          */
@@ -370,6 +377,18 @@ module BABYLON {
          * Build all resources required to render a skeleton
          */
         public prepare(): void {
+            // Update the local matrix of bones with linked transform nodes.
+            if (this._numBonesWithLinkedTransformNode > 0) {
+                for (const bone of this.bones) {
+                    if (bone._linkedTransformNode) {
+                        // Computing the world matrix also computes the local matrix.
+                        bone._linkedTransformNode.computeWorldMatrix();
+                        bone._matrix = bone._linkedTransformNode._localMatrix;
+                        bone.markAsDirty();
+                    }
+                }
+            }
+
             if (!this._isDirty) {
                 return;
             }

+ 5 - 4
src/Mesh/babylon.abstractMesh.ts

@@ -1136,18 +1136,19 @@ module BABYLON {
 
         /** @hidden */
         public _updateBoundingInfo(): AbstractMesh {
+            const effectiveMesh = (this.skeleton && this.skeleton.overrideMesh) || this;
             if (this._boundingInfo) {
-                this._boundingInfo.update(this.worldMatrixFromCache);
+                this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
             }
             else {
-                this._boundingInfo = new BoundingInfo(this.absolutePosition, this.absolutePosition, this.worldMatrixFromCache);
+                this._boundingInfo = new BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
             }
-            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+            this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
             return this;
         }
 
         /** @hidden */
-        public _updateSubMeshesBoundingInfo(matrix: Matrix): AbstractMesh {
+        public _updateSubMeshesBoundingInfo(matrix: DeepImmutable<Matrix>): AbstractMesh {
             if (!this.subMeshes) {
                 return this;
             }

+ 4 - 2
src/Mesh/babylon.mesh.ts

@@ -1505,10 +1505,12 @@ module BABYLON {
                 return this;
             }
 
+            const 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 === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation);
                 }
             }
@@ -1526,7 +1528,7 @@ module BABYLON {
                 this._bind(subMesh, effect, fillMode);
             }
 
-            var world = this.getWorldMatrix();
+            var world = effectiveMesh.getWorldMatrix();
 
             if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);

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

@@ -236,7 +236,7 @@ module BABYLON {
          * @param world defines the world matrix to use to update the bounding info
          * @returns the submesh
          */
-        public updateBoundingInfo(world: Matrix): SubMesh {
+        public updateBoundingInfo(world: DeepImmutable<Matrix>): SubMesh {
             let boundingInfo = this.getBoundingInfo();
 
             if (!boundingInfo) {

+ 11 - 10
src/Mesh/babylon.transformNode.ts

@@ -84,7 +84,8 @@ module BABYLON {
         // Cache
         /** @hidden */
         public _poseMatrix: Matrix;
-        private _localWorld = Matrix.Zero();
+        /** @hidden */
+        public _localMatrix = Matrix.Zero();
 
         private _absolutePosition = Vector3.Zero();
         private _pivotMatrix = Matrix.Identity();
@@ -413,7 +414,7 @@ module BABYLON {
          */
         public setPositionWithLocalVector(vector3: Vector3): TransformNode {
             this.computeWorldMatrix();
-            this.position = Vector3.TransformNormal(vector3, this._localWorld);
+            this.position = Vector3.TransformNormal(vector3, this._localMatrix);
             return this;
         }
 
@@ -424,7 +425,7 @@ module BABYLON {
         public getPositionExpressedInLocalSpace(): Vector3 {
             this.computeWorldMatrix();
             const invLocalWorldMatrix = Tmp.Matrix[0];
-            this._localWorld.invertToRef(invLocalWorldMatrix);
+            this._localMatrix.invertToRef(invLocalWorldMatrix);
             return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         }
 
@@ -435,7 +436,7 @@ module BABYLON {
          */
         public locallyTranslate(vector3: Vector3): TransformNode {
             this.computeWorldMatrix(true);
-            this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
+            this.position = Vector3.TransformCoordinates(vector3, this._localMatrix);
             return this;
         }
 
@@ -940,7 +941,7 @@ module BABYLON {
             }
 
             // Local world
-            Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localWorld);
+            Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localMatrix);
 
             // Parent
             if (this.parent && this.parent.getWorldMatrix) {
@@ -952,22 +953,22 @@ module BABYLON {
                         Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
                     }
 
-                    this._localWorld.getTranslationToRef(Tmp.Vector3[5]);
+                    this._localMatrix.getTranslationToRef(Tmp.Vector3[5]);
                     Vector3.TransformCoordinatesToRef(Tmp.Vector3[5], Tmp.Matrix[5], Tmp.Vector3[5]);
-                    this._worldMatrix.copyFrom(this._localWorld);
+                    this._worldMatrix.copyFrom(this._localMatrix);
                     this._worldMatrix.setTranslation(Tmp.Vector3[5]);
 
                 } else {
                     if (this._transformToBoneReferal) {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
+                        this._localMatrix.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
                         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