|
@@ -2203,7 +2203,8 @@ THREE.ColladaLoader.prototype = {
|
|
|
|
|
|
var data = {
|
|
|
id: parseId( xml.getAttribute( 'url' ) ),
|
|
|
- materials: {}
|
|
|
+ materials: {},
|
|
|
+ skeletons: []
|
|
|
};
|
|
|
|
|
|
for ( var i = 0; i < xml.childNodes.length; i ++ ) {
|
|
@@ -2228,8 +2229,7 @@ THREE.ColladaLoader.prototype = {
|
|
|
break;
|
|
|
|
|
|
case 'skeleton':
|
|
|
- if ( data.skeleton !== undefined ) console.warn( 'THREE.ColladaLoader: The loader only supports one skeleton per instance_controller.' );
|
|
|
- data.skeleton = parseId( child.textContent );
|
|
|
+ data.skeletons.push( parseId( child.textContent ) );
|
|
|
break;
|
|
|
|
|
|
default:
|
|
@@ -2243,67 +2243,43 @@ THREE.ColladaLoader.prototype = {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function getSkeleton( root, controller ) {
|
|
|
+ function getSkeleton( skeletons, joints, skinnedMesh ) {
|
|
|
|
|
|
var boneData = [];
|
|
|
- var missingBoneData = [];
|
|
|
var sortedBoneData = [];
|
|
|
|
|
|
- var joints = controller.skin.joints;
|
|
|
+ var i, j, data;
|
|
|
|
|
|
- // setup bone data from visual scene
|
|
|
-
|
|
|
- root.traverse( function( object ) {
|
|
|
-
|
|
|
- if ( object.isBone === true ) {
|
|
|
+ // a skeleton can have multiple root bones. collada expresses this
|
|
|
+ // situtation with multiple "skeleton" tags per controller instance
|
|
|
|
|
|
- var boneInverse;
|
|
|
-
|
|
|
- for ( var i = 0; i < joints.length; i ++ ) {
|
|
|
-
|
|
|
- var joint = joints[ i ];
|
|
|
+ for ( i = 0; i < skeletons.length; i ++ ) {
|
|
|
|
|
|
- if ( joint.name === object.name ) {
|
|
|
+ var skeleton = skeletons[ i ];
|
|
|
+ var root = getNode( skeleton );
|
|
|
|
|
|
- boneInverse = joint.boneInverse;
|
|
|
- break;
|
|
|
+ // bone hierarchy is a child of the skinned mesh
|
|
|
|
|
|
- }
|
|
|
+ skinnedMesh.add( root );
|
|
|
|
|
|
- }
|
|
|
+ // setup bone data for a single bone hierarchy
|
|
|
|
|
|
- if ( boneInverse === undefined ) {
|
|
|
+ buildBoneHierarchy( root, joints, boneData );
|
|
|
|
|
|
- // Unfortunately, there can be joints in the visual scene that are not part of the
|
|
|
- // corresponding controller. In this case, we have to create a dummy boneInverse matrix
|
|
|
- // for the respective bone. This bone won't affect any vertices, because there are no skin indices
|
|
|
- // and weights defined for it. But we still have to add the bone to the sorted bone list in order to
|
|
|
- // ensure a correct animation of the model.
|
|
|
-
|
|
|
- missingBoneData.push( { bone: object, boneInverse: new THREE.Matrix4() } );
|
|
|
- console.warn( 'THREE.ColladaLoader: Missing data for bone: %s.', object.name );
|
|
|
-
|
|
|
- } else {
|
|
|
-
|
|
|
- boneData.push( { bone: object, boneInverse: boneInverse } );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- } );
|
|
|
+ }
|
|
|
|
|
|
// sort bone data (the order is defined in the corresponding controller)
|
|
|
|
|
|
- for ( var i = 0; i < joints.length; i ++ ) {
|
|
|
+ for ( i = 0; i < joints.length; i ++ ) {
|
|
|
|
|
|
- for ( var j = 0; j < boneData.length; j ++ ) {
|
|
|
+ for ( j = 0; j < boneData.length; j ++ ) {
|
|
|
|
|
|
- var data = boneData[ j ];
|
|
|
+ data = boneData[ j ];
|
|
|
|
|
|
if ( data.bone.name === joints[ i ].name ) {
|
|
|
|
|
|
sortedBoneData[ i ] = data;
|
|
|
+ data.processed = true;
|
|
|
break;
|
|
|
|
|
|
}
|
|
@@ -2312,11 +2288,18 @@ THREE.ColladaLoader.prototype = {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // add missing bone data at the end of the list
|
|
|
+ // add unprocessed bone data at the end of the list
|
|
|
+
|
|
|
+ for ( i = 0; i < boneData.length; i ++ ) {
|
|
|
|
|
|
- for ( var i = 0; i < missingBoneData.length; i ++ ) {
|
|
|
+ data = boneData[ i ];
|
|
|
|
|
|
- sortedBoneData.push( missingBoneData[ i ] );
|
|
|
+ if ( data.processed === false ) {
|
|
|
+
|
|
|
+ sortedBoneData.push( data );
|
|
|
+ data.processed = true;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -2325,9 +2308,9 @@ THREE.ColladaLoader.prototype = {
|
|
|
var bones = [];
|
|
|
var boneInverses = [];
|
|
|
|
|
|
- for ( var i = 0; i < sortedBoneData.length; i ++ ) {
|
|
|
+ for ( i = 0; i < sortedBoneData.length; i ++ ) {
|
|
|
|
|
|
- var data = sortedBoneData[ i ];
|
|
|
+ data = sortedBoneData[ i ];
|
|
|
|
|
|
bones.push( data.bone );
|
|
|
boneInverses.push( data.boneInverse );
|
|
@@ -2338,6 +2321,52 @@ THREE.ColladaLoader.prototype = {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ function buildBoneHierarchy( root, joints, boneData ) {
|
|
|
+
|
|
|
+ // setup bone data from visual scene
|
|
|
+
|
|
|
+ root.traverse( function( object ) {
|
|
|
+
|
|
|
+ if ( object.isBone === true ) {
|
|
|
+
|
|
|
+ var boneInverse;
|
|
|
+
|
|
|
+ // retrieve the boneInverse from the controller data
|
|
|
+
|
|
|
+ for ( var i = 0; i < joints.length; i ++ ) {
|
|
|
+
|
|
|
+ var joint = joints[ i ];
|
|
|
+
|
|
|
+ if ( joint.name === object.name ) {
|
|
|
+
|
|
|
+ boneInverse = joint.boneInverse;
|
|
|
+ break;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( boneInverse === undefined ) {
|
|
|
+
|
|
|
+ // Unfortunately, there can be joints in the visual scene that are not part of the
|
|
|
+ // corresponding controller. In this case, we have to create a dummy boneInverse matrix
|
|
|
+ // for the respective bone. This bone won't affect any vertices, because there are no skin indices
|
|
|
+ // and weights defined for it. But we still have to add the bone to the sorted bone list in order to
|
|
|
+ // ensure a correct animation of the model.
|
|
|
+
|
|
|
+ boneInverse = new THREE.Matrix4();
|
|
|
+ console.warn( 'THREE.ColladaLoader: Missing data for bone: %s.', object.name );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ boneData.push( { bone: object, boneInverse: boneInverse, processed: false } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
function buildNode( data ) {
|
|
|
|
|
|
var objects = [];
|
|
@@ -2371,12 +2400,13 @@ THREE.ColladaLoader.prototype = {
|
|
|
var materials = resolveMaterialBinding( geometry.materialKeys, instance.materials );
|
|
|
var object = getObject( geometry, materials );
|
|
|
|
|
|
- var node = getNode( instance.skeleton );
|
|
|
- var skeleton = getSkeleton( node, controller );
|
|
|
+ var skeletons = instance.skeletons;
|
|
|
+ var joints = controller.skin.joints;
|
|
|
+
|
|
|
+ var skeleton = getSkeleton( skeletons, joints, object );
|
|
|
|
|
|
object.bind( skeleton, controller.skin.bindMatrix );
|
|
|
object.normalizeSkinWeights();
|
|
|
- object.add( node ); // bone hierarchy is a child of the skinned mesh
|
|
|
|
|
|
objects.push( object );
|
|
|
|