Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 51 additions & 32 deletions examples/jsm/loaders/FBXLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@
Vector2,
Vector3,
Vector4,
VectorKeyframeTrack
VectorKeyframeTrack,
MeshStandardMaterial
} from 'three';

import * as fflate from '../libs/fflate.module.js';
import { NURBSCurve } from '../curves/NURBSCurve.js';


let fbxTree;
let connections;
let sceneGraph;
Expand Down Expand Up @@ -168,11 +170,9 @@

}

// console.log( fbxTree );

const textureLoader = new TextureLoader( this.manager ).setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );

return new FBXTreeParser( textureLoader, this.manager ).parse( fbxTree );
return new FBXTreeParser( textureLoader, this.manager ).parse(); // Parse the fbxTree

}

Expand Down Expand Up @@ -259,7 +259,6 @@

const images = {};
const blobs = {};

if ( 'Video' in fbxTree.Objects ) {

const videoNodes = fbxTree.Objects.Video;
Expand Down Expand Up @@ -297,8 +296,7 @@
const filename = images[ id ];

if ( blobs[ filename ] !== undefined ) images[ id ] = blobs[ filename ];
else images[ id ] = images[ id ].split( '\\' ).pop();

else images[ id ] = images[ id ].replace(/^.*[\\/]|[?#].*$/g, ''); // Split on / or ?# as well as \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change required?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding this change. I can see that my comment was a bit unclear as to why this is necassary. When I work in maya, forward slashes has to be used for paths. The loader did only account for backslashes, making the path invalid. The regex (shamefully admitting it being AI-generated) takes both and back and forward slash into account. I also noticed it that it would consider ? and #. Which at first seemed uncessary. But then I thought: "if one for some reason would like to read an image from a web-URL, then query parameters may be included... oh now that I think about it again. Maybe that part was unnecssary. Anyway forward slashes is still causing problems.

}

return images;
Expand Down Expand Up @@ -514,7 +512,6 @@
// Materials are connected to texture maps in FBXTree.Objects.Textures
// FBX format currently only supports Lambert and Phong shading models
parseMaterial( materialNode, textureMap ) {

const ID = materialNode.id;
const name = materialNode.attrName;
let type = materialNode.ShadingModel;
Expand All @@ -541,6 +538,9 @@
case 'lambert':
material = new MeshLambertMaterial();
break;
case 'openpbrsurface':
material = new MeshStandardMaterial();
break;
default:
console.warn( 'THREE.FBXLoader: unknown material type "%s". Defaulting to MeshPhongMaterial.', type );
material = new MeshPhongMaterial();
Expand All @@ -561,15 +561,12 @@

const parameters = {};

if ( materialNode.BumpFactor ) {

parameters.bumpScale = materialNode.BumpFactor.value;

if ( materialNode.BumpFactor || materialNode['Maya|normalCameraFactor']) {
parameters.bumpScale = materialNode.BumpFactor?.value ?? materialNode['Maya|normalCameraFactor'].value;
}

if ( materialNode.Diffuse ) {

parameters.color = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.Diffuse.value ), SRGBColorSpace );
if ( materialNode.Diffuse || materialNode['Maya|baseColor'] ) {
parameters.color = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.Diffuse?.value || materialNode['Maya|baseColor'].value ), SRGBColorSpace );

} else if ( materialNode.DiffuseColor && ( materialNode.DiffuseColor.type === 'Color' || materialNode.DiffuseColor.type === 'ColorRGB' ) ) {

Expand All @@ -584,45 +581,48 @@

}

if ( materialNode.Emissive ) {
if ( materialNode.Emissive || materialNode['Maya|emissionColor'] ) {

parameters.emissive = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.Emissive.value ), SRGBColorSpace );
parameters.emissive = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.Emissive?.value || materialNode['Maya|emissionColor'].value ), SRGBColorSpace );

} else if ( materialNode.EmissiveColor && ( materialNode.EmissiveColor.type === 'Color' || materialNode.EmissiveColor.type === 'ColorRGB' ) ) {

// The blender exporter exports emissive color here instead of in materialNode.Emissive
parameters.emissive = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.EmissiveColor.value ), SRGBColorSpace );

}

if ( materialNode.EmissiveFactor ) {

parameters.emissiveIntensity = parseFloat( materialNode.EmissiveFactor.value );
}

if ( materialNode.EmissiveFactor || materialNode['Maya|emissionLuminance']) {

parameters.emissiveIntensity = parseFloat( materialNode.EmissiveFactor?.value ?? materialNode['Maya|emissionLuminance'].value );
}

// the transparency handling is implemented based on Blender/Unity's approach: https://github.com/sobotka/blender-addons/blob/7d80f2f97161fc8e353a657b179b9aa1f8e5280b/io_scene_fbx/import_fbx.py#L1444-L1459

