浏览代码

Merge pull request #2123 from bghgary/glTFFileLoader

Add support for spline interpolation to glTF file loader
David Catuhe 8 年之前
父节点
当前提交
13fe95b156

+ 183 - 270
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1,242 +1,167 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2 {
-    /**
-    * Values
-    */
-    var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
-    var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
-
-    /**
-    * Utils
-    */
-    var normalizeUVs = (buffer: any): void => {
-        if (!buffer) {
-            return;
-        }
-
-        for (var i = 0; i < buffer.length / 2; i++) {
-            buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
-        }
-    };
-
-    var createStringId = (index: number): string => {
+    var getNodeID = (index: number): string => {
         return "node" + index;
     };
 
-    /**
-    * Returns the animation path (glTF -> Babylon)
-    */
-    var getAnimationPath = (path: string): string => {
-        var index = glTFAnimationPaths.indexOf(path);
-
-        if (index !== -1) {
-            return babylonAnimationPaths[index];
-        }
-
-        return path;
-    };
-
-    /**
-    * Loads and creates animations
-    */
-    var loadAnimations = (runtime: IGLTFRuntime): void => {
-        var animations = runtime.gltf.animations;
-        if (!animations) {
-            return;
-        }
-
-        for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
-            var animation = animations[animationIndex];
-            if (!animation || !animation.channels || !animation.samplers) {
+    var loadAnimation = (runtime: IGLTFRuntime, animation: IGLTFAnimation, animationIndex: number): void => {
+        for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
+            var channel = animation.channels[channelIndex];
+            if (!channel) {
+                Tools.Warn("[Animation " + animationIndex + "] Channel " + channelIndex + " does not exist");
                 continue;
             }
 
-            var lastAnimation: Animation = null;
-
-            for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
-                var channel = animation.channels[channelIndex];
-                if (!channel) {
-                    continue;
-                }
-
-                var sampler = animation.samplers[channel.sampler];
-                if (!sampler) {
-                    continue;
-                }
-
-                var inputData = sampler.input;
-                var outputData = sampler.output;
-
-                var bufferInput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
-                var bufferOutput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
-
-                var targetID = channel.target.node;
-                var targetNode: any = runtime.babylonScene.getNodeByID(createStringId(targetID));
-
-                if (targetNode === null) {
-                    Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
-                    continue;
-                }
-
-                var isBone = targetNode instanceof Bone;
-                var numTargets = 0;
-
-                // Get target path (position, rotation, scaling, or weights)
-                var targetPath = channel.target.path;
-                var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
-
-                if (targetPathIndex !== -1) {
-                    targetPath = babylonAnimationPaths[targetPathIndex];
-                }
-
-                var isMorph = targetPath === "influence";
+            var samplerIndex = channel.sampler;
+            if (samplerIndex === undefined) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + samplerIndex + "] Sampler is not defined");
+                continue;
+            }
 
-                // Determine animation type
-                var animationType = Animation.ANIMATIONTYPE_MATRIX;
+            var sampler = animation.samplers[samplerIndex];
+            if (!sampler) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler " + samplerIndex + " does not exist");
+                continue;
+            }
 
-                if (!isBone) {
-                    if (targetPath === "rotationQuaternion") {
-                        animationType = Animation.ANIMATIONTYPE_QUATERNION;
-                        targetNode.rotationQuaternion = new Quaternion();
-                    }
-                    else if (isMorph) {
-                        animationType = Animation.ANIMATIONTYPE_FLOAT;
-                        numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
-                    }
-                    else {
-                        animationType = Animation.ANIMATIONTYPE_VECTOR3;
-                    }
-                }
+            if (!channel.target) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target does not exist");
+                continue;
+            }
 
-                // Create animation and key frames
-                var babylonAnimation: Animation = null;
-                var keys = [];
-                var arrayOffset = 0;
-                var modifyKey = false;
+            var targetNode = runtime.babylonScene.getNodeByID(getNodeID(channel.target.node));
+            if (!targetNode) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target node " + channel.target.node + " does not exist");
+                continue;
+            }
 
-                if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
-                    babylonAnimation = lastAnimation;
-                    modifyKey = true;
-                }
+            var targetPath = {
+                "translation": "position",
+                "rotation": "rotationQuaternion",
+                "scale": "scaling",
+                "weights": "influence"
+            }[channel.target.path];
+            if (!targetPath) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target path " + channel.target.path + " is invalid");
+                continue;
+            }
 
