瀏覽代碼

Merge pull request #2079 from BeardedGnome/morph-target

Added support to glTF loader for animated morph targets
David Catuhe 8 年之前
父節點
當前提交
2562634f50
共有 2 個文件被更改,包括 82 次插入18 次删除
  1. 74 18
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  2. 8 0
      src/Morph/babylon.morphTargetManager.ts

+ 74 - 18
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -4,8 +4,8 @@ module BABYLON.GLTF2 {
     /**
     /**
     * Values
     * Values
     */
     */
-    var glTFAnimationPaths = ["translation", "rotation", "scale"];
-    var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling"];
+    var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
+    var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
 
 
     /**
     /**
     * Utils
     * Utils
@@ -80,8 +80,9 @@ module BABYLON.GLTF2 {
                 }
                 }
 
 
                 var isBone = targetNode instanceof Bone;
                 var isBone = targetNode instanceof Bone;
+                var numTargets = 0;
 
 
-                // Get target path (position, rotation or scaling)
+                // Get target path (position, rotation, scaling, or weights)
                 var targetPath = channel.target.path;
                 var targetPath = channel.target.path;
                 var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
                 var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
 
 
@@ -89,6 +90,8 @@ module BABYLON.GLTF2 {
                     targetPath = babylonAnimationPaths[targetPathIndex];
                     targetPath = babylonAnimationPaths[targetPathIndex];
                 }
                 }
 
 
+                var isMorph = targetPath === "influence";
+
                 // Determine animation type
                 // Determine animation type
                 var animationType = Animation.ANIMATIONTYPE_MATRIX;
                 var animationType = Animation.ANIMATIONTYPE_MATRIX;
 
 
@@ -97,6 +100,10 @@ module BABYLON.GLTF2 {
                         animationType = Animation.ANIMATIONTYPE_QUATERNION;
                         animationType = Animation.ANIMATIONTYPE_QUATERNION;
                         targetNode.rotationQuaternion = new Quaternion();
                         targetNode.rotationQuaternion = new Quaternion();
                     }
                     }
+                    else if (isMorph) {
+                        animationType = Animation.ANIMATIONTYPE_FLOAT;
+                        numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
+                    }
                     else {
                     else {
                         animationType = Animation.ANIMATIONTYPE_VECTOR3;
                         animationType = Animation.ANIMATIONTYPE_VECTOR3;
                     }
                     }
@@ -113,19 +120,30 @@ module BABYLON.GLTF2 {
                     modifyKey = true;
                     modifyKey = true;
                 }
                 }
 
 
-                if (!modifyKey) {
-                    var animationName = animation.name || "anim" + animationIndex;
-                    babylonAnimation = new Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
+                // 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] = [];
+                    }
                 }
                 }
 
 
                 // For each frame
                 // For each frame
-                for (var j = 0; j < bufferInput.length; j++) {
+                for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
                     var value: any = null;
                     var value: any = null;
 
 
                     if (targetPath === "rotationQuaternion") { // VEC4
                     if (targetPath === "rotationQuaternion") { // VEC4
                         value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
                         value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
                         arrayOffset += 4;
                         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
                     else { // Position and scaling are VEC3
                         value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
                         value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
                         arrayOffset += 3;
                         arrayOffset += 3;
@@ -141,7 +159,7 @@ module BABYLON.GLTF2 {
                         var mat = bone.getBaseMatrix();
                         var mat = bone.getBaseMatrix();
 
 
                         if (modifyKey) {
                         if (modifyKey) {
-                            mat = lastAnimation.getKeys()[j].value;
+                            mat = lastAnimation.getKeys()[frameIndex].value;
                         }
                         }
 
 
                         mat.decompose(scaling, rotationQuaternion, translation);
                         mat.decompose(scaling, rotationQuaternion, translation);
@@ -160,26 +178,64 @@ module BABYLON.GLTF2 {
                     }
                     }
 
 
                     if (!modifyKey) {
                     if (!modifyKey) {
-                        keys.push({
-                            frame: bufferInput[j],
-                            value: value
-                        });
+                        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 {
                     else {
-                        lastAnimation.getKeys()[j].value = value;
+                        lastAnimation.getKeys()[frameIndex].value = value;
                     }
                     }
                 }
                 }
 
 
                 // Finish
                 // Finish
                 if (!modifyKey) {
                 if (!modifyKey) {
-                    babylonAnimation.setKeys(keys);
-                    targetNode.animations.push(babylonAnimation);
+                    if (isMorph) {
+                        for (var influence = 0; influence < numTargets; influence++) {
+                            var morphTarget = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
+                            if ((<any>morphTarget).animations === undefined) {
+                                (<any>morphTarget).animations = [];
+                            }
+
+                            var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
+                            babylonAnimation = new Animation(animationName, targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
+
+                            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);
+                    }
                 }
                 }
 
 
                 lastAnimation = babylonAnimation;
                 lastAnimation = babylonAnimation;
 
 
-                runtime.babylonScene.stopAnimation(targetNode);
-                runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
+                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);
+                }
             }
             }
         }
         }
     };
     };
@@ -672,7 +728,7 @@ module BABYLON.GLTF2 {
         babylonMesh.computeWorldMatrix(true);
         babylonMesh.computeWorldMatrix(true);
 
 
         // Set morph target manager after all vertices data has been processed
         // Set morph target manager after all vertices data has been processed
-        if (morphTargetManager !== undefined && morphTargetManager.numInfluencers > 0) {
+        if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
             babylonMesh.morphTargetManager = morphTargetManager;
             babylonMesh.morphTargetManager = morphTargetManager;
         }
         }
 
 

+ 8 - 0
src/Morph/babylon.morphTargetManager.ts

@@ -38,6 +38,10 @@ module BABYLON {
             return this._supportsTangents;
             return this._supportsTangents;
         }
         }
 
 
+        public get numTargets(): number {
+            return this._targets.length;
+        }
+
         public get numInfluencers(): number {
         public get numInfluencers(): number {
             return this._activeTargets.length;
             return this._activeTargets.length;
         }
         }
@@ -49,6 +53,10 @@ module BABYLON {
         public getActiveTarget(index: number): MorphTarget {
         public getActiveTarget(index: number): MorphTarget {
             return this._activeTargets.data[index];
             return this._activeTargets.data[index];
         }
         }
+
+        public getTarget(index: number): MorphTarget {
+            return this._targets[index];
+        }
        
        
         public addTarget(target: MorphTarget): void {
         public addTarget(target: MorphTarget): void {
             if (this._vertexCount) {
             if (this._vertexCount) {