three
Version:
JavaScript 3D library
168 lines (91 loc) • 3.43 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';
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.getInverse( bindMatrix );
},
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.getInverse( this.matrixWorld );
} else if ( this.bindMode === 'detached' ) {
this.bindMatrixInverse.getInverse( this.bindMatrix );
} else {
console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
}
},
boneTransform: ( function () {
const basePosition = new Vector3();
const skinIndex = new Vector4();
const skinWeight = new Vector4();
const vector = new Vector3();
const matrix = new Matrix4();
return 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 };