diff --git a/examples/js/loaders/FBXLoader.js b/examples/js/loaders/FBXLoader.js index 09165dc41d84da1d965b378ff42a3438524372f3..14ace2ae03396158b11a45bd4c074d72d59fd417 100644 --- a/examples/js/loaders/FBXLoader.js +++ b/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; + + }; + /* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */ diff --git a/examples/webgl_loader_fbx.html b/examples/webgl_loader_fbx.html index 696e46ff97ebf33e807b6b2dc96b65ed1da3c5b4..d1a32293c31f54ac02400d8ea242d2eaca7d1038 100644 --- a/examples/webgl_loader_fbx.html +++ b/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(); }