/** * @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.type = 'SkinnedMesh'; 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 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 ]; p = gbone.pos; q = gbone.rotq; s = gbone.scl; bone = new THREE.Bone( this ); bones.push( bone ); bone.name = gbone.name; bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] ); bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] ); if ( s !== undefined ) { bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] ); } else { bone.scale.set( 1, 1, 1 ); } } for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; if ( gbone.parent !== - 1 ) { bones[ gbone.parent ].add( bones[ b ] ); } else { this.add( bones[ b ] ); } } } this.normalizeSkinWeights(); this.updateMatrixWorld( true ); this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) ); }; THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.SkinnedMesh.prototype.constructor = THREE.SkinnedMesh; THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) { this.skeleton = skeleton; if ( bindMatrix === undefined ) { this.updateMatrixWorld( true ); bindMatrix = this.matrixWorld; } this.bindMatrix.copy( bindMatrix ); this.bindMatrixInverse.getInverse( bindMatrix ); }; THREE.SkinnedMesh.prototype.pose = function () { this.skeleton.pose(); }; THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { if ( this.geometry instanceof THREE.Geometry ) { for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { var sw = this.geometry.skinWeights[ i ]; var scale = 1.0 / sw.lengthManhattan(); if ( scale !== Infinity ) { sw.multiplyScalar( scale ); } else { sw.set( 1 ); // this will be normalized by the shader anyway } } } else { // skinning weights assumed to be normalized for THREE.BufferGeometry } }; 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 { THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); } }; THREE.SkinnedMesh.prototype.clone = function( object ) { if ( object === undefined ) { object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); } THREE.Mesh.prototype.clone.call( this, object ); return object; };