-                // Each morph animation may have more than one more, so we need a
-                // multi dimensional array.
-                if (isMorph) {
-                    for (var influence = 0; influence < numTargets; influence++) {
-                        keys[influence] = [];
-                    }
-                }
+            var inputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.input]);
+            var outputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.output]);
+            var outputBufferOffset = 0;
 
-                // For each frame
-                for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
-                    var value: any = null;
+            var animationType = {
+                "position": Animation.ANIMATIONTYPE_VECTOR3,
+                "rotationQuaternion": Animation.ANIMATIONTYPE_QUATERNION,
+                "scale": Animation.ANIMATIONTYPE_VECTOR3,
+                "influence": Animation.ANIMATIONTYPE_FLOAT,
+            }[targetPath];
 
-                    if (targetPath === "rotationQuaternion") { // VEC4
-                        value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
-                        arrayOffset += 4;
-                    }
-                    else if (isMorph) { // FLOAT
-                        value = [];
-                        // There is 1 value for each morph target for each frame
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            value.push(bufferOutput[arrayOffset + influence]);
-                        }
-                        arrayOffset += numTargets;
-                    }
-                    else { // Position and scaling are VEC3
-                        value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
-                        arrayOffset += 3;
+            var getNextOutputValue: () => any = {
+                "position": () => {
+                    var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 3;
+                    return value;
+                },
+                "rotationQuaternion": () => {
+                    var value = Quaternion.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 4;
+                    return value;
+                },
+                "scale": () => {
+                    var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 3;
+                    return value;
+                },
+                "influence": () => {
+                    var numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
+                    var value = new Array(numTargets);
+                    for (var i = 0; i < numTargets; i++) {
+                        value[i] = outputBuffer[outputBufferOffset++];
                     }
+                    return value;
+                },
+            }[targetPath];
+
+            var getNextKey: (frameIndex) => any = {
+                "LINEAR": frameIndex => ({
+                    frame: inputBuffer[frameIndex],
+                    value: getNextOutputValue()
+                }),
+                "CUBICSPLINE": frameIndex => ({
+                    frame: inputBuffer[frameIndex],
+                    inTangent: getNextOutputValue(),
+                    value: getNextOutputValue(),
+                    outTangent: getNextOutputValue()
+                }),
+            }[sampler.interpolation];
+
+            if (!getNextKey) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler interpolation '" + sampler.interpolation + "' is invalid");
+                continue;
+            }
 
-                    if (isBone) {
-                        var bone = <Bone>targetNode;
-                        var translation = Vector3.Zero();
-                        var rotationQuaternion = new Quaternion();
-                        var scaling = Vector3.Zero();
-
-                        // Warning on decompose
-                        var mat = bone.getBaseMatrix();
+            var keys = new Array(inputBuffer.length);
+            for (var frameIndex = 0; frameIndex < inputBuffer.length; frameIndex++) {
+                keys[frameIndex] = getNextKey(frameIndex);
+            }
 
-                        if (modifyKey) {
-                            mat = lastAnimation.getKeys()[frameIndex].value;
-                        }
+            if (targetPath === "influence") {
+                var targetMesh = <Mesh>targetNode;
 
-                        mat.decompose(scaling, rotationQuaternion, translation);
+                for (var targetIndex = 0; targetIndex < targetMesh.morphTargetManager.numTargets; targetIndex++) {
+                    var morphTarget = targetMesh.morphTargetManager.getTarget(targetIndex);
+                    var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
+                    var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
+                    babylonAnimation.setKeys(keys.map(key => ({
+                        frame: key.frame,
+                        inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
+                        value: key.value[targetIndex],
+                        outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
+                    })));
 
-                        if (targetPath === "position") {
-                            translation = value;
-                        }
-                        else if (targetPath === "rotationQuaternion") {
-                            rotationQuaternion = value;
-                        }
-                        else {
-                            scaling = value;
-                        }
-
-                        value = Matrix.Compose(scaling, rotationQuaternion, translation);
-                    }
-
-                    if (!modifyKey) {
-                        if (isMorph) {
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                keys[influence].push({
-                                    frame: bufferInput[frameIndex],
-                                    value: value[influence]
-                                });
-                            }
-                        }
-                        else {
-                            keys.push({
-                                frame: bufferInput[frameIndex],
-                                value: value
-                            });
-                        }
-                    }
-                    else {
-                        lastAnimation.getKeys()[frameIndex].value = value;
-                    }
+                    morphTarget.animations.push(babylonAnimation);
+                    runtime.babylonScene.beginAnimation(morphTarget, 0, inputBuffer[inputBuffer.length - 1], true);
                 }
