KeyFrameAnimation.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. * @author mrdoob / http://mrdoob.com/
  4. * @author alteredq / http://alteredqualia.com/
  5. * @author khang duong
  6. * @author erik kitson
  7. */
  8. THREE.KeyFrameAnimation = function( root, data, JITCompile ) {
  9. this.root = root;
  10. this.data = THREE.AnimationHandler.get( data );
  11. this.hierarchy = THREE.AnimationHandler.parse( root );
  12. this.currentTime = 0;
  13. this.timeScale = 0.001;
  14. this.isPlaying = false;
  15. this.isPaused = true;
  16. this.loop = true;
  17. this.JITCompile = JITCompile !== undefined ? JITCompile : true;
  18. // initialize to first keyframes
  19. for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
  20. var keys = this.data.hierarchy[h].keys,
  21. sids = this.data.hierarchy[h].sids,
  22. obj = this.hierarchy[h];
  23. if ( keys.length && sids ) {
  24. for ( var s = 0; s < sids.length; s++ ) {
  25. var sid = sids[ s ],
  26. next = this.getNextKeyWith( sid, h, 0 );
  27. if ( next ) {
  28. next.apply( sid );
  29. }
  30. }
  31. obj.matrixAutoUpdate = false;
  32. this.data.hierarchy[h].node.updateMatrix();
  33. obj.matrixWorldNeedsUpdate = true;
  34. }
  35. }
  36. };
  37. // Play
  38. THREE.KeyFrameAnimation.prototype.play = function( loop, startTimeMS ) {
  39. if( !this.isPlaying ) {
  40. this.isPlaying = true;
  41. this.loop = loop !== undefined ? loop : true;
  42. this.currentTime = startTimeMS !== undefined ? startTimeMS : 0;
  43. this.startTimeMs = startTimeMS;
  44. this.startTime = 10000000;
  45. this.endTime = -this.startTime;
  46. // reset key cache
  47. var h, hl = this.hierarchy.length,
  48. object,
  49. node;
  50. for ( h = 0; h < hl; h++ ) {
  51. object = this.hierarchy[ h ];
  52. node = this.data.hierarchy[ h ];
  53. if ( node.animationCache === undefined ) {
  54. node.animationCache = {};
  55. node.animationCache.prevKey = null;
  56. node.animationCache.nextKey = null;
  57. node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix;
  58. }
  59. var keys = this.data.hierarchy[h].keys;
  60. if (keys.length) {
  61. node.animationCache.prevKey = keys[ 0 ];
  62. node.animationCache.nextKey = keys[ 1 ];
  63. this.startTime = Math.min( keys[0].time, this.startTime );
  64. this.endTime = Math.max( keys[keys.length - 1].time, this.endTime );
  65. }
  66. }
  67. this.update( 0 );
  68. }
  69. this.isPaused = false;
  70. THREE.AnimationHandler.addToUpdate( this );
  71. };
  72. // Pause
  73. THREE.KeyFrameAnimation.prototype.pause = function() {
  74. if( this.isPaused ) {
  75. THREE.AnimationHandler.addToUpdate( this );
  76. } else {
  77. THREE.AnimationHandler.removeFromUpdate( this );
  78. }
  79. this.isPaused = !this.isPaused;
  80. };
  81. // Stop
  82. THREE.KeyFrameAnimation.prototype.stop = function() {
  83. this.isPlaying = false;
  84. this.isPaused = false;
  85. THREE.AnimationHandler.removeFromUpdate( this );
  86. // reset JIT matrix and remove cache
  87. for ( var h = 0; h < this.data.hierarchy.length; h++ ) {
  88. var obj = this.hierarchy[ h ];
  89. var node = this.data.hierarchy[ h ];
  90. if ( node.animationCache !== undefined ) {
  91. var original = node.animationCache.originalMatrix;
  92. if( obj instanceof THREE.Bone ) {
  93. original.copy( obj.skinMatrix );
  94. obj.skinMatrix = original;
  95. } else {
  96. original.copy( obj.matrix );
  97. obj.matrix = original;
  98. }
  99. delete node.animationCache;
  100. }
  101. }
  102. };
  103. // Update
  104. THREE.KeyFrameAnimation.prototype.update = function( deltaTimeMS ) {
  105. // early out
  106. if( !this.isPlaying ) return;
  107. // vars
  108. var prevKey, nextKey;
  109. var object;
  110. var node;
  111. var frame;
  112. var JIThierarchy = this.data.JIT.hierarchy;
  113. var currentTime, unloopedCurrentTime;
  114. var looped;
  115. // update
  116. this.currentTime += deltaTimeMS * this.timeScale;
  117. unloopedCurrentTime = this.currentTime;
  118. currentTime = this.currentTime = this.currentTime % this.data.length;
  119. // if looped around, the current time should be based on the startTime
  120. if ( currentTime < this.startTimeMs ) {
  121. currentTime = this.currentTime = this.startTimeMs + currentTime;
  122. }
  123. frame = parseInt( Math.min( currentTime * this.data.fps, this.data.length * this.data.fps ), 10 );
  124. looped = currentTime < unloopedCurrentTime;
  125. if ( looped && !this.loop ) {
  126. // Set the animation to the last keyframes and stop
  127. for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
  128. var keys = this.data.hierarchy[h].keys,
  129. sids = this.data.hierarchy[h].sids,
  130. end = keys.length-1,
  131. obj = this.hierarchy[h];
  132. if ( keys.length ) {
  133. for ( var s = 0; s < sids.length; s++ ) {
  134. var sid = sids[ s ],
  135. prev = this.getPrevKeyWith( sid, h, end );
  136. if ( prev ) {
  137. prev.apply( sid );
  138. }
  139. }
  140. this.data.hierarchy[h].node.updateMatrix();
  141. obj.matrixWorldNeedsUpdate = true;
  142. }
  143. }
  144. this.stop();
  145. return;
  146. }
  147. // check pre-infinity
  148. if ( currentTime < this.startTime ) {
  149. return;
  150. }
  151. // update
  152. for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
  153. object = this.hierarchy[ h ];
  154. node = this.data.hierarchy[ h ];
  155. var keys = node.keys,
  156. animationCache = node.animationCache;
  157. // use JIT?
  158. if ( this.JITCompile && JIThierarchy[ h ][ frame ] !== undefined ) {
  159. if( object instanceof THREE.Bone ) {
  160. object.skinMatrix = JIThierarchy[ h ][ frame ];
  161. object.matrixWorldNeedsUpdate = false;
  162. } else {
  163. object.matrix = JIThierarchy[ h ][ frame ];
  164. object.matrixWorldNeedsUpdate = true;
  165. }
  166. // use interpolation
  167. } else if ( keys.length ) {
  168. // make sure so original matrix and not JIT matrix is set
  169. if ( this.JITCompile && animationCache ) {
  170. if( object instanceof THREE.Bone ) {
  171. object.skinMatrix = animationCache.originalMatrix;
  172. } else {
  173. object.matrix = animationCache.originalMatrix;
  174. }
  175. }
  176. prevKey = animationCache.prevKey;
  177. nextKey = animationCache.nextKey;
  178. if ( prevKey && nextKey ) {
  179. // switch keys?
  180. if ( nextKey.time <= unloopedCurrentTime ) {
  181. // did we loop?
  182. if ( looped && this.loop ) {
  183. prevKey = keys[ 0 ];
  184. nextKey = keys[ 1 ];
  185. while ( nextKey.time < currentTime ) {
  186. prevKey = nextKey;
  187. nextKey = keys[ prevKey.index + 1 ];
  188. }
  189. } else if ( !looped ) {
  190. var lastIndex = keys.length - 1;
  191. while ( nextKey.time < currentTime && nextKey.index !== lastIndex ) {
  192. prevKey = nextKey;
  193. nextKey = keys[ prevKey.index + 1 ];
  194. }
  195. }
  196. animationCache.prevKey = prevKey;
  197. animationCache.nextKey = nextKey;
  198. }
  199. if(nextKey.time >= currentTime)
  200. prevKey.interpolate( nextKey, currentTime );
  201. else
  202. prevKey.interpolate( nextKey, nextKey.time);
  203. }
  204. this.data.hierarchy[h].node.updateMatrix();
  205. object.matrixWorldNeedsUpdate = true;
  206. }
  207. }
  208. // update JIT?
  209. if ( this.JITCompile ) {
  210. if ( JIThierarchy[ 0 ][ frame ] === undefined ) {
  211. this.hierarchy[ 0 ].updateMatrixWorld( true );
  212. for ( var h = 0; h < this.hierarchy.length; h++ ) {
  213. if( this.hierarchy[ h ] instanceof THREE.Bone ) {
  214. JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();
  215. } else {
  216. JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].matrix.clone();
  217. }
  218. }
  219. }
  220. }
  221. };
  222. // Get next key with
  223. THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) {
  224. var keys = this.data.hierarchy[ h ].keys;
  225. key = key % keys.length;
  226. for ( ; key < keys.length; key++ ) {
  227. if ( keys[ key ].hasTarget( sid ) ) {
  228. return keys[ key ];
  229. }
  230. }
  231. return keys[ 0 ];
  232. };
  233. // Get previous key with
  234. THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) {
  235. var keys = this.data.hierarchy[ h ].keys;
  236. key = key >= 0 ? key : key + keys.length;
  237. for ( ; key >= 0; key-- ) {
  238. if ( keys[ key ].hasTarget( sid ) ) {
  239. return keys[ key ];
  240. }
  241. }
  242. return keys[ keys.length - 1 ];
  243. };