David Catuhe 6 년 전
부모
커밋
c1dd4f56db

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 12196 - 12185
Playground/babylon.d.txt


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 12179 - 12168
dist/preview release/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.js


+ 163 - 122
dist/preview release/babylon.max.js

@@ -2761,6 +2761,14 @@ var BABYLON;
                 previousCamera = scene.activeCamera;
                 scene.activeCamera = camera;
             }
+            var renderCanvas = engine.getRenderingCanvas();
+            if (!renderCanvas) {
+                Tools.Error("No rendering canvas found !");
+                return;
+            }
+            var originalSize = { width: renderCanvas.width, height: renderCanvas.height };
+            engine.setSize(width, height);
+            scene.render();
             // At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
             var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             texture.renderList = null;
@@ -2778,6 +2786,7 @@ var BABYLON;
             if (previousCamera) {
                 scene.activeCamera = previousCamera;
             }
+            engine.setSize(originalSize.width, originalSize.height);
             camera.getProjectionMatrix(true); // Force cache refresh;
         };
         /**
@@ -20846,6 +20855,30 @@ var BABYLON;
             return this;
         };
         /**
+         * Gets the position of the current mesh in camera space
+         * @param camera defines the camera to use
+         * @returns a position
+         */
+        TransformNode.prototype.getPositionInCameraSpace = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
+        };
+        /**
+         * Returns the distance from the mesh to the active camera
+         * @param camera defines the camera to use
+         * @returns the distance
+         */
+        TransformNode.prototype.getDistanceToCamera = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return this.absolutePosition.subtract(camera.position).length();
+        };
+        /**
          * Clone the current transform node
          * @param name Name of the new clone
          * @param newParent New parent for the clone
@@ -21966,6 +21999,81 @@ var BABYLON;
                 max: max
             };
         };
+        /**
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
+         */
+        AbstractMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
+            }
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), null);
+            return this;
+        };
+        /** @hidden */
+        AbstractMesh.prototype._refreshBoundingInfo = function (data, bias) {
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
+                if (this._boundingInfo) {
+                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
+                }
+                else {
+                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                }
+            }
+            if (this.subMeshes) {
+                for (var index = 0; index < this.subMeshes.length; index++) {
+                    this.subMeshes[index].refreshBoundingInfo();
+                }
+            }
+            this._updateBoundingInfo();
+        };
+        /** @hidden */
+        AbstractMesh.prototype._getPositionData = function (applySkeleton) {
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (data && applySkeleton && this.skeleton) {
+                data = BABYLON.Tools.Slice(data);
+                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+                if (matricesWeightsData && matricesIndicesData) {
+                    var needExtras = this.numBoneInfluencers > 4;
+                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
+                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
+                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
+                    var tempVector = BABYLON.Tmp.Vector3[0];
+                    var finalMatrix = BABYLON.Tmp.Matrix[0];
+                    var tempMatrix = BABYLON.Tmp.Matrix[1];
+                    var matWeightIdx = 0;
+                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
+                        finalMatrix.reset();
+                        var inf;
+                        var weight;
+                        for (inf = 0; inf < 4; inf++) {
+                            weight = matricesWeightsData[matWeightIdx + inf];
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
+                        }
+                        if (needExtras) {
+                            for (inf = 0; inf < 4; inf++) {
+                                weight = matricesWeightsExtraData[matWeightIdx + inf];
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
+                            }
+                        }
+                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
+                        tempVector.toArray(data, index);
+                    }
+                }
+            }
+            return data;
+        };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
             if (this._boundingInfo) {
@@ -22050,30 +22158,6 @@ var BABYLON;
             }
             return this._boundingInfo.intersectsPoint(point);
         };
-        /**
-         * Gets the position of the current mesh in camera space
-         * @param camera defines the camera to use
-         * @returns a position
-         */
-        AbstractMesh.prototype.getPositionInCameraSpace = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
-        };
-        /**
-         * Returns the distance from the mesh to the active camera
-         * @param camera defines the camera to use
-         * @returns the distance
-         */
-        AbstractMesh.prototype.getDistanceToCamera = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return this.absolutePosition.subtract(camera.position).length();
-        };
         Object.defineProperty(AbstractMesh.prototype, "checkCollisions", {
             // Collisions
             /**
@@ -28722,6 +28806,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByID(id);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByID(id);
             if (light) {
                 return light;
@@ -28731,7 +28819,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByID(id);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a node (Mesh, Camera, Light) using a given name
@@ -28743,6 +28834,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByName(name);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByName(name);
             if (light) {
                 return light;
@@ -28752,7 +28847,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByName(name);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a mesh using a given name
@@ -33299,77 +33397,18 @@ var BABYLON;
         /**
          * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
          * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
          * @returns the current mesh
          */
-        Mesh.prototype.refreshBoundingInfo = function () {
-            return this._refreshBoundingInfo(false);
-        };
-        /** @hidden */
-        Mesh.prototype._refreshBoundingInfo = function (applySkeleton) {
+        Mesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
             if (this._boundingInfo && this._boundingInfo.isLocked) {
                 return this;
             }
-            var data = this._getPositionData(applySkeleton);
-            if (data) {
-                var bias = this.geometry ? this.geometry.boundingBias : null;
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
-                if (this._boundingInfo) {
-                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
-                }
-                else {
-                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-                }
-            }
-            if (this.subMeshes) {
-                for (var index = 0; index < this.subMeshes.length; index++) {
-                    this.subMeshes[index].refreshBoundingInfo();
-                }
-            }
-            this._updateBoundingInfo();
+            var bias = this.geometry ? this.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), bias);
             return this;
         };
-        Mesh.prototype._getPositionData = function (applySkeleton) {
-            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            if (data && applySkeleton && this.skeleton) {
-                data = BABYLON.Tools.Slice(data);
-                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
-                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
-                if (matricesWeightsData && matricesIndicesData) {
-                    var needExtras = this.numBoneInfluencers > 4;
-                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
-                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
-                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
-                    var tempVector = BABYLON.Tmp.Vector3[0];
-                    var finalMatrix = BABYLON.Tmp.Matrix[0];
-                    var tempMatrix = BABYLON.Tmp.Matrix[1];
-                    var matWeightIdx = 0;
-                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
-                        finalMatrix.reset();
-                        var inf;
-                        var weight;
-                        for (inf = 0; inf < 4; inf++) {
-                            weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight > 0) {
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
-                            }
-                        }
-                        if (needExtras) {
-                            for (inf = 0; inf < 4; inf++) {
-                                weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight > 0) {
-                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                    finalMatrix.addToSelf(tempMatrix);
-                                }
-                            }
-                        }
-                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
-                        tempVector.toArray(data, index);
-                    }
-                }
-            }
-            return data;
-        };
         /** @hidden */
         Mesh.prototype._createGlobalSubMesh = function (force) {
             var totalVertices = this.getTotalVertices();
@@ -41299,6 +41338,8 @@ var BABYLON;
             }
             // morphTargets
             mesh._syncGeometryWithMorphTargetManager();
+            // instances
+            mesh.synchronizeInstances();
         };
         Geometry.prototype.notifyUpdate = function (kind) {
             if (this.onGeometryUpdated) {
@@ -65454,18 +65495,18 @@ var BABYLON;
             configurable: true
         });
         /**
-         * reconstructs and updates the BoundingInfo of the mesh.
-         * @returns the mesh.
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
          */
-        InstancedMesh.prototype.refreshBoundingInfo = function () {
-            var meshBB = this._sourceMesh.getBoundingInfo();
-            if (this._boundingInfo) {
-                this._boundingInfo.reConstruct(meshBB.minimum, meshBB.maximum);
-            }
-            else {
-                this._boundingInfo = new BABYLON.BoundingInfo(meshBB.minimum, meshBB.maximum);
+        InstancedMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
             }
-            this._updateBoundingInfo();
+            var bias = this._sourceMesh.geometry ? this._sourceMesh.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._sourceMesh._getPositionData(applySkeleton), bias);
             return this;
         };
         /** @hidden */
@@ -71596,9 +71637,9 @@ var BABYLON;
                 if (this._streamingSource) {
                     this._streamingSource.disconnect();
                 }
-                if (this._connectedMesh && this._registerFunc) {
-                    this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
-                    this._connectedMesh = null;
+                if (this._connectedTransformNode && this._registerFunc) {
+                    this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+                    this._connectedTransformNode = null;
                 }
             }
         };
@@ -71813,23 +71854,23 @@ var BABYLON;
          */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.isPlaying) {
                 this._updateDirection();
             }
         };
         Sound.prototype._updateDirection = function () {
-            if (!this._connectedMesh || !this._soundPanner) {
+            if (!this._connectedTransformNode || !this._soundPanner) {
                 return;
             }
-            var mat = this._connectedMesh.getWorldMatrix();
+            var mat = this._connectedTransformNode.getWorldMatrix();
             var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
         /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
-                var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
+                var distance = this._connectedTransformNode.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
@@ -71864,7 +71905,7 @@ var BABYLON;
                                 this._soundPanner.coneInnerAngle = this._coneInnerAngle;
                                 this._soundPanner.coneOuterAngle = this._coneOuterAngle;
                                 this._soundPanner.coneOuterGain = this._coneOuterGain;
-                                if (this._connectedMesh) {
+                                if (this._connectedTransformNode) {
                                     this._updateDirection();
                                 }
                                 else {
@@ -72025,16 +72066,16 @@ var BABYLON;
         };
         /**
          * Attach the sound to a dedicated mesh
-         * @param meshToConnectTo The mesh to connect the sound with
+         * @param transformNode The transform node to connect the sound with
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
-        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+        Sound.prototype.attachToMesh = function (transformNode) {
             var _this = this;
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
             }
-            this._connectedMesh = meshToConnectTo;
+            this._connectedTransformNode = transformNode;
             if (!this.spatialSound) {
                 this.spatialSound = true;
                 this._createSpatialParameters();
@@ -72043,19 +72084,19 @@ var BABYLON;
                     this.play();
                 }
             }
-            this._onRegisterAfterWorldMatrixUpdate(this._connectedMesh);
-            this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
-            meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
+            this._onRegisterAfterWorldMatrixUpdate(this._connectedTransformNode);
+            this._registerFunc = function (transformNode) { return _this._onRegisterAfterWorldMatrixUpdate(transformNode); };
+            this._connectedTransformNode.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
         /**
          * Detach the sound from the previously attached mesh
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
         Sound.prototype.detachFromMesh = function () {
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
-                this._connectedMesh = null;
+                this._connectedTransformNode = null;
             }
         };
         Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (node) {
@@ -72142,8 +72183,8 @@ var BABYLON;
                 soundTrackId: this.soundTrackId
             };
             if (this.spatialSound) {
-                if (this._connectedMesh) {
-                    serializationObject.connectedMeshId = this._connectedMesh.id;
+                if (this._connectedTransformNode) {
+                    serializationObject.connectedMeshId = this._connectedTransformNode.id;
                 }
                 serializationObject.position = this._position.asArray();
                 serializationObject.refDistance = this.refDistance;

+ 163 - 122
dist/preview release/babylon.no-module.max.js

@@ -2728,6 +2728,14 @@ var BABYLON;
                 previousCamera = scene.activeCamera;
                 scene.activeCamera = camera;
             }
+            var renderCanvas = engine.getRenderingCanvas();
+            if (!renderCanvas) {
+                Tools.Error("No rendering canvas found !");
+                return;
+            }
+            var originalSize = { width: renderCanvas.width, height: renderCanvas.height };
+            engine.setSize(width, height);
+            scene.render();
             // At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
             var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             texture.renderList = null;
@@ -2745,6 +2753,7 @@ var BABYLON;
             if (previousCamera) {
                 scene.activeCamera = previousCamera;
             }
+            engine.setSize(originalSize.width, originalSize.height);
             camera.getProjectionMatrix(true); // Force cache refresh;
         };
         /**
@@ -20813,6 +20822,30 @@ var BABYLON;
             return this;
         };
         /**
+         * Gets the position of the current mesh in camera space
+         * @param camera defines the camera to use
+         * @returns a position
+         */
+        TransformNode.prototype.getPositionInCameraSpace = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
+        };
+        /**
+         * Returns the distance from the mesh to the active camera
+         * @param camera defines the camera to use
+         * @returns the distance
+         */
+        TransformNode.prototype.getDistanceToCamera = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return this.absolutePosition.subtract(camera.position).length();
+        };
+        /**
          * Clone the current transform node
          * @param name Name of the new clone
          * @param newParent New parent for the clone
@@ -21933,6 +21966,81 @@ var BABYLON;
                 max: max
             };
         };
+        /**
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
+         */
+        AbstractMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
+            }
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), null);
+            return this;
+        };
+        /** @hidden */
+        AbstractMesh.prototype._refreshBoundingInfo = function (data, bias) {
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
+                if (this._boundingInfo) {
+                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
+                }
+                else {
+                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                }
+            }
+            if (this.subMeshes) {
+                for (var index = 0; index < this.subMeshes.length; index++) {
+                    this.subMeshes[index].refreshBoundingInfo();
+                }
+            }
+            this._updateBoundingInfo();
+        };
+        /** @hidden */
+        AbstractMesh.prototype._getPositionData = function (applySkeleton) {
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (data && applySkeleton && this.skeleton) {
+                data = BABYLON.Tools.Slice(data);
+                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+                if (matricesWeightsData && matricesIndicesData) {
+                    var needExtras = this.numBoneInfluencers > 4;
+                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
+                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
+                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
+                    var tempVector = BABYLON.Tmp.Vector3[0];
+                    var finalMatrix = BABYLON.Tmp.Matrix[0];
+                    var tempMatrix = BABYLON.Tmp.Matrix[1];
+                    var matWeightIdx = 0;
+                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
+                        finalMatrix.reset();
+                        var inf;
+                        var weight;
+                        for (inf = 0; inf < 4; inf++) {
+                            weight = matricesWeightsData[matWeightIdx + inf];
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
+                        }
+                        if (needExtras) {
+                            for (inf = 0; inf < 4; inf++) {
+                                weight = matricesWeightsExtraData[matWeightIdx + inf];
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
+                            }
+                        }
+                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
+                        tempVector.toArray(data, index);
+                    }
+                }
+            }
+            return data;
+        };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
             if (this._boundingInfo) {
@@ -22017,30 +22125,6 @@ var BABYLON;
             }
             return this._boundingInfo.intersectsPoint(point);
         };
