Browse Source

initial attempt at implementing @mrdoob's suggestion here: https://github.com/mrdoob/three.js/pull/6934#discussion_r36212808

Ben Houston 10 years ago
parent
commit
ef5fc2e00c

+ 7 - 7
examples/js/AnimationClipCreator.js

@@ -34,7 +34,7 @@ THREE.AnimationClipCreator.CreateMorphAnimation = function( morphTargets, durati
 
 		var morphName = morphTargets[i].name;
 		var trackName = '.morphTargetInfluences[' + morphName + ']';
-		var track = new THREE.KeyframeTrack( trackName, keys );
+		var track = new THREE.NumberKeyframeTrack( trackName, keys );
 
 		tracks.push( track );
 	}
@@ -54,7 +54,7 @@ THREE.AnimationClipCreator.CreateRotationAnimation = function( period, axis ) {
 	axis = axis || 'x';
 	var trackName = '.rotation[' + axis + ']';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.NumberKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'rotate.x', 10, [ track ] );
 	//console.log( 'rotateClip', clip );
@@ -71,7 +71,7 @@ THREE.AnimationClipCreator.CreateScaleAxisAnimation = function( period, axis ) {
 	axis = axis || 'x';
 	var trackName = '.scale[' + axis + ']';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.NumberKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'scale.x', 10, [ track ] );
 	//console.log( 'scaleClip', clip );
@@ -94,7 +94,7 @@ THREE.AnimationClipCreator.CreateShakeAnimation = function( duration, shakeScale
 
 	var trackName = '.position';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.VectorKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'shake' + duration, duration, [ track ] );
 	//console.log( 'shakeClip', clip );
@@ -119,7 +119,7 @@ THREE.AnimationClipCreator.CreatePulsationAnimation = function( duration, pulseS
 
 	var trackName = '.scale';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.VectorKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'scale' + duration, duration, [ track ] );
 	//console.log( 'scaleClip', clip );
@@ -146,7 +146,7 @@ THREE.AnimationClipCreator.CreateVisibilityAnimation = function( duration ) {
 
 	var trackName = '.visible';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.BooleanKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'visible' + duration, duration, [ track ] );
 	//console.log( 'scaleClip', clip );
@@ -165,7 +165,7 @@ THREE.AnimationClipCreator.CreateMaterialColorAnimation = function( duration, co
 
 	var trackName = '.material[0].color';
 
-	var track = new THREE.KeyframeTrack( trackName, keys );
+	var track = new THREE.ColorKeyframeTrack( trackName, keys );
 
 	var clip = new THREE.AnimationClip( 'colorDiffuse', 10, [ track ] );
 	//console.log( 'diffuseClip', clip );

+ 8 - 8
src/animation/AnimationClip.js

@@ -95,7 +95,7 @@ THREE.AnimationClip.CreateMorphAnimationFromNames = function( morphTargetNames,
 
 		var morphName = morphTargetNames[i];
 		var trackName = '.morphTargetInfluences[' + morphName + ']';
-		var track = new THREE.KeyframeTrack( trackName, keys );
+		var track = new THREE.NumberKeyframeTrack( trackName, keys );
 
 		tracks.push( track );
 	}
@@ -170,7 +170,7 @@ THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeNa
 		return null;
 	}
 
-	var convertTrack = function( trackName, animationKeys, propertyName, animationKeyToValueFunc ) {
+	var convertTrack = function( trackName, animationKeys, propertyName, trackType, animationKeyToValueFunc ) {
 
 		var keys = [];
 
@@ -187,8 +187,8 @@ THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeNa
 
 		// only return track if there are actually keys.
 		if( keys.length > 0 ) {
-
-			return new THREE.KeyframeTrack( trackName, keys );
+		
+			return new trackType( trackName, keys );
 
 		}
 
@@ -245,7 +245,7 @@ THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeNa
 				
 				}
 
-				tracks.push( new THREE.KeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) );
+				tracks.push( new THREE.NumberKeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) );
 
 			}
 
