瀏覽代碼

Animation system clean up. Fixes #4377.

Mr.doob 11 年之前
父節點
當前提交
52f78940ac

+ 3 - 9
examples/js/loaders/ColladaLoader.js

@@ -4220,7 +4220,7 @@ THREE.ColladaLoader = function () {
 	// TODO: Currently only doing linear interpolation. Should support full COLLADA spec.
 	Key.prototype.interpolate = function ( nextKey, time ) {
 
-		for ( var i = 0; i < this.targets.length; ++i ) {
+		for ( var i = 0, l = this.targets.length; i < l; i ++ ) {
 
 			var target = this.targets[ i ],
 				nextTarget = nextKey.getTarget( target.sid ),
@@ -4232,14 +4232,8 @@ THREE.ColladaLoader = function () {
 					nextData = nextTarget.data,
 					prevData = target.data;
 
-				// check scale error
-
-				if ( scale < 0 || scale > 1 ) {
-
-					console.log( "Key.interpolate: Warning! Scale out of bounds:" + scale );
-					scale = scale < 0 ? 0 : 1;
-
-				}
+				if ( scale < 0 ) scale = 0;
+				if ( scale > 1 ) scale = 1;
 
 				if ( prevData.length ) {
 

+ 1 - 2
examples/webgl_animation_skinning.html

@@ -190,8 +190,7 @@
 
 				for( var i = 0; i < animations.length; i ++ ) {
 
-					animations[ i ].offset = 0.05 * Math.random();
-					animations[ i ].play();
+					animations[ i ].play( 0.05 * Math.random() );
 
 				}
 

+ 1 - 1
examples/webgl_animation_skinning_morph.html

@@ -246,7 +246,7 @@
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 
-				animation = new THREE.Animation( mesh, geometry.animation.name );
+				var animation = new THREE.Animation( mesh, geometry.animation.name );
 				animation.play();
 
 			}

+ 2 - 2
examples/webgl_loader_collada_keyframe.html

@@ -120,8 +120,8 @@
 
 				// Add the COLLADA
 
-				model.getChildByName( 'camEye_camera', true ).visible = false;
-				model.getChildByName( 'camTarget_camera', true ).visible = false;
+				model.getObjectByName( 'camEye_camera', true ).visible = false;
+				model.getObjectByName( 'camTarget_camera', true ).visible = false;
 
 				scene.add( model );
 

+ 1 - 1
examples/webgl_loader_collada_skinning.html

@@ -97,7 +97,7 @@
 							skin,
 							skin.geometry.animation.name
 						  );
-						animation.loop = false;
+						// animation.loop = false;
 						animation.play();
 						
 					}

+ 69 - 108
src/extras/animation/Animation.js

@@ -32,36 +32,7 @@ THREE.Animation.prototype.play = function ( startTime ) {
 
 		this.isPlaying = true;
 
-		// reset key cache
-
-		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
-
-			var object = this.hierarchy[ h ];
-
-			object.matrixAutoUpdate = true;
-
-			if ( object.animationCache === undefined ) {
-
-				object.animationCache = {};
-				object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
-				object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
-				object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
-
-			}
-
-			var prevKey = object.animationCache.prevKey;
-			var nextKey = object.animationCache.nextKey;
-
-			prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
-			prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
-			prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
-
-			nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
-			nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
-			nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
-
-		}
-
+		this.reset();
 		this.update( 0 );
 
 	}
@@ -98,100 +69,85 @@ THREE.Animation.prototype.stop = function() {
 
 };
 
+THREE.Animation.prototype.reset = function () {
 
-THREE.Animation.prototype.update = function ( deltaTimeMS ) {
-
-	// early out
-
-	if ( this.isPlaying === false ) return;
+	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
+		var object = this.hierarchy[ h ];
 
-	// vars
+		object.matrixAutoUpdate = true;
 
-	var types = [ "pos", "rot", "scl" ];
-	var type;
-	var scale;
-	var vector;
-	var prevXYZ, nextXYZ;
-	var prevKey, nextKey;
-	var object;
-	var animationCache;
-	var frame;
-	var JIThierarchy = this.data.JIT.hierarchy;
-	var currentTime, unloopedCurrentTime;
-	var currentPoint, forwardPoint, angle;
+		if ( object.animationCache === undefined ) {
 
+			object.animationCache = {};
+			object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
+			object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
+			object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
 
-	this.currentTime += deltaTimeMS * this.timeScale;
+		}
 
-	unloopedCurrentTime = this.currentTime;
+		var prevKey = object.animationCache.prevKey;
+		var nextKey = object.animationCache.nextKey;
 
-	// Mod operation fails on floats
-	// was this supposed to be in frames?
-	while ( this.currentTime > this.data.length ) {
+		prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
+		prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
+		prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
 
-		this.currentTime -= this.data.length;
+		nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
+		nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
+		nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
 
 	}
 
-	currentTime = this.currentTime = this.currentTime % this.data.length;
-
-	
-	frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
-
+};
 
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-		object = this.hierarchy[ h ];
-		animationCache = object.animationCache;
+THREE.Animation.prototype.update = function ( delta ) {
 
-		// loop through pos/rot/scl
+	if ( this.isPlaying === false ) return;
 
-		for ( var t = 0; t < 3; t ++ ) {
+	this.currentTime += delta * this.timeScale;
 
-			// get keys
+	//
 
-			type    = types[ t ];
-			prevKey = animationCache.prevKey[ type ];
-			nextKey = animationCache.nextKey[ type ];
+	var vector;
+	var types = [ "pos", "rot", "scl" ];
 
-			// switch keys?
-			
-			if ( nextKey.time <= unloopedCurrentTime ) {
+	var duration = this.data.length;
+	var currentTime = this.currentTime;
 
-				// did we loop?
+	if ( this.loop === true ) {
 
-				if ( currentTime <= unloopedCurrentTime ) {
+		currentTime %= duration;
 
-					if ( this.loop ) {
+	}
 
-						prevKey = this.data.hierarchy[ h ].keys[ 0 ];
-						nextKey = this.getNextKeyWith( type, h, 1 );
+	currentTime = Math.min( currentTime, duration );
 
-						// if ( nextKey.index < prevKey.index ) then we have wrapped over the end, and nextKey.time < currentTime will loop forever
-						while ( nextKey !== null && nextKey.time < currentTime && nextKey.index > prevKey.index) {
+	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-							prevKey = nextKey;
-							nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+		var object = this.hierarchy[ h ];
+		var animationCache = object.animationCache;
 
-						}
+		// loop through pos/rot/scl
 
-					} else {
+		for ( var t = 0; t < 3; t ++ ) {
 
-						this.stop();
-						return;
+			// get keys
 
-					}
+			var type    = types[ t ];
+			var prevKey = animationCache.prevKey[ type ];
+			var nextKey = animationCache.nextKey[ type ];
 
-				} else {
+			if ( nextKey.time <= currentTime ) {
 
-					do {
+				prevKey = this.data.hierarchy[ h ].keys[ 0 ];
+				nextKey = this.getNextKeyWith( type, h, 1 );
 
-						prevKey = nextKey;
-						nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+				while ( nextKey.time < currentTime && nextKey.index > prevKey.index ) {
 
-					} while ( nextKey !== null && nextKey.time < currentTime && nextKey.index > prevKey.index )
-					// if ( nextKey.index < prevKey.index ) then we have wrapped over the end, and nextKey.time < currentTime will loop forever
+					prevKey = nextKey;
+					nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
 
 				}
 
@@ -200,23 +156,16 @@ THREE.Animation.prototype.update = function ( deltaTimeMS ) {
 
 			}
 
-
 			object.matrixAutoUpdate = true;
 			object.matrixWorldNeedsUpdate = true;
 
-			scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
-			prevXYZ = prevKey[ type ];
-			nextXYZ = nextKey[ type ];
-
+			var scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
 
-			// check scale error
+			var prevXYZ = prevKey[ type ];
+			var nextXYZ = nextKey[ type ];
 
-			if ( scale < 0 || scale > 1 ) {
-
-				console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h );
-				scale = scale < 0 ? 0 : 1;
-
-			}
+			if ( scale < 0 ) scale = 0;
+			if ( scale > 1 ) scale = 1;
 
 			// interpolate
 
@@ -231,7 +180,7 @@ THREE.Animation.prototype.update = function ( deltaTimeMS ) {
 					vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
 
 				} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-						    this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+					this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
 					this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
 					this.points[ 1 ] = prevXYZ;
@@ -240,7 +189,7 @@ THREE.Animation.prototype.update = function ( deltaTimeMS ) {
 
 					scale = scale * 0.33 + 0.33;
 
-					currentPoint = this.interpolateCatmullRom( this.points, scale );
+					var currentPoint = this.interpolateCatmullRom( this.points, scale );
 
 					vector.x = currentPoint[ 0 ];
 					vector.y = currentPoint[ 1 ];
@@ -248,14 +197,14 @@ THREE.Animation.prototype.update = function ( deltaTimeMS ) {
 
 					if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
-						forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 );
+						var forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 );
 
 						this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
 						this.target.sub( vector );
 						this.target.y = 0;
 						this.target.normalize();
 
-						angle = Math.atan2( this.target.x, this.target.z );
+						var angle = Math.atan2( this.target.x, this.target.z );
 						object.rotation.set( 0, angle, 0 );
 
 					}
@@ -280,6 +229,18 @@ THREE.Animation.prototype.update = function ( deltaTimeMS ) {
 
 	}
 
+	if ( this.currentTime > duration ) {
+
+		this.reset();
+
+		if ( this.loop === false ) {
+
+			this.stop();
+
+		}
+
+	}
+
 };
 
 // Catmull-Rom spline
@@ -364,7 +325,7 @@ THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {
 	var keys = this.data.hierarchy[ h ].keys;
 
 	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+		this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
 		key = key > 0 ? key : 0;
 

+ 0 - 12
src/extras/animation/AnimationHandler.js

@@ -228,18 +228,6 @@ THREE.AnimationHandler = (function() {
 
 		}
 
-
-		// JIT
-
-		var lengthInFrames = parseInt( data.length * data.fps, 10 );
-
-		data.JIT = {};
-		data.JIT.hierarchy = [];
-
-		for( var h = 0; h < data.hierarchy.length; h ++ )
-			data.JIT.hierarchy.push( new Array( lengthInFrames ) );
-
-
 		// done
 
 		data.initialized = true;

+ 4 - 5
src/extras/animation/AnimationMorphTarget.js

@@ -19,14 +19,13 @@ THREE.AnimationMorphTarget = function( root, data ) {
  * Play
  */
 
-THREE.AnimationMorphTarget.prototype.play = function( loop, startTimeMS ) {
+THREE.AnimationMorphTarget.prototype.play = function ( startTime ) {
 
-	if( !this.isPlaying ) {
+	this.currentTime = startTime !== undefined ? startTime : 0;
 
-		this.isPlaying = true;
-		this.loop = loop !== undefined ? loop : true;
-		this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
+	if ( this.isPlaying === false ) {
 
+		this.isPlaying = true;
 
 		// reset key cache
 

+ 34 - 179
src/extras/animation/KeyFrameAnimation.js

@@ -6,7 +6,7 @@
  * @author erik kitson
  */
 
-THREE.KeyFrameAnimation = function( root, data, JITCompile ) {
+THREE.KeyFrameAnimation = function ( root, data ) {
 
 	this.root = root;
 	this.data = THREE.AnimationHandler.get( data );
@@ -16,11 +16,10 @@ THREE.KeyFrameAnimation = function( root, data, JITCompile ) {
 	this.isPlaying = false;
 	this.isPaused = true;
 	this.loop = true;
-	this.JITCompile = JITCompile !== undefined ? JITCompile : true;
 
 	// initialize to first keyframes
 
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
+	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
 		var keys = this.data.hierarchy[h].keys,
 			sids = this.data.hierarchy[h].sids,
@@ -53,17 +52,13 @@ THREE.KeyFrameAnimation = function( root, data, JITCompile ) {
 
 // Play
 
-THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) {
+THREE.KeyFrameAnimation.prototype.play = function ( startTime ) {
 
-	if( !this.isPlaying ) {
+	this.currentTime = startTime !== undefined ? startTime : 0;
 
-		this.isPlaying = true;
-		this.loop = loop !== undefined ? loop : true;
-		this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
-		this.startTimeMs = startTimeMS;
-		this.startTime = 10000000;
-		this.endTime = -this.startTime;
+	if ( this.isPlaying === false ) {
 
+		this.isPlaying = true;
 
 		// reset key cache
 
@@ -136,14 +131,14 @@ THREE.KeyFrameAnimation.prototype.stop = function() {
 
 	this.isPlaying = false;
 	this.isPaused  = false;
-	THREE.AnimationHandler.removeFromUpdate( this );
 
+	THREE.AnimationHandler.removeFromUpdate( this );
 
 	// reset JIT matrix and remove cache
 
 	for ( var h = 0; h < this.data.hierarchy.length; h++ ) {
         
-        var obj = this.hierarchy[ h ];
+		var obj = this.hierarchy[ h ];
 		var node = this.data.hierarchy[ h ];
 
 		if ( node.animationCache !== undefined ) {
@@ -173,210 +168,70 @@ THREE.KeyFrameAnimation.prototype.stop = function() {
 
 // Update
 
-THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) {
-
-	// early out
-
-	if( !this.isPlaying ) return;
-
-
-	// vars
-
-	var prevKey, nextKey;
-	var object;
-	var node;
-	var frame;
-	var JIThierarchy = this.data.JIT.hierarchy;
-	var currentTime, unloopedCurrentTime;
-	var looped;
-
-
-	// update
-
-	this.currentTime += deltaTimeMS * this.timeScale;
-
-	unloopedCurrentTime = this.currentTime;
-	currentTime         = this.currentTime = this.currentTime % this.data.length;
-
-	// if looped around, the current time should be based on the startTime
-	if ( currentTime < this.startTimeMs ) {
-
-		currentTime = this.currentTime = this.startTimeMs + currentTime;
-
-	}
-
-	frame               = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
-	looped 				= currentTime < unloopedCurrentTime;
-
-	if ( looped && !this.loop ) {
+THREE.KeyFrameAnimation.prototype.update = function ( delta ) {
 
-		// Set the animation to the last keyframes and stop
-		for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
+	if ( this.isPlaying === false ) return;
 
-			var keys = this.data.hierarchy[h].keys,
-				sids = this.data.hierarchy[h].sids,
-				end = keys.length-1,
-				obj = this.hierarchy[h];
+	this.currentTime += delta * this.timeScale;
 
-			if ( keys.length ) {
+	//
 
-				for ( var s = 0; s < sids.length; s++ ) {
+	var duration = this.data.length;
+	var currentTime = this.currentTime;
 
-					var sid = sids[ s ],
-						prev = this.getPrevKeyWith( sid, h, end );
+	if ( this.loop === true ) {
 
-					if ( prev ) {
-						prev.apply( sid );
-
-					}
-
-				}
-
-				this.data.hierarchy[h].node.updateMatrix();
-				obj.matrixWorldNeedsUpdate = true;
-
-			}
-
-		}
-
-		this.stop();
-		return;
-
-	}
-
-	// check pre-infinity
-	if ( currentTime < this.startTime ) {
-
-		return;
+		currentTime %= duration;
 
 	}
 
-	// update
+	currentTime = Math.min( currentTime, duration );
 
 	for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
 
-		object = this.hierarchy[ h ];
-		node = this.data.hierarchy[ h ];
+		var object = this.hierarchy[ h ];
+		var node = this.data.hierarchy[ h ];
 
 		var keys = node.keys,
 			animationCache = node.animationCache;
 
-		// use JIT?
-
-		if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) {
-
-			if( object instanceof THREE.Bone ) {
-
-				object.skinMatrix = JIThierarchy[ h ][ frame ];
-				object.matrixWorldNeedsUpdate = false;
-
-			} else {
-
-				object.matrix = JIThierarchy[ h ][ frame ];
-				object.matrixWorldNeedsUpdate = true;
 
-			}
-
-		// use interpolation
-
-		} else if ( keys.length ) {
-
-			// make sure so original matrix and not JIT matrix is set
-
-			if ( this.JITCompile && animationCache ) {
+		if ( keys.length ) {
 
-				if( object instanceof THREE.Bone ) {
+			var prevKey = animationCache.prevKey;
+			var nextKey = animationCache.nextKey;
 
-					object.skinMatrix = animationCache.originalMatrix;
+			if ( nextKey.time <= currentTime ) {
 
-				} else {
+				while ( nextKey.time < currentTime && nextKey.index > prevKey.index ) {
 
-					object.matrix = animationCache.originalMatrix;
+					prevKey = nextKey;
+					nextKey = keys[ prevKey.index + 1 ];
 
 				}
 
-			}
-
-			prevKey = animationCache.prevKey;
-			nextKey = animationCache.nextKey;
-
-			if ( prevKey && nextKey ) {
-
-				// switch keys?
-
-				if ( nextKey.time <= unloopedCurrentTime ) {
+				animationCache.prevKey = prevKey;
+				animationCache.nextKey = nextKey;
 
-					// did we loop?
-
-					if ( looped && this.loop ) {
-
-						prevKey = keys[ 0 ];
-						nextKey = keys[ 1 ];
-
-						while ( nextKey.time < currentTime ) {
-
-							prevKey = nextKey;
-							nextKey = keys[ prevKey.index + 1 ];
-
-						}
-
-					} else if ( !looped ) {
-
-						var lastIndex = keys.length - 1;
-
-						while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) {
-
-							prevKey = nextKey;
-							nextKey = keys[ prevKey.index + 1 ];
+			}
 
-						}
+			if ( nextKey.time >= currentTime ) {
 
-					}
+				prevKey.interpolate( nextKey, currentTime );
 
-					animationCache.prevKey = prevKey;
-					animationCache.nextKey = nextKey;
+			} else {
 
-				}
-                if(nextKey.time >= currentTime)
-                    prevKey.interpolate( nextKey, currentTime );
-                else
-                    prevKey.interpolate( nextKey, nextKey.time);
+				prevKey.interpolate( nextKey, nextKey.time );
 
 			}
 
-			this.data.hierarchy[h].node.updateMatrix();
+			this.data.hierarchy[ h ].node.updateMatrix();
 			object.matrixWorldNeedsUpdate = true;
 
 		}
 
 	}
 
-	// update JIT?
-
-	if ( this.JITCompile ) {
-
-		if ( JIThierarchy[ 0 ][ frame ] === undefined ) {
-
-			this.hierarchy[ 0 ].updateMatrixWorld( true );
-
-			for ( var h = 0; h < this.hierarchy.length; h++ ) {
-
-				if( this.hierarchy[ h ] instanceof THREE.Bone ) {
-
-					JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();
-
-				} else {
-
-					JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone();
-
-				}
-
-			}
-
-		}
-
-	}
-
 };
 
 // Get next key with