Răsfoiți Sursa

Merge pull request #11517 from Mugen87/dev

ColladaLoader2: Improved skeletal animation
Mr.doob 8 ani în urmă
părinte
comite
19b7a18ea4
1 a modificat fișierele cu 88 adăugiri și 9 ștergeri
  1. 88 9
      examples/js/loaders/ColladaLoader2.js

+ 88 - 9
examples/js/loaders/ColladaLoader2.js

@@ -432,8 +432,10 @@ THREE.ColladaLoader.prototype = {
 
 			var keyframes = prepareAnimationData( data, defaultMatrix );
 
+			if ( node.sid === null ) console.warn( 'THREE.ColladaLoader: Invalid node in joint hierarchy: ', node );
+
 			var animation = {
-				name: '.bones[' + node.sid + ']',
+				name: '.skeleton.bones[' + node.sid + ']',
 				keyframes: keyframes
 			}
 
@@ -864,7 +866,7 @@ THREE.ColladaLoader.prototype = {
 			var BONE_LIMIT = 4;
 
 			var build = {
-				bones: {},
+				joints: [], // this must be an array to preserve the joint order
 				indices: {
 					array: [],
 					stride: BONE_LIMIT
@@ -949,7 +951,7 @@ THREE.ColladaLoader.prototype = {
 				var name = jointSource.array[ i ];
 				var boneInverse = new THREE.Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose();
 
-				build.bones[ name ] = boneInverse;
+				build.joints.push( { name: name, boneInverse: boneInverse } );
 
 			}
 
@@ -2232,21 +2234,99 @@ THREE.ColladaLoader.prototype = {
 
 		function getSkeleton( root, controller ) {
 
-			var boneArray = [];
-			var boneInverseArray = [];
+			var boneData = [];
+			var missingBoneData = [];
+			var sortedBoneData = [];
+
+			var joints = controller.skin.joints;
+
+			root.updateMatrixWorld( true );
+
+			// setup bone data from visual scene
 
 			root.traverse( function( object ) {
 
 				if ( object.isBone === true ) {
 
-					boneArray.push( object );
-					boneInverseArray.push( controller.skin.bones[ object.name ] );
+					var boneInverse;
+
+					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 boneInverse matrix
+						// for the respective bone. These data won't affect the skeleton, because there are no skin indices
+						// and weights defined for the bone. But we still have to add these data to the sorted bone list in order to
+						// ensure a correct animation of the model.
+
+						boneInverse = new THREE.Matrix4().getInverse( object.matrixWorld );
+						console.warn( 'THREE.ColladaLoader: Missing data for bone: %s.', object.name );
+						missingBoneData.push( { bone: object, boneInverse: boneInverse } );
+
+					} else {
+
+						boneData.push( { bone: object, boneInverse: boneInverse } );
+
+					}
 
 				}
 
 			} );
 
-			return new THREE.Skeleton( boneArray, boneInverseArray );
+			// sort bone data (the order is defined in the corresponding controller)
+
+			for ( var i = 0; i < joints.length; i ++ ) {
+
+				for ( var j = 0; j < boneData.length; j ++ ) {
+
+					var data = boneData[ j ];
+
+					if ( data.bone.name === joints[ i ].name ) {
+
+						sortedBoneData[ i ] = data;
+						break;
+
+					}
+
+				}
+
+			}
+
+			// add missing bone data at the end of the list
+
+			for ( var i = 0; i < missingBoneData.length; i ++ ) {
+
+				sortedBoneData.push( missingBoneData[ i ] );
+
+			}
+
+			// setup arrays for skeleton creation
+
+			var bones = [];
+			var boneInverses = [];
+
+			for ( var i = 0; i < sortedBoneData.length; i ++ ) {
+
+				var data = sortedBoneData[ i ];
+
+				bones.push( data.bone );
+				boneInverses.push( data.boneInverse );
+
+			}
+
+			return new THREE.Skeleton( bones, boneInverses );
 
 		}
 
@@ -2288,7 +2368,6 @@ THREE.ColladaLoader.prototype = {
 
 				object.bind( skeleton, controller.skin.bindMatrix );
 				object.normalizeSkinWeights();
-				object.bones = skeleton.bones; // this is necessary for property binding
 				object.add( node ); // bone hierarchy is a child of the skinned mesh
 
 				objects.push( object );