@@ -257,14 +257,14 @@ THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeNa
 			var boneName = nodeName + '.bones[' + bones[ h ].name + ']';
 		
 			// track contains positions...
-			var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', function( animationKey ) {
+			var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', THREE.VectorKeyframeTrack, function( animationKey ) {
 					return new THREE.Vector3().fromArray( animationKey.pos )
 				} );
 
 			if( positionTrack ) tracks.push( positionTrack );
 			
 			// track contains quaternions...
-			var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', function( animationKey ) {
+			var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', THREE.QuaternionKeyframeTrack, function( animationKey ) {
 					if( animationKey.rot.slerp ) {
 						return animationKey.rot.clone();
 					}
@@ -276,7 +276,7 @@ THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeNa
 			if( quaternionTrack ) tracks.push( quaternionTrack );
 
 			// track contains quaternions...
-			var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', function( animationKey ) {
+			var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', THREE.VectorKeyframeTrack, function( animationKey ) {
 					return new THREE.Vector3().fromArray( animationKey.scl )
 				} );
 

+ 42 - 0
src/animation/BooleanKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Boolean
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.BooleanKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value;
+
+};
+
+THREE.BooleanKeyframeTrack.prototype = {
+
+	constructor: THREE.BooleanKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result = value;
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return ( alpha < 1.0 ) ? value0 : value1;
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return ( value0 === value1 );
+
+	}
+
+};

+ 31 - 30
src/animation/KeyframeTrack.js

@@ -13,9 +13,6 @@ THREE.KeyframeTrack = function ( name, keys ) {
 	this.name = name;
 	this.keys = keys;	// time in seconds, value as value
 
-	// local cache of value type to avoid allocations during runtime.
-	this.result = THREE.AnimationUtils.clone( this.keys[0].value );
-
 	// the index of the last result, used as a starting point for local search.
 	this.lastIndex = 0;
 
@@ -73,6 +70,7 @@ THREE.KeyframeTrack.prototype = {
 
 	},
 
+	// required implementations:
 	setResult: function( value ) {
 
 		if( this.result.copy ) {
@@ -181,14 +179,14 @@ THREE.KeyframeTrack.prototype = {
 			}
 
 			// remove completely unnecessary keyframes that are the same as their prev and next keys
-			if( equalsFunc( prevKey.value, currKey.value ) && equalsFunc( currKey.value, nextKey.value ) ) {
+			if( this.compareValues( prevKey.value, currKey.value ) && this.compareValues( currKey.value, nextKey.value ) ) {
 
 				continue;
 
 			}
 
 			// determine if interpolation is required
-			prevKey.constantToNext = equalsFunc( prevKey.value, currKey.value );
+			prevKey.constantToNext = this.compareValues( prevKey.value, currKey.value );
 
 			newKeys.push( currKey );
 			prevKey = currKey;
@@ -197,34 +195,37 @@ THREE.KeyframeTrack.prototype = {
 
 		this.keys = newKeys;
 
-	},
+	}
 
-	// removes keyframes before and after animation without changing any values within the range [0,duration].
-	// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values
- 	trim: function( duration ) {
-		
-		var firstKeysToRemove = 0;
-		for( var i = 1; i < this.keys.length; i ++ ) {
-			if( this.keys[i] <= 0 ) {
-				firstKeysToRemove ++;
-			}
-		}
+};
 
-		var lastKeysToRemove = 0;
-		for( var i = this.keys.length - 2; i > 0; i ++ ) {
-			if( this.keys[i] >= duration ) {
-				lastKeysToRemove ++;
-			}
-			else {
-				break;
-			}
-		}
 
-		// remove last keys first because it doesn't affect the position of the first keys (the otherway around doesn't work as easily)
-		if( ( firstKeysToRemove + lastKeysToRemove ) > 0 ) {
-			this.keys = this.keys.splice( firstKeysToRemove, this.keys.length - lastKeysToRemove - firstKeysToRemove );;
-		}
+THREE.KeyframeTrack.GetTrackTypeForValue = function( value ) {
+	switch( typeof value ) {
+	 	case "object": {
 
-	}
+			if( value.lerp ) {
 
+				return THREE.VectorKeyframeTrack;
+
+			}
+			if( value.slerp ) {
+
+				return THREE.QuaternionKeyframeTrack;
+
+			}
+			break;
+		}
+	 	case "number": {
+			return THREE.NumberKeyframeTrack;
+	 	}	
+	 	case "boolean": {
+			return THREE.BooleanKeyframeTrack;
+	 	}
+	 	case "string": {
+	 		return THREE.StringKeyframeTrack;
+	 	}
+	};
+
+	throw new Error( "Unsupported value type" );
 };

+ 42 - 0
src/animation/tracks/BooleanKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Boolean
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.BooleanKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value;
+
+};
+
+THREE.BooleanKeyframeTrack.prototype = {
+
+	constructor: THREE.BooleanKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result = value;
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return ( alpha < 1.0 ) ? value0 : value1;
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return ( value0 === value1 );
+
+	}
+
+};

