Animation.js 8.5 KB
Newer Older
1 2
/**
 * @author mikael emtinger / http://gomo.se/
A
alteredq 已提交
3
 * @author mrdoob / http://mrdoob.com/
4
 * @author alteredq / http://alteredqualia.com/
5 6
 */

M
Mr.doob 已提交
7
THREE.Animation = function ( root, name, interpolationType ) {
M
Mr.doob 已提交
8 9

	this.root = root;
10
	this.data = THREE.AnimationHandler.get( name );
M
Mikael Emtinger 已提交
11
	this.hierarchy = THREE.AnimationHandler.parse( root );
12

M
Mikael Emtinger 已提交
13
	this.currentTime = 0;
14
	this.timeScale = 1;
15

16
	this.isPlaying = false;
M
Mikael Emtinger 已提交
17
	this.isPaused = true;
M
Mr.doob 已提交
18
	this.loop = true;
19

M
Mikael Emtinger 已提交
20
	this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR;
21

A
alteredq 已提交
22
	this.points = [];
23
	this.target = new THREE.Vector3();
A
alteredq 已提交
24 25 26

};

M
Mr.doob 已提交
27
THREE.Animation.prototype.play = function ( loop, startTimeMS ) {
28

M
Mr.doob 已提交
29
	if ( this.isPlaying === false ) {
M
Mr.doob 已提交
30

31
		this.isPlaying = true;
M
Mikael Emtinger 已提交
32 33 34
		this.loop = loop !== undefined ? loop : true;
		this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;

35
		// reset key cache
M
Mr.doob 已提交
36

A
alteredq 已提交
37
		var h, hl = this.hierarchy.length,
38
			object;
39

40
		for ( h = 0; h < hl; h ++ ) {
M
Mr.doob 已提交
41

A
alteredq 已提交
42
			object = this.hierarchy[ h ];
43

44 45 46 47 48
			if ( this.interpolationType !== THREE.AnimationHandler.CATMULLROM_FORWARD ) {

				object.useQuaternion = true;

			}
49

50
			object.matrixAutoUpdate = true;
M
Mr.doob 已提交
51

52
			if ( object.animationCache === undefined ) {
M
Mr.doob 已提交
53

54 55 56 57
				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;
58

59
			}
M
Mr.doob 已提交
60

61 62
			var prevKey = object.animationCache.prevKey;
			var nextKey = object.animationCache.nextKey;
M
Mr.doob 已提交
63

64 65 66
			prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
			prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
			prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
67

68 69 70
			nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
			nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
			nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
A
alteredq 已提交
71

M
Mikael Emtinger 已提交
72
		}
73

M
Mikael Emtinger 已提交
74
		this.update( 0 );
A
alteredq 已提交
75

76 77
	}

M
Mikael Emtinger 已提交
78 79 80
	this.isPaused = false;

	THREE.AnimationHandler.addToUpdate( this );
A
alteredq 已提交
81

82 83 84 85
};


THREE.Animation.prototype.pause = function() {
M
Mr.doob 已提交
86

M
Mr.doob 已提交
87
	if ( this.isPaused === true ) {
88

M
Mikael Emtinger 已提交
89
		THREE.AnimationHandler.addToUpdate( this );
90

M
Mikael Emtinger 已提交
91
	} else {
92

M
Mikael Emtinger 已提交
93
		THREE.AnimationHandler.removeFromUpdate( this );
94

M
Mikael Emtinger 已提交
95
	}
96

M
Mikael Emtinger 已提交
97
	this.isPaused = !this.isPaused;
98

A
alteredq 已提交
99
};
100

A
alteredq 已提交
101

102
THREE.Animation.prototype.stop = function() {
M
Mr.doob 已提交
103

104
	this.isPlaying = false;
M
Mikael Emtinger 已提交
105
	this.isPaused  = false;
M
Mikael Emtinger 已提交
106
	THREE.AnimationHandler.removeFromUpdate( this );
107

A
alteredq 已提交
108
};
109 110


