SkinnedMesh.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { Mesh } from './Mesh.js';
  2. import { Vector4 } from '../math/Vector4.js';
  3. import { Skeleton } from './Skeleton.js';
  4. import { Bone } from './Bone.js';
  5. import { Matrix4 } from '../math/Matrix4.js';
  6. /**
  7. * @author mikael emtinger / http://gomo.se/
  8. * @author alteredq / http://alteredqualia.com/
  9. * @author ikerr / http://verold.com
  10. */
  11. function SkinnedMesh( geometry, material ) {
  12. Mesh.call( this, geometry, material );
  13. this.type = 'SkinnedMesh';
  14. this.bindMode = 'attached';
  15. this.bindMatrix = new Matrix4();
  16. this.bindMatrixInverse = new Matrix4();
  17. var bones = this.initBones();
  18. var skeleton = new Skeleton( bones );
  19. this.bind( skeleton, this.matrixWorld );
  20. this.normalizeSkinWeights();
  21. }
  22. SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
  23. constructor: SkinnedMesh,
  24. isSkinnedMesh: true,
  25. initBones: function () {
  26. var bones = [], bone, gbone;
  27. var i, il;
  28. if ( this.geometry && this.geometry.bones !== undefined ) {
  29. // first, create array of 'Bone' objects from geometry data
  30. for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
  31. gbone = this.geometry.bones[ i ];
  32. // create new 'Bone' object
  33. bone = new Bone();
  34. bones.push( bone );
  35. // apply values
  36. bone.name = gbone.name;
  37. bone.position.fromArray( gbone.pos );
  38. bone.quaternion.fromArray( gbone.rotq );
  39. if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
  40. }
  41. // second, create bone hierarchy
  42. for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
  43. gbone = this.geometry.bones[ i ];
  44. if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
  45. // subsequent bones in the hierarchy
  46. bones[ gbone.parent ].add( bones[ i ] );
  47. } else {
  48. // topmost bone, immediate child of the skinned mesh
  49. this.add( bones[ i ] );
  50. }
  51. }
  52. }
  53. // now the bones are part of the scene graph and children of the skinned mesh.
  54. // let's update the corresponding matrices
  55. this.updateMatrixWorld( true );
  56. return bones;
  57. },
  58. bind: function ( skeleton, bindMatrix ) {
  59. this.skeleton = skeleton;
  60. if ( bindMatrix === undefined ) {
  61. this.updateMatrixWorld( true );
  62. this.skeleton.calculateInverses();
  63. bindMatrix = this.matrixWorld;
  64. }
  65. this.bindMatrix.copy( bindMatrix );
  66. this.bindMatrixInverse.getInverse( bindMatrix );
  67. },
  68. pose: function () {
  69. this.skeleton.pose();
  70. },
  71. normalizeSkinWeights: function () {
  72. var scale, i;
  73. if ( this.geometry && this.geometry.isGeometry ) {
  74. for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {
  75. var sw = this.geometry.skinWeights[ i ];
  76. scale = 1.0 / sw.manhattanLength();
  77. if ( scale !== Infinity ) {
  78. sw.multiplyScalar( scale );
  79. } else {
  80. sw.set( 1, 0, 0, 0 ); // do something reasonable
  81. }
  82. }
  83. } else if ( this.geometry && this.geometry.isBufferGeometry ) {
  84. var vec = new Vector4();
  85. var skinWeight = this.geometry.attributes.skinWeight;
  86. for ( i = 0; i < skinWeight.count; i ++ ) {
  87. vec.x = skinWeight.getX( i );
  88. vec.y = skinWeight.getY( i );
  89. vec.z = skinWeight.getZ( i );
  90. vec.w = skinWeight.getW( i );
  91. scale = 1.0 / vec.manhattanLength();
  92. if ( scale !== Infinity ) {
  93. vec.multiplyScalar( scale );
  94. } else {
  95. vec.set( 1, 0, 0, 0 ); // do something reasonable
  96. }
  97. skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w );
  98. }
  99. }
  100. },
  101. updateMatrixWorld: function ( force ) {
  102. Mesh.prototype.updateMatrixWorld.call( this, force );
  103. if ( this.bindMode === 'attached' ) {
  104. this.bindMatrixInverse.getInverse( this.matrixWorld );
  105. } else if ( this.bindMode === 'detached' ) {
  106. this.bindMatrixInverse.getInverse( this.bindMatrix );
  107. } else {
  108. console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
  109. }
  110. },
  111. clone: function () {
  112. return new this.constructor( this.geometry, this.material ).copy( this );
  113. }
  114. } );
  115. export { SkinnedMesh };