+            }
+            else {
+                var animationName = animation.name || "anim" + animationIndex;
+                var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
+                babylonAnimation.setKeys(keys);
 
-                // Finish
-                if (!modifyKey) {
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            var morphTarget = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
-                            if ((<any>morphTarget).animations === undefined) {
-                                (<any>morphTarget).animations = [];
-                            }
+                targetNode.animations.push(babylonAnimation);
+                runtime.babylonScene.beginAnimation(targetNode, 0, inputBuffer[inputBuffer.length - 1], true);
+            }
+        }
+    }
 
-                            var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
-                            babylonAnimation = new Animation(animationName, targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
+    /**
+    * Loads and creates animations
+    */
+    var loadAnimations = (runtime: IGLTFRuntime): void => {
+        var animations = runtime.gltf.animations;
+        if (!animations || animations.length === 0) {
+            return;
+        }
 
-                            babylonAnimation.setKeys(keys[influence]);
-                            (<any>morphTarget).animations.push(babylonAnimation);
-                        }
-                    }
-                    else {
-                        var animationName = animation.name || "anim" + animationIndex;
-                        babylonAnimation = new Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
-                
-                        babylonAnimation.setKeys(keys);
-                        targetNode.animations.push(babylonAnimation);
-                    }
-                }
+        for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
+            var animation = animations[animationIndex];
+            if (!animation) {
+                Tools.Warn("Animation " + animationIndex + " not found");
+                continue;
+            }
 
-                lastAnimation = babylonAnimation;
+            if (!animation.channels || animation.channels.length === 0) {
+                Tools.Warn("Animation " + animationIndex + " has no channels");
+            }
 
-                if (isMorph) {
-                    for (var influence = 0; influence < numTargets; influence++) {
-                        var morph = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
-                        runtime.babylonScene.stopAnimation(morph);
-                        runtime.babylonScene.beginAnimation(morph, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                    }
-                }
-                else {
-                    runtime.babylonScene.stopAnimation(targetNode);
-                    runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                }
+            if (!animation.samplers || animation.samplers.length === 0) {
+                Tools.Warn("Animation " + animationIndex + " has no samplers");
+                continue;
             }
+
+            loadAnimation(runtime, animation, animationIndex);
         }
     };
 
