|
@@ -1,31 +1,28 @@
|
|
|
/**
|
|
|
* @author mikael emtinger / http://gomo.se/
|
|
|
* @author alteredq / http://alteredqualia.com/
|
|
|
+ * @author ikerr / http://verold.com
|
|
|
*/
|
|
|
|
|
|
THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
|
|
|
|
|
|
THREE.Mesh.call( this, geometry, material );
|
|
|
|
|
|
- this.useVertexTexture = useVertexTexture;
|
|
|
-
|
|
|
- this.identityMatrix = new THREE.Matrix4();
|
|
|
-
|
|
|
- this.bones = [];
|
|
|
-
|
|
|
- this.boneMatrices = null;
|
|
|
+ this.bindMode = "attached";
|
|
|
+ this.bindMatrix = new THREE.Matrix4();
|
|
|
+ this.bindMatrixInverse = new THREE.Matrix4();
|
|
|
|
|
|
// init bones
|
|
|
|
|
|
// TODO: remove bone creation as there is no reason (other than
|
|
|
// convenience) for THREE.SkinnedMesh to do this.
|
|
|
|
|
|
- var bone, gbone, p, q, s;
|
|
|
-
|
|
|
var bones = [];
|
|
|
|
|
|
if ( this.geometry && this.geometry.bones !== undefined ) {
|
|
|
|
|
|
+ var bone, gbone, p, q, s;
|
|
|
+
|
|
|
for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
|
|
|
|
|
|
gbone = this.geometry.bones[ b ];
|
|
@@ -34,7 +31,7 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
|
|
|
q = gbone.rotq;
|
|
|
s = gbone.scl;
|
|
|
|
|
|
- bone = new Bone( this );
|
|
|
+ bone = new THREE.Bone( this );
|
|
|
bones.push( bone );
|
|
|
|
|
|
bone.name = gbone.name;
|
|
@@ -61,160 +58,46 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
|
|
|
|
|
|
bones[ gbone.parent ].add( bones[ b ] );
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- this.bind( bones );
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
|
|
|
-
|
|
|
-THREE.SkinnedMesh.prototype.bind = function( bones ) {
|
|
|
-
|
|
|
- bones = bones || [];
|
|
|
- this.bones = bones.slice( 0 );
|
|
|
- this.boneInverses = undefined;
|
|
|
-
|
|
|
- // update bone matrices and/or texture
|
|
|
-
|
|
|
- this.initBoneMatrices();
|
|
|
-
|
|
|
- // update bone inverses
|
|
|
-
|
|
|
- this.pose();
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-THREE.SkinnedMesh.prototype.initBoneInverses = function () {
|
|
|
-
|
|
|
- this.boneInverses = [];
|
|
|
-
|
|
|
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
|
|
|
-
|
|
|
- var inverse = new THREE.Matrix4();
|
|
|
+ } else {
|
|
|
|
|
|
- if ( this.bones[ b ] ) {
|
|
|
+ this.add( bones[ b ] );
|
|
|
|
|
|
- inverse.getInverse( this.bones[ b ].matrixWorld );
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- inverse.multiply( this.matrixWorld );
|
|
|
-
|
|
|
- this.boneInverses.push( inverse );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-};
|
|
|
-
|
|
|
-THREE.SkinnedMesh.prototype.initBoneMatrices = function () {
|
|
|
-
|
|
|
- var nBones = this.bones.length;
|
|
|
-
|
|
|
- // clear the old bone texture and float array
|
|
|
-
|
|
|
- this.boneMatrices = null;
|
|
|
- this.boneTextureWidth = undefined;
|
|
|
- this.boneTextureHeight = undefined;
|
|
|
-
|
|
|
- if ( this.boneTexture ) {
|
|
|
-
|
|
|
- this.boneTexture.dispose();
|
|
|
- this.boneTexture = undefined;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
- // create a bone texture or an array of floats
|
|
|
-
|
|
|
- if ( this.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;
|
|
|
-
|
|
|
- this.boneTextureWidth = size;
|
|
|
- this.boneTextureHeight = size;
|
|
|
-
|
|
|
- this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
|
|
|
- this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
|
|
|
- this.boneTexture.minFilter = THREE.NearestFilter;
|
|
|
- this.boneTexture.magFilter = THREE.NearestFilter;
|
|
|
- this.boneTexture.generateMipmaps = false;
|
|
|
- this.boneTexture.flipY = false;
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- this.boneMatrices = new Float32Array( 16 * nBones );
|
|
|
+ this.normalizeSkinWeights();
|
|
|
|
|
|
- }
|
|
|
+ this.updateMatrixWorld( true );
|
|
|
+ this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );
|
|
|
|
|
|
};
|
|
|
|
|
|
-THREE.SkinnedMesh.prototype.updateBoneMatrices = function () {
|
|
|
-
|
|
|
- var offsetMatrix = new THREE.Matrix4();
|
|
|
-
|
|
|
- var invMatrixWorld = new THREE.Matrix4().getInverse( this.matrixWorld );
|
|
|
-
|
|
|
- // make a snapshot of the bones' rest position
|
|
|
|
|
|
- if ( this.boneInverses === undefined ) {
|
|
|
-
|
|
|
- this.initBoneInverses();
|
|
|
-
|
|
|
- }
|
|
|
+THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
|
|
|
|
|
|
- // flatten bone matrices to array
|
|
|
+THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {
|
|
|
|
|
|
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
|
|
|
+ this.skeleton = skeleton;
|
|
|
|
|
|
- // compute the offset between the current and the original transform;
|
|
|
+ if ( bindMatrix === undefined ) {
|
|
|
|
|
|
- var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;
|
|
|
+ this.updateMatrixWorld( true );
|
|
|
|
|
|
- offsetMatrix.multiplyMatrices( invMatrixWorld, matrix );
|
|
|
- offsetMatrix.multiply( this.boneInverses[ b ] );
|
|
|
- offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
|
|
|
+ bindMatrix = this.matrixWorld;
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( this.useVertexTexture ) {
|
|
|
-
|
|
|
- this.boneTexture.needsUpdate = true;
|
|
|
-
|
|
|
- }
|
|
|
+ this.bindMatrix.copy( bindMatrix );
|
|
|
+ this.bindMatrixInverse.getInverse( bindMatrix );
|
|
|
|
|
|
};
|
|
|
|
|
|
THREE.SkinnedMesh.prototype.pose = function () {
|
|
|
|
|
|
- this.updateMatrixWorld( true );
|
|
|
-
|
|
|
- // force recomputation of bone inverses
|
|
|
-
|
|
|
- this.boneInverses = undefined;
|
|
|
- this.updateBoneMatrices();
|
|
|
-
|
|
|
- this.normalizeSkinWeights();
|
|
|
+ this.skeleton.pose();
|
|
|
|
|
|
};
|
|
|
|
|
@@ -248,7 +131,27 @@ THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {
|
|
|
|
|
|
};
|
|
|
|
|
|
-THREE.SkinnedMesh.prototype.clone = function ( object ) {
|
|
|
+THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {
|
|
|
+
|
|
|
+ THREE.Mesh.prototype.updateMatrixWorld.call( this, true );
|
|
|
+
|
|
|
+ if ( this.bindMode === "attached" ) {
|
|
|
+
|
|
|
+ this.bindMatrixInverse.getInverse( this.matrixWorld );
|
|
|
+
|
|
|
+ } else if ( this.bindMode === "detached" ) {
|
|
|
+
|
|
|
+ this.bindMatrixInverse.getInverse( this.bindMatrix );
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+THREE.SkinnedMesh.prototype.clone = function( object ) {
|
|
|
|
|
|
if ( object === undefined ) {
|
|
|
|