Explorar el Código

AnimationUtils: Add mergeMorphTargetTracks().

Don McCurdy hace 6 años
padre
commit
fe5d2414fc

+ 11 - 0
docs/api/en/animation/AnimationUtils.html

@@ -49,6 +49,17 @@
 		Returns *true* if the object is a typed array.
 		</p>
 
+		<h3>[method:AnimationClip mergeMorphTargetTracks]( [param:AnimationClip tracks], [param:Object3D root] )</h3>
+		<p>
+		Merges all KeyframeTracks that animate morph targets on a single mesh. The clip provided will
+		be modified and returned.
+		</p>
+		<p>
+		If a clip contains three tracks each controlling one of an object's five morph targets, those
+		three tracks will be merged and two empty tracks created for the remaining morph targets, so
+		that all morph targets are controlled by a single track.
+		</p>
+
 		<h3>[method:Array sortedArray]( values, stride, order )</h3>
 		<p>
 		Sorts the array previously returned by [page:AnimationUtils.getKeyframeOrder getKeyframeOrder].

+ 3 - 100
examples/js/exporters/GLTFExporter.js

@@ -286,105 +286,6 @@ THREE.GLTFExporter.prototype = {
 
 		}
 
-		/**
-		 * Merges KeyframeTracks that animate morph targets on a given object. In
-		 * three.js it is possible to have separate tracks for each morph target,
-		 * but in glTF a clip must animate all morph targets simultaneously.
-		 *
-		 * @param  {Array<KeyframeTrack>} sourceTracks
-		 * @param  {THREE.Object3D} root
-		 * @return {Array<KeyframeTrack>}
-		 */
-		function mergeMorphTargetTracks( sourceTracks, root ) {
-
-			var tracks = [];
-			var mergedTracks = {};
-
-			for ( var i = 0; i < sourceTracks.length; ++ i ) {
-
-				var sourceTrack = sourceTracks[ i ];
-				var sourceTrackBinding = THREE.PropertyBinding.parseTrackName( sourceTrack.name );
-				var sourceTrackNode = THREE.PropertyBinding.findNode( root, sourceTrackBinding.nodeName );
-
-				if ( sourceTrackBinding.propertyName !== 'morphTargetInfluences' ) {
-
-					// Tracks that don't affect morph targets can be kept as-is.
-					tracks.push( sourceTrack );
-					continue;
-
-				}
-
-				if ( sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete
-					&& sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear ) {
-
-					if ( sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
-
-						// This should never happen, because glTF morph target animations
-						// affect all targets already.
-						throw new Error( 'THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.' );
-
-					}
-
-					console.warn( 'THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.' );
-
-					sourceTrack = sourceTrack.clone();
-					sourceTrack.setInterpolation( THREE.InterpolateLinear );
-
-				}
-
-				var targetCount = sourceTrackNode.morphTargetInfluences.length;
-				var targetIndex = sourceTrackNode.morphTargetDictionary[ sourceTrackBinding.propertyIndex ];
-
-				if ( targetIndex === undefined ) {
-
-					throw new Error( 'THREE.AnimationUtils: Morph target name not found: ' + sourceTrackBinding.propertyIndex );
-
-				}
-
-				var mergedTrack;
-
-				// If this is the first time we've seen this object, create a new
-				// track to store merged keyframe data for each morph target.
-				if ( mergedTracks[ sourceTrackNode.uuid ] === undefined ) {
-
-					mergedTrack = sourceTrack.clone();
-
-					var values = new mergedTrack.ValueBufferType( targetCount * mergedTrack.times.length );
-
-					for ( var j = 0; j < mergedTrack.times.length; j ++ ) {
-
-						values[ j * targetCount + targetIndex ] = mergedTrack.values[ j ];
-
-					}
-
-					mergedTrack.name = '.morphTargetInfluences';
-					mergedTrack.values = values;
-
-					mergedTracks[ sourceTrackNode.uuid ] = mergedTrack;
-					tracks.push( mergedTrack );
-
-					continue;
-
-				}
-
-				var sourceKeyframeIndex = 0;
-				var mergedKeyframeIndex = 0;
-
-				mergedTrack = mergedTracks[ sourceTrackNode.uuid ];
-
-				for ( var j = 0; j < sourceTrack.times.length; j ++ ) {
-
-					var keyframeIndex = THREE.AnimationUtils.insertKeyframe( mergedTrack, sourceTrack.times[ j ] );
-					mergedTrack.values[ keyframeIndex * targetCount + targetIndex ] = sourceTrack.values[ j ];
-
-				}
-
-			}
-
-			return tracks;
-
-		}
-
 		/**
 		 * Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
 		 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
@@ -1507,7 +1408,9 @@ THREE.GLTFExporter.prototype = {
 
 			}
 
-			var tracks = mergeMorphTargetTracks( clip.tracks, root );
+			THREE.AnimationUtils.mergeMorphTargetTracks( clip, root );
+
+			var tracks = clip.tracks;
 			var channels = [];
 			var samplers = [];
 

+ 93 - 0
src/animation/AnimationUtils.js

@@ -242,6 +242,99 @@ var AnimationUtils = {
 
 		return index;
 
+	},
+
+	mergeMorphTargetTracks: function ( clip, root ) {
+
+		var tracks = [];
+		var mergedTracks = {};
+		var sourceTracks = clip.tracks;
+
+		for ( var i = 0; i < sourceTracks.length; ++ i ) {
+
+			var sourceTrack = sourceTracks[ i ];
+			var sourceTrackBinding = THREE.PropertyBinding.parseTrackName( sourceTrack.name );
+			var sourceTrackNode = THREE.PropertyBinding.findNode( root, sourceTrackBinding.nodeName );
+
+			if ( sourceTrackBinding.propertyName !== 'morphTargetInfluences' ) {
+
+				// Tracks that don't affect morph targets can be kept as-is.
+				tracks.push( sourceTrack );
+				continue;
+
+			}
+
+			if ( sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete
+				&& sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear ) {
+
+				if ( sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
+
+					// This should never happen, because glTF morph target animations
+					// affect all targets already.
+					throw new Error( 'THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.' );
+
+				}
+
+				console.warn( 'THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.' );
+
+				sourceTrack = sourceTrack.clone();
+				sourceTrack.setInterpolation( THREE.InterpolateLinear );
+
+			}
+
+			var targetCount = sourceTrackNode.morphTargetInfluences.length;
+			var targetIndex = sourceTrackNode.morphTargetDictionary[ sourceTrackBinding.propertyIndex ];
+
+			if ( targetIndex === undefined ) {
+
+				throw new Error( 'THREE.AnimationUtils: Morph target name not found: ' + sourceTrackBinding.propertyIndex );
+
+			}
+
+			var mergedTrack;
+
+			// If this is the first time we've seen this object, create a new
+			// track to store merged keyframe data for each morph target.
+			if ( mergedTracks[ sourceTrackNode.uuid ] === undefined ) {
+
+				mergedTrack = sourceTrack.clone();
+
+				var values = new mergedTrack.ValueBufferType( targetCount * mergedTrack.times.length );
+
+				for ( var j = 0; j < mergedTrack.times.length; j ++ ) {
+
+					values[ j * targetCount + targetIndex ] = mergedTrack.values[ j ];
+
+				}
+
+				mergedTrack.name = '.morphTargetInfluences';
+				mergedTrack.values = values;
+
+				mergedTracks[ sourceTrackNode.uuid ] = mergedTrack;
+				tracks.push( mergedTrack );
+
+				continue;
+
+			}
+
+			var sourceKeyframeIndex = 0;
+			var mergedKeyframeIndex = 0;
+
+			mergedTrack = mergedTracks[ sourceTrackNode.uuid ];
+
+			for ( var j = 0; j < sourceTrack.times.length; j ++ ) {
+
+				var keyframeIndex = THREE.AnimationUtils.insertKeyframe( mergedTrack, sourceTrack.times[ j ] );
+				mergedTrack.values[ keyframeIndex * targetCount + targetIndex ] = sourceTrack.values[ j ];
+
+			}
+
+		}
+
+		clip.tracks = tracks;
+
+		return clip;
+
 	}
 
 };