1
0

Animation.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. */
  4. THREE.Animation = function( root, data, interpolationType, JITCompile ) {
  5. this.root = root;
  6. this.data = THREE.AnimationHandler.get( data );
  7. this.hierarchy = THREE.AnimationHandler.parse( root );
  8. this.currentTime = 0;
  9. this.isPlaying = false;
  10. this.isPaused = true;
  11. this.loop = true;
  12. this.interpolationType = interpolationType !== undefined ? interpolationType : THREE.AnimationHandler.LINEAR;
  13. this.JITCompile = JITCompile !== undefined ? JITCompile : true;
  14. }
  15. /*
  16. * Play
  17. */
  18. THREE.Animation.prototype.play = function( loop, startTimeMS ) {
  19. if( !this.isPlaying ) {
  20. this.isPlaying = true;
  21. this.loop = loop !== undefined ? loop : true;
  22. this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
  23. // reset key cache
  24. for ( var h = 0; h < this.hierarchy.length; h++ ) {
  25. this.hierarchy[ h ].useQuaternion = true;
  26. this.hierarchy[ h ].matrixAutoUpdate = true;
  27. if ( this.hierarchy[ h ].animationCache === undefined ) {
  28. this.hierarchy[ h ].animationCache = {};
  29. this.hierarchy[ h ].animationCache.prevKey = { pos: 0, rot: 0, scl: 0 };
  30. this.hierarchy[ h ].animationCache.nextKey = { pos: 0, rot: 0, scl: 0 };
  31. this.hierarchy[ h ].animationCache.originalMatrix = this.hierarchy[ h ] instanceof THREE.Bone ? this.hierarchy[ h ].skinMatrix : this.hierarchy[ h ].matrix;
  32. }
  33. var prevKey = this.hierarchy[ h ].animationCache.prevKey;
  34. var nextKey = this.hierarchy[ h ].animationCache.nextKey;
  35. prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
  36. prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
  37. prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
  38. nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
  39. nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
  40. nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
  41. }
  42. this.update( 0 );
  43. }
  44. this.isPaused = false;
  45. THREE.AnimationHandler.addToUpdate( this );
  46. };
  47. /*
  48. * Pause
  49. */
  50. THREE.Animation.prototype.pause = function() {
  51. if( this.isPaused ) {
  52. THREE.AnimationHandler.addToUpdate( this );
  53. } else {
  54. THREE.AnimationHandler.removeFromUpdate( this );
  55. }
  56. this.isPaused = !this.isPaused;
  57. }
  58. /*
  59. * Stop
  60. */
  61. THREE.Animation.prototype.stop = function() {
  62. this.isPlaying = false;
  63. THREE.AnimationHandler.removeFromUpdate( this );
  64. // reset JIT matrix and remove cache
  65. for ( var h = 0; h < this.hierarchy.length; h++ ) {
  66. if ( this.hierarchy[ h ].animationCache !== undefined ) {
  67. if( this.hierarchy[ h ] instanceof THREE.Bone ) {
  68. this.hierarchy[ h ].skinMatrix = this.hierarchy[ h ].animationCache.originalMatrix;
  69. } else {
  70. this.hierarchy[ h ].matrix = this.hierarchy[ h ].animationCache.originalMatrix;
  71. }
  72. delete this.hierarchy[ h ].animationCache;
  73. }
  74. }
  75. }
  76. /*
  77. * Update
  78. */
  79. THREE.Animation.prototype.update = function( deltaTimeMS ) {
  80. // early out
  81. if( !this.isPlaying ) return;
  82. // vars
  83. var types = [ "pos", "rot", "scl" ];
  84. var type;
  85. var scale;
  86. var vector;
  87. var prevXYZ, nextXYZ;
  88. var prevKey, nextKey;
  89. var object;
  90. var animationCache;
  91. var frame;
  92. var JIThierarchy = this.data.JIT.hierarchy;
  93. var currentTime, unloopedCurrentTime;
  94. // update
  95. this.currentTime += deltaTimeMS;
  96. unloopedCurrentTime = this.currentTime;
  97. currentTime = this.currentTime = this.currentTime % this.data.length;
  98. frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
  99. // update
  100. for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
  101. object = this.hierarchy[ h ];
  102. animationCache = object.animationCache;
  103. // use JIT?
  104. if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) {
  105. if( object instanceof THREE.Bone ) {
  106. object.skinMatrix = JIThierarchy[ h ][ frame ];
  107. object.matrixAutoUpdate = false;
  108. object.matrixNeedsUpdate = false;
  109. }
  110. else {
  111. object.matrix = JIThierarchy[ h ][ frame ];
  112. object.matrixAutoUpdate = false;
  113. object.matrixNeedsUpdate = true;
  114. }
  115. // use interpolation
  116. } else {
  117. // make sure so original matrix and not JIT matrix is set
  118. if ( this.JITCompile ) {
  119. if( object instanceof THREE.Bone ) {
  120. object.skinMatrix = object.animationCache.originalMatrix;
  121. } else {
  122. object.matrix = object.animationCache.originalMatrix;
  123. }
  124. }
  125. // loop through pos/rot/scl
  126. for ( var t = 0; t < 3; t++ ) {
  127. // get keys
  128. type = types[ t ];
  129. prevKey = animationCache.prevKey[ type ];
  130. nextKey = animationCache.nextKey[ type ];
  131. // switch keys?
  132. if ( nextKey.time <= unloopedCurrentTime ) {
  133. // did we loop?
  134. if ( currentTime <= unloopedCurrentTime ) {
  135. if ( this.loop ) {
  136. prevKey = this.data.hierarchy[ h ].keys[ 0 ];
  137. nextKey = this.getNextKeyWith( type, h, 1 );
  138. while( nextKey.time < currentTime ) {
  139. prevKey = nextKey;
  140. nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
  141. }
  142. } else {
  143. this.stop();
  144. return;
  145. }
  146. } else {
  147. do {
  148. prevKey = nextKey;
  149. nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
  150. } while( nextKey.time < currentTime )
  151. }
  152. animationCache.prevKey[ type ] = prevKey;
  153. animationCache.nextKey[ type ] = nextKey;
  154. }
  155. object.matrixAutoUpdate = true;
  156. object.matrixNeedsUpdate = true;
  157. scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
  158. prevXYZ = prevKey[ type ];
  159. nextXYZ = nextKey[ type ];
  160. // check scale error
  161. if ( scale < 0 || scale > 1 ) {
  162. console.log( "THREE.Animation.update: Warning! Scale out of bounds:" + scale + " on bone " + h );
  163. scale = scale < 0 ? 0 : 1;
  164. }
  165. // interpolate
  166. if ( type === "pos" ) {
  167. if( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
  168. vector = object.position;
  169. vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
  170. vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
  171. vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
  172. } else {
  173. var points = [];
  174. points[ 0 ] = this.getPrevKeyWith( type, h, prevKey.index - 1 )[ type ];
  175. points[ 1 ] = prevXYZ;
  176. points[ 2 ] = nextXYZ;
  177. points[ 3 ] = this.getNextKeyWith( type, h, nextKey.index + 1 )[ type ];
  178. scale = scale * 0.33 + 0.33;
  179. var result = this.interpolateCatmullRom( points, scale );
  180. object.position.x = result[ 0 ];
  181. object.position.y = result[ 1 ];
  182. object.position.z = result[ 2 ];
  183. }
  184. }
  185. else if ( type === "rot" ) {
  186. THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );
  187. }
  188. else if( type === "scl" ) {
  189. vector = object.scale;
  190. vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
  191. vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
  192. vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
  193. }
  194. }
  195. }
  196. }
  197. // update JIT?
  198. if ( this.JITCompile ) {
  199. if ( JIThierarchy[ 0 ][ frame ] === undefined ) {
  200. this.hierarchy[ 0 ].update( undefined, true );
  201. for ( var h = 0; h < this.hierarchy.length; h++ ) {
  202. if( this.hierarchy[ h ] instanceof THREE.Bone ) {
  203. JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();
  204. } else {
  205. JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone();
  206. }
  207. }
  208. }
  209. }
  210. };
  211. /**
  212. * Spline from Tween.js, slightly optimized
  213. * Modified to fit to THREE.Animation.js
  214. *
  215. * http://sole.github.com/tween.js/examples/05_spline.html
  216. *
  217. * @author mrdoob / http://mrdoob.com/
  218. */
  219. THREE.Animation.prototype.interpolateCatmullRom = function ( points, scale ) {
  220. var c = [], v3 = [],
  221. point, intPoint, weight, w2, w3,
  222. pa, pb, pc, pd;
  223. point = ( points.length - 1 ) * scale;
  224. intPoint = Math.floor( point );
  225. weight = point - intPoint;
  226. c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
  227. c[ 1 ] = intPoint;
  228. c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
  229. c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;
  230. pa = points[ c[ 0 ] ];
  231. pb = points[ c[ 1 ] ];
  232. pc = points[ c[ 2 ] ];
  233. pd = points[ c[ 3 ] ];
  234. w2 = weight * weight;
  235. w3 = weight * w2;
  236. v3[ 0 ] = this.interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
  237. v3[ 1 ] = this.interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
  238. v3[ 2 ] = this.interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );
  239. return v3;
  240. }
  241. THREE.Animation.prototype.interpolate = function( p0, p1, p2, p3, t, t2, t3 ) {
  242. var v0 = ( p2 - p0 ) * 0.5,
  243. v1 = ( p3 - p1 ) * 0.5;
  244. return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
  245. }
  246. /*
  247. * Get next key with
  248. */
  249. THREE.Animation.prototype.getNextKeyWith = function( type, h, key ) {
  250. var keys = this.data.hierarchy[ h ].keys;
  251. key = key % keys.length;
  252. for ( ; key < keys.length; key++ ) {
  253. if ( keys[ key ][ type ] !== undefined ) {
  254. return keys[ key ];
  255. }
  256. }
  257. return this.data.hierarchy[ h ].keys[ 0 ];
  258. }
  259. THREE.Animation.prototype.getPrevKeyWith = function( type, h, key ) {
  260. var keys = this.data.hierarchy[ h ].keys;
  261. key = key >= 0 ? key : key + keys.length;
  262. for ( ; key >= 0; key-- ) {
  263. if ( keys[ key ][ type ] !== undefined ) {
  264. return keys[ key ];
  265. }
  266. }
  267. return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
  268. }
粤ICP备19079148号