|
@@ -18,66 +18,84 @@ function SkinnedMesh( geometry, material ) {
|
|
|
|
|
|
this.type = 'SkinnedMesh';
|
|
|
|
|
|
- this.bindMode = "attached";
|
|
|
+ this.bindMode = 'attached';
|
|
|
this.bindMatrix = new Matrix4();
|
|
|
this.bindMatrixInverse = new Matrix4();
|
|
|
|
|
|
- // init bones
|
|
|
+ var bones = this.initBones();
|
|
|
+ var skeleton = new Skeleton( bones );
|
|
|
|
|
|
- // TODO: remove bone creation as there is no reason (other than
|
|
|
- // convenience) for THREE.SkinnedMesh to do this.
|
|
|
+ this.bind( skeleton, this.matrixWorld );
|
|
|
|
|
|
- var bones = [];
|
|
|
+ this.normalizeSkinWeights();
|
|
|
|
|
|
- if ( this.geometry && this.geometry.bones !== undefined ) {
|
|
|
+}
|
|
|
|
|
|
- var bone, gbone;
|
|
|
+SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
|
|
|
|
|
- for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {
|
|
|
+ constructor: SkinnedMesh,
|
|
|
|
|
|
- gbone = this.geometry.bones[ b ];
|
|
|
+ isSkinnedMesh: true,
|
|
|
|
|
|
- bone = new Bone();
|
|
|
- bones.push( bone );
|
|
|
+ initBones: function () {
|
|
|
|
|
|
- bone.name = gbone.name;
|
|
|
- bone.position.fromArray( gbone.pos );
|
|
|
- bone.quaternion.fromArray( gbone.rotq );
|
|
|
- if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
|
|
|
+ var bones = [], bone, gbone;
|
|
|
+ var i, il;
|
|
|
|
|
|
- }
|
|
|
+ if ( this.geometry && this.geometry.bones !== undefined ) {
|
|
|
+
|
|
|
+ // first, create array of 'Bone' objects from geometry data
|
|
|
|
|
|
- for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) {
|
|
|
+ for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
|
|
|
|
|
|
- gbone = this.geometry.bones[ b ];
|
|
|
+ gbone = this.geometry.bones[ i ];
|
|
|
|
|
|
- if ( gbone.parent !== - 1 && gbone.parent !== null &&
|
|
|
- bones[ gbone.parent ] !== undefined ) {
|
|
|
+ // create new 'Bone' object
|
|
|
|
|
|
- bones[ gbone.parent ].add( bones[ b ] );
|
|
|
+ bone = new Bone();
|
|
|
+ bones.push( bone );
|
|
|
|
|
|
- } else {
|
|
|
+ // apply values
|
|
|
|
|
|
- this.add( bones[ b ] );
|
|
|
+ bone.name = gbone.name;
|
|
|
+ bone.position.fromArray( gbone.pos );
|
|
|
+ bone.quaternion.fromArray( gbone.rotq );
|
|
|
+ if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl );
|
|
|
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
+ // second, create bone hierarchy
|
|
|
|
|
|
- }
|
|
|
+ for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) {
|
|
|
|
|
|
- this.normalizeSkinWeights();
|
|
|
+ gbone = this.geometry.bones[ i ];
|
|
|
|
|
|
- this.updateMatrixWorld( true );
|
|
|
- this.bind( new Skeleton( bones ), this.matrixWorld );
|
|
|
+ if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) {
|
|
|
|
|
|
-}
|
|
|
+ // subsequent bones in the hierarchy
|
|
|
|
|
|
-SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
|
|
+ bones[ gbone.parent ].add( bones[ i ] );
|
|
|
|
|
|
- constructor: SkinnedMesh,
|
|
|
+ } else {
|
|
|
|
|
|
- isSkinnedMesh: true,
|
|
|
+ // topmost bone, immediate child of the skinned mesh
|
|
|
+
|
|
|
+ this.add( bones[ i ] );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // now the bones are part of the scene graph and children of the skinned mesh
|
|
|
+ // let's update the corresponding matrices
|
|
|
+
|
|
|
+ this.updateMatrixWorld( true );
|
|
|
+
|
|
|
+ return bones;
|
|
|
+
|
|
|
+ },
|
|
|
|
|
|
bind: function ( skeleton, bindMatrix ) {
|
|
|
|
|
@@ -106,13 +124,15 @@ SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
|
|
|
|
|
normalizeSkinWeights: function () {
|
|
|
|
|
|
+ var scale, i;
|
|
|
+
|
|
|
if ( this.geometry && this.geometry.isGeometry ) {
|
|
|
|
|
|
- for ( var i = 0; i < this.geometry.skinWeights.length; i ++ ) {
|
|
|
+ for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) {
|
|
|
|
|
|
var sw = this.geometry.skinWeights[ i ];
|
|
|
|
|
|
- var scale = 1.0 / sw.lengthManhattan();
|
|
|
+ scale = 1.0 / sw.lengthManhattan();
|
|
|
|
|
|
if ( scale !== Infinity ) {
|
|
|
|
|
@@ -132,14 +152,14 @@ SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
|
|
|
|
|
var skinWeight = this.geometry.attributes.skinWeight;
|
|
|
|
|
|
- for ( var i = 0; i < skinWeight.count; i ++ ) {
|
|
|
+ for ( i = 0; i < skinWeight.count; i ++ ) {
|
|
|
|
|
|
vec.x = skinWeight.getX( i );
|
|
|
vec.y = skinWeight.getY( i );
|
|
|
vec.z = skinWeight.getZ( i );
|
|
|
vec.w = skinWeight.getW( i );
|
|
|
|
|
|
- var scale = 1.0 / vec.lengthManhattan();
|
|
|
+ scale = 1.0 / vec.lengthManhattan();
|
|
|
|
|
|
if ( scale !== Infinity ) {
|
|
|
|
|
@@ -159,9 +179,9 @@ SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
|
|
|
|
|
|
},
|
|
|
|
|
|
- updateMatrixWorld: function () {
|
|
|
+ updateMatrixWorld: function ( force ) {
|
|
|
|
|
|
- Mesh.prototype.updateMatrixWorld.call( this, true );
|
|
|
+ Mesh.prototype.updateMatrixWorld.call( this, force );
|
|
|
|
|
|
if ( this.bindMode === "attached" ) {
|
|
|
|