mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.9k stars 35.32k forks source link

FBXLoader: model having some parts at wrong positions after loading #15287

Closed DucNguyenPTIT closed 3 years ago

DucNguyenPTIT commented 5 years ago
Description of the problem

I’m using FBXLoader to load my .fbx model, without modifying its position. The loading succeeded, but the model appeared to have some of its parts standing at wrong positions. I tried viewing the model with 3D Viewer and saw that it’s absolutely OK. I was reported that this problem is due to the latest update of FBXLoader. Please fix it soon! Thanks a lot!

Here is the loading code:

var fbxLoader = new THREE.FBXLoader();
fbxLoader.load('baotang.fbx', (object) => {
    object.traverse((child) => {
        if (child.isMesh) {
            child.castShadow = true;
            child.receiveShadow = true;
        }
    });

    scene.add(object);
)};

Here is the error scene: (the big ball, the light and the black plane was added for other purposes. I’ve tried loading the model without them and can confirm that they have no relevant to the problem) image

Viewing the model with 3D Viewer: image

Here is the link to download the model for testing

Three.js version
Browser
OS
pikilipita commented 5 years ago

I am experiencing similar issues, but only with rigged fbx files exported from Cinema 4D

yazancash commented 5 years ago

i have the same problem with Mixamo FBX animated models.

TripNRaVeR commented 5 years ago

