Browse Source

Added morph target animation support

Lewy Blue 7 years ago
parent
commit
28c150bb44
1 changed files with 87 additions and 17 deletions
  1. 87 17
      examples/js/loaders/FBXLoader.js

+ 87 - 17
examples/js/loaders/FBXLoader.js

@@ -100,7 +100,7 @@
 
 			}
 
-			// console.log( FBXTree );
+			console.log( FBXTree.Objects );
 
 			var textureLoader = new THREE.TextureLoader( this.manager ).setPath( resourceDirectory ).setCrossOrigin( this.crossOrigin );
 
@@ -110,7 +110,7 @@
 			var materials = parseMaterials( FBXTree, textures, connections );
 			var deformers = parseDeformers( FBXTree, connections );
 			var geometryMap = parseGeometries( FBXTree, connections, deformers );
-			var sceneGraph = parseScene( FBXTree, connections, deformers.skeletons, geometryMap, materials );
+			var sceneGraph = parseScene( FBXTree, connections, deformers, geometryMap, materials );
 
 			return sceneGraph;
 
@@ -633,7 +633,7 @@
 						id: nodeID,
 					};
 
-					morphTarget.rawTargets = parseMorphTargets( relationships, deformerNode, DeformerNodes, connections );
+					morphTarget.rawTargets = parseMorphTargets( relationships, DeformerNodes, connections );
 					morphTarget.id = nodeID;
 
 					if ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: morph target attached to more than one geometry is not supported.' );
@@ -701,7 +701,7 @@
 	}
 
 	// The top level morph deformer node has type "BlendShape" and sub nodes have type "BlendShapeChannel"