@@ -265,7 +190,7 @@ module BABYLON.GLTF2 {
     */
     var getParentBone = (runtime: IGLTFRuntime, skin: IGLTFSkin, index: number, newSkeleton: Skeleton): Bone => {
         // Try to find
-        var nodeStringID = createStringId(index);
+        var nodeStringID = getNodeID(index);
         for (var i = 0; i < newSkeleton.bones.length; i++) {
             if (newSkeleton.bones[i].id === nodeStringID) {
                 return newSkeleton.bones[i].getParent();
@@ -289,8 +214,8 @@ module BABYLON.GLTF2 {
                 if (childID === index)
                 {
                     var mat = configureBoneTransformation(parent);
-                    var bone = new Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
-                    bone.id = createStringId(parentID);
+                    var bone = new Bone(parent.name || getNodeID(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
+                    bone.id = getNodeID(parentID);
                     return bone;
                 }
             }
@@ -361,8 +286,8 @@ module BABYLON.GLTF2 {
 
             // Create node to root bone
             var mat = configureBoneTransformation(node);
-            var bone = new Bone(node.name || createStringId(i), newSkeleton, null, mat);
-            bone.id = createStringId(i);
+            var bone = new Bone(node.name || getNodeID(i), newSkeleton, null, mat);
+            bone.id = getNodeID(i);
             nodesToRoot.push({ bone: bone, node: node, index: i });
         }
 
@@ -428,7 +353,7 @@ module BABYLON.GLTF2 {
             }
 
             var index = jointNode.index;
-            var stringID = createStringId(index);
+            var stringID = getNodeID(index);
 
             // Optimize, if the bone already exists...
             var existingBone = runtime.babylonScene.getBoneByID(stringID);
@@ -493,7 +418,7 @@ module BABYLON.GLTF2 {
                 continue;
             }
 
-            var jointNodeStringId = createStringId(jointNode.index);
+            var jointNodeStringId = getNodeID(jointNode.index);
             for (var j = 0; j < bones.length; j++) {
                 if (bones[j].id === jointNodeStringId) {
                     babylonSkeleton.bones.push(bones[j]);
@@ -564,7 +489,7 @@ module BABYLON.GLTF2 {
         var indexStarts = [];
         var indexCounts = [];
 
-        var morphTargetManager = new BABYLON.MorphTargetManager();
+        var morphTargetManager: MorphTargetManager;
 
         // Positions, normals and UVs
         for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -578,7 +503,7 @@ module BABYLON.GLTF2 {
 
             var attributes = primitive.attributes;
             var accessor: IGLTFAccessor = null;
-            var buffer: any = null;
+            var buffer: ArrayBufferView = null;
 
             // Set positions, normal and uvs
             for (var semantic in attributes) {
@@ -588,37 +513,28 @@ module BABYLON.GLTF2 {
                 buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
 
                 if (semantic === "NORMAL") {
-                    tempVertexData.normals = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.normals).set(buffer);
+                    tempVertexData.normals = <Float32Array>buffer;
                 }
                 else if (semantic === "POSITION") {
-                    tempVertexData.positions = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.positions).set(buffer);
+                    tempVertexData.positions = <Float32Array>buffer;
                     verticesCounts.push(tempVertexData.positions.length);
                 }
                 else if (semantic === "TANGENT") {
-                    tempVertexData.tangents = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.tangents).set(buffer);
+                    tempVertexData.tangents = <Float32Array>buffer;
                 }
                 else if (semantic.indexOf("TEXCOORD_") !== -1) {
                     var channel = Number(semantic.split("_")[1]);
                     var uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                    var uvs = new Float32Array(buffer.length);
-                    (<Float32Array>uvs).set(buffer);
-                    normalizeUVs(uvs);
-                    tempVertexData.set(uvs, uvKind);
+                    tempVertexData.set(<Float32Array>buffer, uvKind);
                 }
                 else if (semantic === "JOINT") {
-                    tempVertexData.matricesIndices = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.matricesIndices).set(buffer);
+                    tempVertexData.matricesIndices = <Float32Array>buffer;
                 }
                 else if (semantic === "WEIGHT") {
-                    tempVertexData.matricesWeights = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.matricesWeights).set(buffer);
+                    tempVertexData.matricesWeights = <Float32Array>buffer;
                 }
                 else if (semantic === "COLOR_0") {
-                    tempVertexData.colors = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.colors).set(buffer);
+                    tempVertexData.colors = <Float32Array>buffer;
                 }
                 else {
                     Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
@@ -629,19 +545,16 @@ module BABYLON.GLTF2 {
             accessor = runtime.gltf.accessors[primitive.indices];
             if (accessor) {
                 buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-
-                tempVertexData.indices = new Int32Array(buffer.length);
-                (<Float32Array>tempVertexData.indices).set(buffer);
+                tempVertexData.indices = <Uint32Array>buffer;
                 indexCounts.push(tempVertexData.indices.length);
             }
             else {
                 // Set indices on the fly
-                var indices: number[] = [];
-                for (var index = 0; index < tempVertexData.positions.length / 3; index++) {
-                    indices.push(index);
+                tempVertexData.indices = new Uint32Array(tempVertexData.positions.length / 3);
+                for (var index = 0; index < tempVertexData.indices.length; index++) {
+                    tempVertexData.indices[index] = index;
                 }
 
-                tempVertexData.indices = new Int32Array(indices);
                 indexCounts.push(tempVertexData.indices.length);
             }
 
@@ -653,26 +566,26 @@ module BABYLON.GLTF2 {
             multiMat.subMaterials.push(material);
 
             // Morph Targets
-            if (primitive.targets !== undefined) {
+            if (primitive.targets) {
                 for (var targetsIndex = 0; targetsIndex < primitive.targets.length; targetsIndex++) {
                     var target = primitive.targets[targetsIndex];
 
                     var weight = 0.0;
-                    if (node.weights !== undefined) {
+                    if (node.weights) {
                         weight = node.weights[targetsIndex];
                     }
-                    else if (mesh.weights !== undefined) {
+                    else if (mesh.weights) {
                         weight = mesh.weights[targetsIndex];
                     }
 
-                    var morph = new BABYLON.MorphTarget("morph" + targetsIndex, weight);
+                    var morph = new MorphTarget("morph" + targetsIndex, weight);
 
                     for (var semantic in target) {
                         // Link accessor and buffer view
                         accessor = runtime.gltf.accessors[target[semantic]];
-                        buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
+                        var values = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, accessor);
 
-                        if (accessor.name !== undefined) {
+                        if (accessor.name) {
                             morph.name = accessor.name;
                         }
 
@@ -681,35 +594,40 @@ module BABYLON.GLTF2 {
                         // As a result we have to add the original data to the delta to calculate
                         // the final data.
                         if (semantic === "NORMAL") {
-                            for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.normals)[bufferIndex];
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.normals[i];
                             }
-                            morph.setNormals(buffer);
+                            morph.setNormals(values);
                         }
                         else if (semantic === "POSITION") {
-                            for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.positions)[bufferIndex];
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.positions[i];
                             }
-                            morph.setPositions(buffer);
+                            morph.setPositions(values);
                         }
                         else if (semantic === "TANGENT") {
                             // Tangent data for morph targets is stored as xyz delta.
                             // The vertexData.tangent is stored as xyzw.
                             // So we need to skip every fourth vertexData.tangent.
-                            for (var bufferIndex = 0, tangentsIndex = 0; bufferIndex < buffer.length; bufferIndex++, tangentsIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.tangents)[tangentsIndex];
-                                if ((bufferIndex + 1) % 3 == 0) {
-                                    tangentsIndex++;
+                            for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                values[i] += vertexData.tangents[j];
+                                if ((i + 1) % 3 == 0) {
+                                    j++;
                                 }
                             }
-                            morph.setTangents(buffer);
+                            morph.setTangents(values);
                         }
                         else {
                             Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
                         }
                     }
-                    
-                    if (morph.getPositions() !== undefined) {
+
+                    if (morph.getPositions()) {
+                        if (!morphTargetManager) {
+                            morphTargetManager = new MorphTargetManager();
+                            babylonMesh.morphTargetManager = morphTargetManager;
+                        }
+
                         morphTargetManager.addTarget(morph);
                     }
                     else {
@@ -727,11 +645,6 @@ module BABYLON.GLTF2 {
         geometry.setAllVerticesData(vertexData, false);
         babylonMesh.computeWorldMatrix(true);
 
-        // Set morph target manager after all vertices data has been processed
-        if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
-            babylonMesh.morphTargetManager = morphTargetManager;
-        }
-
         // Apply submeshes
         babylonMesh.subMeshes = [];
         for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -889,7 +802,7 @@ module BABYLON.GLTF2 {
             newNode = importNode(runtime, node);
 
             if (newNode !== null) {
-                newNode.id = createStringId(index);
+                newNode.id = getNodeID(index);
                 newNode.parent = parent;
             }
         }
@@ -1214,7 +1127,7 @@ module BABYLON.GLTF2 {
             var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
             var samplingMode = GLTFUtils.GetTextureFilterMode(sampler.minFilter);
 
-            var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, () => {
+            var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, false, samplingMode, () => {
                 onSuccess(babylonTexture);
             }, onError);
 
@@ -1352,7 +1265,7 @@ module BABYLON.GLTF2 {
 
         private static _loadMaterialsAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
             var materials = runtime.gltf.materials;
-            if (!materials) {
+            if (!materials || materials.length === 0) {
                 onSuccess();
                 return;
             }

+ 1 - 1
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -102,7 +102,7 @@ module BABYLON.GLTF2 {
          * @param runtime: the GLTF runtime
          * @param accessor: the GLTF accessor
          */
-        public static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): any {
+        public static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): ArrayBufferView {
             var bufferView = runtime.gltf.bufferViews[accessor.bufferView];
             var byteOffset = accessor.byteOffset || 0;
             var byteLength = accessor.count * GLTFUtils.GetByteStrideFromType(accessor);

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

@@ -93,6 +93,39 @@ module BABYLON {
             return this._absoluteTransform;
         }
 
+        // Properties (matches AbstractMesh properties)
+        public get position(): Vector3 {
+            return this.getPosition();
+        }
+
+        public set position(newPosition: Vector3) {
+            this.setPosition(newPosition);
+        }
+
+        public get rotation(): Vector3 {
+            return this.getRotation();
+        }
+
+        public set rotation(newRotation: Vector3) {
+            this.setRotation(newRotation);
+        }
+
+        public get rotationQuaternion() {
+            return this.getRotationQuaternion();
+        }
+
+        public set rotationQuaternion(newRotation: Quaternion) {
+            this.setRotationQuaternion(newRotation);
+        }
+
+        public get scaling(): Vector3 {
+            return this.getScale();
+        }
+
+        public set scaling(newScaling: Vector3) {
+            this.setScale(newScaling.x, newScaling.y, newScaling.z);
+        }
+
         // Methods
         public updateMatrix(matrix: Matrix, updateDifferenceMatrix = true): void {
             this._baseMatrix = matrix.clone();

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

@@ -116,7 +116,7 @@
         public definedFacingForward = true; // orientation for POV movement & rotation
         public position = new Vector3(0.0, 0.0, 0.0);
         private _rotation = new Vector3(0.0, 0.0, 0.0);
-        public _rotationQuaternion: Quaternion;
+        private _rotationQuaternion: Quaternion;
         private _scaling = new Vector3(1.0, 1.0, 1.0);
         public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;