M
Mr.doob 已提交
111
THREE.Animation.prototype.update = function ( deltaTimeMS ) {
112 113

	// early out
M
Mr.doob 已提交
114

M
Mr.doob 已提交
115
	if ( this.isPlaying === false ) return;
116 117 118


	// vars
M
Mr.doob 已提交
119

120 121 122 123 124
	var types = [ "pos", "rot", "scl" ];
	var type;
	var scale;
	var vector;
	var prevXYZ, nextXYZ;
M
Mikael Emtinger 已提交
125
	var prevKey, nextKey;
126
	var object;
127
	var animationCache;
128 129
	var frame;
	var JIThierarchy = this.data.JIT.hierarchy;
M
Mikael Emtinger 已提交
130
	var currentTime, unloopedCurrentTime;
131
	var currentPoint, forwardPoint, angle;
132

M
Mr.doob 已提交
133

M
Mikael Emtinger 已提交
134
	this.currentTime += deltaTimeMS * this.timeScale;
M
Mr.doob 已提交
135

M
Mikael Emtinger 已提交
136
	unloopedCurrentTime = this.currentTime;
M
Mr.doob 已提交
137 138
	currentTime = this.currentTime = this.currentTime % this.data.length;
	frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
139 140


141
	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
M
Mikael Emtinger 已提交
142

143
		object = this.hierarchy[ h ];
144
		animationCache = object.animationCache;
145

M
Mr.doob 已提交
146
		// loop through pos/rot/scl
147

M
Mr.doob 已提交
148
		for ( var t = 0; t < 3; t ++ ) {
149

M
Mr.doob 已提交
150
			// get keys
151

M
Mr.doob 已提交
152 153 154
			type    = types[ t ];
			prevKey = animationCache.prevKey[ type ];
			nextKey = animationCache.nextKey[ type ];
155

M
Mr.doob 已提交
156
			// switch keys?
A
alteredq 已提交
157

M
Mr.doob 已提交
158
			if ( nextKey.time <= unloopedCurrentTime ) {
159

M
Mr.doob 已提交
160
				// did we loop?
161

M
Mr.doob 已提交
162
				if ( currentTime < unloopedCurrentTime ) {
M
Mikael Emtinger 已提交
163

M
Mr.doob 已提交
164
					if ( this.loop ) {
165

M
Mr.doob 已提交
166 167
						prevKey = this.data.hierarchy[ h ].keys[ 0 ];
						nextKey = this.getNextKeyWith( type, h, 1 );
M
Mikael Emtinger 已提交
168

M
Mr.doob 已提交
169
						while( nextKey.time < currentTime ) {
M
Mikael Emtinger 已提交
170

M
Mr.doob 已提交
171 172
							prevKey = nextKey;
							nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
173

174
						}
175

176
					} else {
177

M
Mr.doob 已提交
178 179
						this.stop();
						return;
A
alteredq 已提交
180

M
Mikael Emtinger 已提交
181
					}
A
alteredq 已提交
182

M
Mr.doob 已提交
183
				} else {
184

M
Mr.doob 已提交
185
					do {
186

M
Mr.doob 已提交
187 188
						prevKey = nextKey;
						nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
189

M
Mr.doob 已提交
190
					} while( nextKey.time < currentTime )
191 192 193

				}

M
Mr.doob 已提交
194 195
				animationCache.prevKey[ type ] = prevKey;
				animationCache.nextKey[ type ] = nextKey;
196

M
Mr.doob 已提交
197
			}
198 199


M
Mr.doob 已提交
200 201
			object.matrixAutoUpdate = true;
			object.matrixWorldNeedsUpdate = true;
202

M
Mr.doob 已提交
203 204 205
			scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
			prevXYZ = prevKey[ type ];
			nextXYZ = nextKey[ type ];
206 207


M
Mr.doob 已提交
208
			// check scale error
209

M
Mr.doob 已提交
210
			if ( scale < 0 || scale > 1 ) {
211

M
Mr.doob 已提交
212 213
				console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h );
				scale = scale < 0 ? 0 : 1;
214

M
Mr.doob 已提交
215
			}
216

M
Mr.doob 已提交
217
			// interpolate
218

M
Mr.doob 已提交
219
			if ( type === "pos" ) {
220

M
Mr.doob 已提交
221
				vector = object.position;
222

M
Mr.doob 已提交
223
				if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
224 225 226 227 228

					vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
					vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
					vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;

M
Mr.doob 已提交
229 230
				} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
						    this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
231

M
Mr.doob 已提交
232 233 234 235
					this.points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
					this.points[ 1 ] = prevXYZ;
					this.points[ 2 ] = nextXYZ;
					this.points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];
236

M
Mr.doob 已提交
237
					scale = scale * 0.33 + 0.33;
A
alteredq 已提交
238

M
Mr.doob 已提交
239
					currentPoint = this.interpolateCatmullRom( this.points, scale );
M
Mr.doob 已提交
240

