Browse Source

Merge pull request #11480 from Mugen87/dev

ColladaLoader2: Added skeleton data
Mr.doob 8 years ago
parent
commit
032d69e851
1 changed files with 95 additions and 23 deletions
  1. 95 23
      examples/js/loaders/ColladaLoader2.js

+ 95 - 23
examples/js/loaders/ColladaLoader2.js

@@ -71,6 +71,23 @@ THREE.ColladaLoader.prototype = {
 
 		}
 
+		function parseStrings( text ) {
+
+			if ( text.length === 0 ) return [];
+
+			var parts = text.trim().split( /\s+/ );
+			var array = new Array( parts.length );
+
+			for ( var i = 0, l = parts.length; i < l; i ++ ) {
+
+				array[ i ] = parts[ i ];
+
+			}
+
+			return array;
+
+		}
+
 		function parseFloats( text ) {
 
 			if ( text.length === 0 ) return [];
@@ -310,9 +327,7 @@ THREE.ColladaLoader.prototype = {
 
 		function parseController( xml ) {
 
-			var data = {
-				skin: {}
-			};
+			var data = {};
 
 			for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
 
@@ -324,8 +339,8 @@ THREE.ColladaLoader.prototype = {
 
 					case 'skin':
 						// there is exactly one skin per controller
-						data.skin.id = parseId( child.getAttribute( 'source' ) );
-						data.skin.data = parseSkin( child );
+						data.id = parseId( child.getAttribute( 'source' ) );
+						data.skin = parseSkin( child );
 						break;
 
 				}
@@ -444,14 +459,14 @@ THREE.ColladaLoader.prototype = {
 
 			var build = {};
 
-			build.id = data.skin.id;
-			build.sources = buildSkin( data.skin.data );
+			build.id = data.id;
+			build.skin = buildSkin( data.skin );
 
 			// we enhance the 'sources' property of the corresponding geometry with our skin data
 
 			var geometry = library.geometries[ build.id ];
-			geometry.sources.skinIndices = build.sources.skinIndices;
-			geometry.sources.skinWeights = build.sources.skinWeights;
+			geometry.sources.skinIndices = build.skin.indices;
+			geometry.sources.skinWeights = build.skin.weights;
 
 			return build;
 
@@ -462,11 +477,12 @@ THREE.ColladaLoader.prototype = {
 			var BONE_LIMIT = 4;
 
 			var build = {
-				skinIndices: {
+				bones: {},
+				indices: {
 					array: [],
 					stride: BONE_LIMIT
 				},
-				skinWeights: {
+				weights: {
 					array: [],
 					stride: BONE_LIMIT
 				}
@@ -480,20 +496,22 @@ THREE.ColladaLoader.prototype = {
 			var jointOffset = vertexWeights.inputs.JOINT.offset;
 			var weightOffset = vertexWeights.inputs.WEIGHT.offset;
 
+			var jointSource = data.sources[ data.joints.inputs.JOINT ];
+			var inverseSource = data.sources[ data.joints.inputs.INV_BIND_MATRIX ];
+
 			var weights = sources[ vertexWeights.inputs.WEIGHT.id ].array;
 			var stride = 0;
 
-			var skinIndices = [];
-			var skinWeights = [];
+			var i, j, l;
 
 			// procces skin data for each vertex
 
-			for ( var i = 0, l = vcount.length; i < l; i ++ ) {
+			for ( i = 0, l = vcount.length; i < l; i ++ ) {
 
 				var jointCount = vcount[ i ]; // this is the amount of joints that affect a single vertex
 				var vertexSkinData = [];
 
-				for ( var j = 0; j < jointCount; j ++ ) {
+				for ( j = 0; j < jointCount; j ++ ) {
 
 					var skinIndex = v[ stride + jointOffset ];
 					var weightId = v[ stride + weightOffset ];
@@ -513,19 +531,19 @@ THREE.ColladaLoader.prototype = {
 				// now we provide for each vertex a set of four index and weight values.
 				// the order of the skin data matches the order of vertices
 
-				for ( var j = 0; j < BONE_LIMIT; j ++ ) {
+				for ( j = 0; j < BONE_LIMIT; j ++ ) {
 
 					var d = vertexSkinData[ j ];
 
 					if ( d !== undefined ) {
 
-						build.skinIndices.array.push( d.index );
-						build.skinWeights.array.push( d.weight );
+						build.indices.array.push( d.index );
+						build.weights.array.push( d.weight );
 
 					} else {
 
-						build.skinIndices.array.push( 0 );
-						build.skinWeights.array.push( 0 );
+						build.indices.array.push( 0 );
+						build.weights.array.push( 0 );
 
 					}
 
@@ -533,6 +551,21 @@ THREE.ColladaLoader.prototype = {
 
 			}
 
+			// setup bind matrix
+
+			build.bindMatrix = new THREE.Matrix4().fromArray( data.bindShapeMatrix ).transpose();
+
+			// process bones and inverse bind matrix data
+
+			for ( i = 0, l = jointSource.array.length; i < l; i ++ ) {
+
+				var name = jointSource.array[ i ];
+				var boneInverse = new THREE.Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose();
+
+				build.bones[ name ] = boneInverse;
+
+			}
+
 			return build;
 
 			// array sort function
@@ -1379,6 +1412,10 @@ THREE.ColladaLoader.prototype = {
 						data.array = parseFloats( child.textContent );
 						break;
 
+					case 'Name_array':
+						data.array = parseStrings( child.textContent );
+						break;
+
 					case 'technique_common':
 						var accessor = getElementsByTagName( child, 'accessor' )[ 0 ];
 
@@ -1467,6 +1504,8 @@ THREE.ColladaLoader.prototype = {
 			var vertices = data.vertices;
 			var primitives = data.primitives;
 
+			var skinning = false;
+
 			if ( primitives.length === 0 ) return group;
 
 			for ( var p = 0; p < primitives.length; p ++ ) {
@@ -1494,6 +1533,8 @@ THREE.ColladaLoader.prototype = {
 									geometry.addAttribute( 'skinWeight', buildGeometryAttribute( primitive, sources.skinWeights, input.offset ) );
 									geometry.addAttribute( 'skinIndex', buildGeometryAttribute( primitive, sources.skinIndices, input.offset ) );
 
+									skinning = true;
+
 								}
 
 							}
@@ -1529,7 +1570,7 @@ THREE.ColladaLoader.prototype = {
 
 					case 'triangles':
 					case 'polylist':
-						object = new THREE.Mesh( geometry, DEFAULT_MESHMATERIAL );
+						object = ( skinning === true ) ? new THREE.SkinnedMesh( geometry, DEFAULT_MESHMATERIAL ) : new THREE.Mesh( geometry, DEFAULT_MESHMATERIAL );
 						break;
 
 				}
@@ -1639,6 +1680,8 @@ THREE.ColladaLoader.prototype = {
 
 			var data = {
 				name: xml.getAttribute( 'name' ),
+				type: xml.getAttribute( 'type' ),
+				sid: xml.getAttribute( 'sid' ),
 				matrix: new THREE.Matrix4(),
 				nodes: [],
 				instanceCameras: [],
@@ -1772,12 +1815,33 @@ THREE.ColladaLoader.prototype = {
 
 		}
 
+		function getSkeleton( root, controller ) {
+
+			var boneArray = [];
+			var boneInverseArray = [];
+
+			root.traverse( function( object ) {
+
+				if ( object.isBone === true ) {
+
+					boneArray.push( object );
+					boneInverseArray.push( controller.skin.bones[ object.name ] );
+
+				}
+
+			} );
+
+			return new THREE.Skeleton( boneArray, boneInverseArray );
+
+		}
+
 		function buildNode( data ) {
 
 			var objects = [];
 
 			var matrix = data.matrix;
 			var nodes = data.nodes;
+			var type = data.type;
 			var instanceCameras = data.instanceCameras;
 			var instanceControllers = data.instanceControllers;
 			var instanceLights = data.instanceLights;
@@ -1802,13 +1866,21 @@ THREE.ColladaLoader.prototype = {
 				var controller = getController( instance.id );
 				var geometries = getGeometry( controller.id );
 
+				var node = getNode( instance.skeleton );
+				var skeleton = getSkeleton( node, controller );
+
 				for ( var key in geometries ) {
 
 					var object = geometries[ key ].clone();
 
 					if ( instance.materials[ key ] !== undefined ) {
 
+						object.bind( skeleton, controller.skin.bindMatrix );
+						object.normalizeSkinWeights();
+						object.add( node ); // bone hierarchy is a child of the skinned mesh
+
 						object.material = getMaterial( instance.materials[ key ] );
+						object.material.skinning = true;
 
 					}
 
@@ -1859,7 +1931,7 @@ THREE.ColladaLoader.prototype = {
 
 			} else {
 
-				object = new THREE.Group();
+				object = ( type === 'JOINT' ) ? new THREE.Bone() : new THREE.Group();
 
 				for ( var i = 0; i < objects.length; i ++ ) {
 
@@ -1869,7 +1941,7 @@ THREE.ColladaLoader.prototype = {
 
 			}
 
-			object.name = data.name;
+			object.name = ( type === 'JOINT' ) ? data.sid : data.name;
 			object.matrix.copy( matrix );
 			object.matrix.decompose( object.position, object.quaternion, object.scale );