Dart DocumentationthreeSkinnedMesh

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

Object3D > Mesh > SkinnedMesh

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

List boneMatrices #

List boneMatrices

List bones #

List bones

DataTexture boneTexture #

DataTexture boneTexture

num boneTextureHeight #

num boneTextureWidth, boneTextureHeight

num boneTextureWidth #

num boneTextureWidth

num boundRadius #

inherited from Object3D
num boundRadius

num boundRadiusScale #

inherited from Object3D
num boundRadius, boundRadiusScale

bool castShadow #

inherited from Object3D
bool visible = false, castShadow = false

List children #

inherited from Object3D
List children

var customDepthMaterial #

inherited from Object3D
var customDepthMaterial

bool doubleSided #

inherited from Object3D
bool _dynamic, doubleSided

String eulerOrder #

inherited from Object3D
String eulerOrder

bool flipSided #

inherited from Object3D
bool _dynamic, doubleSided, flipSided

bool frustumCulled #

inherited from Object3D
bool visible = false, castShadow = false, receiveShadow = false, frustumCulled = false

Geometry geometry #

inherited from Mesh
Geometry geometry

int id #

inherited from Object3D
int id

Matrix4 identityMatrix #

Matrix4 identityMatrix

bool isDynamic #

inherited from Object3D
bool get isDynamic => _dynamic;
set isDynamic(bool flag) => _dynamic = flag;

Material material #

inherited from Mesh
Material material

Matrix4 matrix #

inherited from Object3D
Matrix4 matrix

bool matrixAutoUpdate #

inherited from Object3D
bool matrixAutoUpdate = false

Matrix4 matrixRotationWorld #

inherited from Object3D
Matrix4 matrix, matrixWorld, matrixRotationWorld

Matrix4 matrixWorld #

inherited from Object3D
Matrix4 matrix, matrixWorld

bool matrixWorldNeedsUpdate #

inherited from Object3D
bool matrixAutoUpdate = false, matrixWorldNeedsUpdate = false

num morphTargetBase #

inherited from Mesh
num morphTargetBase = 0

List morphTargetForcedOrder #

inherited from Mesh
List morphTargetForcedOrder

List morphTargetInfluences #

inherited from Mesh
List morphTargetInfluences

String name #

inherited from Object3D
String name

Object3D parent #

inherited from Object3D
Object3D parent

Vector3 position #

inherited from Object3D
Vector3 up, position

Map properties #

inherited from Object3D
Map properties

var quaternion #

inherited from Object3D
var quaternion

bool receiveShadow #

inherited from Object3D
bool visible = false, castShadow = false, receiveShadow = false

int renderDepth #

inherited from Object3D
int renderDepth

Vector3 rotation #

inherited from Object3D
Vector3 up, position, rotation

bool rotationAutoUpdate #

inherited from Object3D
bool _dynamic, doubleSided, flipSided, rotationAutoUpdate

Vector3 scale #

inherited from Object3D
Vector3 up, position, rotation, scale

Vector3 up #

inherited from Object3D
Vector3 up

bool useQuaternion #

inherited from Object3D
bool useQuaternion

bool useVertexTexture #

bool useVertexTexture

bool visible #

inherited from Object3D
bool visible = false

Operators

dynamic operator [](String key) #

inherited from Object3D
operator [] (String key) => _data[key];

dynamic operator []=(String key, value) #

inherited from Object3D
operator []= (String key, value) => _data[key] = value;

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();
}

dynamic clone() #

inherited from Object3D
clone() {

 // TODO

}

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;
	  }

	}

dynamic worldToLocal(Vector3 vector) #

inherited from Object3D
worldToLocal(Vector3 vector) {
 Matrix4 m = this.matrixWorld.clone();
 m.invert();
 m.transform3( vector );
}