-        /**
-         * Gets the position of the current mesh in camera space
-         * @param camera defines the camera to use
-         * @returns a position
-         */
-        AbstractMesh.prototype.getPositionInCameraSpace = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
-        };
-        /**
-         * Returns the distance from the mesh to the active camera
-         * @param camera defines the camera to use
-         * @returns the distance
-         */
-        AbstractMesh.prototype.getDistanceToCamera = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return this.absolutePosition.subtract(camera.position).length();
-        };
         Object.defineProperty(AbstractMesh.prototype, "checkCollisions", {
             // Collisions
             /**
@@ -28689,6 +28773,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByID(id);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByID(id);
             if (light) {
                 return light;
@@ -28698,7 +28786,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByID(id);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a node (Mesh, Camera, Light) using a given name
@@ -28710,6 +28801,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByName(name);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByName(name);
             if (light) {
                 return light;
@@ -28719,7 +28814,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByName(name);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a mesh using a given name
@@ -33266,77 +33364,18 @@ var BABYLON;
         /**
          * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
          * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
          * @returns the current mesh
          */
-        Mesh.prototype.refreshBoundingInfo = function () {
-            return this._refreshBoundingInfo(false);
-        };
-        /** @hidden */
-        Mesh.prototype._refreshBoundingInfo = function (applySkeleton) {
+        Mesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
             if (this._boundingInfo && this._boundingInfo.isLocked) {
                 return this;
             }
-            var data = this._getPositionData(applySkeleton);
-            if (data) {
-                var bias = this.geometry ? this.geometry.boundingBias : null;
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
-                if (this._boundingInfo) {
-                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
-                }
-                else {
-                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-                }
-            }
-            if (this.subMeshes) {
-                for (var index = 0; index < this.subMeshes.length; index++) {
-                    this.subMeshes[index].refreshBoundingInfo();
-                }
-            }
-            this._updateBoundingInfo();
+            var bias = this.geometry ? this.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), bias);
             return this;
         };
-        Mesh.prototype._getPositionData = function (applySkeleton) {
-            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            if (data && applySkeleton && this.skeleton) {
-                data = BABYLON.Tools.Slice(data);
-                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
-                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
-                if (matricesWeightsData && matricesIndicesData) {
-                    var needExtras = this.numBoneInfluencers > 4;
-                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
-                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
-                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
-                    var tempVector = BABYLON.Tmp.Vector3[0];
-                    var finalMatrix = BABYLON.Tmp.Matrix[0];
-                    var tempMatrix = BABYLON.Tmp.Matrix[1];
-                    var matWeightIdx = 0;
-                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
-                        finalMatrix.reset();
-                        var inf;
-                        var weight;
-                        for (inf = 0; inf < 4; inf++) {
-                            weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight > 0) {
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
-                            }
-                        }
-                        if (needExtras) {
-                            for (inf = 0; inf < 4; inf++) {
-                                weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight > 0) {
-                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                    finalMatrix.addToSelf(tempMatrix);
-                                }
-                            }
-                        }
-                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
-                        tempVector.toArray(data, index);
-                    }
-                }
-            }
-            return data;
-        };
         /** @hidden */
         Mesh.prototype._createGlobalSubMesh = function (force) {
             var totalVertices = this.getTotalVertices();
@@ -41266,6 +41305,8 @@ var BABYLON;
             }
             // morphTargets
             mesh._syncGeometryWithMorphTargetManager();
+            // instances
+            mesh.synchronizeInstances();
         };
         Geometry.prototype.notifyUpdate = function (kind) {
             if (this.onGeometryUpdated) {
@@ -65421,18 +65462,18 @@ var BABYLON;
             configurable: true
         });
         /**
-         * reconstructs and updates the BoundingInfo of the mesh.
-         * @returns the mesh.
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
          */
-        InstancedMesh.prototype.refreshBoundingInfo = function () {
-            var meshBB = this._sourceMesh.getBoundingInfo();
-            if (this._boundingInfo) {
-                this._boundingInfo.reConstruct(meshBB.minimum, meshBB.maximum);
-            }
-            else {
-                this._boundingInfo = new BABYLON.BoundingInfo(meshBB.minimum, meshBB.maximum);
+        InstancedMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
             }
-            this._updateBoundingInfo();
+            var bias = this._sourceMesh.geometry ? this._sourceMesh.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._sourceMesh._getPositionData(applySkeleton), bias);
             return this;
         };
         /** @hidden */
@@ -71563,9 +71604,9 @@ var BABYLON;
                 if (this._streamingSource) {
                     this._streamingSource.disconnect();
                 }
-                if (this._connectedMesh && this._registerFunc) {
-                    this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
-                    this._connectedMesh = null;
+                if (this._connectedTransformNode && this._registerFunc) {
+                    this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+                    this._connectedTransformNode = null;
                 }
             }
         };
@@ -71780,23 +71821,23 @@ var BABYLON;
          */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.isPlaying) {
                 this._updateDirection();
             }
         };
         Sound.prototype._updateDirection = function () {
-            if (!this._connectedMesh || !this._soundPanner) {
+            if (!this._connectedTransformNode || !this._soundPanner) {
                 return;
             }
-            var mat = this._connectedMesh.getWorldMatrix();
+            var mat = this._connectedTransformNode.getWorldMatrix();
             var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
         /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
-                var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
+                var distance = this._connectedTransformNode.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
@@ -71831,7 +71872,7 @@ var BABYLON;
                                 this._soundPanner.coneInnerAngle = this._coneInnerAngle;
                                 this._soundPanner.coneOuterAngle = this._coneOuterAngle;
                                 this._soundPanner.coneOuterGain = this._coneOuterGain;
-                                if (this._connectedMesh) {
+                                if (this._connectedTransformNode) {
                                     this._updateDirection();
                                 }
                                 else {
@@ -71992,16 +72033,16 @@ var BABYLON;
         };
         /**
          * Attach the sound to a dedicated mesh
-         * @param meshToConnectTo The mesh to connect the sound with
+         * @param transformNode The transform node to connect the sound with
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
-        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+        Sound.prototype.attachToMesh = function (transformNode) {
             var _this = this;
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
             }
-            this._connectedMesh = meshToConnectTo;
+            this._connectedTransformNode = transformNode;
             if (!this.spatialSound) {
                 this.spatialSound = true;
                 this._createSpatialParameters();
@@ -72010,19 +72051,19 @@ var BABYLON;
                     this.play();
                 }
             }
-            this._onRegisterAfterWorldMatrixUpdate(this._connectedMesh);
-            this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
-            meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
+            this._onRegisterAfterWorldMatrixUpdate(this._connectedTransformNode);
+            this._registerFunc = function (transformNode) { return _this._onRegisterAfterWorldMatrixUpdate(transformNode); };
+            this._connectedTransformNode.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
         /**
          * Detach the sound from the previously attached mesh
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
         Sound.prototype.detachFromMesh = function () {
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
-                this._connectedMesh = null;
+                this._connectedTransformNode = null;
             }
         };
         Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (node) {
@@ -72109,8 +72150,8 @@ var BABYLON;
                 soundTrackId: this.soundTrackId
             };
             if (this.spatialSound) {
-                if (this._connectedMesh) {
-                    serializationObject.connectedMeshId = this._connectedMesh.id;
+                if (this._connectedTransformNode) {
+                    serializationObject.connectedMeshId = this._connectedTransformNode.id;
                 }
                 serializationObject.position = this._position.asArray();
                 serializationObject.refDistance = this.refDistance;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.worker.js


+ 163 - 122
dist/preview release/es6.js

@@ -2728,6 +2728,14 @@ var BABYLON;
                 previousCamera = scene.activeCamera;
                 scene.activeCamera = camera;
             }
+            var renderCanvas = engine.getRenderingCanvas();
+            if (!renderCanvas) {
+                Tools.Error("No rendering canvas found !");
+                return;
+            }
+            var originalSize = { width: renderCanvas.width, height: renderCanvas.height };
+            engine.setSize(width, height);
+            scene.render();
             // At this point size can be a number, or an object (according to engine.prototype.createRenderTargetTexture method)
             var texture = new BABYLON.RenderTargetTexture("screenShot", size, scene, false, false, BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT, false, BABYLON.Texture.NEAREST_SAMPLINGMODE);
             texture.renderList = null;
@@ -2745,6 +2753,7 @@ var BABYLON;
             if (previousCamera) {
                 scene.activeCamera = previousCamera;
             }
+            engine.setSize(originalSize.width, originalSize.height);
             camera.getProjectionMatrix(true); // Force cache refresh;
         };
         /**
@@ -20813,6 +20822,30 @@ var BABYLON;
             return this;
         };
         /**
+         * Gets the position of the current mesh in camera space
+         * @param camera defines the camera to use
+         * @returns a position
+         */
+        TransformNode.prototype.getPositionInCameraSpace = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
+        };
+        /**
+         * Returns the distance from the mesh to the active camera
+         * @param camera defines the camera to use
+         * @returns the distance
+         */
+        TransformNode.prototype.getDistanceToCamera = function (camera) {
+            if (camera === void 0) { camera = null; }
+            if (!camera) {
+                camera = this.getScene().activeCamera;
+            }
+            return this.absolutePosition.subtract(camera.position).length();
+        };
+        /**
          * Clone the current transform node
          * @param name Name of the new clone
          * @param newParent New parent for the clone
@@ -21933,6 +21966,81 @@ var BABYLON;
                 max: max
             };
         };
+        /**
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
+         */
+        AbstractMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
+            }
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), null);
+            return this;
+        };
+        /** @hidden */
+        AbstractMesh.prototype._refreshBoundingInfo = function (data, bias) {
+            if (data) {
+                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
+                if (this._boundingInfo) {
+                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
+                }
+                else {
+                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                }
+            }
+            if (this.subMeshes) {
+                for (var index = 0; index < this.subMeshes.length; index++) {
+                    this.subMeshes[index].refreshBoundingInfo();
+                }
+            }
+            this._updateBoundingInfo();
+        };
+        /** @hidden */
+        AbstractMesh.prototype._getPositionData = function (applySkeleton) {
+            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+            if (data && applySkeleton && this.skeleton) {
+                data = BABYLON.Tools.Slice(data);
+                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+                if (matricesWeightsData && matricesIndicesData) {
+                    var needExtras = this.numBoneInfluencers > 4;
+                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
+                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
+                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
+                    var tempVector = BABYLON.Tmp.Vector3[0];
+                    var finalMatrix = BABYLON.Tmp.Matrix[0];
+                    var tempMatrix = BABYLON.Tmp.Matrix[1];
+                    var matWeightIdx = 0;
+                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
+                        finalMatrix.reset();
+                        var inf;
+                        var weight;
+                        for (inf = 0; inf < 4; inf++) {
+                            weight = matricesWeightsData[matWeightIdx + inf];
+                            if (weight > 0) {
+                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                finalMatrix.addToSelf(tempMatrix);
+                            }
+                        }
+                        if (needExtras) {
+                            for (inf = 0; inf < 4; inf++) {
+                                weight = matricesWeightsExtraData[matWeightIdx + inf];
+                                if (weight > 0) {
+                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
+                                    finalMatrix.addToSelf(tempMatrix);
+                                }
+                            }
+                        }
+                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
+                        tempVector.toArray(data, index);
+                    }
+                }
+            }
+            return data;
+        };
         /** @hidden */
         AbstractMesh.prototype._updateBoundingInfo = function () {
             if (this._boundingInfo) {
@@ -22017,30 +22125,6 @@ var BABYLON;
             }
             return this._boundingInfo.intersectsPoint(point);
         };
