mrdoob / three.js

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

FBXLoader fails to load file #18986

Closed wtaisto closed 4 years ago

wtaisto commented 4 years ago

I have a series of exports from a small-ish CAD software in FBX. When I try to load any of them in the browser with three.FBXLoader (including the attached fbx file), I get errors and the file does not appear. I can view the files without problems in Autodesk FBX Review software.

My loading code:

var loader = new FBXLoader();
      console.log("Loading...");
      loader.load(
        "http://localhost:5000/Roof.fbx",
        function(result) {
          console.log("Loaded, adding to scene:", result);
          scene.add(result);
          console.log("Added to scene, rendering");
          THIS.render();

          console.log("Done!");
        },
        // called while loading is progressing
        function(xhr) {
          console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
        },
        // called when loading has errors
        function(error) {
          console.log("An error happened", error);
        }
      );

Chrome console output:

THREE.WebGLRenderer 106
Test3d.vue:117 Loading...
Test3d.vue:130 28.505811121163617% loaded
Test3d.vue:130 100% loaded
FBXLoader.js:3297 THREE.FBXLoader: FBX binary version: 7500
Test3d.vue:134 An error happened TypeError: Cannot read property 'a' of undefined
    at GeometryParser.parseUVs (FBXLoader.js:2210)
    at GeometryParser.parseGeoNode (FBXLoader.js:1769)
    at GeometryParser.genGeometry (FBXLoader.js:1635)
    at GeometryParser.parseMeshGeometry (FBXLoader.js:1625)
    at GeometryParser.parseGeometry (FBXLoader.js:1565)
    at GeometryParser.parse (FBXLoader.js:1547)
    at FBXTreeParser.parse (FBXLoader.js:173)
    at FBXLoader.parse (FBXLoader.js:147)
    at Object.onLoad (FBXLoader.js:99)
    at XMLHttpRequest.<anonymous> (three.module.js:35829)

Roof.zip

Three.js version
Browser
OS
Hardware Requirements (graphics card, VR Device, ...)
looeee commented 4 years ago

The issue seems to be that there are UV nodes without any data. I'm not sure if this is something we should handle or if it's a bug in your exporter. What program are you exporting from?

It should be possible to fix this by adding appropriate checked to the parseUVs method inside the loader. In particular, the line var buffer = UVNode.UV.a; causes errors since UVNode.UV is undefined.

When I view your file in FBX review I see a simple green roof:

r

Is this the entire model? Inside the FBX there's 16 geometries, which seem high, including "Line" type geometries which I haven't seen before.

WestLangley commented 4 years ago

I'm not sure if this is something we should handle or if it's a bug in your exporter.

@looeee I noticed that online converters parse this FBX file, so it seems FBXLoader should, too.

wtaisto commented 4 years ago

Yes, that is the entirety of the model. It comes from a timber-build construction program called Cadwork. The software uses 3d volumetric objects like boards and panels as it's primitives, so each "board" comes out as it's own named geometry, which is required for my context.

I've noticed that when I try and convert these FBX's to GLTF's (both via FBX2glTF and Aspose.3d), the resulting GLTF's also generate other errors when rendering in three.js; so your observation about empty nodes is probably leading to that too.

I have limited ability to push back requests to the creators of Cadwork; a fix to the three.js source to gracefully ignore the missing objects would be incredibly appreciated. My limited reading of the three.js source did seem to imply a null check at the line you mentioned could fix it as I didn't notice anything downstream which would be effected.

wtaisto commented 4 years ago

BTW, when I run FBX2glTF on these files, they load, but then I get the error below when render is next invoked (but the GLTF's display fine in other viewers):

vue.runtime.esm.js:1888 TypeError: Cannot read property 'getUniforms' of undefined
    at setProgram (three.module.js:24649)
    at WebGLRenderer.renderBufferDirect (three.module.js:23698)
    at renderObject (three.module.js:24415)
    at renderObjects (three.module.js:24385)
    at WebGLRenderer.render (three.module.js:24183)
    at VueComponent.<anonymous> (Test3d.vue:161)
    at Array.<anonymous> (vue.runtime.esm.js:1980)
    at flushCallbacks (vue.runtime.esm.js:1906)
looeee commented 4 years ago

The file generated by FBX2glTF loads fine for me in https://gltf-viewer.donmccurdy.com/ although I get a warning when converting the file:

unsupported transform inheritance type 'eInheritRrSs'

Previously I've only encountered this warning when dealing with Maya FBX files. What app are you using to create the FBX?

a null check at the line you mentioned could fix it

Unfortunately not quite that simple, as I tested this.

looeee commented 4 years ago

@looeee I noticed that online converters parse this FBX file, so it seems FBXLoader should, too.

I'd love to make the loader work for every single program with an FBX exporter, but unfortunately, I don't have time. My goal was limited to supporting Autodesk programs and Blender.

If someone else is interested in taking over the work to support files generated by other programs, or edge case from Autodesk and Blender, I have a collection of files that currently don't load correctly which I'll share with anyone interested (I'm not sure of the licensing on these files so I won't share them publicly).

@wtaisto that means you're on your own with this, although if you do try to fix the loader feel free to reach out for advice. In the meantime, converting your files to glTF does work.

WestLangley commented 4 years ago

The parser indicates UVs exist, but the UV data is not actually present.

As a temporary workaround, it appears you can make the following change to parseGeoNode() in your copy of the loader:

if ( geoNode.LayerElementUV ) {

    geoInfo.uv = [];

    var i = 0;

    while ( geoNode.LayerElementUV[ i ] ) {

        if ( geoNode.LayerElementUV[ i ].UV ) { // temporary workaround

            geoInfo.uv.push( this.parseUVs( geoNode.LayerElementUV[ i ] ) );

        }

        i ++;

    }

}

This is a workaround only.

wtaisto commented 4 years ago

Thank you all, so very much for your feedback. I've shifted to a workaround of taking my (apparently poorly exported) FBX files and running them through FBX2glTF before loading them and just operating on the GLB versions, which the rest of my toolchain accepts and works great.

WestLangley commented 4 years ago

@looeee This may be an inconsistency in the FBX file, or it may be the loader is creating a UV node it should not. In any event, I think you can remove the bug label and close this if you do not intend to pursue it further.

looeee commented 4 years ago

In any event, I think you can remove the bug label and close this if you do not intend to pursue it further.

Hopefully, someone else will fix it. I wasn't the first person to work on the FBXLoader, and there's no reason to presume I'll be the last. Even aside from bug fixes, there's loads more work that could be done on the loader to improve efficiency and speed.

If you want to close this to keep the number of issues down, that's fine. But otherwise, I think it's useful to have a list of open issues since that might inspire someone else to try and fix them.