Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/flo-bit/shapecraft. flo-bit.dev/shapecraft
Something went wrong. Try again.
5.4 kB · 257 lines
JavaScript
at commit 049ef598
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258import { Mesh } from './Mesh.js';import { Box3 } from '../math/Box3.js';import { Matrix4 } from '../math/Matrix4.js';import { Sphere } from '../math/Sphere.js';import { Vector3 } from '../math/Vector3.js';import { Vector4 } from '../math/Vector4.js';import { Ray } from '../math/Ray.js';import { AttachedBindMode, DetachedBindMode } from '../constants.js';
const _basePosition = /*@__PURE__*/ new Vector3();
const _skinIndex = /*@__PURE__*/ new Vector4();const _skinWeight = /*@__PURE__*/ new Vector4();
const _vector3 = /*@__PURE__*/ new Vector3();const _matrix4 = /*@__PURE__*/ new Matrix4();const _vertex = /*@__PURE__*/ new Vector3();
const _sphere = /*@__PURE__*/ new Sphere();const _inverseMatrix = /*@__PURE__*/ new Matrix4();const _ray = /*@__PURE__*/ new Ray();
class SkinnedMesh extends Mesh {
constructor( geometry, material ) {
super( geometry, material );
this.isSkinnedMesh = true;
this.type = 'SkinnedMesh';
this.bindMode = AttachedBindMode; this.bindMatrix = new Matrix4(); this.bindMatrixInverse = new Matrix4();
this.boundingBox = null; this.boundingSphere = null;
}
computeBoundingBox() {
const geometry = this.geometry;
if ( this.boundingBox === null ) {
this.boundingBox = new Box3();
}
this.boundingBox.makeEmpty();
const positionAttribute = geometry.getAttribute( 'position' );
for ( let i = 0; i < positionAttribute.count; i ++ ) {
this.getVertexPosition( i, _vertex ); this.boundingBox.expandByPoint( _vertex );
}
}
computeBoundingSphere() {
const geometry = this.geometry;
if ( this.boundingSphere === null ) {
this.boundingSphere = new Sphere();
}
this.boundingSphere.makeEmpty();
const positionAttribute = geometry.getAttribute( 'position' );
for ( let i = 0; i < positionAttribute.count; i ++ ) {
this.getVertexPosition( i, _vertex ); this.boundingSphere.expandByPoint( _vertex );
}
}
copy( source, recursive ) {
super.copy( source, recursive );
this.bindMode = source.bindMode; this.bindMatrix.copy( source.bindMatrix ); this.bindMatrixInverse.copy( source.bindMatrixInverse );
this.skeleton = source.skeleton;
if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();
return this;
}
raycast( raycaster, intersects ) {
const material = this.material; const matrixWorld = this.matrixWorld;
if ( material === undefined ) return;
// test with bounding sphere in world space
if ( this.boundingSphere === null ) this.computeBoundingSphere();
_sphere.copy( this.boundingSphere ); _sphere.applyMatrix4( matrixWorld );
if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;
// convert ray to local space of skinned mesh
_inverseMatrix.copy( matrixWorld ).invert(); _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );
// test with bounding box in local space
if ( this.boundingBox !== null ) {
if ( _ray.intersectsBox( this.boundingBox ) === false ) return;
}
// test for intersections with geometry
this._computeIntersections( raycaster, intersects, _ray );
}
getVertexPosition( index, target ) {
super.getVertexPosition( index, target );
this.applyBoneTransform( index, target );
return target;
}
bind( 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() {
this.skeleton.pose();
}
normalizeSkinWeights() {
const vector = new Vector4();
const skinWeight = this.geometry.attributes.skinWeight;
for ( let i = 0, l = skinWeight.count; i < l; i ++ ) {
vector.fromBufferAttribute( skinWeight, 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( force ) {
super.updateMatrixWorld( force );
if ( this.bindMode === AttachedBindMode ) {
this.bindMatrixInverse.copy( this.matrixWorld ).invert();
} else if ( this.bindMode === DetachedBindMode ) {
this.bindMatrixInverse.copy( this.bindMatrix ).invert();
} else {
console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );
}
}
applyBoneTransform( index, vector ) {
const skeleton = this.skeleton; const geometry = this.geometry;
_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
_basePosition.copy( vector ).applyMatrix4( this.bindMatrix );
vector.set( 0, 0, 0 );
for ( let i = 0; i < 4; i ++ ) {
const weight = _skinWeight.getComponent( i );
if ( weight !== 0 ) {
const boneIndex = _skinIndex.getComponent( i );
_matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );
}
}
return vector.applyMatrix4( this.bindMatrixInverse );
}
}
export { SkinnedMesh };