three
Version:
JavaScript 3D library
164 lines (89 loc) • 3.39 kB
JavaScript
import { Mesh } from './Mesh.js';
import { Matrix4 } from '../math/Matrix4.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector4 } from '../math/Vector4.js';
const _basePosition = new Vector3();
const _skinIndex = new Vector4();
const _skinWeight = new Vector4();
const _vector = new Vector3();
const _matrix = new Matrix4();
function SkinnedMesh( geometry, material ) {
if ( geometry && geometry.isGeometry ) {
console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
}
Mesh.call( this, geometry, material );
this.type = 'SkinnedMesh';
this.bindMode = 'attached';
this.bindMatrix = new Matrix4();
this.bindMatrixInverse = new Matrix4();
}
SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
constructor: SkinnedMesh,
isSkinnedMesh: true,
copy: function ( source ) {
Mesh.prototype.copy.call( this, source );
this.bindMode = source.bindMode;
this.bindMatrix.copy( source.bindMatrix );
this.bindMatrixInverse.copy( source.bindMatrixInverse );
this.skeleton = source.skeleton;
return this;
},
bind: function ( skeleton, bindMatrix ) {
this.skeleton = skeleton;
if ( bindMatrix === undefined ) {
this.updateMatrixWorld( true );
this.skeleton.calculateInverses();
bindMatrix = this.matrixWorld;
}
this.bindMatrix.copy( bindMatrix );
this.bindMatrixInverse.copy( bindMatrix ).invert();
},
pose: function () {
this.skeleton.pose();
},
normalizeSkinWeights: function () {
const vector = new Vector4();
const skinWeight = this.geometry.attributes.skinWeight;
for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
vector.x = skinWeight.getX( i );
vector.y = skinWeight.getY( i );
vector.z = skinWeight.getZ( i );
vector.w = skinWeight.getW( i );
const scale = 1.0 / vector.manhattanLength();
if ( scale !== Infinity ) {
vector.multiplyScalar( scale );
} else {
vector.set( 1, 0, 0, 0 ); // do something reasonable
}
skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );
}
},
updateMatrixWorld: function ( force ) {
Mesh.prototype.updateMatrixWorld.call( this, force );
if ( this.bindMode === 'attached' ) {
this.bindMatrixInverse.copy( this.matrixWorld ).invert();
} else if ( this.bindMode === 'detached' ) {
this.bindMatrixInverse.copy( this.bindMatrix ).invert();
} else {
console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
}
},
boneTransform: function ( index, target ) {
const skeleton = this.skeleton;
const geometry = this.geometry;
_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
_basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix );
target.set( 0, 0, 0 );
for ( let i = 0; i < 4; i ++ ) {
const weight = _skinWeight.getComponent( i );
if ( weight !== 0 ) {
const boneIndex = _skinIndex.getComponent( i );
_matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
target.addScaledVector( _vector.copy( _basePosition ).applyMatrix4( _matrix ), weight );
}
}
return target.applyMatrix4( this.bindMatrixInverse );
}
} );
export { SkinnedMesh };