+ 42 - 0
src/animation/tracks/ColorKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Color
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.ColorKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value.clone();
+
+};
+
+THREE.ColorKeyframeTrack.prototype = {
+
+	constructor: THREE.ColorKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result.copy( value );
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return value0.slerp( value1, alpha );
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return value0.equals( value1 );
+
+	}
+
+};

+ 42 - 0
src/animation/tracks/NumberKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Numbers
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.NumberKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value;
+
+};
+
+THREE.NumberKeyframeTrack.prototype = {
+
+	constructor: THREE.NumberKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result = value;
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return value0 * ( 1 - alpha ) + value1 * alpha;
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return ( value0 === value1 );
+
+	}
+
+};

+ 42 - 0
src/animation/tracks/QuaternionKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Quaternion
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.QuaternionKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value.clone();
+
+};
+
+THREE.QuaternionKeyframeTrack.prototype = {
+
+	constructor: THREE.QuaternionKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result.copy( value );
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return value0.lerp( value1, alpha );
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return value0.equals( value1 );
+
+	}
+
+};

+ 42 - 0
src/animation/tracks/StringKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Strings
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.StringKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value;
+
+};
+
+THREE.StringKeyframeTrack.prototype = {
+
+	constructor: THREE.StringKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result = value;
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return ( alpha < 1.0 ) ? value0 : value1;
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return ( value0 === value1 );
+
+	}
+
+};

+ 42 - 0
src/animation/tracks/VectorKeyframeTrack.js

@@ -0,0 +1,42 @@
+/**
+ *
+ * A Track that interpolates Vectors
+ * 
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+THREE.VectorKeyframeTrack = function ( name, keys ) {
+
+	THREE.KeyframeTrack.call( this, name, keys );
+
+	// local cache of value type to avoid allocations during runtime.
+	this.result = this.keys[0].value.clone();
+
+};
+
+THREE.VectorKeyframeTrack.prototype = {
+
+	constructor: THREE.VectorKeyframeTrack,
+
+	setResult: function( value ) {
+
+		this.result.copy( value );
+
+	},
+
+	// memoization of the lerp function for speed.
+	// NOTE: Do not optimize as a prototype initialization closure, as value0 will be different on a per class basis.
+	lerpValues: function( value0, value1, alpha ) {
+
+		return value0.slerp( value1, alpha );
+
+	},
+
+	compareValues: function( value0, value1 ) {
+
+		return value0.equals( value1 );
+
+	}
+
+};

+ 5 - 0
utils/build/includes/common.json

@@ -40,6 +40,11 @@
 	"src/animation/AnimationUtils.js",
 	"src/animation/KeyframeTrack.js",
 	"src/animation/PropertyBinding.js",
+	"src/animation/track/VectorKeyframeTrack.js",
+	"src/animation/track/QuaternionKeyframeTrack.js",
+	"src/animation/track/StringKeyframeTrack.js",
+	"src/animation/track/BooleanKeyframeTrack.js",
+	"src/animation/track/NumberKeyframeTrack.js",
 	"src/cameras/Camera.js",
 	"src/cameras/CubeCamera.js",
 	"src/cameras/OrthographicCamera.js",