parameters.opacity = 1 - ( materialNode.TransparencyFactor ? parseFloat( materialNode.TransparencyFactor.value ) : 0 );
if(materialNode.TransparencyFactor){
Copy link
Collaborator

@Mugen87 Mugen87 Dec 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameters.opacity should always be set which is not true anymore with your new code. I suggest you restore the deleted line and just add

if ( materialNode[ 'Maya|transmissionWeight' ] ) {

    parameters.opacity = 1 - materialNode[ 'Maya|transmissionWeight' ].value;

}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I will look into that.

parameters.opacity = 1 - ( materialNode.TransparencyFactor ? parseFloat( materialNode.TransparencyFactor.value ) : 0 );

if ( parameters.opacity === 1 || parameters.opacity === 0 ) {
if ( parameters.opacity === 1 || parameters.opacity === 0 ) {

parameters.opacity = ( materialNode.Opacity ? parseFloat( materialNode.Opacity.value ) : null );
parameters.opacity = ( materialNode.Opacity ? parseFloat( materialNode.Opacity.value ) : null );

if ( parameters.opacity === null ) {
if ( parameters.opacity === null ) {

parameters.opacity = 1 - ( materialNode.TransparentColor ? parseFloat( materialNode.TransparentColor.value[ 0 ] ) : 0 );
parameters.opacity = 1 - ( materialNode.TransparentColor ? parseFloat( materialNode.TransparentColor.value[ 0 ] ) : 0 );

}
}

}
}else if(materialNode['Maya|transmissionWeight']){
parameters.opacity = 1 - materialNode['Maya|transmissionWeight'].value;
}

if ( parameters.opacity < 1.0 ) {

parameters.transparent = true;

}

if ( materialNode.ReflectionFactor ) {

parameters.reflectivity = materialNode.ReflectionFactor.value;
Expand All @@ -645,10 +645,14 @@
parameters.specular = ColorManagement.colorSpaceToWorking( new Color().fromArray( materialNode.SpecularColor.value ), SRGBColorSpace );

}

if ( materialNode['Maya|baseMetalness'] ){
parameters.metalness = materialNode['Maya|baseMetalness'].value;
}

const scope = this;
connections.get( ID ).children.forEach( function ( child ) {

const type = child.relationship;

switch ( type ) {
Expand All @@ -660,7 +664,7 @@
case 'Maya|TEX_ao_map':
parameters.aoMap = scope.getTexture( textureMap, child.ID );
break;

case 'DiffuseColor':
case 'Maya|TEX_color_map':
parameters.map = scope.getTexture( textureMap, child.ID );
Expand All @@ -669,7 +673,15 @@
parameters.map.colorSpace = SRGBColorSpace;

}
break;

case 'Maya|baseColor':
parameters.map = scope.getTexture( textureMap, child.ID );
if ( parameters.map !== undefined ) {
parameters.color = ColorManagement.colorSpaceToWorking( new Color("white") ) // MATERIAL COLOR GETS SET TO BLACK BY MAYA WHEN A COLOR MAP IS APPLIED, SO SETTING IT TO WHITE TO RESOLVE THAT PROBLEM

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (94% of all statements in
the enclosing function
have an explicit semicolon).
parameters.map.colorSpace = SRGBColorSpace;

}
break;

case 'DisplacementColor':
Expand All @@ -683,10 +695,18 @@
parameters.emissiveMap.colorSpace = SRGBColorSpace;

}
break;

case 'Maya|emissionColor':
parameters.emissiveMap = scope.getTexture( textureMap, child.ID );
if ( parameters.emissiveMap !== undefined ) {
parameters.emissive = ColorManagement.colorSpaceToWorking( new Color("white") ) // MATERIAL COLOR GETS SET TO BLACK BY MAYA WHEN A COLOR MAP IS APPLIED, SO SETTING IT TO WHITE TO RESOLVE THAT PROBLEM

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (94% of all statements in
the enclosing function
have an explicit semicolon).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your PR breaks the formatting and linter rules. Please make sure your editor properly supports ESLint so the file is correctly formatted when you save it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @Mugen87 for the feedback about the PR breaks and linter rules. Will look into that.

parameters.emissiveMap.colorSpace = SRGBColorSpace;
}
break;

case 'NormalMap':
case 'Maya|normalCamera':
case 'Maya|TEX_normal_map':
parameters.normalMap = scope.getTexture( textureMap, child.ID );
break;
Expand Down Expand Up @@ -744,7 +764,6 @@
id = connections.get( id ).children[ 0 ].ID;

}

return textureMap.get( id );

}
Expand Down