-        /**
-         * Gets the position of the current mesh in camera space
-         * @param camera defines the camera to use
-         * @returns a position
-         */
-        AbstractMesh.prototype.getPositionInCameraSpace = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return BABYLON.Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
-        };
-        /**
-         * Returns the distance from the mesh to the active camera
-         * @param camera defines the camera to use
-         * @returns the distance
-         */
-        AbstractMesh.prototype.getDistanceToCamera = function (camera) {
-            if (camera === void 0) { camera = null; }
-            if (!camera) {
-                camera = this.getScene().activeCamera;
-            }
-            return this.absolutePosition.subtract(camera.position).length();
-        };
         Object.defineProperty(AbstractMesh.prototype, "checkCollisions", {
             // Collisions
             /**
@@ -28689,6 +28773,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByID(id);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByID(id);
             if (light) {
                 return light;
@@ -28698,7 +28786,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByID(id);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a node (Mesh, Camera, Light) using a given name
@@ -28710,6 +28801,10 @@ var BABYLON;
             if (mesh) {
                 return mesh;
             }
+            var transformNode = this.getTransformNodeByName(name);
+            if (transformNode) {
+                return transformNode;
+            }
             var light = this.getLightByName(name);
             if (light) {
                 return light;
@@ -28719,7 +28814,10 @@ var BABYLON;
                 return camera;
             }
             var bone = this.getBoneByName(name);
-            return bone;
+            if (bone) {
+                return bone;
+            }
+            return null;
         };
         /**
          * Gets a mesh using a given name
@@ -33266,77 +33364,18 @@ var BABYLON;
         /**
          * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
          * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
          * @returns the current mesh
          */
-        Mesh.prototype.refreshBoundingInfo = function () {
-            return this._refreshBoundingInfo(false);
-        };
-        /** @hidden */
-        Mesh.prototype._refreshBoundingInfo = function (applySkeleton) {
+        Mesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
             if (this._boundingInfo && this._boundingInfo.isLocked) {
                 return this;
             }
-            var data = this._getPositionData(applySkeleton);
-            if (data) {
-                var bias = this.geometry ? this.geometry.boundingBias : null;
-                var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this.getTotalVertices(), bias);
-                if (this._boundingInfo) {
-                    this._boundingInfo.reConstruct(extend.minimum, extend.maximum);
-                }
-                else {
-                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-                }
-            }
-            if (this.subMeshes) {
-                for (var index = 0; index < this.subMeshes.length; index++) {
-                    this.subMeshes[index].refreshBoundingInfo();
-                }
-            }
-            this._updateBoundingInfo();
+            var bias = this.geometry ? this.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._getPositionData(applySkeleton), bias);
             return this;
         };
-        Mesh.prototype._getPositionData = function (applySkeleton) {
-            var data = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);
-            if (data && applySkeleton && this.skeleton) {
-                data = BABYLON.Tools.Slice(data);
-                var matricesIndicesData = this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
-                var matricesWeightsData = this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
-                if (matricesWeightsData && matricesIndicesData) {
-                    var needExtras = this.numBoneInfluencers > 4;
-                    var matricesIndicesExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesExtraKind) : null;
-                    var matricesWeightsExtraData = needExtras ? this.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsExtraKind) : null;
-                    var skeletonMatrices = this.skeleton.getTransformMatrices(this);
-                    var tempVector = BABYLON.Tmp.Vector3[0];
-                    var finalMatrix = BABYLON.Tmp.Matrix[0];
-                    var tempMatrix = BABYLON.Tmp.Matrix[1];
-                    var matWeightIdx = 0;
-                    for (var index = 0; index < data.length; index += 3, matWeightIdx += 4) {
-                        finalMatrix.reset();
-                        var inf;
-                        var weight;
-                        for (inf = 0; inf < 4; inf++) {
-                            weight = matricesWeightsData[matWeightIdx + inf];
-                            if (weight > 0) {
-                                BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                finalMatrix.addToSelf(tempMatrix);
-                            }
-                        }
-                        if (needExtras) {
-                            for (inf = 0; inf < 4; inf++) {
-                                weight = matricesWeightsExtraData[matWeightIdx + inf];
-                                if (weight > 0) {
-                                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(skeletonMatrices, Math.floor(matricesIndicesExtraData[matWeightIdx + inf] * 16), weight, tempMatrix);
-                                    finalMatrix.addToSelf(tempMatrix);
-                                }
-                            }
-                        }
-                        BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(data[index], data[index + 1], data[index + 2], finalMatrix, tempVector);
-                        tempVector.toArray(data, index);
-                    }
-                }
-            }
-            return data;
-        };
         /** @hidden */
         Mesh.prototype._createGlobalSubMesh = function (force) {
             var totalVertices = this.getTotalVertices();
@@ -41266,6 +41305,8 @@ var BABYLON;
             }
             // morphTargets
             mesh._syncGeometryWithMorphTargetManager();
+            // instances
+            mesh.synchronizeInstances();
         };
         Geometry.prototype.notifyUpdate = function (kind) {
             if (this.onGeometryUpdated) {
@@ -65421,18 +65462,18 @@ var BABYLON;
             configurable: true
         });
         /**
-         * reconstructs and updates the BoundingInfo of the mesh.
-         * @returns the mesh.
+         * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
+         * This means the mesh underlying bounding box and sphere are recomputed.
+         * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
+         * @returns the current mesh
          */
