SkinnedMesh class
class SkinnedMesh extends Mesh { bool useVertexTexture; num boneTextureWidth, boneTextureHeight; List bones; List boneMatrices; Matrix4 identityMatrix; DataTexture boneTexture; SkinnedMesh( geometry, material, {this.useVertexTexture: true} ) : identityMatrix = new Matrix4.identity(), bones = [], boneMatrices = [], super(geometry, material) { var gbone, bone; var p, q, s; if ( geometry["bones"] != null ) { for( gbone in geometry["bones"]) { p = gbone.pos; q = gbone.rotq; s = gbone.scl; bone = addBone(); bone.name = gbone.name; bone.position.set( p[0], p[1], p[2] ); bone.quaternion.set( q[0], q[1], q[2], q[3] ); bone.useQuaternion = true; if ( s != null ) { bone.scale.set( s[0], s[1], s[2] ); } else { bone.scale.set( 1, 1, 1 ); } } for ( var b = 0; b < this.bones.length; b ++ ) { gbone = geometry["bones"][ b ]; bone = bones[ b ]; if ( gbone.parent == -1 ) { this.add( bone ); } else { bones[ gbone.parent ].add( bone ); } } // var nBones = bones.length; if ( useVertexTexture ) { // layout (1 matrix = 4 pixels) // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) // with 8x8 pixel texture max 16 bones (8 * 8 / 4) // 16x16 pixel texture max 64 bones (16 * 16 / 4) // 32x32 pixel texture max 256 bones (32 * 32 / 4) // 64x64 pixel texture max 1024 bones (64 * 64 / 4) var size; if ( nBones > 256 ) { size = 64; } else if ( nBones > 64 ) { size = 32; } else if ( nBones > 16 ) { size = 16; } else { size = 8; } boneTextureWidth = size; boneTextureHeight = size; boneMatrices = new Float32List( boneTextureWidth * boneTextureHeight * 4 ); // 4 floats per RGBA pixel boneTexture = new DataTexture( boneMatrices, boneTextureWidth, boneTextureHeight, RGBAFormat, type: FloatType ); boneTexture.minFilter = NearestFilter; boneTexture.magFilter = NearestFilter; boneTexture.generateMipmaps = false; boneTexture.flipY = false; } else { boneMatrices = new Float32List( 16 * nBones ); } pose(); } } addBone( {Bone bone} ) { if ( bone == null ) { bone = new Bone( this ); } bones.add( bone ); return bone; } updateMatrixWorld({force: false}) { if(matrixAutoUpdate) updateMatrix(); // update matrixWorld if ( matrixWorldNeedsUpdate || force ) { if ( parent != null) { matrixWorld = parent.matrixWorld * matrix; } else { matrixWorld.setFrom( matrix ); } matrixWorldNeedsUpdate = false; force = true; } // update children children.forEach((child) { if ( child is Bone ) { child.update( identityMatrix, false ); } else { child.updateMatrixWorld( true ); } }); // flatten bone matrices to array var b, bl = this.bones.length, ba = this.bones, bm = this.boneMatrices; for ( b = 0; b < bl; b ++ ) { ba[ b ].skinMatrix.flattenToArrayOffset( bm, b * 16 ); } if ( useVertexTexture ) { boneTexture.needsUpdate = true; } } /* * Pose */ pose() { updateMatrixWorld( force: true ); var bim, bone; List<Matrix4> boneInverses = []; for ( var b = 0; b < bones.length; b ++ ) { bone = bones[ b ]; var inverseMatrix = bone.skinMatrix.clone(); inverseMatrix.invert(); boneInverses.add( inverseMatrix ); bone.skinMatrix.flattenToArrayOffset( boneMatrices, b * 16 ); } // project vertices to local if ( geometry["skinVerticesA"] == null ) { geometry["skinVerticesA"] = []; geometry["skinVerticesA"] = []; var orgVertex, vertex; for ( var i = 0; i < geometry.skinIndices.length; i ++ ) { orgVertex = geometry.vertices[ i ]; var indexA = geometry.skinIndices[ i ].x; var indexB = geometry.skinIndices[ i ].y; vertex = new Vector3( orgVertex.x, orgVertex.y, orgVertex.z ); geometry["skinVerticesA"].add(vertex.applyProjection(boneInverses[indexA])); vertex = new Vector3( orgVertex.x, orgVertex.y, orgVertex.z ); geometry["skinVerticesA"].add(vertex.applyProjection(boneInverses[indexB])); // todo: add more influences // normalize weights if ( geometry.skinWeights[ i ].x + geometry.skinWeights[ i ].y != 1 ) { var len = ( 1.0 - ( geometry.skinWeights[ i ].x + geometry.skinWeights[ i ].y ) ) * 0.5; geometry.skinWeights[ i ].x += len; geometry.skinWeights[ i ].y += len; } } } } }
Extends
Constructors
new SkinnedMesh(geometry, material, {bool useVertexTexture: true}) #
Creates a new Object instance.
Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.
docs inherited from Object
SkinnedMesh( geometry, material, {this.useVertexTexture: true} ) : identityMatrix = new Matrix4.identity(), bones = [], boneMatrices = [], super(geometry, material) { var gbone, bone; var p, q, s; if ( geometry["bones"] != null ) { for( gbone in geometry["bones"]) { p = gbone.pos; q = gbone.rotq; s = gbone.scl; bone = addBone(); bone.name = gbone.name; bone.position.set( p[0], p[1], p[2] ); bone.quaternion.set( q[0], q[1], q[2], q[3] ); bone.useQuaternion = true; if ( s != null ) { bone.scale.set( s[0], s[1], s[2] ); } else { bone.scale.set( 1, 1, 1 ); } } for ( var b = 0; b < this.bones.length; b ++ ) { gbone = geometry["bones"][ b ]; bone = bones[ b ]; if ( gbone.parent == -1 ) { this.add( bone ); } else { bones[ gbone.parent ].add( bone ); } } // var nBones = bones.length; if ( useVertexTexture ) { // layout (1 matrix = 4 pixels) // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) // with 8x8 pixel texture max 16 bones (8 * 8 / 4) // 16x16 pixel texture max 64 bones (16 * 16 / 4) // 32x32 pixel texture max 256 bones (32 * 32 / 4) // 64x64 pixel texture max 1024 bones (64 * 64 / 4) var size; if ( nBones > 256 ) { size = 64; } else if ( nBones > 64 ) { size = 32; } else if ( nBones > 16 ) { size = 16; } else { size = 8; } boneTextureWidth = size; boneTextureHeight = size; boneMatrices = new Float32List( boneTextureWidth * boneTextureHeight * 4 ); // 4 floats per RGBA pixel boneTexture = new DataTexture( boneMatrices, boneTextureWidth, boneTextureHeight, RGBAFormat, type: FloatType ); boneTexture.minFilter = NearestFilter; boneTexture.magFilter = NearestFilter; boneTexture.generateMipmaps = false; boneTexture.flipY = false; } else { boneMatrices = new Float32List( 16 * nBones ); } pose(); } }
Properties
DataTexture boneTexture #
DataTexture boneTexture
bool frustumCulled #
inherited from Object3D
bool visible = false, castShadow = false, receiveShadow = false, frustumCulled = false
bool isDynamic #
inherited from Object3D
bool get isDynamic => _dynamic;
set isDynamic(bool flag) => _dynamic = flag;
Matrix4 matrixRotationWorld #
inherited from Object3D
Matrix4 matrix, matrixWorld, matrixRotationWorld
bool matrixWorldNeedsUpdate #
inherited from Object3D
bool matrixAutoUpdate = false, matrixWorldNeedsUpdate = false
bool receiveShadow #
inherited from Object3D
bool visible = false, castShadow = false, receiveShadow = false
Operators
Methods
void add(Object3D object) #
inherited from Object3D
void add( Object3D object ) { if ( object == this ) { print( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); return; } if ( object.parent != null ) { object.parent.remove( object ); } object.parent = this; children.add( object ); // add to scene Object3D scene = this; while ( scene.parent != null ) { scene = scene.parent; } if ( scene is Scene ) { scene.addObject( object ); } }
dynamic addBone({Bone bone}) #
addBone( {Bone bone} ) { if ( bone == null ) { bone = new Bone( this ); } bones.add( bone ); return bone; }
void applyMatrix(Matrix4 matrix) #
inherited from Object3D
void applyMatrix ( Matrix4 matrix ) { this.matrix = matrix * this.matrix; this.scale = getScaleFromMatrix( this.matrix ); Matrix4 mat = extractRotation(new Matrix4.identity(), this.matrix ); this.rotation = calcEulerFromRotationMatrix( mat, this.eulerOrder ); this.position = this.matrix.getTranslation(); }
Object3D getChildByName(String name, bool doRecurse) #
inherited from Object3D
Object3D getChildByName( String name, bool doRecurse ) { int c; int cl = children.length; Object3D child, recurseResult; children.forEach((child){ if ( child.name == name ) { return child; } if ( doRecurse ) { recurseResult = child.getChildByName( name, doRecurse ); if ( recurseResult != null ) { return recurseResult; } } }); return null; }
num getMorphTargetIndexByName(name) #
inherited from Mesh
num getMorphTargetIndexByName( name ) { if ( _morphTargetDictionary[ name ] != null ) { return _morphTargetDictionary[ name ]; } print( "THREE.Mesh.getMorphTargetIndexByName: morph target $name does not exist. Returning 0." ); return 0; }
dynamic localToWorld(Vector3 vector) #
inherited from Object3D
localToWorld(Vector3 vector) => vector.applyProjection(matrixWorld);
void lookAt(Vector3 vector) #
inherited from Object3D
void lookAt( Vector3 vector ) { // TODO: Add hierarchy support. makeLookAt( matrix, vector, position, up ); if ( rotationAutoUpdate ) { if(useQuaternion) quaternion.setFromRotationMatrix(matrix); else rotation = calcEulerFromRotationMatrix( matrix, eulerOrder ); } }
dynamic pose() #
pose() { updateMatrixWorld( force: true ); var bim, bone; List<Matrix4> boneInverses = []; for ( var b = 0; b < bones.length; b ++ ) { bone = bones[ b ]; var inverseMatrix = bone.skinMatrix.clone(); inverseMatrix.invert(); boneInverses.add( inverseMatrix ); bone.skinMatrix.flattenToArrayOffset( boneMatrices, b * 16 ); } // project vertices to local if ( geometry["skinVerticesA"] == null ) { geometry["skinVerticesA"] = []; geometry["skinVerticesA"] = []; var orgVertex, vertex; for ( var i = 0; i < geometry.skinIndices.length; i ++ ) { orgVertex = geometry.vertices[ i ]; var indexA = geometry.skinIndices[ i ].x; var indexB = geometry.skinIndices[ i ].y; vertex = new Vector3( orgVertex.x, orgVertex.y, orgVertex.z ); geometry["skinVerticesA"].add(vertex.applyProjection(boneInverses[indexA])); vertex = new Vector3( orgVertex.x, orgVertex.y, orgVertex.z ); geometry["skinVerticesA"].add(vertex.applyProjection(boneInverses[indexB])); // todo: add more influences // normalize weights if ( geometry.skinWeights[ i ].x + geometry.skinWeights[ i ].y != 1 ) { var len = ( 1.0 - ( geometry.skinWeights[ i ].x + geometry.skinWeights[ i ].y ) ) * 0.5; geometry.skinWeights[ i ].x += len; geometry.skinWeights[ i ].y += len; } } } }
void remove(Object3D object) #
inherited from Object3D
void remove( Object3D object ) { int index = children.indexOf( object ); if ( index != - 1 ){ object.parent = null; children.removeAt(index); // remove from scene Object3D scene = this; while ( scene.parent != null ) { scene = scene.parent; } if (scene is Scene ) { scene.removeObject( object ); } } }
void translate(num distance, Vector3 axis) #
inherited from Object3D
void translate( num distance, Vector3 axis ) { matrix.rotate3( axis ); axis.normalize(); position.add( axis.scale( distance ) ); }
void translateX(num distance) #
inherited from Object3D
void translateX( num distance ) => translate( distance, _vector.setValues( 1.0, 0.0, 0.0 ) );
void translateY(num distance) #
inherited from Object3D
void translateY( num distance ) => translate( distance, _vector.setValues( 0.0, 1.0, 0.0 ) );
void translateZ(num distance) #
inherited from Object3D
void translateZ( num distance ) => translate( distance, _vector.setValues( 0.0, 0.0, 1.0 ) );
void updateMatrix() #
inherited from Object3D
void updateMatrix() { if ( useQuaternion ) { setRotationFromQuaternion( matrix, quaternion ); } else { setRotationFromEuler( matrix, rotation, eulerOrder ); } matrix.setTranslation( position ); if ( scale.x != 1.0 || scale.y != 1.0 || scale.z != 1.0 ) { matrix.scale( scale ); boundRadiusScale = Math.max( scale.x, Math.max( scale.y, scale.z ) ); } matrixWorldNeedsUpdate = true; }
dynamic updateMatrixWorld({force: false}) #
updateMatrixWorld({force: false}) { if(matrixAutoUpdate) updateMatrix(); // update matrixWorld if ( matrixWorldNeedsUpdate || force ) { if ( parent != null) { matrixWorld = parent.matrixWorld * matrix; } else { matrixWorld.setFrom( matrix ); } matrixWorldNeedsUpdate = false; force = true; } // update children children.forEach((child) { if ( child is Bone ) { child.update( identityMatrix, false ); } else { child.updateMatrixWorld( true ); } }); // flatten bone matrices to array var b, bl = this.bones.length, ba = this.bones, bm = this.boneMatrices; for ( b = 0; b < bl; b ++ ) { ba[ b ].skinMatrix.flattenToArrayOffset( bm, b * 16 ); } if ( useVertexTexture ) { boneTexture.needsUpdate = true; } }