AnimationClip.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /**
  2. *
  3. * Reusable set of Tracks that represent an animation.
  4. *
  5. * @author Ben Houston / http://clara.io/
  6. * @author David Sarno / http://lighthaus.us/
  7. */
  8. THREE.AnimationClip = function ( name, duration, tracks ) {
  9. this.name = name;
  10. this.tracks = tracks;
  11. this.duration = duration || 1;
  12. // maybe only do these on demand, as doing them here could potentially slow down loading
  13. // but leaving these here during development as this ensures a lot of testing of these functions
  14. this.trim();
  15. this.optimize();
  16. this.results = [];
  17. };
  18. THREE.AnimationClip.prototype = {
  19. constructor: THREE.AnimationClip,
  20. getAt: function( clipTime ) {
  21. clipTime = Math.max( 0, Math.min( clipTime, this.duration ) );
  22. for( var i = 0; i < this.tracks.length; i ++ ) {
  23. var track = this.tracks[ i ];
  24. this.results[ i ] = track.getAt( clipTime );
  25. }
  26. return this.results;
  27. },
  28. trim: function() {
  29. for( var i = 0; i < this.tracks.length; i ++ ) {
  30. this.tracks[ i ].trim( this.duration );
  31. }
  32. },
  33. optimize: function() {
  34. for( var i = 0; i < this.tracks.length; i ++ ) {
  35. this.tracks[ i ].optimize();
  36. }
  37. }
  38. };
  39. THREE.AnimationClip.CreateMorphAnimationFromNames = function( morphTargetNames, duration ) {
  40. var tracks = [];
  41. var frameStep = duration / morphTargetNames.length;
  42. for( var i = 0; i < morphTargetNames.length; i ++ ) {
  43. var keys = [];
  44. if( ( i - 1 ) >= 0 ) {
  45. keys.push( { time: ( i - 1 ) * frameStep, value: 0 } );
  46. }
  47. keys.push( { time: i * frameStep, value: 1 } );
  48. if( ( i + 1 ) <= morphTargetNames.length ) {
  49. keys.push( { time: ( i + 1 ) * frameStep, value: 0 } );
  50. }
  51. if( ( i - 1 ) < 0 ) {
  52. keys.push( { time: ( morphTargetNames.length - 1 ) * frameStep, value: 0 } );
  53. keys.push( { time: morphTargetNames.length * frameStep, value: 1 } );
  54. }
  55. var morphName = morphTargetNames[i];
  56. var trackName = '.morphTargetInfluences[' + morphName + ']';
  57. var track = new THREE.KeyframeTrack( trackName, keys );
  58. tracks.push( track );
  59. }
  60. var clip = new THREE.AnimationClip( 'morphAnimation', duration, tracks );
  61. return clip;
  62. };
  63. THREE.AnimationClip.CreateMorphAnimation = function( morphTargets, duration ) {
  64. var morphTargetNames = [];
  65. for( var i = 0; i < morphTargets.length; i ++ ) {
  66. morphTargetNames.push( morphTargets[i].name );
  67. }
  68. return THREE.AnimationClip.CreateMorphAnimationFromNames( morphTargetNames, duration );
  69. };
  70. THREE.AnimationClip.FromImplicitMorphTargetAnimations = function( morphTargets, fps ) {
  71. var animations = {};
  72. var animationsArray = [];
  73. var pattern = /([a-z]+)_?(\d+)/;
  74. for ( var i = 0, il = morphTargets.length; i < il; i ++ ) {
  75. var morphTarget = morphTargets[ i ];
  76. var parts = morphTarget.name.match( pattern );
  77. if ( parts && parts.length > 1 ) {
  78. var animationName = parts[ 1 ];
  79. var animation = animations[ animationName ];
  80. if ( ! animation ) {
  81. animations[ animationName ] = animation = { name: animationName, morphTargetNames: [] };
  82. animationsArray.push( animation );
  83. }
  84. animation.morphTargetNames.push( morphTarget.name );
  85. }
  86. }
  87. var clips = [];
  88. for( var i = 0; i < animationsArray.length; i ++ ) {
  89. var animation = animationsArray[i];
  90. var clip = new THREE.AnimationClip.CreateMorphAnimationFromNames( animation.morphTargetNames, animation.morphTargetNames.length * fps );
  91. clip.name = animation.name;
  92. clips.push( clip );
  93. }
  94. return clips;
  95. };
  96. THREE.AnimationClip.FromJSONLoaderAnimation = function( animation, bones, nodeName ) {
  97. if( ! animation ) {
  98. console.error( " no animation in JSONLoader data" );
  99. return null;
  100. }
  101. var convertTrack = function( trackName, animationKeys, propertyName, animationKeyToValueFunc ) {
  102. var keys = [];
  103. for( var k = 0; k < animationKeys.length; k ++ ) {
  104. var animationKey = animationKeys[k];
  105. if( animationKey[propertyName] !== undefined ) {
  106. keys.push( { time: animationKey.time, value: animationKeyToValueFunc( animationKey ) } );
  107. }
  108. }
  109. // only return track if there are actually keys.
  110. if( keys.length > 0 ) {
  111. return new THREE.KeyframeTrack( trackName, keys );
  112. }
  113. return null;
  114. };
  115. var clipName = animation.name;
  116. var duration = animation.length;
  117. var fps = animation.fps;
  118. var tracks = [];
  119. var animationTracks = animation.hierarchy;
  120. for ( var h = 0; h < animationTracks.length; h ++ ) {
  121. var animationKeys = animationTracks[ h ].keys;
  122. // skip empty tracks
  123. if( ! animationKeys || animationKeys.length == 0 ) {
  124. continue;
  125. }
  126. // process morph targets in a way exactly compatible with AnimationHandler.init( animation )
  127. if( animationKeys[0].morphTargets ) {
  128. // figure out all morph targets used in this track
  129. var morphTargetNames = {};
  130. for( var k = 0; k < animationKeys.length; k ++ ) {
  131. if( animationKeys[k].morphTargets ) {
  132. for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
  133. morphTargetNames[ animationKeys[k].morphTargets[m] ] = -1;
  134. }
  135. }
  136. }
  137. // create a track for each morph target with all zero morphTargetInfluences except for the keys in which the morphTarget is named.
  138. for( var morphTargetName in morphTargetNames ) {
  139. var keys = [];
  140. for( var m = 0; m < animationKeys[k].morphTargets.length; m ++ ) {
  141. var animationKey = animationKeys[k];
  142. keys.push( {
  143. time: animationKey.time,
  144. value: (( animationKey.morphTarget === morphTargetName ) ? 1 : 0 )
  145. });
  146. }
  147. tracks.push( new THREE.KeyframeTrack( nodeName + '.morphTargetInfluence[' + morphTargetName + ']', keys ) );
  148. }
  149. duration = morphTargetNames.length * ( fps || 1.0 );
  150. }
  151. else {
  152. var boneName = nodeName + '.bones[' + bones[ h ].name + ']';
  153. // track contains positions...
  154. var positionTrack = convertTrack( boneName + '.position', animationKeys, 'pos', function( animationKey ) {
  155. return new THREE.Vector3().fromArray( animationKey.pos )
  156. } );
  157. if( positionTrack ) tracks.push( positionTrack );
  158. // track contains quaternions...
  159. var quaternionTrack = convertTrack( boneName + '.quaternion', animationKeys, 'rot', function( animationKey ) {
  160. if( animationKey.rot.slerp ) {
  161. return animationKey.rot.clone();
  162. }
  163. else {
  164. return new THREE.Quaternion().fromArray( animationKey.rot );
  165. }
  166. } );
  167. if( quaternionTrack ) tracks.push( quaternionTrack );
  168. // track contains quaternions...
  169. var scaleTrack = convertTrack( boneName + '.scale', animationKeys, 'scl', function( animationKey ) {
  170. return new THREE.Vector3().fromArray( animationKey.scl )
  171. } );
  172. if( scaleTrack ) tracks.push( scaleTrack );
  173. }
  174. }
  175. var clip = new THREE.AnimationClip( clipName, duration, tracks );
  176. return clip;
  177. };