-        InstancedMesh.prototype.refreshBoundingInfo = function () {
-            var meshBB = this._sourceMesh.getBoundingInfo();
-            if (this._boundingInfo) {
-                this._boundingInfo.reConstruct(meshBB.minimum, meshBB.maximum);
-            }
-            else {
-                this._boundingInfo = new BABYLON.BoundingInfo(meshBB.minimum, meshBB.maximum);
+        InstancedMesh.prototype.refreshBoundingInfo = function (applySkeleton) {
+            if (applySkeleton === void 0) { applySkeleton = false; }
+            if (this._boundingInfo && this._boundingInfo.isLocked) {
+                return this;
             }
-            this._updateBoundingInfo();
+            var bias = this._sourceMesh.geometry ? this._sourceMesh.geometry.boundingBias : null;
+            this._refreshBoundingInfo(this._sourceMesh._getPositionData(applySkeleton), bias);
             return this;
         };
         /** @hidden */
@@ -71563,9 +71604,9 @@ var BABYLON;
                 if (this._streamingSource) {
                     this._streamingSource.disconnect();
                 }
-                if (this._connectedMesh && this._registerFunc) {
-                    this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
-                    this._connectedMesh = null;
+                if (this._connectedTransformNode && this._registerFunc) {
+                    this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+                    this._connectedTransformNode = null;
                 }
             }
         };
@@ -71780,23 +71821,23 @@ var BABYLON;
          */
         Sound.prototype.setLocalDirectionToMesh = function (newLocalDirection) {
             this._localDirection = newLocalDirection;
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.isPlaying) {
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.isPlaying) {
                 this._updateDirection();
             }
         };
         Sound.prototype._updateDirection = function () {
-            if (!this._connectedMesh || !this._soundPanner) {
+            if (!this._connectedTransformNode || !this._soundPanner) {
                 return;
             }
-            var mat = this._connectedMesh.getWorldMatrix();
+            var mat = this._connectedTransformNode.getWorldMatrix();
             var direction = BABYLON.Vector3.TransformNormal(this._localDirection, mat);
             direction.normalize();
             this._soundPanner.setOrientation(direction.x, direction.y, direction.z);
         };
         /** @hidden */
         Sound.prototype.updateDistanceFromListener = function () {
-            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedMesh && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
-                var distance = this._connectedMesh.getDistanceToCamera(this._scene.activeCamera);
+            if (BABYLON.Engine.audioEngine.canUseWebAudio && this._connectedTransformNode && this.useCustomAttenuation && this._soundGain && this._scene.activeCamera) {
+                var distance = this._connectedTransformNode.getDistanceToCamera(this._scene.activeCamera);
                 this._soundGain.gain.value = this._customAttenuationFunction(this._volume, distance, this.maxDistance, this.refDistance, this.rolloffFactor);
             }
         };
@@ -71831,7 +71872,7 @@ var BABYLON;
                                 this._soundPanner.coneInnerAngle = this._coneInnerAngle;
                                 this._soundPanner.coneOuterAngle = this._coneOuterAngle;
                                 this._soundPanner.coneOuterGain = this._coneOuterGain;
-                                if (this._connectedMesh) {
+                                if (this._connectedTransformNode) {
                                     this._updateDirection();
                                 }
                                 else {
@@ -71992,16 +72033,16 @@ var BABYLON;
         };
         /**
          * Attach the sound to a dedicated mesh
-         * @param meshToConnectTo The mesh to connect the sound with
+         * @param transformNode The transform node to connect the sound with
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
-        Sound.prototype.attachToMesh = function (meshToConnectTo) {
+        Sound.prototype.attachToMesh = function (transformNode) {
             var _this = this;
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
             }
-            this._connectedMesh = meshToConnectTo;
+            this._connectedTransformNode = transformNode;
             if (!this.spatialSound) {
                 this.spatialSound = true;
                 this._createSpatialParameters();
@@ -72010,19 +72051,19 @@ var BABYLON;
                     this.play();
                 }
             }
-            this._onRegisterAfterWorldMatrixUpdate(this._connectedMesh);
-            this._registerFunc = function (connectedMesh) { return _this._onRegisterAfterWorldMatrixUpdate(connectedMesh); };
-            meshToConnectTo.registerAfterWorldMatrixUpdate(this._registerFunc);
+            this._onRegisterAfterWorldMatrixUpdate(this._connectedTransformNode);
+            this._registerFunc = function (transformNode) { return _this._onRegisterAfterWorldMatrixUpdate(transformNode); };
+            this._connectedTransformNode.registerAfterWorldMatrixUpdate(this._registerFunc);
         };
         /**
          * Detach the sound from the previously attached mesh
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music#attaching-a-sound-to-a-mesh
          */
         Sound.prototype.detachFromMesh = function () {
-            if (this._connectedMesh && this._registerFunc) {
-                this._connectedMesh.unregisterAfterWorldMatrixUpdate(this._registerFunc);
+            if (this._connectedTransformNode && this._registerFunc) {
+                this._connectedTransformNode.unregisterAfterWorldMatrixUpdate(this._registerFunc);
                 this._registerFunc = null;
-                this._connectedMesh = null;
+                this._connectedTransformNode = null;
             }
         };
         Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (node) {
@@ -72109,8 +72150,8 @@ var BABYLON;
                 soundTrackId: this.soundTrackId
             };
             if (this.spatialSound) {
-                if (this._connectedMesh) {
-                    serializationObject.connectedMeshId = this._connectedMesh.id;
+                if (this._connectedTransformNode) {
+                    serializationObject.connectedMeshId = this._connectedTransformNode.id;
                 }
                 serializationObject.position = this._position.asArray();
                 serializationObject.refDistance = this.refDistance;

+ 21 - 15
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -451,10 +451,10 @@ declare module BABYLON.GLTF2.Loader {
         occlusionTexture?: IMaterialOcclusionTextureInfo;
         emissiveTexture?: ITextureInfo;
         /** @hidden */
-        _babylonData?: {
-            [drawMode: number]: {
-                material: Material;
-                meshes: AbstractMesh[];
+        _data?: {
+            [babylonDrawMode: number]: {
+                babylonMaterial: Material;
+                babylonMeshes: AbstractMesh[];
                 promise: Promise<void>;
             };
         };
@@ -469,6 +469,11 @@ declare module BABYLON.GLTF2.Loader {
      * Loader interface with additional members.
      */
     interface IMeshPrimitive extends GLTF2.IMeshPrimitive, IArrayItem {
+        /** @hidden */
+        _instanceData?: {
+            babylonSourceMesh: Mesh;
+            promise: Promise<any>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -479,9 +484,9 @@ declare module BABYLON.GLTF2.Loader {
          */
         parent?: INode;
         /** @hidden */
-        _babylonMesh?: Mesh;
+        _babylonTransformNode?: TransformNode;
         /** @hidden */
-        _primitiveBabylonMeshes?: Mesh[];
+        _primitiveBabylonMeshes?: AbstractMesh[];
         /** @hidden */
         _babylonBones?: Bone[];
         /** @hidden */
@@ -511,9 +516,10 @@ declare module BABYLON.GLTF2.Loader {
      */
     interface ISkin extends GLTF2.ISkin, IArrayItem {
         /** @hidden */
-        _babylonSkeleton?: Skeleton;
-        /** @hidden */
-        _promise?: Promise<void>;
+        _data?: {
+            babylonSkeleton: Skeleton;
+            promise: Promise<void>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -647,7 +653,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon mesh when the load is complete
          */
-        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonMesh: Mesh) => void): Promise<Mesh>;
+        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonTransformNode: TransformNode) => void): Promise<TransformNode>;
         private _loadMeshAsync;
         private _loadMeshPrimitiveAsync;
         private _loadVertexDataAsync;
@@ -845,9 +851,9 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param node The glTF node property
          * @param assign A function called synchronously after parsing the glTF properties
-         * @returns A promise that resolves with the loaded Babylon mesh when the load is complete or null if not handled
+         * @returns A promise that resolves with the loaded Babylon transform node when the load is complete or null if not handled
          */
-        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /**
          * Define this method to modify the default behavior when loading cameras.
          * @param context The context when loading the asset
@@ -957,7 +963,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onReady(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
@@ -1018,7 +1024,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadSceneAsync(context: string, scene: IScene): Nullable<Promise<void>>;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         loadAnimationAsync(context: string, animation: IAnimation): Nullable<Promise<AnimationGroup>>;
         private _loadClipAsync;
@@ -1110,7 +1116,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onLoading(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
     }
 }
 

+ 178 - 139
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -954,6 +954,9 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
+                        if (_this._rootBabylonMesh) {
+                            _this._rootBabylonMesh.setEnabled(true);
+                        }
                         _this._setState(BABYLON.GLTFLoaderState.READY);
                         _this._extensionsOnReady();
                         _this._startAnimations();
@@ -1063,8 +1066,9 @@ var BABYLON;
             };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this.babylonScene);
+                this._rootBabylonMesh.setEnabled(false);
                 var rootNode = {
-                    _babylonMesh: this._rootBabylonMesh,
+                    _babylonTransformNode: this._rootBabylonMesh,
                     index: -1
                 };
                 switch (this._parent.coordinateSystemMode) {
@@ -1121,8 +1125,8 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else {
-                    callback(node._babylonMesh);
+                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
+                    callback(node._babylonTransformNode);
                 }
             };
             GLTFLoader.prototype._getMeshes = function () {
@@ -1133,15 +1137,9 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
                         var node = nodes_1[_i];
-                        if (node._babylonMesh) {
-                            meshes.push(node._babylonMesh);
-                        }
-                        if (node._primitiveBabylonMeshes) {
-                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
-                                var babylonMesh = _b[_a];
-                                meshes.push(babylonMesh);
-                            }
-                        }
+                        this._forEachPrimitive(node, function (babylonMesh) {
+                            meshes.push(babylonMesh);
+                        });
                     }
                 }
                 return meshes;
@@ -1152,8 +1150,8 @@ var BABYLON;
                 if (skins) {
                     for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
                         var skin = skins_1[_i];
-                        if (skin._babylonSkeleton) {
-                            skeletons.push(skin._babylonSkeleton);
+                        if (skin._data) {
+                            skeletons.push(skin._data.babylonSkeleton);
                         }
                     }
                 }
@@ -1213,113 +1211,145 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                if (node._babylonMesh) {
+                if (node._babylonTransformNode) {
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
                 this.logOpen(context + " " + (node.name || ""));
-                var babylonMesh = new BABYLON.Mesh(node.name || "node" + node.index, this.babylonScene);
-                node._babylonMesh = babylonMesh;
-                babylonMesh.setEnabled(false);
-                GLTFLoader._LoadTransform(node, babylonMesh);
-                if (node.mesh != undefined) {
-                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
-                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, babylonMesh));
-                }
-                if (node.camera != undefined) {
-                    var camera = ArrayItem.Get(context + "/camera", this.gltf.cameras, node.camera);
-                    promises.push(this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
-                        babylonCamera.parent = babylonMesh;
-                    }));
-                }
-                if (node.children) {
-                    var _loop_1 = function (index) {
-                        var childNode = ArrayItem.Get(context + "/children/" + index, this_1.gltf.nodes, index);
-                        promises.push(this_1.loadNodeAsync("#/nodes/" + node.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 = babylonMesh;
+                var loadNode = function (babylonTransformNode) {
+                    GLTFLoader._LoadTransform(node, babylonTransformNode);
+                    if (node.camera != undefined) {
+                        var camera = ArrayItem.Get(context + "/camera", _this.gltf.cameras, node.camera);
+                        promises.push(_this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
+                            babylonCamera.parent = babylonTransformNode;
                         }));
-                    };
-                    var this_1 = this;
-                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                        var index = _a[_i];
-                        _loop_1(index);
                     }
+                    if (node.children) {
+                        var _loop_1 = function (index) {
+                            var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
+                            promises.push(_this.loadNodeAsync("#/nodes/" + node.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);
+                };
+                if (node.mesh == undefined) {
+                    var nodeName = node.name || "node" + node.index;
+                    node._babylonTransformNode = new BABYLON.TransformNode(nodeName, this.babylonScene);
+                    loadNode(node._babylonTransformNode);
+                }
+                else {
+                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
+                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, loadNode));
                 }
-                assign(babylonMesh);
-                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    babylonMesh.setEnabled(true);
-                    return babylonMesh;
+                    _this._forEachPrimitive(node, function (babylonMesh) {
+                        babylonMesh.refreshBoundingInfo(true);
+                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
-                var _this = this;
-                var promises = new Array();
-                this.logOpen(context + " " + (mesh.name || ""));
+            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, assign) {
                 var primitives = mesh.primitives;
-                if (!primitives || primitives.length === 0) {
+                if (!primitives || !primitives.length) {
                     throw new Error(context + ": Primitives are missing");
                 }
-                ArrayItem.Assign(primitives);
+                if (primitives[0].index == undefined) {
+                    ArrayItem.Assign(primitives);
+                }
+                var promises = new Array();
+                this.logOpen(context + " " + (mesh.name || ""));
+                var name = node.name || "node" + node.index;
                 if (primitives.length === 1) {
-                    var primitive = primitives[0];
-                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, babylonMesh));
+                    var primitive = mesh.primitives[0];
+                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index + "}", name, node, mesh, primitive, function (babylonMesh) {
+                        node._babylonTransformNode = babylonMesh;
+                    }));
                 }
                 else {
-                    node._primitiveBabylonMeshes = [];
+                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._babylonTransformNode = babylonTransformNode_1;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
-                        var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive.index, this.babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
-                        promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, primitiveBabylonMesh));
-                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        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 || [];
+                            node._primitiveBabylonMeshes.push(babylonMesh);
+                        }));
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = ArrayItem.Get(context + "/skin", this.gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin.index, node, skin));
                 }
+                assign(node._babylonTransformNode);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    _this._forEachPrimitive(node, function (babylonMesh) {
-                        babylonMesh._refreshBoundingInfo(true);
-                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
+            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
                 var _this = this;
-                var promises = new Array();
                 this.logOpen("" + context);
-                this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
-                promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
-                    return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
-                        babylonGeometry.applyToMesh(babylonMesh);
-                    });
-                }));
-                var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
-                if (primitive.material == undefined) {
-                    var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
-                    if (!babylonMaterial) {
-                        babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
-                        this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                        this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
-                    }
-                    babylonMesh.material = babylonMaterial;
+                var canInstance = (node.skin == undefined && !mesh.primitives[0].targets);
+                var babylonAbstractMesh;
+                var promise;
+                var instanceData = primitive._instanceData;
+                if (canInstance && instanceData) {
+                    babylonAbstractMesh = instanceData.babylonSourceMesh.createInstance(name);
+                    promise = instanceData.promise;
                 }
                 else {
-                    var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
-                    promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                        babylonMesh.material = babylonMaterial;
+                    var promises = new Array();
+                    var babylonMesh_1 = new BABYLON.Mesh(name, this.babylonScene);
+                    this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
+                    promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
+                        return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                            babylonGeometry.applyToMesh(babylonMesh_1);
+                        });
                     }));
+                    var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
+                    if (primitive.material == undefined) {
+                        var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
+                        if (!babylonMaterial) {
+                            babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
+                            this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
+                        }
+                        babylonMesh_1.material = babylonMaterial;
+                    }
+                    else {
+                        var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
+                        promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh_1, babylonDrawMode, function (babylonMaterial) {
+                            babylonMesh_1.material = babylonMaterial;
+                        }));
+                    }
+                    promise = Promise.all(promises);
+                    if (canInstance) {
+                        primitive._instanceData = {
+                            babylonSourceMesh: babylonMesh_1,
+                            promise: promise
+                        };
+                    }
+                    babylonAbstractMesh = babylonMesh_1;
                 }
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonAbstractMesh);
+                assign(babylonAbstractMesh);
                 this.logClose();
-                return Promise.all(promises).then(function () { });
+                return promise.then(function () {
+                    return babylonAbstractMesh;
+                });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 var _this = this;
@@ -1446,6 +1476,11 @@ var BABYLON;
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader._LoadTransform = function (node, babylonNode) {
+                // Ignore the TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (node.skin != undefined) {
+                    return;
+                }
                 var position = BABYLON.Vector3.Zero();
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
@@ -1474,45 +1509,45 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skeleton;
                     });
-                    // Ignore the TRS of skinned nodes.
-                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                    node._babylonMesh.position = BABYLON.Vector3.Zero();
-                    node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
-                    node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
-                if (skin._promise) {
-                    return skin._promise.then(function () {
-                        assignSkeleton(skin._babylonSkeleton);
+                if (skin._data) {
+                    var data_1 = skin._data;
+                    return data_1.promise.then(function () {
+                        assignSkeleton(data_1.babylonSkeleton);
                     });
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
-                skin._babylonSkeleton = babylonSkeleton;
-                this._loadBones(context, skin);
+                this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
-                return (skin._promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
+                var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
                     _this._updateBoneMatrices(babylonSkeleton, inverseBindMatricesData);
-                }));
+                });
+                skin._data = {
+                    babylonSkeleton: babylonSkeleton,
+                    promise: promise
+                };
+                return promise;
             };
-            GLTFLoader.prototype._loadBones = function (context, skin) {
+            GLTFLoader.prototype._loadBones = function (context, skin, babylonSkeleton) {
                 var babylonBones = {};
                 for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
                     var index = _a[_i];
                     var node = ArrayItem.Get(context + "/joints/" + index, this.gltf.nodes, index);
-                    this._loadBone(node, skin, babylonBones);
+                    this._loadBone(node, skin, babylonSkeleton, babylonBones);
                 }
             };
-            GLTFLoader.prototype._loadBone = function (node, skin, babylonBones) {
+            GLTFLoader.prototype._loadBone = function (node, skin, babylonSkeleton, babylonBones) {
                 var babylonBone = babylonBones[node.index];
                 if (babylonBone) {
                     return babylonBone;
                 }
                 var babylonParentBone = null;
-                if (node.parent && node.parent._babylonMesh !== this._rootBabylonMesh) {
-                    babylonParentBone = this._loadBone(node.parent, skin, babylonBones);
+                if (node.parent && node.parent._babylonTransformNode !== this._rootBabylonMesh) {
+                    babylonParentBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
                 }
                 var boneIndex = skin.joints.indexOf(node.index);
-                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, skin._babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
+                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
                 babylonBones[node.index] = babylonBone;
                 node._babylonBones = node._babylonBones || [];
                 node._babylonBones.push(babylonBone);
@@ -1643,7 +1678,7 @@ var BABYLON;
                 var targetNode = ArrayItem.Get(context + "/target/node", this.gltf.nodes, channel.target.node);
                 // Ignore animations that have no animation targets.
                 if ((channel.target.path === "weights" /* WEIGHTS */ && !targetNode._numMorphTargets) ||
-                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonMesh)) {
+                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
                 // Ignore animations targeting TRS of skinned nodes.
@@ -1774,8 +1809,10 @@ var BABYLON;
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        if (targetNode._babylonBones) {
-                            var babylonAnimationTargets = [targetNode._babylonMesh].concat(targetNode._babylonBones);
+                        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);
@@ -1783,8 +1820,8 @@ var BABYLON;
                             babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
                         }
                         else {
-                            targetNode._babylonMesh.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonMesh);
+                            babylonTransformNode.animations.push(babylonAnimation);
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
                         }
                     }
                 });
@@ -1987,30 +2024,30 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                material._babylonData = material._babylonData || {};
-                var babylonData = material._babylonData[babylonDrawMode];
+                material._data = material._data || {};
+                var babylonData = material._data[babylonDrawMode];
                 if (!babylonData) {
                     this.logOpen(context + " " + (material.name || ""));
                     var babylonMaterial = this.createMaterial(context, material, babylonDrawMode);
                     babylonData = {
-                        material: babylonMaterial,
-                        meshes: [],
+                        babylonMaterial: babylonMaterial,
+                        babylonMeshes: [],
                         promise: this.loadMaterialPropertiesAsync(context, material, babylonMaterial)
                     };
-                    material._babylonData[babylonDrawMode] = babylonData;
+                    material._data[babylonDrawMode] = babylonData;
                     this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     this.logClose();
                 }
-                babylonData.meshes.push(babylonMesh);
+                babylonData.babylonMeshes.push(babylonMesh);
                 babylonMesh.onDisposeObservable.addOnce(function () {
-                    var index = babylonData.meshes.indexOf(babylonMesh);
+                    var index = babylonData.babylonMeshes.indexOf(babylonMesh);
                     if (index !== -1) {
-                        babylonData.meshes.splice(index, 1);
+                        babylonData.babylonMeshes.splice(index, 1);
                     }
                 });
-                assign(babylonData.material);
+                assign(babylonData.babylonMaterial);
                 return babylonData.promise.then(function () {
-                    return babylonData.material;
+                    return babylonData.babylonMaterial;
                 });
             };
             GLTFLoader.prototype._createDefaultMaterial = function (name, babylonDrawMode) {
@@ -2403,14 +2440,14 @@ var BABYLON;
                 if (this.gltf.materials) {
                     for (var _i = 0, _a = this.gltf.materials; _i < _a.length; _i++) {
                         var material = _a[_i];
-                        if (material._babylonData) {
-                            for (var babylonDrawMode in material._babylonData) {
-                                var babylonData = material._babylonData[babylonDrawMode];
-                                for (var _b = 0, _c = babylonData.meshes; _b < _c.length; _b++) {
+                        if (material._data) {
+                            for (var babylonDrawMode in material._data) {
+                                var babylonData = material._data[babylonDrawMode];
+                                for (var _b = 0, _c = babylonData.babylonMeshes; _b < _c.length; _b++) {
                                     var babylonMesh = _c[_b];
                                     // Ensure nonUniformScaling is set if necessary.
                                     babylonMesh.computeWorldMatrix(true);
-                                    var babylonMaterial = babylonData.material;
+                                    var babylonMaterial = babylonData.babylonMaterial;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
                                     if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
@@ -2710,16 +2747,18 @@ var BABYLON;
                                     _this._nodeIndexLOD = indexLOD;
                                     _this._nodeSignalLODs[indexLOD] = _this._nodeSignalLODs[indexLOD] || new BABYLON.Deferred();
                                 }
-                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD).then(function (babylonMesh) {
+                                var assign_1 = function (babylonTransformNode) { babylonTransformNode.setEnabled(false); };
+                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD, assign_1).then(function (babylonMesh) {
                                     if (indexLOD !== 0) {
                                         // TODO: should not rely on _babylonMesh
                                         var previousNodeLOD = nodeLODs[indexLOD - 1];
-                                        if (previousNodeLOD._babylonMesh) {
-                                            previousNodeLOD._babylonMesh.dispose();
-                                            delete previousNodeLOD._babylonMesh;
+                                        if (previousNodeLOD._babylonTransformNode) {
+                                            previousNodeLOD._babylonTransformNode.dispose();
+                                            delete previousNodeLOD._babylonTransformNode;
                                             _this._disposeUnusedMaterials();
                                         }
                                     }
+                                    babylonMesh.setEnabled(true);
                                     return babylonMesh;
                                 });
                                 if (indexLOD === 0) {
@@ -2761,11 +2800,11 @@ var BABYLON;
                                 }).then(function (babylonMaterial) {
                                     if (indexLOD !== 0) {
                                         assign(babylonMaterial);
-                                        // TODO: should not rely on _babylonData
-                                        var previousBabylonDataLOD = materialLODs[indexLOD - 1]._babylonData;
-                                        if (previousBabylonDataLOD[babylonDrawMode]) {
-                                            previousBabylonDataLOD[babylonDrawMode].material.dispose();
-                                            delete previousBabylonDataLOD[babylonDrawMode];
+                                        // TODO: should not rely on _data
+                                        var previousDataLOD = materialLODs[indexLOD - 1]._data;
+                                        if (previousDataLOD[babylonDrawMode]) {
+                                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                                            delete previousDataLOD[babylonDrawMode];
                                         }
                                     }
                                     return babylonMaterial;
@@ -2826,17 +2865,17 @@ var BABYLON;
                         return properties;
                     };
                     MSFT_lod.prototype._disposeUnusedMaterials = function () {
-                        // TODO: should not rely on _babylonData
+                        // TODO: should not rely on _data
                         var materials = this._loader.gltf.materials;
                         if (materials) {
                             for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
                                 var material = materials_1[_i];
-                                if (material._babylonData) {
-                                    for (var drawMode in material._babylonData) {
-                                        var babylonData = material._babylonData[drawMode];
-                                        if (babylonData.meshes.length === 0) {
-                                            babylonData.material.dispose(false, true);
-                                            delete material._babylonData[drawMode];
+                                if (material._data) {
+                                    for (var drawMode in material._data) {
+                                        var data = material._data[drawMode];
+                                        if (data.babylonMeshes.length === 0) {
+                                            data.babylonMaterial.dispose(false, true);
+                                            delete material._data[drawMode];
                                         }
                                     }
                                 }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 21 - 15
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -1013,10 +1013,10 @@ declare module BABYLON.GLTF2.Loader {
         occlusionTexture?: IMaterialOcclusionTextureInfo;
         emissiveTexture?: ITextureInfo;
         /** @hidden */
-        _babylonData?: {
-            [drawMode: number]: {
-                material: Material;
-                meshes: AbstractMesh[];
+        _data?: {
+            [babylonDrawMode: number]: {
+                babylonMaterial: Material;
+                babylonMeshes: AbstractMesh[];
                 promise: Promise<void>;
             };
         };
@@ -1031,6 +1031,11 @@ declare module BABYLON.GLTF2.Loader {
      * Loader interface with additional members.
      */
     interface IMeshPrimitive extends GLTF2.IMeshPrimitive, IArrayItem {
+        /** @hidden */
+        _instanceData?: {
+            babylonSourceMesh: Mesh;
+            promise: Promise<any>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1041,9 +1046,9 @@ declare module BABYLON.GLTF2.Loader {
          */
         parent?: INode;
         /** @hidden */
-        _babylonMesh?: Mesh;
+        _babylonTransformNode?: TransformNode;
         /** @hidden */
-        _primitiveBabylonMeshes?: Mesh[];
+        _primitiveBabylonMeshes?: AbstractMesh[];
         /** @hidden */
         _babylonBones?: Bone[];
         /** @hidden */
@@ -1073,9 +1078,10 @@ declare module BABYLON.GLTF2.Loader {
      */
     interface ISkin extends GLTF2.ISkin, IArrayItem {
         /** @hidden */
-        _babylonSkeleton?: Skeleton;
-        /** @hidden */
-        _promise?: Promise<void>;
+        _data?: {
+            babylonSkeleton: Skeleton;
+            promise: Promise<void>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1209,7 +1215,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon mesh when the load is complete
          */
-        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonMesh: Mesh) => void): Promise<Mesh>;
+        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonTransformNode: TransformNode) => void): Promise<TransformNode>;
         private _loadMeshAsync;
         private _loadMeshPrimitiveAsync;
         private _loadVertexDataAsync;
@@ -1407,9 +1413,9 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param node The glTF node property
          * @param assign A function called synchronously after parsing the glTF properties
-         * @returns A promise that resolves with the loaded Babylon mesh when the load is complete or null if not handled
+         * @returns A promise that resolves with the loaded Babylon transform node when the load is complete or null if not handled
          */
-        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /**
          * Define this method to modify the default behavior when loading cameras.
          * @param context The context when loading the asset
@@ -1519,7 +1525,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onReady(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
@@ -1580,7 +1586,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadSceneAsync(context: string, scene: IScene): Nullable<Promise<void>>;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         loadAnimationAsync(context: string, animation: IAnimation): Nullable<Promise<AnimationGroup>>;
         private _loadClipAsync;
@@ -1672,7 +1678,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onLoading(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
     }
 }
 

+ 178 - 139
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3162,6 +3162,9 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
+                        if (_this._rootBabylonMesh) {
+                            _this._rootBabylonMesh.setEnabled(true);
+                        }
                         _this._setState(BABYLON.GLTFLoaderState.READY);
                         _this._extensionsOnReady();
                         _this._startAnimations();
@@ -3271,8 +3274,9 @@ var BABYLON;
             };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this.babylonScene);
+                this._rootBabylonMesh.setEnabled(false);
                 var rootNode = {
-                    _babylonMesh: this._rootBabylonMesh,
+                    _babylonTransformNode: this._rootBabylonMesh,
                     index: -1
                 };
                 switch (this._parent.coordinateSystemMode) {
@@ -3329,8 +3333,8 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else {
-                    callback(node._babylonMesh);
+                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
+                    callback(node._babylonTransformNode);
                 }
             };
             GLTFLoader.prototype._getMeshes = function () {
@@ -3341,15 +3345,9 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
                         var node = nodes_1[_i];
-                        if (node._babylonMesh) {
-                            meshes.push(node._babylonMesh);
-                        }
-                        if (node._primitiveBabylonMeshes) {
-                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
-                                var babylonMesh = _b[_a];
-                                meshes.push(babylonMesh);
-                            }
-                        }
+                        this._forEachPrimitive(node, function (babylonMesh) {
+                            meshes.push(babylonMesh);
+                        });
                     }
                 }
                 return meshes;
@@ -3360,8 +3358,8 @@ var BABYLON;
                 if (skins) {
                     for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
                         var skin = skins_1[_i];
-                        if (skin._babylonSkeleton) {
-                            skeletons.push(skin._babylonSkeleton);
+                        if (skin._data) {
+                            skeletons.push(skin._data.babylonSkeleton);
                         }
                     }
                 }
@@ -3421,113 +3419,145 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                if (node._babylonMesh) {
+                if (node._babylonTransformNode) {
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
                 this.logOpen(context + " " + (node.name || ""));
-                var babylonMesh = new BABYLON.Mesh(node.name || "node" + node.index, this.babylonScene);
-                node._babylonMesh = babylonMesh;
-                babylonMesh.setEnabled(false);
-                GLTFLoader._LoadTransform(node, babylonMesh);
-                if (node.mesh != undefined) {
-                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
-                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, babylonMesh));
-                }
-                if (node.camera != undefined) {
-                    var camera = ArrayItem.Get(context + "/camera", this.gltf.cameras, node.camera);
-                    promises.push(this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
-                        babylonCamera.parent = babylonMesh;
-                    }));
-                }
-                if (node.children) {
-                    var _loop_1 = function (index) {
-                        var childNode = ArrayItem.Get(context + "/children/" + index, this_1.gltf.nodes, index);
-                        promises.push(this_1.loadNodeAsync("#/nodes/" + node.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 = babylonMesh;
+                var loadNode = function (babylonTransformNode) {
+                    GLTFLoader._LoadTransform(node, babylonTransformNode);
+                    if (node.camera != undefined) {
+                        var camera = ArrayItem.Get(context + "/camera", _this.gltf.cameras, node.camera);
+                        promises.push(_this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
+                            babylonCamera.parent = babylonTransformNode;
                         }));
-                    };
-                    var this_1 = this;
-                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                        var index = _a[_i];
-                        _loop_1(index);
                     }
+                    if (node.children) {
+                        var _loop_1 = function (index) {
+                            var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
+                            promises.push(_this.loadNodeAsync("#/nodes/" + node.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);
+                };
+                if (node.mesh == undefined) {
+                    var nodeName = node.name || "node" + node.index;
+                    node._babylonTransformNode = new BABYLON.TransformNode(nodeName, this.babylonScene);
+                    loadNode(node._babylonTransformNode);
+                }
+                else {
+                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
+                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, loadNode));
                 }
-                assign(babylonMesh);
-                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    babylonMesh.setEnabled(true);
-                    return babylonMesh;
+                    _this._forEachPrimitive(node, function (babylonMesh) {
+                        babylonMesh.refreshBoundingInfo(true);
+                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
-                var _this = this;
-                var promises = new Array();
-                this.logOpen(context + " " + (mesh.name || ""));
+            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, assign) {
                 var primitives = mesh.primitives;
-                if (!primitives || primitives.length === 0) {
+                if (!primitives || !primitives.length) {
                     throw new Error(context + ": Primitives are missing");
                 }
-                ArrayItem.Assign(primitives);
+                if (primitives[0].index == undefined) {
+                    ArrayItem.Assign(primitives);
+                }
+                var promises = new Array();
+                this.logOpen(context + " " + (mesh.name || ""));
+                var name = node.name || "node" + node.index;
                 if (primitives.length === 1) {
-                    var primitive = primitives[0];
-                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, babylonMesh));
+                    var primitive = mesh.primitives[0];
+                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index + "}", name, node, mesh, primitive, function (babylonMesh) {
+                        node._babylonTransformNode = babylonMesh;
+                    }));
                 }
                 else {
-                    node._primitiveBabylonMeshes = [];
+                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._babylonTransformNode = babylonTransformNode_1;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
-                        var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive.index, this.babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
-                        promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, primitiveBabylonMesh));
-                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        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 || [];
+                            node._primitiveBabylonMeshes.push(babylonMesh);
+                        }));
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = ArrayItem.Get(context + "/skin", this.gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin.index, node, skin));
                 }
+                assign(node._babylonTransformNode);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    _this._forEachPrimitive(node, function (babylonMesh) {
-                        babylonMesh._refreshBoundingInfo(true);
-                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
+            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
                 var _this = this;
-                var promises = new Array();
                 this.logOpen("" + context);
-                this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
-                promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
-                    return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
-                        babylonGeometry.applyToMesh(babylonMesh);
-                    });
-                }));
-                var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
-                if (primitive.material == undefined) {
-                    var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
-                    if (!babylonMaterial) {
-                        babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
-                        this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                        this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
-                    }
-                    babylonMesh.material = babylonMaterial;
+                var canInstance = (node.skin == undefined && !mesh.primitives[0].targets);
+                var babylonAbstractMesh;
+                var promise;
+                var instanceData = primitive._instanceData;
+                if (canInstance && instanceData) {
+                    babylonAbstractMesh = instanceData.babylonSourceMesh.createInstance(name);
+                    promise = instanceData.promise;
                 }
                 else {
-                    var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
-                    promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                        babylonMesh.material = babylonMaterial;
+                    var promises = new Array();
+                    var babylonMesh_1 = new BABYLON.Mesh(name, this.babylonScene);
+                    this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
+                    promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
+                        return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                            babylonGeometry.applyToMesh(babylonMesh_1);
+                        });
                     }));
+                    var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
+                    if (primitive.material == undefined) {
+                        var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
+                        if (!babylonMaterial) {
+                            babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
+                            this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
+                        }
+                        babylonMesh_1.material = babylonMaterial;
+                    }
+                    else {
+                        var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
+                        promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh_1, babylonDrawMode, function (babylonMaterial) {
+                            babylonMesh_1.material = babylonMaterial;
+                        }));
+                    }
+                    promise = Promise.all(promises);
+                    if (canInstance) {
+                        primitive._instanceData = {
+                            babylonSourceMesh: babylonMesh_1,
+                            promise: promise
+                        };
+                    }
+                    babylonAbstractMesh = babylonMesh_1;
                 }
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonAbstractMesh);
+                assign(babylonAbstractMesh);
                 this.logClose();
-                return Promise.all(promises).then(function () { });
+                return promise.then(function () {
+                    return babylonAbstractMesh;
+                });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 var _this = this;
@@ -3654,6 +3684,11 @@ var BABYLON;
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader._LoadTransform = function (node, babylonNode) {
+                // Ignore the TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (node.skin != undefined) {
+                    return;
+                }
                 var position = BABYLON.Vector3.Zero();
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
@@ -3682,45 +3717,45 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skeleton;
                     });
-                    // Ignore the TRS of skinned nodes.
-                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                    node._babylonMesh.position = BABYLON.Vector3.Zero();
-                    node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
-                    node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
-                if (skin._promise) {
-                    return skin._promise.then(function () {
-                        assignSkeleton(skin._babylonSkeleton);
+                if (skin._data) {
+                    var data_1 = skin._data;
+                    return data_1.promise.then(function () {
+                        assignSkeleton(data_1.babylonSkeleton);
                     });
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
-                skin._babylonSkeleton = babylonSkeleton;
-                this._loadBones(context, skin);
+                this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
-                return (skin._promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
+                var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
                     _this._updateBoneMatrices(babylonSkeleton, inverseBindMatricesData);
-                }));
+                });
+                skin._data = {
+                    babylonSkeleton: babylonSkeleton,
+                    promise: promise
+                };
+                return promise;
             };
-            GLTFLoader.prototype._loadBones = function (context, skin) {
+            GLTFLoader.prototype._loadBones = function (context, skin, babylonSkeleton) {
                 var babylonBones = {};
                 for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
                     var index = _a[_i];
                     var node = ArrayItem.Get(context + "/joints/" + index, this.gltf.nodes, index);
-                    this._loadBone(node, skin, babylonBones);
+                    this._loadBone(node, skin, babylonSkeleton, babylonBones);
                 }
             };
-            GLTFLoader.prototype._loadBone = function (node, skin, babylonBones) {
+            GLTFLoader.prototype._loadBone = function (node, skin, babylonSkeleton, babylonBones) {
                 var babylonBone = babylonBones[node.index];
                 if (babylonBone) {
                     return babylonBone;
                 }
                 var babylonParentBone = null;
-                if (node.parent && node.parent._babylonMesh !== this._rootBabylonMesh) {
-                    babylonParentBone = this._loadBone(node.parent, skin, babylonBones);
+                if (node.parent && node.parent._babylonTransformNode !== this._rootBabylonMesh) {
+                    babylonParentBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
                 }
                 var boneIndex = skin.joints.indexOf(node.index);
-                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, skin._babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
+                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
                 babylonBones[node.index] = babylonBone;
                 node._babylonBones = node._babylonBones || [];
                 node._babylonBones.push(babylonBone);
@@ -3851,7 +3886,7 @@ var BABYLON;
                 var targetNode = ArrayItem.Get(context + "/target/node", this.gltf.nodes, channel.target.node);
                 // Ignore animations that have no animation targets.
                 if ((channel.target.path === "weights" /* WEIGHTS */ && !targetNode._numMorphTargets) ||
-                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonMesh)) {
+                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
                 // Ignore animations targeting TRS of skinned nodes.
@@ -3982,8 +4017,10 @@ var BABYLON;
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        if (targetNode._babylonBones) {
-                            var babylonAnimationTargets = [targetNode._babylonMesh].concat(targetNode._babylonBones);
+                        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);
@@ -3991,8 +4028,8 @@ var BABYLON;
                             babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
                         }
                         else {
-                            targetNode._babylonMesh.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonMesh);
+                            babylonTransformNode.animations.push(babylonAnimation);
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
                         }
                     }
                 });
@@ -4195,30 +4232,30 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                material._babylonData = material._babylonData || {};
-                var babylonData = material._babylonData[babylonDrawMode];
+                material._data = material._data || {};
+                var babylonData = material._data[babylonDrawMode];
                 if (!babylonData) {
                     this.logOpen(context + " " + (material.name || ""));
                     var babylonMaterial = this.createMaterial(context, material, babylonDrawMode);
                     babylonData = {
-                        material: babylonMaterial,
-                        meshes: [],
+                        babylonMaterial: babylonMaterial,
+                        babylonMeshes: [],
                         promise: this.loadMaterialPropertiesAsync(context, material, babylonMaterial)
                     };
-                    material._babylonData[babylonDrawMode] = babylonData;
+                    material._data[babylonDrawMode] = babylonData;
                     this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     this.logClose();
                 }
-                babylonData.meshes.push(babylonMesh);
+                babylonData.babylonMeshes.push(babylonMesh);
                 babylonMesh.onDisposeObservable.addOnce(function () {
-                    var index = babylonData.meshes.indexOf(babylonMesh);
+                    var index = babylonData.babylonMeshes.indexOf(babylonMesh);
                     if (index !== -1) {
-                        babylonData.meshes.splice(index, 1);
+                        babylonData.babylonMeshes.splice(index, 1);
                     }
                 });
-                assign(babylonData.material);
+                assign(babylonData.babylonMaterial);
                 return babylonData.promise.then(function () {
-                    return babylonData.material;
+                    return babylonData.babylonMaterial;
                 });
             };
             GLTFLoader.prototype._createDefaultMaterial = function (name, babylonDrawMode) {
@@ -4611,14 +4648,14 @@ var BABYLON;
                 if (this.gltf.materials) {
                     for (var _i = 0, _a = this.gltf.materials; _i < _a.length; _i++) {
                         var material = _a[_i];
-                        if (material._babylonData) {
-                            for (var babylonDrawMode in material._babylonData) {
-                                var babylonData = material._babylonData[babylonDrawMode];
-                                for (var _b = 0, _c = babylonData.meshes; _b < _c.length; _b++) {
+                        if (material._data) {
+                            for (var babylonDrawMode in material._data) {
+                                var babylonData = material._data[babylonDrawMode];
+                                for (var _b = 0, _c = babylonData.babylonMeshes; _b < _c.length; _b++) {
                                     var babylonMesh = _c[_b];
                                     // Ensure nonUniformScaling is set if necessary.
                                     babylonMesh.computeWorldMatrix(true);
-                                    var babylonMaterial = babylonData.material;
+                                    var babylonMaterial = babylonData.babylonMaterial;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
                                     if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
@@ -4918,16 +4955,18 @@ var BABYLON;
                                     _this._nodeIndexLOD = indexLOD;
                                     _this._nodeSignalLODs[indexLOD] = _this._nodeSignalLODs[indexLOD] || new BABYLON.Deferred();
                                 }
-                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD).then(function (babylonMesh) {
+                                var assign_1 = function (babylonTransformNode) { babylonTransformNode.setEnabled(false); };
+                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD, assign_1).then(function (babylonMesh) {
                                     if (indexLOD !== 0) {
                                         // TODO: should not rely on _babylonMesh
                                         var previousNodeLOD = nodeLODs[indexLOD - 1];
-                                        if (previousNodeLOD._babylonMesh) {
-                                            previousNodeLOD._babylonMesh.dispose();
-                                            delete previousNodeLOD._babylonMesh;
+                                        if (previousNodeLOD._babylonTransformNode) {
+                                            previousNodeLOD._babylonTransformNode.dispose();
+                                            delete previousNodeLOD._babylonTransformNode;
                                             _this._disposeUnusedMaterials();
                                         }
                                     }
+                                    babylonMesh.setEnabled(true);
                                     return babylonMesh;
                                 });
                                 if (indexLOD === 0) {
@@ -4969,11 +5008,11 @@ var BABYLON;
                                 }).then(function (babylonMaterial) {
                                     if (indexLOD !== 0) {
                                         assign(babylonMaterial);
-                                        // TODO: should not rely on _babylonData
-                                        var previousBabylonDataLOD = materialLODs[indexLOD - 1]._babylonData;
-                                        if (previousBabylonDataLOD[babylonDrawMode]) {
-                                            previousBabylonDataLOD[babylonDrawMode].material.dispose();
-                                            delete previousBabylonDataLOD[babylonDrawMode];
+                                        // TODO: should not rely on _data
+                                        var previousDataLOD = materialLODs[indexLOD - 1]._data;
+                                        if (previousDataLOD[babylonDrawMode]) {
+                                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                                            delete previousDataLOD[babylonDrawMode];
                                         }
                                     }
                                     return babylonMaterial;
@@ -5034,17 +5073,17 @@ var BABYLON;
                         return properties;
                     };
                     MSFT_lod.prototype._disposeUnusedMaterials = function () {
-                        // TODO: should not rely on _babylonData
+                        // TODO: should not rely on _data
                         var materials = this._loader.gltf.materials;
                         if (materials) {
                             for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
                                 var material = materials_1[_i];
-                                if (material._babylonData) {
-                                    for (var drawMode in material._babylonData) {
-                                        var babylonData = material._babylonData[drawMode];
-                                        if (babylonData.meshes.length === 0) {
-                                            babylonData.material.dispose(false, true);
-                                            delete material._babylonData[drawMode];
+                                if (material._data) {
+                                    for (var drawMode in material._data) {
+                                        var data = material._data[drawMode];
+                                        if (data.babylonMeshes.length === 0) {
+                                            data.babylonMaterial.dispose(false, true);
+                                            delete material._data[drawMode];
                                         }
                                     }
                                 }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 21 - 15
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -1143,10 +1143,10 @@ declare module BABYLON.GLTF2.Loader {
         occlusionTexture?: IMaterialOcclusionTextureInfo;
         emissiveTexture?: ITextureInfo;
         /** @hidden */
-        _babylonData?: {
-            [drawMode: number]: {
-                material: Material;
-                meshes: AbstractMesh[];
+        _data?: {
+            [babylonDrawMode: number]: {
+                babylonMaterial: Material;
+                babylonMeshes: AbstractMesh[];
                 promise: Promise<void>;
             };
         };
@@ -1161,6 +1161,11 @@ declare module BABYLON.GLTF2.Loader {
      * Loader interface with additional members.
      */
     interface IMeshPrimitive extends GLTF2.IMeshPrimitive, IArrayItem {
+        /** @hidden */
+        _instanceData?: {
+            babylonSourceMesh: Mesh;
+            promise: Promise<any>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1171,9 +1176,9 @@ declare module BABYLON.GLTF2.Loader {
          */
         parent?: INode;
         /** @hidden */
-        _babylonMesh?: Mesh;
+        _babylonTransformNode?: TransformNode;
         /** @hidden */
-        _primitiveBabylonMeshes?: Mesh[];
+        _primitiveBabylonMeshes?: AbstractMesh[];
         /** @hidden */
         _babylonBones?: Bone[];
         /** @hidden */
@@ -1203,9 +1208,10 @@ declare module BABYLON.GLTF2.Loader {
      */
     interface ISkin extends GLTF2.ISkin, IArrayItem {
         /** @hidden */
-        _babylonSkeleton?: Skeleton;
-        /** @hidden */
-        _promise?: Promise<void>;
+        _data?: {
+            babylonSkeleton: Skeleton;
+            promise: Promise<void>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1339,7 +1345,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon mesh when the load is complete
          */
-        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonMesh: Mesh) => void): Promise<Mesh>;
+        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonTransformNode: TransformNode) => void): Promise<TransformNode>;
         private _loadMeshAsync;
         private _loadMeshPrimitiveAsync;
         private _loadVertexDataAsync;
@@ -1537,9 +1543,9 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param node The glTF node property
          * @param assign A function called synchronously after parsing the glTF properties
-         * @returns A promise that resolves with the loaded Babylon mesh when the load is complete or null if not handled
+         * @returns A promise that resolves with the loaded Babylon transform node when the load is complete or null if not handled
          */
-        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /**
          * Define this method to modify the default behavior when loading cameras.
          * @param context The context when loading the asset
@@ -1649,7 +1655,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onReady(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
@@ -1710,7 +1716,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadSceneAsync(context: string, scene: IScene): Nullable<Promise<void>>;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         loadAnimationAsync(context: string, animation: IAnimation): Nullable<Promise<AnimationGroup>>;
         private _loadClipAsync;
@@ -1802,7 +1808,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onLoading(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
     }
 }
 

+ 178 - 139
dist/preview release/loaders/babylonjs.loaders.js

@@ -4224,6 +4224,9 @@ var BABYLON;
                         promises.push(_this._compileShadowGeneratorsAsync());
                     }
                     var resultPromise = Promise.all(promises).then(function () {
+                        if (_this._rootBabylonMesh) {
+                            _this._rootBabylonMesh.setEnabled(true);
+                        }
                         _this._setState(BABYLON.GLTFLoaderState.READY);
                         _this._extensionsOnReady();
                         _this._startAnimations();
@@ -4333,8 +4336,9 @@ var BABYLON;
             };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this.babylonScene);
+                this._rootBabylonMesh.setEnabled(false);
                 var rootNode = {
-                    _babylonMesh: this._rootBabylonMesh,
+                    _babylonTransformNode: this._rootBabylonMesh,
                     index: -1
                 };
                 switch (this._parent.coordinateSystemMode) {
@@ -4391,8 +4395,8 @@ var BABYLON;
                         callback(babylonMesh);
                     }
                 }
-                else {
-                    callback(node._babylonMesh);
+                else if (node._babylonTransformNode instanceof BABYLON.AbstractMesh) {
+                    callback(node._babylonTransformNode);
                 }
             };
             GLTFLoader.prototype._getMeshes = function () {
@@ -4403,15 +4407,9 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
                         var node = nodes_1[_i];
-                        if (node._babylonMesh) {
-                            meshes.push(node._babylonMesh);
-                        }
-                        if (node._primitiveBabylonMeshes) {
-                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
-                                var babylonMesh = _b[_a];
-                                meshes.push(babylonMesh);
-                            }
-                        }
+                        this._forEachPrimitive(node, function (babylonMesh) {
+                            meshes.push(babylonMesh);
+                        });
                     }
                 }
                 return meshes;
@@ -4422,8 +4420,8 @@ var BABYLON;
                 if (skins) {
                     for (var _i = 0, skins_1 = skins; _i < skins_1.length; _i++) {
                         var skin = skins_1[_i];
-                        if (skin._babylonSkeleton) {
-                            skeletons.push(skin._babylonSkeleton);
+                        if (skin._data) {
+                            skeletons.push(skin._data.babylonSkeleton);
                         }
                     }
                 }
@@ -4483,113 +4481,145 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                if (node._babylonMesh) {
+                if (node._babylonTransformNode) {
                     throw new Error(context + ": Invalid recursive node hierarchy");
                 }
                 var promises = new Array();
                 this.logOpen(context + " " + (node.name || ""));
-                var babylonMesh = new BABYLON.Mesh(node.name || "node" + node.index, this.babylonScene);
-                node._babylonMesh = babylonMesh;
-                babylonMesh.setEnabled(false);
-                GLTFLoader._LoadTransform(node, babylonMesh);
-                if (node.mesh != undefined) {
-                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
-                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, babylonMesh));
-                }
-                if (node.camera != undefined) {
-                    var camera = ArrayItem.Get(context + "/camera", this.gltf.cameras, node.camera);
-                    promises.push(this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
-                        babylonCamera.parent = babylonMesh;
-                    }));
-                }
-                if (node.children) {
-                    var _loop_1 = function (index) {
-                        var childNode = ArrayItem.Get(context + "/children/" + index, this_1.gltf.nodes, index);
-                        promises.push(this_1.loadNodeAsync("#/nodes/" + node.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 = babylonMesh;
+                var loadNode = function (babylonTransformNode) {
+                    GLTFLoader._LoadTransform(node, babylonTransformNode);
+                    if (node.camera != undefined) {
+                        var camera = ArrayItem.Get(context + "/camera", _this.gltf.cameras, node.camera);
+                        promises.push(_this.loadCameraAsync("#/cameras/" + camera.index, camera, function (babylonCamera) {
+                            babylonCamera.parent = babylonTransformNode;
                         }));
-                    };
-                    var this_1 = this;
-                    for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
-                        var index = _a[_i];
-                        _loop_1(index);
                     }
+                    if (node.children) {
+                        var _loop_1 = function (index) {
+                            var childNode = ArrayItem.Get(context + "/children/" + index, _this.gltf.nodes, index);
+                            promises.push(_this.loadNodeAsync("#/nodes/" + node.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);
+                };
+                if (node.mesh == undefined) {
+                    var nodeName = node.name || "node" + node.index;
+                    node._babylonTransformNode = new BABYLON.TransformNode(nodeName, this.babylonScene);
+                    loadNode(node._babylonTransformNode);
+                }
+                else {
+                    var mesh = ArrayItem.Get(context + "/mesh", this.gltf.meshes, node.mesh);
+                    promises.push(this._loadMeshAsync("#/meshes/" + mesh.index, node, mesh, loadNode));
                 }
-                assign(babylonMesh);
-                this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    babylonMesh.setEnabled(true);
-                    return babylonMesh;
+                    _this._forEachPrimitive(node, function (babylonMesh) {
+                        babylonMesh.refreshBoundingInfo(true);
+                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, babylonMesh) {
-                var _this = this;
-                var promises = new Array();
-                this.logOpen(context + " " + (mesh.name || ""));
+            GLTFLoader.prototype._loadMeshAsync = function (context, node, mesh, assign) {
                 var primitives = mesh.primitives;
-                if (!primitives || primitives.length === 0) {
+                if (!primitives || !primitives.length) {
                     throw new Error(context + ": Primitives are missing");
                 }
-                ArrayItem.Assign(primitives);
+                if (primitives[0].index == undefined) {
+                    ArrayItem.Assign(primitives);
+                }
+                var promises = new Array();
+                this.logOpen(context + " " + (mesh.name || ""));
+                var name = node.name || "node" + node.index;
                 if (primitives.length === 1) {
-                    var primitive = primitives[0];
-                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, babylonMesh));
+                    var primitive = mesh.primitives[0];
+                    promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index + "}", name, node, mesh, primitive, function (babylonMesh) {
+                        node._babylonTransformNode = babylonMesh;
+                    }));
                 }
                 else {
-                    node._primitiveBabylonMeshes = [];
+                    var babylonTransformNode_1 = new BABYLON.TransformNode(name, this.babylonScene);
+                    node._babylonTransformNode = babylonTransformNode_1;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
-                        var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive.index, this.babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
-                        promises.push(this._loadMeshPrimitiveAsync(context + "/primitives/" + primitive.index, node, mesh, primitive, primitiveBabylonMesh));
-                        this._parent.onMeshLoadedObservable.notifyObservers(babylonMesh);
+                        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 || [];
+                            node._primitiveBabylonMeshes.push(babylonMesh);
+                        }));
                     }
                 }
                 if (node.skin != undefined) {
                     var skin = ArrayItem.Get(context + "/skin", this.gltf.skins, node.skin);
                     promises.push(this._loadSkinAsync("#/skins/" + skin.index, node, skin));
                 }
+                assign(node._babylonTransformNode);
                 this.logClose();
                 return Promise.all(promises).then(function () {
-                    _this._forEachPrimitive(node, function (babylonMesh) {
-                        babylonMesh._refreshBoundingInfo(true);
-                    });
+                    return node._babylonTransformNode;
                 });
             };
-            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, node, mesh, primitive, babylonMesh) {
+            GLTFLoader.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
                 var _this = this;
-                var promises = new Array();
                 this.logOpen("" + context);
-                this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
-                promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then(function (babylonGeometry) {
-                    return _this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(function () {
-                        babylonGeometry.applyToMesh(babylonMesh);
-                    });
-                }));
-                var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
-                if (primitive.material == undefined) {
-                    var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
-                    if (!babylonMaterial) {
-                        babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
-                        this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                        this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
-                    }
-                    babylonMesh.material = babylonMaterial;
+                var canInstance = (node.skin == undefined && !mesh.primitives[0].targets);
+                var babylonAbstractMesh;
+                var promise;
+                var instanceData = primitive._instanceData;
+                if (canInstance && instanceData) {
+                    babylonAbstractMesh = instanceData.babylonSourceMesh.createInstance(name);
+                    promise = instanceData.promise;
                 }
                 else {
-                    var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
-                    promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh, babylonDrawMode, function (babylonMaterial) {
-                        babylonMesh.material = babylonMaterial;
+                    var promises = new Array();
+                    var babylonMesh_1 = new BABYLON.Mesh(name, this.babylonScene);
+                    this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
+                    promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
+                        return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                            babylonGeometry.applyToMesh(babylonMesh_1);
+                        });
                     }));
+                    var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
+                    if (primitive.material == undefined) {
+                        var babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
+                        if (!babylonMaterial) {
+                            babylonMaterial = this._createDefaultMaterial("__gltf_default", babylonDrawMode);
+                            this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
+                            this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
+                        }
+                        babylonMesh_1.material = babylonMaterial;
+                    }
+                    else {
+                        var material = ArrayItem.Get(context + "/material", this.gltf.materials, primitive.material);
+                        promises.push(this._loadMaterialAsync("#/materials/" + material.index, material, babylonMesh_1, babylonDrawMode, function (babylonMaterial) {
+                            babylonMesh_1.material = babylonMaterial;
+                        }));
+                    }
+                    promise = Promise.all(promises);
+                    if (canInstance) {
+                        primitive._instanceData = {
+                            babylonSourceMesh: babylonMesh_1,
+                            promise: promise
+                        };
+                    }
+                    babylonAbstractMesh = babylonMesh_1;
                 }
+                this._parent.onMeshLoadedObservable.notifyObservers(babylonAbstractMesh);
+                assign(babylonAbstractMesh);
                 this.logClose();
-                return Promise.all(promises).then(function () { });
+                return promise.then(function () {
+                    return babylonAbstractMesh;
+                });
             };
             GLTFLoader.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                 var _this = this;
@@ -4716,6 +4746,11 @@ var BABYLON;
                 return Promise.all(promises).then(function () { });
             };
             GLTFLoader._LoadTransform = function (node, babylonNode) {
+                // Ignore the TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (node.skin != undefined) {
+                    return;
+                }
                 var position = BABYLON.Vector3.Zero();
                 var rotation = BABYLON.Quaternion.Identity();
                 var scaling = BABYLON.Vector3.One();
@@ -4744,45 +4779,45 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skeleton;
                     });
-                    // Ignore the TRS of skinned nodes.
-                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
-                    node._babylonMesh.position = BABYLON.Vector3.Zero();
-                    node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
-                    node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
-                if (skin._promise) {
-                    return skin._promise.then(function () {
-                        assignSkeleton(skin._babylonSkeleton);
+                if (skin._data) {
+                    var data_1 = skin._data;
+                    return data_1.promise.then(function () {
+                        assignSkeleton(data_1.babylonSkeleton);
                     });
                 }
                 var skeletonId = "skeleton" + skin.index;
                 var babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this.babylonScene);
-                skin._babylonSkeleton = babylonSkeleton;
-                this._loadBones(context, skin);
+                this._loadBones(context, skin, babylonSkeleton);
                 assignSkeleton(babylonSkeleton);
-                return (skin._promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
+                var promise = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
                     _this._updateBoneMatrices(babylonSkeleton, inverseBindMatricesData);
-                }));
+                });
+                skin._data = {
+                    babylonSkeleton: babylonSkeleton,
+                    promise: promise
+                };
+                return promise;
             };
-            GLTFLoader.prototype._loadBones = function (context, skin) {
+            GLTFLoader.prototype._loadBones = function (context, skin, babylonSkeleton) {
                 var babylonBones = {};
                 for (var _i = 0, _a = skin.joints; _i < _a.length; _i++) {
                     var index = _a[_i];
                     var node = ArrayItem.Get(context + "/joints/" + index, this.gltf.nodes, index);
-                    this._loadBone(node, skin, babylonBones);
+                    this._loadBone(node, skin, babylonSkeleton, babylonBones);
                 }
             };
-            GLTFLoader.prototype._loadBone = function (node, skin, babylonBones) {
+            GLTFLoader.prototype._loadBone = function (node, skin, babylonSkeleton, babylonBones) {
                 var babylonBone = babylonBones[node.index];
                 if (babylonBone) {
                     return babylonBone;
                 }
                 var babylonParentBone = null;
-                if (node.parent && node.parent._babylonMesh !== this._rootBabylonMesh) {
-                    babylonParentBone = this._loadBone(node.parent, skin, babylonBones);
+                if (node.parent && node.parent._babylonTransformNode !== this._rootBabylonMesh) {
+                    babylonParentBone = this._loadBone(node.parent, skin, babylonSkeleton, babylonBones);
                 }
                 var boneIndex = skin.joints.indexOf(node.index);
-                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, skin._babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
+                babylonBone = new BABYLON.Bone(node.name || "joint" + node.index, babylonSkeleton, babylonParentBone, this._getNodeMatrix(node), null, null, boneIndex);
                 babylonBones[node.index] = babylonBone;
                 node._babylonBones = node._babylonBones || [];
                 node._babylonBones.push(babylonBone);
@@ -4913,7 +4948,7 @@ var BABYLON;
                 var targetNode = ArrayItem.Get(context + "/target/node", this.gltf.nodes, channel.target.node);
                 // Ignore animations that have no animation targets.
                 if ((channel.target.path === "weights" /* WEIGHTS */ && !targetNode._numMorphTargets) ||
-                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonMesh)) {
+                    (channel.target.path !== "weights" /* WEIGHTS */ && !targetNode._babylonTransformNode)) {
                     return Promise.resolve();
                 }
                 // Ignore animations targeting TRS of skinned nodes.
@@ -5044,8 +5079,10 @@ var BABYLON;
                         var animationName = babylonAnimationGroup.name + "_channel" + babylonAnimationGroup.targetedAnimations.length;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
-                        if (targetNode._babylonBones) {
-                            var babylonAnimationTargets = [targetNode._babylonMesh].concat(targetNode._babylonBones);
+                        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);
@@ -5053,8 +5090,8 @@ var BABYLON;
                             babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonAnimationTargets);
                         }
                         else {
-                            targetNode._babylonMesh.animations.push(babylonAnimation);
-                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, targetNode._babylonMesh);
+                            babylonTransformNode.animations.push(babylonAnimation);
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, babylonTransformNode);
                         }
                     }
                 });
@@ -5257,30 +5294,30 @@ var BABYLON;
                 if (extensionPromise) {
                     return extensionPromise;
                 }
-                material._babylonData = material._babylonData || {};
-                var babylonData = material._babylonData[babylonDrawMode];
+                material._data = material._data || {};
+                var babylonData = material._data[babylonDrawMode];
                 if (!babylonData) {
                     this.logOpen(context + " " + (material.name || ""));
                     var babylonMaterial = this.createMaterial(context, material, babylonDrawMode);
                     babylonData = {
-                        material: babylonMaterial,
-                        meshes: [],
+                        babylonMaterial: babylonMaterial,
+                        babylonMeshes: [],
                         promise: this.loadMaterialPropertiesAsync(context, material, babylonMaterial)
                     };
-                    material._babylonData[babylonDrawMode] = babylonData;
+                    material._data[babylonDrawMode] = babylonData;
                     this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
                     this.logClose();
                 }
-                babylonData.meshes.push(babylonMesh);
+                babylonData.babylonMeshes.push(babylonMesh);
                 babylonMesh.onDisposeObservable.addOnce(function () {
-                    var index = babylonData.meshes.indexOf(babylonMesh);
+                    var index = babylonData.babylonMeshes.indexOf(babylonMesh);
                     if (index !== -1) {
-                        babylonData.meshes.splice(index, 1);
+                        babylonData.babylonMeshes.splice(index, 1);
                     }
                 });
-                assign(babylonData.material);
+                assign(babylonData.babylonMaterial);
                 return babylonData.promise.then(function () {
-                    return babylonData.material;
+                    return babylonData.babylonMaterial;
                 });
             };
             GLTFLoader.prototype._createDefaultMaterial = function (name, babylonDrawMode) {
@@ -5673,14 +5710,14 @@ var BABYLON;
                 if (this.gltf.materials) {
                     for (var _i = 0, _a = this.gltf.materials; _i < _a.length; _i++) {
                         var material = _a[_i];
-                        if (material._babylonData) {
-                            for (var babylonDrawMode in material._babylonData) {
-                                var babylonData = material._babylonData[babylonDrawMode];
-                                for (var _b = 0, _c = babylonData.meshes; _b < _c.length; _b++) {
+                        if (material._data) {
+                            for (var babylonDrawMode in material._data) {
+                                var babylonData = material._data[babylonDrawMode];
+                                for (var _b = 0, _c = babylonData.babylonMeshes; _b < _c.length; _b++) {
                                     var babylonMesh = _c[_b];
                                     // Ensure nonUniformScaling is set if necessary.
                                     babylonMesh.computeWorldMatrix(true);
-                                    var babylonMaterial = babylonData.material;
+                                    var babylonMaterial = babylonData.babylonMaterial;
                                     promises.push(babylonMaterial.forceCompilationAsync(babylonMesh));
                                     if (this._parent.useClipPlane) {
                                         promises.push(babylonMaterial.forceCompilationAsync(babylonMesh, { clipPlane: true }));
@@ -5980,16 +6017,18 @@ var BABYLON;
                                     _this._nodeIndexLOD = indexLOD;
                                     _this._nodeSignalLODs[indexLOD] = _this._nodeSignalLODs[indexLOD] || new BABYLON.Deferred();
                                 }
-                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD).then(function (babylonMesh) {
+                                var assign_1 = function (babylonTransformNode) { babylonTransformNode.setEnabled(false); };
+                                var promise = _this._loader.loadNodeAsync("#/nodes/" + nodeLOD.index, nodeLOD, assign_1).then(function (babylonMesh) {
                                     if (indexLOD !== 0) {
                                         // TODO: should not rely on _babylonMesh
                                         var previousNodeLOD = nodeLODs[indexLOD - 1];
-                                        if (previousNodeLOD._babylonMesh) {
-                                            previousNodeLOD._babylonMesh.dispose();
-                                            delete previousNodeLOD._babylonMesh;
+                                        if (previousNodeLOD._babylonTransformNode) {
+                                            previousNodeLOD._babylonTransformNode.dispose();
+                                            delete previousNodeLOD._babylonTransformNode;
                                             _this._disposeUnusedMaterials();
                                         }
                                     }
+                                    babylonMesh.setEnabled(true);
                                     return babylonMesh;
                                 });
                                 if (indexLOD === 0) {
@@ -6031,11 +6070,11 @@ var BABYLON;
                                 }).then(function (babylonMaterial) {
                                     if (indexLOD !== 0) {
                                         assign(babylonMaterial);
-                                        // TODO: should not rely on _babylonData
-                                        var previousBabylonDataLOD = materialLODs[indexLOD - 1]._babylonData;
-                                        if (previousBabylonDataLOD[babylonDrawMode]) {
-                                            previousBabylonDataLOD[babylonDrawMode].material.dispose();
-                                            delete previousBabylonDataLOD[babylonDrawMode];
+                                        // TODO: should not rely on _data
+                                        var previousDataLOD = materialLODs[indexLOD - 1]._data;
+                                        if (previousDataLOD[babylonDrawMode]) {
+                                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                                            delete previousDataLOD[babylonDrawMode];
                                         }
                                     }
                                     return babylonMaterial;
@@ -6096,17 +6135,17 @@ var BABYLON;
                         return properties;
                     };
                     MSFT_lod.prototype._disposeUnusedMaterials = function () {
-                        // TODO: should not rely on _babylonData
+                        // TODO: should not rely on _data
                         var materials = this._loader.gltf.materials;
                         if (materials) {
                             for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
                                 var material = materials_1[_i];
-                                if (material._babylonData) {
-                                    for (var drawMode in material._babylonData) {
-                                        var babylonData = material._babylonData[drawMode];
-                                        if (babylonData.meshes.length === 0) {
-                                            babylonData.material.dispose(false, true);
-                                            delete material._babylonData[drawMode];
+                                if (material._data) {
+                                    for (var drawMode in material._data) {
+                                        var data = material._data[drawMode];
+                                        if (data.babylonMeshes.length === 0) {
+                                            data.babylonMaterial.dispose(false, true);
+                                            delete material._data[drawMode];
                                         }
                                     }
                                 }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 21 - 15
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1150,10 +1150,10 @@ declare module BABYLON.GLTF2.Loader {
         occlusionTexture?: IMaterialOcclusionTextureInfo;
         emissiveTexture?: ITextureInfo;
         /** @hidden */
-        _babylonData?: {
-            [drawMode: number]: {
-                material: Material;
-                meshes: AbstractMesh[];
+        _data?: {
+            [babylonDrawMode: number]: {
+                babylonMaterial: Material;
+                babylonMeshes: AbstractMesh[];
                 promise: Promise<void>;
             };
         };
@@ -1168,6 +1168,11 @@ declare module BABYLON.GLTF2.Loader {
      * Loader interface with additional members.
      */
     interface IMeshPrimitive extends GLTF2.IMeshPrimitive, IArrayItem {
+        /** @hidden */
+        _instanceData?: {
+            babylonSourceMesh: Mesh;
+            promise: Promise<any>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1178,9 +1183,9 @@ declare module BABYLON.GLTF2.Loader {
          */
         parent?: INode;
         /** @hidden */
-        _babylonMesh?: Mesh;
+        _babylonTransformNode?: TransformNode;
         /** @hidden */
-        _primitiveBabylonMeshes?: Mesh[];
+        _primitiveBabylonMeshes?: AbstractMesh[];
         /** @hidden */
         _babylonBones?: Bone[];
         /** @hidden */
@@ -1210,9 +1215,10 @@ declare module BABYLON.GLTF2.Loader {
      */
     interface ISkin extends GLTF2.ISkin, IArrayItem {
         /** @hidden */
-        _babylonSkeleton?: Skeleton;
-        /** @hidden */
-        _promise?: Promise<void>;
+        _data?: {
+            babylonSkeleton: Skeleton;
+            promise: Promise<void>;
+        };
     }
     /**
      * Loader interface with additional members.
@@ -1346,7 +1352,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon mesh when the load is complete
          */
-        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonMesh: Mesh) => void): Promise<Mesh>;
+        loadNodeAsync(context: string, node: Loader.INode, assign?: (babylonTransformNode: TransformNode) => void): Promise<TransformNode>;
         private _loadMeshAsync;
         private _loadMeshPrimitiveAsync;
         private _loadVertexDataAsync;
@@ -1544,9 +1550,9 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param node The glTF node property
          * @param assign A function called synchronously after parsing the glTF properties
-         * @returns A promise that resolves with the loaded Babylon mesh when the load is complete or null if not handled
+         * @returns A promise that resolves with the loaded Babylon transform node when the load is complete or null if not handled
          */
-        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync?(context: string, node: Loader.INode, assign: (babylonMesh: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /**
          * Define this method to modify the default behavior when loading cameras.
          * @param context The context when loading the asset
@@ -1656,7 +1662,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onReady(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
@@ -1717,7 +1723,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadSceneAsync(context: string, scene: IScene): Nullable<Promise<void>>;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
         loadAnimationAsync(context: string, animation: IAnimation): Nullable<Promise<AnimationGroup>>;
         private _loadClipAsync;
@@ -1809,7 +1815,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         onLoading(): void;
         /** @hidden */
-        loadNodeAsync(context: string, node: INode, assign: (babylonMesh: Mesh) => void): Nullable<Promise<Mesh>>;
+        loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
     }
 }
 

+ 1 - 41
dist/preview release/viewer/babylon.viewer.d.ts

@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,20 +1558,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
@@ -1679,32 +1665,6 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
-    /**
-        * Defines an animation to be applied to a model (translation, scale or rotation).
-        */
-    export interface IModelAnimationConfiguration {
-            /**
-                * Time of animation, in seconds
-                */
-            time?: number;
-            /**
-                * Scale to apply
-                */
-            scaling?: {
-                    x: number;
-                    y: number;
-                    z: number;
-            };
-            /**
-                * Easing function to apply
-                */
-            easingFunction?: number;
-            /**
-                * An Easing mode to apply to the easing function
-                * See BABYLON.EasingFunction
-                */
-            easingMode?: number;
-    }
 }
 declare module BabylonViewer {
     export class TelemetryLoaderPlugin implements ILoaderPlugin {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -985,14 +985,13 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1663,22 +1662,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
@@ -1809,32 +1792,7 @@ declare module 'babylonjs-viewer/labs/viewerLabs' {
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/modelAnimationConfiguration' {
-    /**
-        * Defines an animation to be applied to a model (translation, scale or rotation).
-        */
-    export interface IModelAnimationConfiguration {
-            /**
-                * Time of animation, in seconds
-                */
-            time?: number;
-            /**
-                * Scale to apply
-                */
-            scaling?: {
-                    x: number;
-                    y: number;
-                    z: number;
-            };
-            /**
-                * Easing function to apply
-                */
-            easingFunction?: number;
-            /**
-                * An Easing mode to apply to the easing function
-                * See BABYLON.EasingFunction
-                */
-            easingMode?: number;
-    }
+    
 }
 
 declare module 'babylonjs-viewer/loader/plugins/telemetryLoaderPlugin' {