2
0
Эх сурвалжийг харах

interpolate euler rotations to allow converting to quaternions

Lewy Blue 7 жил өмнө
parent
commit
51addcd1f9

+ 74 - 15
examples/js/loaders/FBXLoader.js

@@ -2120,7 +2120,7 @@
 
 			var offset = animationCurve.times[ 0 ];
 
-			for ( var i = 0; i < animationCurve.times.length; i++ ) {
+			for ( var i = 0; i < animationCurve.times.length; i ++ ) {
 
 				animationCurve.times[ i ] -= offset;
 
@@ -2132,28 +2132,21 @@
 
 				var animationCurveID = relationships.parents[ 0 ].ID;
 				var animationCurveRelationship = relationships.parents[ 0 ].relationship;
-				var axis = '';
 
 				if ( animationCurveRelationship.match( /X/ ) ) {
 
-					axis = 'x';
+					curveNodesMap.get( animationCurveID ).curves[ 'x' ] = animationCurve;
 
 				} else if ( animationCurveRelationship.match( /Y/ ) ) {
 
-					axis = 'y';
+					curveNodesMap.get( animationCurveID ).curves[ 'y' ] = animationCurve;
 
 				} else if ( animationCurveRelationship.match( /Z/ ) ) {
 
-					axis = 'z';
-
-				} else {
-
-					continue;
+					curveNodesMap.get( animationCurveID ).curves[ 'z' ] = animationCurve;
 
 				}
 
-				curveNodesMap.get( animationCurveID ).curves[ axis ] = animationCurve;
-
 			}
 
 		}
@@ -2162,7 +2155,7 @@
 
 	// parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references
 	// to various AnimationCurveNodes and is referenced by an AnimationStack node
-	// note: theoretically a stack can multiple layers, however in practice there always seems to be one per stack
+	// note: theoretically a stack can have multiple layers, however in practice there always seems to be one per stack
 	function parseAnimationLayers( FBXTree, connections, curveNodesMap ) {
 
 		var rawLayers = FBXTree.Objects.AnimationLayer;
@@ -2356,9 +2349,24 @@
 
 	function generateRotationTrack( modelName, curves, initialValue, preRotations ) {
 
-		if ( curves.x !== undefined ) curves.x.values = curves.x.values.map( THREE.Math.degToRad );
-		if ( curves.y !== undefined ) curves.y.values = curves.y.values.map( THREE.Math.degToRad );
-		if ( curves.z !== undefined ) curves.z.values = curves.z.values.map( THREE.Math.degToRad );
+		if ( curves.x !== undefined ) {
+
+			interpolateRotations( curves.x );
+			curves.x.values = curves.x.values.map( THREE.Math.degToRad );
+
+		}
+		if ( curves.y !== undefined ) {
+
+			interpolateRotations( curves.y );
+			curves.y.values = curves.y.values.map( THREE.Math.degToRad );
+
+		}
+		if ( curves.z !== undefined ) {
+
+			interpolateRotations( curves.z );
+			curves.z.values = curves.z.values.map( THREE.Math.degToRad );
+
+		}
 
 		var times = getTimesForAllAxes( curves );
 		var values = getKeyframeTrackValues( times, curves, initialValue );
@@ -2480,6 +2488,50 @@
 
 	}
 
+	// Rotations are defined as Euler angles which can have values  of any size
+	// These will be converted to quaternions which don't support values greater than
+	// PI, so we'll interpolate large rotations
+	function interpolateRotations( curve ) {
+
+		for ( var i = 1; i < curve.values.length; i ++ ) {
+
+			var initialValue = curve.values[ i - 1 ];
+			var valuesSpan = curve.values[ i ] - initialValue;
+
+			if ( valuesSpan > 180 ) {
+
+				var numSubIntervals = Math.abs( valuesSpan / 180 );
+
+				var step = valuesSpan / numSubIntervals;
+				var nextValue = initialValue + step;
+
+				var initialTime = curve.times[ i - 1 ];
+				var timeSpan = curve.times[ i ] - initialTime;
+				var interval = timeSpan / numSubIntervals;
+				var nextTime = initialTime + interval;
+
+				var interpolatedTimes = [];
+				var interpolatedValues = [];
+
+				while ( nextTime < curve.times[ i ] ) {
+
+					interpolatedTimes.push( nextTime );
+					nextTime += interval;
+
+					interpolatedValues.push( nextValue );
+					nextValue += step;
+
+				}
+
+				curve.times = inject( curve.times, i, interpolatedTimes );
+				curve.values = inject( curve.values, i, interpolatedValues );
+
+			}
+
+		}
+
+	}
+
 	// parse an FBX file in ASCII format
 	function TextParser() {}
 
@@ -3504,4 +3556,11 @@
 
 	}
 
+	// inject array a2 into array a1 at index
+	function inject( a1, index, a2 ) {
+
+		return a1.slice( 0, index ).concat( a2 ).concat( a1.slice( index ) );
+
+	}
+
 } )();