瀏覽代碼

Merge pull request #10212 from Kyle-Larson/feature/FBX-Material-Import

FBX Material Import
Mr.doob 8 年之前
父節點
當前提交
13dd7b0907
共有 2 個文件被更改,包括 180 次插入55 次删除
  1. 174 53
      examples/js/loaders/FBXLoader.js
  2. 6 2
      examples/webgl_loader_fbx.html

+ 174 - 53
examples/js/loaders/FBXLoader.js

@@ -1,5 +1,6 @@
 /**
  * @author yamahigashi https://github.com/yamahigashi
+ * @author Kyle-Larson https://github.com/Kyle-Larson
  *
  * This loader loads FBX file in *ASCII and version 7 format*.
  *
@@ -121,6 +122,7 @@
 		scope.weights	= ( new Weights() ).parse( nodes, scope.hierarchy );
 		scope.animations = ( new Animation() ).parse( nodes, scope.hierarchy );
 		scope.textures = ( new Textures() ).parse( nodes, scope.hierarchy );
+		scope.materials = ( new Materials() ).parse( nodes, scope.hierarchy );
 		console.timeEnd( 'FBXLoader: ObjectParser' );
 
 		console.time( 'FBXLoader: GeometryParser' );
@@ -237,7 +239,6 @@
 		geometry.computeBoundingSphere();
 		geometry.computeBoundingBox();
 
-		// TODO: texture & material support
 		var texture;
 		var texs = this.textures.getById( nodes.searchConnectionParent( geo.id ) );
 		if ( texs !== undefined && texs.length > 0 ) {
@@ -251,15 +252,68 @@
 
 		}
 
+		var materials = [];
 		var material;
-		if ( texture !== undefined ) {
+		var mats = this.materials.getById( nodes.searchConnectionParent( geo.id ) );
+		if ( mats !== undefined && mats.length > 0) {
+			for(var i = 0; i < mats.length; ++i) {
+				var mat_data = mats[i];
+				var tmpMat;
+
+				// TODO:
+				// Cannot find a list of possible ShadingModel values.
+				// If someone finds a list, please add additional cases
+				// and map to appropriate materials.
+				switch(mat_data.type) {
+					case "phong":
+					tmpMat = new THREE.MeshPhongMaterial();
+					break;
+					case "Lambert":
+					tmpMat = new THREE.MeshLambertMaterial();
+					break;
+					default:
+					console.warn("No implementation given for material type " + mat_data.type + " in FBXLoader.js.  Defaulting to basic material")
+					tmpMat = new THREE.MeshBasicMaterial({ color: 0x3300ff });
+					break;
+				}
+				if (texture !== undefined) {
+					mat_data.parameters.map = texture;
+				}
+				tmpMat.setValues(mat_data.parameters);
+
+				materials.push(tmpMat);
+			}
+
+			if(materials.length === 1) {
+				material = materials[0];
+			} else {
+				//Set up for multi-material
+				material = new THREE.MultiMaterial(materials);
+				var material_groupings = [];
+				var last_material_group = -1;
+				var material_index_list = toInt(node.subNodes.LayerElementMaterial.subNodes.Materials.properties.a.split( ',' ));
+				for(var i = 0; i < geo.polyIndices.length; ++i) {
+					if(last_material_group !== material_index_list[geo.polyIndices[i]]) {
+						material_groupings.push({start: i * 3, count: 0, materialIndex: material_index_list[geo.polyIndices[i]]});
+						last_material_group = material_index_list[geo.polyIndices[i]];
+					}
+					material_groupings[material_groupings.length - 1].count += 3;
+				}
+				geometry.groups = material_groupings;
+			}
 
-			material = new THREE.MeshBasicMaterial( { map: texture } );
 
 		} else {
+			//No material found for this geometry, create default
+			if (texture !== undefined) {
+
+				material = new THREE.MeshBasicMaterial({ map: texture });
+
+			} else {
 
-			material = new THREE.MeshBasicMaterial( { color: 0x3300ff } );
+				material = new THREE.MeshBasicMaterial({ color: 0x3300ff });
 
+			}
 		}
 
 		geometry = new THREE.Geometry().fromBufferGeometry( geometry );
@@ -480,51 +534,6 @@
 
 	};
 
-	THREE.FBXLoader.prototype.parseMaterials = function ( node ) {
-
-		// has not mat, return []
-		if ( ! ( 'Material' in node.subNodes ) ) {
-
-			return [];
-
-		}
-
-		// has many
-		var matCount = 0;
-		for ( var mat in node.subNodes.Materials ) {
-
-			if ( mat.match( /^\d+$/ ) ) {
-
-				matCount ++;
-
-			}
-
-		}
-
-		var res = [];
-		if ( matCount > 0 ) {
-
-			for ( mat in node.subNodes.Material ) {
-
-				res.push( parseMaterial( node.subNodes.Material[ mat ] ) );
-
-			}
-
-		} else {
-
-			res.push( parseMaterial( node.subNodes.Material ) );
-
-		}
-
-		return res;
-
-	};
-
-	// TODO
-	THREE.FBXLoader.prototype.parseMaterial = function ( node ) {
-
-	};
-
 
 	THREE.FBXLoader.prototype.loadFile = function ( url, onLoad, onProgress, onError, responseType ) {
 
@@ -1564,8 +1573,10 @@
 
 		if ( this.getPolygonTopologyMax() > 3 ) {
 
-			this.indices = this.convertPolyIndicesToTri(
+			var indexInfo = this.convertPolyIndicesToTri(
 								this.indices, this.getPolygonTopologyArray() );
+			this.indices = indexInfo.res;
+			this.polyIndices = indexInfo.polyIndices;
 
 		}
 
@@ -1709,14 +1720,16 @@
 	//
 	// [( a, b, c, d ) ...........
 	// [( a, b, c ), (a, c, d )....
+
+	// Also keep track of original poly index.
 	Geometry.prototype.convertPolyIndicesToTri = function ( indices, strides ) {
 
 		var res = [];
 
 		var i = 0;
-		var tmp = [];
 		var currentPolyNum = 0;
 		var currentStride = 0;
+		var polyIndices = [];
 
 		while ( i < indices.length ) {
 
@@ -1729,14 +1742,14 @@
 				res.push( indices[ i + ( currentStride - 2 - j ) ] );
 				res.push( indices[ i + ( currentStride - 1 - j ) ] );
 
+				polyIndices.push(currentPolyNum);
 			}
 
 			currentPolyNum ++;
 			i += currentStride;
-
 		}
 
-		return res;
+		return {res: res, polyIndices: polyIndices};
 
 	};
 
@@ -2503,6 +2516,114 @@
 
 	};
 
+	function Materials() {
+		this.materials = [];
+		this.perGeoMap = {};
+	}
+
+	Materials.prototype.add = function ( mat ) {
+
+		if ( this.materials === undefined ) {
+
+			this.materials = [];
+
+		}
+
+		this.materials.push( mat );
+
+		for ( var i = 0; i < mat.parentIds.length; ++ i ) {
+
+			if ( this.perGeoMap[ mat.parentIds[ i ] ] === undefined ) {
+
+				this.perGeoMap[ mat.parentIds[ i ] ] = [];
+
+			}
+
+			this.perGeoMap[ mat.parentIds[ i ] ].push( this.materials[ this.materials.length - 1 ] );
+
+		}
+
+	};
+
+	Materials.prototype.parse = function ( node, bones ) {
+
+		var rawNodes = node.Objects.subNodes.Material;
+
+		for ( var n in rawNodes ) {
+
+			var mat = ( new Material() ).parse( rawNodes[ n ], node );
+			this.add( mat );
+
+		}
+
+		return this;
+
+	};
+
+	Materials.prototype.getById = function ( id ) {
+
+		return this.perGeoMap[ id ];
+
+	};
+
+	function Material() {
+
+		this.fileName = "";
+		this.name = "";
+		this.id = null;
+		this.parentIds = [];
+
+	}
+
+	Material.prototype.parse = function ( node, nodes ) {
+
+		this.id = node.id;
+		this.name = node.attrName;
+		this.type = node.properties.ShadingModel;
+
+		this.parameters = this.getParameters( node.properties );
+
+		this.parentIds = this.searchParents( this.id, nodes );
+
+		return this;
+
+	};
+
+	Material.prototype.getParameters = function( properties ) {
+		var parameters = {};
+
+		//TODO: Missing parameters:
+		// - Ambient
+		// - AmbientColor
+		// - (Diffuse?) Using DiffuseColor, which has same value, so I dunno.
+		// - (Emissive?) Same as above)
+		// - MultiLayer
+		// - ShininessExponent (Same vals as Shininess)
+		// - Specular (Same vals as SpecularColor)
+		// - TransparencyFactor (Maybe same as Opacity?).
+
+		parameters.color = new THREE.Color().fromArray(toFloat([properties.DiffuseColor.value.x, properties.DiffuseColor.value.y, properties.DiffuseColor.value.z]));
+		parameters.specular = new THREE.Color().fromArray(toFloat([properties.SpecularColor.value.x, properties.SpecularColor.value.y, properties.SpecularColor.value.z]));
+		parameters.shininess = properties.Shininess.value;
+		parameters.emissive = new THREE.Color().fromArray(toFloat([properties.EmissiveColor.value.x, properties.EmissiveColor.value.y, properties.EmissiveColor.value.z]));
+		parameters.emissiveIntensity = properties.EmissiveFactor.value;
+		parameters.reflectivity = properties.Reflectivity.value;
+		parameters.opacity = properties.Opacity.value;
+		if(parameters.opacity < 1.0) {
+			parameters.transparent = true;
+		}
+
+		return parameters;
+	};
+
+	Material.prototype.searchParents = function ( id, nodes ) {
+
+		var p = nodes.searchConnectionParent( id );
+
+		return p;
+
+	};
+
 
 	/* --------------------------------------------------------------------- */
 	/* --------------------------------------------------------------------- */

+ 6 - 2
examples/webgl_loader_fbx.html

@@ -44,7 +44,7 @@
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 			var container, stats, controls;
-			var camera, scene, renderer;
+			var camera, scene, renderer, light;
 
 			var clock = new THREE.Clock();
 
@@ -93,7 +93,7 @@
 				};
 
 				var loader = new THREE.FBXLoader( manager );
-				loader.load( 'models/fbx/xsi_man_skinning.fbx', function( object ) {
+				loader.load( 'models/fbx/xsi_man.fbx', function( object ) {
 
 					object.traverse( function( child ) {
 
@@ -138,6 +138,10 @@
 
 				window.addEventListener( 'resize', onWindowResize, false );
 
+				light = new THREE.DirectionalLight(0xffffff, 1.0);
+				light.position.set(0, 1, 0);
+				scene.add(light);
+
 				animate();
 
 			}