SkinnedMesh.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
  6. THREE.Mesh.call( this, geometry, material );
  7. //
  8. this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
  9. // init bones
  10. this.identityMatrix = new THREE.Matrix4();
  11. this.bones = [];
  12. this.boneMatrices = [];
  13. var b, bone, gbone, p, q, s;
  14. if ( this.geometry && this.geometry.bones !== undefined ) {
  15. for ( b = 0; b < this.geometry.bones.length; b ++ ) {
  16. gbone = this.geometry.bones[ b ];
  17. p = gbone.pos;
  18. q = gbone.rotq;
  19. s = gbone.scl;
  20. bone = this.addBone();
  21. bone.name = gbone.name;
  22. bone.position.set( p[0], p[1], p[2] );
  23. bone.quaternion.set( q[0], q[1], q[2], q[3] );
  24. bone.useQuaternion = true;
  25. if ( s !== undefined ) {
  26. bone.scale.set( s[0], s[1], s[2] );
  27. } else {
  28. bone.scale.set( 1, 1, 1 );
  29. }
  30. }
  31. for ( b = 0; b < this.bones.length; b ++ ) {
  32. gbone = this.geometry.bones[ b ];
  33. bone = this.bones[ b ];
  34. if ( gbone.parent === -1 ) {
  35. this.add( bone );
  36. } else {
  37. this.bones[ gbone.parent ].add( bone );
  38. }
  39. }
  40. //
  41. var nBones = this.bones.length;
  42. if ( this.useVertexTexture ) {
  43. // layout (1 matrix = 4 pixels)
  44. // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
  45. // with 8x8 pixel texture max 16 bones (8 * 8 / 4)
  46. // 16x16 pixel texture max 64 bones (16 * 16 / 4)
  47. // 32x32 pixel texture max 256 bones (32 * 32 / 4)
  48. // 64x64 pixel texture max 1024 bones (64 * 64 / 4)
  49. var size;
  50. if ( nBones > 256 )
  51. size = 64;
  52. else if ( nBones > 64 )
  53. size = 32;
  54. else if ( nBones > 16 )
  55. size = 16;
  56. else
  57. size = 8;
  58. this.boneTextureWidth = size;
  59. this.boneTextureHeight = size;
  60. this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
  61. this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
  62. this.boneTexture.minFilter = THREE.NearestFilter;
  63. this.boneTexture.magFilter = THREE.NearestFilter;
  64. this.boneTexture.generateMipmaps = false;
  65. this.boneTexture.flipY = false;
  66. } else {
  67. this.boneMatrices = new Float32Array( 16 * nBones );
  68. }
  69. this.pose();
  70. }
  71. };
  72. THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
  73. THREE.SkinnedMesh.prototype.addBone = function( bone ) {
  74. if ( bone === undefined ) {
  75. bone = new THREE.Bone( this );
  76. }
  77. this.bones.push( bone );
  78. return bone;
  79. };
  80. THREE.SkinnedMesh.prototype.updateMatrixWorld = function ( force ) {
  81. this.matrixAutoUpdate && this.updateMatrix();
  82. // update matrixWorld
  83. if ( this.matrixWorldNeedsUpdate || force ) {
  84. if ( this.parent ) {
  85. this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );
  86. } else {
  87. this.matrixWorld.copy( this.matrix );
  88. }
  89. this.matrixWorldNeedsUpdate = false;
  90. force = true;
  91. }
  92. // update children
  93. for ( var i = 0, l = this.children.length; i < l; i ++ ) {
  94. var child = this.children[ i ];
  95. if ( child instanceof THREE.Bone ) {
  96. child.update( this.identityMatrix, false );
  97. } else {
  98. child.updateMatrixWorld( true );
  99. }
  100. }
  101. // make a snapshot of the bones' rest position
  102. if ( this.boneInverses == undefined ) {
  103. this.boneInverses = [];
  104. for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
  105. var inverse = new THREE.Matrix4();
  106. inverse.getInverse( this.bones[ b ].skinMatrix );
  107. this.boneInverses.push( inverse );
  108. }
  109. }
  110. // flatten bone matrices to array
  111. for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
  112. // compute the offset between the current and the original transform;
  113. //TODO: we could get rid of this multiplication step if the skinMatrix
  114. // was already representing the offset; however, this requires some
  115. // major changes to the animation system
  116. THREE.SkinnedMesh.offsetMatrix.multiply( this.bones[ b ].skinMatrix, this.boneInverses[ b ] );
  117. THREE.SkinnedMesh.offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
  118. }
  119. if ( this.useVertexTexture ) {
  120. this.boneTexture.needsUpdate = true;
  121. }
  122. };
  123. THREE.SkinnedMesh.prototype.pose = function() {
  124. this.updateMatrixWorld( true );
  125. for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {
  126. // normalize weights
  127. var sw = this.geometry.skinWeights[ i ];
  128. var scale = 1.0 / sw.lengthManhattan();
  129. if ( scale !== Infinity ) {
  130. sw.multiplyScalar( scale );
  131. } else {
  132. sw.set( 1 ); // this will be normalized by the shader anyway
  133. }
  134. }
  135. };
  136. THREE.SkinnedMesh.prototype.clone = function ( object ) {
  137. if ( object === undefined ) object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture );
  138. THREE.Mesh.prototype.clone.call( this, object );
  139. return object;
  140. };
  141. THREE.SkinnedMesh.offsetMatrix = new THREE.Matrix4();
粤ICP备19079148号