i also came by this issue and after two days of messing arround i have fixed it by loading the fbx like this:

                    loader.load( 'model.fbx', function ( object3d ) {
                    object3d.traverse( function ( child ) {

                    let material = child.material;

                    let mesh = new THREE.Mesh(child.geometry, material);

                    if ( child instanceof THREE.Mesh  ) {
                        const wireframeMaterial = new THREE.LineBasicMaterial( { color: 0x000000 } );
                        const wireframe = new THREE.LineSegments( new THREE.EdgesGeometry( child.geometry ), wireframeMaterial );
                        mesh.add( wireframe );

                    }

                    mesh.applyMatrix(child.matrix); //this fixed it

                    scene.add(mesh);

if you need more info or help just hit me up, hope this helpes you guys in solving it correctly

KaikePing commented 5 years ago

meet the same issue with fbx exported by Cinema 4D

looeee commented 5 years ago

I am experiencing similar issues, but only with rigged fbx files exported from Cinema 4D

meet the same issue with fbx exported by Cinema 4D

@pikilipita, @KaikePing have you guys reported this to Cinema 4D? It may be a bug in their exporter. Unfortunately I don't have the resources to track down inconsistencies in every FBX exporter, so unless we can confirm that this is a bug on our end and not with Cinema 4D I reccomend to close this as "won't fix".

i have the same problem with Mixamo FBX animated models.

@yazancash do you know what program the model was originally made with? Mixamo doesn't change the underlying model - it just adds a skeleton and animations to it - and most Mixamo models do work, so this is probably coming from whatever program the model was made in.

mrdoob commented 5 years ago

@looeee Do you know if Unity3D has this issue too? Or is it able to load correctly fbx produced with 3dsmax and maya?

yazancash commented 5 years ago

@looeee

is FBXLoader updated during the last month? animation was totally not working before. now it works, but needs to be smooth between Mesh Childs.

models are basically in OBJ format. uploaded to Mixamo (to rig & animate) then downloaded in FBX format. models are working perfectly in Unity3D & FBX2glTF & Unwrap3D...etc

Here is example model: (Copy-Paste from Mixamo FBX) https://rigmodels.com/del/old/models/ETLKXWN98V2AHQIUHW4YU4222_running_inPlace_admin.zip

in ThreeJS. it works but animation sounds broken. (last months it was totally not working, now im surprised it's working 80% as needed) demo: https://rigmodels.com/del/old/111.php

if i convert model to glTF then convert back to FBX, it works perfectly even on ThreeJS. demo: https://rigmodels.com/del/old/111B.php

the difference sounds small. but it looks really bad in other models/animations. especially in Jump animations.

The animation is working perfectly in other software, without convert: https://rigmodels.com/del/old/TrueVision3D.png https://rigmodels.com/del/old/Unwarp3D.png https://rigmodels.com/del/old/Blender.png

So, i wonder why Animation is working in 001.php - but not smooth as 001B.php

anyway, it's good step forward. thanks for your time!

yazancash commented 5 years ago

here the bug is more clear. not good in ThreeJS but working perfectly in other software. https://rigmodels.com/del/old/111C.php

looeee commented 5 years ago

@looeee Do you know if Unity3D has this issue too?

No, sorry. I don't have unity installed.

@yazancash thanks for the additional info. I don't think that your issue is related to this one since it seems to be a problem with skinning, can you please open a new issue so we can track it there?

yazancash commented 5 years ago

@looeee i believe my problem is related to Matrix of mesh childs. not skinning. if i remove the animation in ThreeJS, remove the Mixer & disable action.play() i get static model not showing correctly. preview: https://rigmodels.com/del/old/models/case1.png

when i change the code (as @TripNRaVeR mentioned above) change scene.add( object ); to this :

          object.traverse( function ( child ) {
            var mesh = new THREE.Mesh(child.geometry, child.material);
        mesh.applyMatrix(child.matrix); //this fixed it
        scene.add(mesh);
          });

the model then showing correctly. preview: https://rigmodels.com/del/old/models/case2.png

problem sounds related to *Deformer: TransformLink:16** (the relation between nodes)

looeee commented 5 years ago

OK, thanks for looking more deeply into this.

It sounds like it might be a fairly easy fix. Do you want to take a look and see if you can figure out where to apply the child matrix within the FBXLoader? If you do that and open a PR here I'll triage the new code.

yazancash commented 5 years ago

after more tests. i find there is no need for this: mesh.applyMatrix(child.matrix); but only change scene.add( object ); to this below:

        object.traverse( function ( child ) {
            if (child.isMesh) scene.add(child);
        });

so if we add Childs one by one, not the whole Object, it works. (this is for static model)

in FBXLoader.js, we can add scene.add(child); inside

    sceneGraph.traverse( function ( child ) {
        if ( child.isMesh ) {
            scene.add(child); // here

it works, but model will be added to scene directly on fbxloader.load() this is not recommended, user may apply custom Materials on childs before adding to scene.

im still testing. will update here if anything new.

looeee commented 5 years ago

It looks like the transform is being applied to the child instead of the parent.

I think this is caused by the top level group we create in the loader.

I remember thinking that is not correct, that we should instead return an array or dictionary of models - I think that is more correct in terms of how the FBX file specifies model. We should be returning a dictionary similar to the GLTFLoader, something like:

object = {
animationClips: { ... },
models: { ... }
materials: { ... }
skeletons: { ... }
textures: { ... }
}

Unfortunately the loader was not set up like this originally so it's quite a breaking change and would require some refactoring - for example, bones need to be added to the child as well.

Here, you can play the animation correctly on your model like this:

loader.load( 'models/fbx/yazancash/model.fbx', function ( object ) {

    mixer = new THREE.AnimationMixer( object );

    var action = mixer.clipAction( object.animations[ 0 ] );
    action.play();

    const skinnedMesh = object.children[ 0 ];  // should be object.models[ 0 ]

        // should be object.skeletons[ 0 ], and should be automatically added to the correct model
    const skeleton = object.children[ 1 ]; 

    skinnedMesh.add( skeleton );

    scene.add( skinnedMesh );

} );
looeee commented 5 years ago

By the way, I think the smoothness of the model is unrelated. I recently had a lot of trouble with a model exported from Maya, and discovered that FBX geometry has some kind of smoothness/tessellation setting. That's probably not something we'll add support for in three.js - instead you'll have to make sure that any tesselation/turbosmooth/meshsmooth/opensubdiv or similar modifiers are applied to the geometry before exporting to FBX.

yazancash commented 5 years ago

I spent hours playing with TransformLink: *16 matrix inside model file (FBX Ascii). Finally this solved the problem. demo: https://rigmodels.com/del/old/111D.php

so, the problem is not in FBXLoaded itself. but it's very sensitive to Data written in model file. Other software maybe ignore TransformLink matrix. so it was reading correctly in these software whatever the TransformLink matrix is.

Many thanks for your time, FBXLoader is really cool.

looeee commented 5 years ago

Finally this solved the problem. demo: https://rigmodels.com/del/old/111D.php

What changes did you make? Did you just set the TransformLink to the identity matrix?

Other software maybe ignore TransformLink matrix.

Hmm, perhaps. But I think that's unlikely.

yazancash commented 5 years ago

i convert model to glTF then convert back to FBX. this solves the problem as i said above. after comparing between 2 FBX copies (Original vs Converted) i found there is difference in Deformer: { TransformLink: { matrix.

the change is about the Initial Position of Childs. ( last 4 values of *16 matrix )

Other software are able to read the model correctly whatever i write in TransformLink. (like they ignore it) FBXLoader is Sensitive. any error in this matrix => error in display.

so i can say, the Error is in FBX file itself. but other software ignore this error somehow.

yazancash commented 5 years ago

** regarding the change i made in TransformLink matrix. i changed Positions based on Nodes Tree. for my model, Node 5 correct-location = Node 5 local + Node 4 local + Node 3 local + Node 2 local. Node 4 location = Node 4 local + Node 3 local.

i do not know how to explain. but i added extra Position values for SOME Nodes. based on Tree of nodes.

BVR83 commented 4 years ago

Any updates on this thread.

I still have issues loading an fbx which is a converted and optimized cad file out of C4D It has lots of groups and seperate parts.

even with in the .js code: object.traverse( function ( child ) { if (child.isMesh) scene.add(child); });

and in FBXLoader.js I have added scene.add(child); inside

sceneGraph.traverse( function ( child ) {
    if ( child.isMesh ) {
        scene.add(child); // here

Its pretty crucial to get this working. Are there still any updates to FBXloader planned?

looeee commented 4 years ago

Are there still any updates to FBXloader planned?

I'm no longer working on the loader, as I only use it for rapid prototyping models from 3DS Max and I don't have any issues with loading these models.

Well, that and a lack of time.

If anyone else starts working on the loader, I'll be available to give advice and feedback.

BVR83 commented 4 years ago

Thank you for your fast and honest reply.

To all struggling with this issue, for static objects making sure all pivots are zeroed out help me out.

pikilipita commented 4 years ago

Hi, we also encounter this issue with some fbx files, using an older version of the fbx loader usually give better results. For some reason some fbx files that used to be loaded correctly are glitchy on the newest versions of the loader.

You can try this (old) version: http://xr.plus/tmp/FBXLoader1204-fix.js.zip

Let me know if it helped