-	function parseMorphTargets( relationships, deformerNode, deformerNodes, connections ) {
+	function parseMorphTargets( relationships, deformerNodes, connections ) {
 
 		var rawMorphTargets = [];
 
@@ -734,16 +734,33 @@
 
 			targetRelationships.children.forEach( function ( child ) {
 
-				if ( child.relationship === 'DeformPercent' ) {
 
-					// TODO: animation of morph targets is currently unsupported
+				if ( child.relationship === 'DeformPercent' ) { // animation info for morph target
+
+					var animConnections = connections.get( child.ID );
+					// parent relationship 'DeformPercent' === morphTargetNode /2605340465664
+					// parent relationship 'undefined' === AnimationLayer /2606600117184
+					// child relationship 'd|DeformPercent' === AnimationCurve /2606284032736
+
 					rawMorphTarget.weightCurveID = child.ID;
-					// weightCurve = FBXTree.Objects.AnimationCurveNode[ weightCurveID ];
+
+					animConnections.parents.forEach( function ( parent ) {
+
+						if ( parent.relationship === undefined ) {
+
+							// assuming each morph target is in a single animation layer for now
+							rawMorphTarget.animationLayerID = parent.ID;
+
+						}
+
+					} )
+
+					// assuming each morph target has a single animation curve for now
+					rawMorphTarget.animationCurveID = animConnections.children[ 0 ].ID;
 
 				} else {
 
 					rawMorphTarget.geoID = child.ID;
-					// morphGeo = FBXTree.Objects.Geometry[ geoID ];
 
 				}
 
@@ -1626,11 +1643,11 @@
 	}
 
 	// create the main THREE.Group() to be returned by the loader
-	function parseScene( FBXTree, connections, skeletons, geometryMap, materialMap ) {
+	function parseScene( FBXTree, connections, deformers, geometryMap, materialMap ) {
 
 		var sceneGraph = new THREE.Group();
 
-		var modelMap = parseModels( FBXTree, skeletons, geometryMap, materialMap, connections );
+		var modelMap = parseModels( FBXTree, deformers.skeletons, geometryMap, materialMap, connections );
 
 		var modelNodes = FBXTree.Objects.Model;
 
@@ -1657,7 +1674,7 @@
 
 		} );
 
-		bindSkeleton( FBXTree, skeletons, geometryMap, modelMap, connections );
+		bindSkeleton( FBXTree, deformers.skeletons, geometryMap, modelMap, connections );
 
 		addAnimations( FBXTree, connections, sceneGraph );
 
@@ -2273,7 +2290,6 @@
 		var curveNodesMap = parseAnimationCurveNodes( FBXTree );
 
 		parseAnimationCurves( FBXTree, connections, curveNodesMap );
-
 		var layersMap = parseAnimationLayers( FBXTree, connections, curveNodesMap );
 		var rawClips = parseAnimStacks( FBXTree, connections, layersMap );
 
@@ -2294,7 +2310,7 @@
 
 			var rawCurveNode = rawCurveNodes[ nodeID ];
 
-			if ( rawCurveNode.attrName.match( /S|R|T/ ) !== null ) {
+			if ( rawCurveNode.attrName.match( /S|R|T|DeformPercent/ ) !== null ) {
 
 				var curveNode = {
 
@@ -2350,6 +2366,10 @@
 
 					curveNodesMap.get( animationCurveID ).curves[ 'z' ] = animationCurve;
 
+				} else if ( animationCurveRelationship.match( /d|DeformPercent/ ) ) {
+
+					curveNodesMap.get( animationCurveID ).curves[ 'morph' ] = animationCurve;
+
 				}
 
 			}
@@ -2385,18 +2405,19 @@
 						var curveNode = curveNodesMap.get( child.ID );
 
 						// check that the curves are defined for at least one axis, otherwise ignore the curveNode
-						if ( curveNode.curves.x !== undefined || curveNode.curves.y !== undefined || curveNode.curves.z !== undefined ) {
+						if ( curveNode.curves.x !== undefined || curveNode.curves.y !== undefined || curveNode.curves.z !== undefined  ) {
 
 							if ( layerCurveNodes[ i ] === undefined ) {
 
 								var modelID;
 
-								connections.get( child.ID ).parents.forEach( function ( parent ) {
+								connections.get( curveNode.ID ).parents.forEach( function ( parent ) {
 
 									if ( parent.relationship !== undefined ) modelID = parent.ID;
 
 								} );
 
+
 								var rawModel = FBXTree.Objects.Model[ modelID.toString() ];
 
 								var node = {
@@ -2424,9 +2445,40 @@
 
 							layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
 
-						}
+						} else if ( curveNode.curves.morph !== undefined ) {
+
+							if ( layerCurveNodes[ i ] === undefined ) {
+
+								var deformerID;
+
+								connections.get( child.ID ).parents.forEach( function ( parent ) {
+
+									if ( parent.relationship !== undefined ) deformerID = parent.ID;
+
+								} );
+
+
+								var morpherID = connections.get( deformerID ).parents[ 0 ].ID;
+								var geoID = connections.get( morpherID ).parents[ 0 ].ID;
+
+								// assuming geometry is not used in more than one model
+								var modelID = connections.get( geoID ).parents[ 0 ].ID;
 
+								var rawModel = FBXTree.Objects.Model[ modelID ];
 
+								var node = {
+
+									modelName: THREE.PropertyBinding.sanitizeNodeName( rawModel.attrName ),
+
+								};
+
+								layerCurveNodes[ i ] = node;
+
+							}
+
+							layerCurveNodes[ i ][ curveNode.attr ] = curveNode;
+
+						}
 
 					}
 
@@ -2487,7 +2539,6 @@
 
 		if ( rawClips === undefined ) return;
 
-
 		for ( var key in rawClips ) {
 
 			var rawClip = rawClips[ key ];
@@ -2539,6 +2590,13 @@
 
 		}
 
+		if ( rawTracks.DeformPercent !== undefined && Object.keys( rawTracks.DeformPercent.curves ).length > 0 ) {
+
+			var morphTrack = generateMorphTrack( rawTracks.modelName, rawTracks.DeformPercent.curves.morph );
+			if ( morphTrack !== undefined ) tracks.push( morphTrack );
+
+		}
+
 		return tracks;
 
 	}
@@ -2607,6 +2665,18 @@
 
 	}
 
+	function generateMorphTrack( modelName, curve ) {
+
+		var values = curve.values.map( function ( val ) {
+
+			return val / 100;
+
+		} );
+
+		return new THREE.NumberKeyframeTrack( modelName + '.morphTargetInfluences[0]', curve.times, values );
+
+	}
+
 	function getKeyframeTrackValues( times, curves, initialValue ) {
 
 		var prevValue = initialValue;