SkinnedMesh.js 5.1 KB

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