M
Mr.doob 已提交
241 242 243
					vector.x = currentPoint[ 0 ];
					vector.y = currentPoint[ 1 ];
					vector.z = currentPoint[ 2 ];
M
Mr.doob 已提交
244

M
Mr.doob 已提交
245
					if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
246

M
Mr.doob 已提交
247
						forwardPoint = this.interpolateCatmullRom( this.points, scale * 1.01 );
248

M
Mr.doob 已提交
249 250 251 252
						this.target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
						this.target.subSelf( vector );
						this.target.y = 0;
						this.target.normalize();
253

M
Mr.doob 已提交
254 255
						angle = Math.atan2( this.target.x, this.target.z );
						object.rotation.set( 0, angle, 0 );
256

M
Mr.doob 已提交
257
					}
258

M
Mr.doob 已提交
259
				}
260

M
Mr.doob 已提交
261
			} else if ( type === "rot" ) {
262

M
Mr.doob 已提交
263
				THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );
264

M
Mr.doob 已提交
265 266 267 268 269 270 271
			} else if ( type === "scl" ) {

				vector = object.scale;

				vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
				vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
				vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
272

M
Mikael Emtinger 已提交
273
			}
274

M
Mr.doob 已提交
275 276
		}

277 278 279 280
	}

};

A
alteredq 已提交
281
// Catmull-Rom spline
282

M
Mikael Emtinger 已提交
283 284 285 286 287
THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) {

	var c = [], v3 = [],
	point, intPoint, weight, w2, w3,
	pa, pb, pc, pd;
288

M
Mikael Emtinger 已提交
289 290 291 292
	point = ( points.length - 1 ) * scale;
	intPoint = Math.floor( point );
	weight = point - intPoint;

293
	c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
M
Mikael Emtinger 已提交
294 295 296 297 298 299 300 301 302 303 304
	c[ 1 ] = intPoint;
	c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
	c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;

	pa = points[ c[ 0 ] ];
	pb = points[ c[ 1 ] ];
	pc = points[ c[ 2 ] ];
	pd = points[ c[ 3 ] ];

	w2 = weight * weight;
	w3 = weight * w2;
305

M
Mikael Emtinger 已提交
306 307 308
	v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
	v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
	v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );
309

M
Mikael Emtinger 已提交
310
	return v3;
A
alteredq 已提交
311 312

};
313

M
Mr.doob 已提交
314
THREE.Animation.prototype.interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
M
Mikael Emtinger 已提交
315 316 317 318 319 320

	var v0 = ( p2 - p0 ) * 0.5,
		v1 = ( p3 - p1 ) * 0.5;

	return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;

A
alteredq 已提交
321
};
322

A
alteredq 已提交
323 324 325


// Get next key with
M
Mikael Emtinger 已提交
326

M
Mr.doob 已提交
327
THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) {
328

M
Mr.doob 已提交
329
	var keys = this.data.hierarchy[ h ].keys;
330

A
alteredq 已提交
331 332
	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
333

A
alteredq 已提交
334 335 336
		key = key < keys.length - 1 ? key : keys.length - 1;

	} else {
337

A
alteredq 已提交
338 339 340
		key = key % keys.length;

	}
341

M
Mr.doob 已提交
342
	for ( ; key < keys.length; key++ ) {
343

344
		if ( keys[ key ][ type ] !== undefined ) {
345

M
Mr.doob 已提交
346
			return keys[ key ];
347

M
Mr.doob 已提交
348
		}
349

M
Mr.doob 已提交
350
	}
351

352
	return this.data.hierarchy[ h ].keys[ 0 ];
353

A
alteredq 已提交
354 355 356
};

// Get previous key with
M
Mikael Emtinger 已提交
357

M
Mr.doob 已提交
358
THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {
359

M
Mikael Emtinger 已提交
360
	var keys = this.data.hierarchy[ h ].keys;
361

A
alteredq 已提交
362 363
	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
364

A
alteredq 已提交
365 366 367
		key = key > 0 ? key : 0;

	} else {
368

A
alteredq 已提交
369 370 371 372
		key = key >= 0 ? key : key + keys.length;

	}

M
Mikael Emtinger 已提交
373

374
	for ( ; key >= 0; key -- ) {
M
Mikael Emtinger 已提交
375

376
		if ( keys[ key ][ type ] !== undefined ) {
M
Mikael Emtinger 已提交
377 378 379 380 381 382 383

			return keys[ key ];

		}

	}

384
	return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
A
alteredq 已提交
385

M
Mr.doob 已提交
386
};