Three.js: FBX Binary format not supported?

Created on 14 Oct 2016  ·  100Comments  ·  Source: mrdoob/three.js

Description of the problem

qq 20161014151051

FBXLoader only supports FBX text format?

Three.js version
  • [ ] Dev
  • [x] r81
  • [ ] ...

    Browser
  • [x] All of them

  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer

    OS
  • [x] All of them

  • [ ] Windows
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
    Hardware Requirements (graphics card, VR Device, ...)
Enhancement

Most helpful comment

I'm gonna start to work on FBX binary parser again from April.
LMK if anyone is in hurry.

All 100 comments

Yes. Right now FBXLoader only supports ASCII format in version 7.

Three.js version : r77

qq 20161014175807

Why?

/ping @yamahigashi

Why?

because there is no reference open-source implementation? if you know one, I would be curious to see it.

Ah, wait, I thought it was about binary. For ASCII FBX below v7, I had the code here and a bunch of test models somewhere in my hard drive.

Anyone here who has made or is making binary FBX parser?
If not, I'm feeling like trying to make that...

you have to love reverse engineering stuff to do this ) and, you may be lucky if it is simple tags, but if they serialize every data type uniquely, you are properf-ed: you're facing tweaking one number per model and saving it to see what has changed, at a time.

Thanks for the advice.
I've achieved to make a FBX binary parser by seeing this site now.

https://code.blender.org/2013/08/fbx-binary-file-format-specification/

I'll try to make ObjectParser which makes an object
from the result of the binary parser next.

oh wow, someone already went through the hell ,and there are specs )

@takahirox It would be great if the new parser would have a similar structure like THREE.PLYLoader. This implementation uses an uniform logic for creating the THREE.BufferGeometry object after parsing the data from an ASCII or Binary input (see usage of method handleElement).

ok I'll try. And I'm thinking if I also can use that for MMDLoader.

BTW does anyone here know if FBX binary format remains the same even below version 7?

I have no idea.

Maybe @mrdoob knows?

@takahirox did you share your binary fbx parser anywhere?

Not yet... I'll do soon!

@takahirox Any updates :) ? Thanks!

Sorry I've been busy lately... but soon soon!

@takahirox Awesome \o/

I'm gonna start to work on FBX binary parser again from April.
LMK if anyone is in hurry.

@takahirox Do you have something rough to share? We're doing a presentation at the end of the week and could really use FBX binary loading for the demo.

Hi @takahirox I'm actually in a hurry, is there any update on this? I can help where able, but this is all still new to me.

I'm just starting to work on that again.
At least, I still need some weeks to share that.

How many weeks do you think?

Hm, maybe two or three weeks?

Just out of curiosity, could this be done in a week or so if i were able to sponsor some of the dev work?

Well, I can't promise but I'll try.
Do you have any specific models data you can share?
Wanna work with them as reference.

testfile.fbx.zip
This is similar to what we need if it helps

In the meantime...

For https://with.in/watch/under-neon-lights/ we used plain-text FBX but we changed the extension to .fbx.txt so the server would gzip it. I also optimised quite a lot the FBXLoader2. It ended up being a pretty decent workflow.

I wonder if there is anythingFBXLoader supports that FBXLoader2 doesn't or we can replace it already...

@kyle-larson?

Side note: The FBX example already uses FBXLoader2, too.

@mrdoob The only difference between the FBXLoader and FBXLoader2 is the use of Index buffers. FBXLoader2 does not use index buffers. Other than that, FBXLoader2 should include all the features of the previous loader.

Ah! Time to replace it then 👌

Is there any update on this guys? Happy to help out where I can.

Do you have a text file version of testfile.fbx.zip?
I wanna compare.

Binary parser progress...

image

@adam-clarey

Can you share the screenshot of the model?
Even the text file couldn't be loaded on the Three.js.

Another model's screenshot....

image

Model: https://free3d.com/3d-model/robot-2162.html

Looking good! 😀

Thank you all!

I'll try and upload a screenshot soon. Essentially my use case is being able to bundle in material images and model into a single file

block.fbx.zip
screen shot 2017-05-05 at 15 19 12

Here is a simple block with an image material baked into the fbx with an accompanying image of what it looks like in blender

You mean, the texture image data should be in the fbx file?

Yes. I may have exported that model incorrectly

I can't find the image data in the fbx binary data...
Let me know if anyone knows baked texture image data specification.

maybe try this one
block2.fbx.zip

Still can't find...
Are those files be loadable on other viewers?

Please let me know if anyone knows baked texture image data specification.

I just tried to open block2.fbx.zip with blender and with 3ds max. Both show only the filename, but no image. It seems that there is only the reference to .../Users/adamclarey/Documents/burger-screen.jpg in the file.

Yup, my parser extracts the file name but no image data.

Ok. I'm obviously doing something wrong. Blender isn't the most intuitive app to use. I'll try something else

I never heard that image data could be baked into a 3D export/import format (but only relative paths to the ressources).

Is this even possible?

I just noticed: it is possible.

I will create such a test file and post it here.

Great stuff.

This FBX was created in 3ds max and exported with the "embed media" option:
TestcubeWithImage.zip

Screenshot from 3ds max:

testcubescreenshot

Opened in blender (on a different machine):

screenshot_blender

In blender I didn't discover an option to export an FBX with baked images up to now. Perhaps baking has to be done before exporting? - I have no experience with blender.

@takahirox Here is the same file, also created in 3ds max, but exported without the "embed media" option:

Testcube.zip

It might be interesting for comparising purposes.

If you need other files for testing, feel free to post it here.

I found data looking like image data under Video.ID.properties.Content property of TestcubeWithImage.fbx.
This doesn't exist in other binary files posted in this thread.

I'll take a look closer...

image

Progress... 😄

image

So, embedded texture looks ok now.
Can anyone share the binary fbx including animation if you have?

Here are 3 test files with different kinds of keyframe animations:

AnimationTranslate.zip
AnimationMorph.zip
AnimationBones.zip

But unfortunately I didn't manage to produce files which behave in the same way in different programs.

They are all created with 3ds max.

  • All is okay when reimporting to 3ds max.
  • The AnimationTranslate example is okay in Blender and Clara.io.
  • The AnimationMorph example is okay in Blender, but the animation doesn't work in Clara.io.
  • The AnimationBones example is okay in Clara.io, but the animation is not quite okay in Blender.

@takahirox Our team has been looking for a three.js binary FBX parser for a while now, and this looks great! Have you made the source available anywhere yet? For our purposes, we need to be able to extract the meshes, the normals, UVs and the visual scene from the FBX, and it seems that that is working fine.

If the source is available, it would be great if you could point me to where it is.

Thanks for the great work!

https://github.com/takahirox/three.js/blob/FixLoaderBinaryParser/examples/js/loaders/FBXLoader2.js

Note that this's very temporal.
I need to clean up and optimize the code.
And functionality could be broken right now.

@takahirox Please note: After some testing in different programs I updated my previous comment.

@jostschmithals

Thanks.
Translate and Bone seem working now.
FBXLoader doesn't support Morph animation yet even with ascii file.
It'd be our next work....

I've tried loading the testcube file in my three.js project but nothing loads.
I get a 404 on the image file, after inspecing the FBXTree object I can see it still holds a reference to the absolute filepath.

screen shot 2017-05-07 at 15 01 23
screen shot 2017-05-07 at 14 59 00

I just tested it (on a machine where the original jpg is not available), and it works fine.

Note: You have to use
https://github.com/takahirox/three.js/blob/FixLoaderBinaryParser/examples/js/loaders/FBXLoader2.js,
but the loader is simply called THREE.FBXLoader (without the version number 2).

That's what I'm using. I'll investigate further

Try TestcubeWithImage.fbx
Testcube.fbx doesn't include image data so you should get 404

@ In my test which is working fine I get exactly the same console output like @adam-clarey - except the GET ... 404 message.

BTW: I tested on Windows 10.

Progress...
Animation seems working fine now 😄

image

Can you paste the code you are using to load the model please? For some reason it just doesn't load for me.

I've tried substituting the Testcube file into the webgl_loader_fbx.html example (also swapping the FBXLoader2.js file) and it still doesn't render the model.

@adam-clarey That's exactly what I did (deactivating the animations, of course), and it worked without any other changes.

how bizarre...

screen shot 2017-05-08 at 09 50 40

And it is sure that you are using TestcubeWithImage.fbx (as @takahirox pointed out)?
Any further error messages?
Which OS are you using?
The same in all browsers?

AAHHH, what a numpty i am! I just scrolled up until I found the first testcube file.

My mistake

Hi! I'm also getting this error when trying to load an external .fbx model which is export from Autodesk. Can anyone give me a solution for this

Thank you!

https://github.com/takahirox/three.js/blob/FixLoaderBinaryParser/examples/js/loaders/FBXLoader2.js
Note that this's very temporal.
I need to clean up and optimize the code.
And functionality could be broken right now.

@hmtri1011

@RicoLiu This is what I got when used THREE.FBXLoader. I implemented a loader_fbx example by replacing the URL of the model.

And when I used THREE.FBXLoader2 I got the error THREE.FBXLoader2 is not a constructor

image

You can use the webgl_loader_fbx.example:

  1. load https://github.com/takahirox/three.js/blob/FixLoaderBinaryParser/examples/js/loaders/FBXLoader2.js
    instead of the FBXLoader2.js of the current threejs branch,
  2. use THREE.FBXLoader (without the version number 2 !),
  3. (deactivate the animations, if there are no animations in your model),

and it should work.

@jostschmithals I follow your step then getting a new error Zlib is not defined

Seems that your model file is compressed?

image
Full Error what I get

Add this line in your example.

    <script src="js/libs/zlib_and_gzip.min.js"></script>

image
Done, and another error appeared.... :(

As I wrote above, you have to deactivate the animation code (in the loading section and in the render loop), if you use the example code with a model file that doesn't contain any animations.

I'm experiencing a different issue, im sure is related to materials. My problem is that under certain conditions some fbx models render and some dont.

To reproduce:
in the webgl_loader_fbx.html example file, just inside init() place the following code to create an environment

 var loadSkyDomeAndGroundBowl = function(scene, onLoad, onProgress, onError) {
                var pathtop="path/to/top.jpg";
                var pathbot="path/to/bottom.jpg";
                var radius=40;
                var bottomtopfactor=0.1;
                var sinkin=0.05;

                var texturetop;
                var texturebot;

                var onTextureLoadTop=function(texture) {
                  console.log('onTextureLoadTop');
                  texturetop=texture;
                  onTextureLoaded();
                };
                var onTextureLoadBot=function(texture) {
                  console.log('onTextureLoadBot');
                  texturebot=texture;
                  onTextureLoaded();
                };

                var onTextureProgress=function(xhr) {
                  console.log('onTextureProgress');
                  if(onProgress)
                    onProgress('Loading sky dome / ground bowl texture');
                };
                var onTextureError=function(xhr) {
                  console.log('onTextureError');
                  if(onError)
                    onError('Error loading sky dome / ground bowl texture');
                };

                var onTextureLoaded=function() {
                  console.log('onTextureLoaded');
                  if(texturetop && texturebot) {
                    console.log('onTextureLoaded 2');
                    var geometrytop = new THREE.SphereGeometry( radius*10, 600, 400, 0, Math.PI*2, 0, Math.PI*0.5);
                    var materialtop = new THREE.MeshBasicMaterial();

                    materialtop.map = texturetop;
                    materialtop.side = THREE.BackSide;
                    var skydome = new THREE.Mesh( geometrytop, materialtop );
                    skydome.position.y=bottomtopfactor*radius+sinkin;
                    scene.add( skydome );

                    var geometrybot = new THREE.SphereGeometry( radius, 60, 40, 0, Math.PI*2, Math.PI*0.5, Math.PI*0.5);
                    var materialbot = new THREE.MeshBasicMaterial();
                    materialbot.map = texturebot;
                    materialbot.side = THREE.BackSide;
                    var groundbowl = new THREE.Mesh( geometrybot, materialbot );
                    groundbowl.scale.set(1,bottomtopfactor,1);
                    groundbowl.position.y=bottomtopfactor*radius+sinkin;
                    scene.add( groundbowl );

                    if(onLoad)
                      onLoad();
                  }
                };

                var loader=new THREE.TextureLoader();
                loader.load(pathtop, onTextureLoadTop, onTextureProgress, onTextureError);
                loader.load(pathbot, onTextureLoadBot, onTextureProgress, onTextureError);
              }

Which basically just adds a skydome and ground with 2 images.

Then after the scene is initialized, run: loadSkyDomeAndGroundBowl(scene);

You will see that the 2 fbx models load and render fine within this new environment.

Now, if you replace the xsi_man_skinning.fbx reference with the TestcudeWithImages.fbx (also comment out animation code) you will see that the code does not render at all.

I've noticed this with other fbx files too. Binary fbx files do not seem to be compatible with environments.

Or I could just be doing something wrong...
(and yes its using the latest FBXLoader2 file)

This is my example code:
`


three.js - FBXLoader test

<script src="../build/three.js"></script>

<script src="js/controls/OrbitControls.js"></script>

<script src="js/curves/NURBSCurve.js"></script>
<script src="js/curves/NURBSUtils.js"></script>
<script src="js/loaders/FBXLoader2.js"></script>

<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/libs/zlib_and_gzip.min.js"></script>
<script>
    if (!Detector.webgl) Detector.addGetWebGLMessage();

    var container, stats, controls;
    var camera, scene, renderer, light;

    var clock = new THREE.Clock();

    var mixers = [];

    init();

    function init() {

        container = document.createElement('div');
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);

        scene = new THREE.Scene();

        // grid
        var gridHelper = new THREE.GridHelper(28, 28, 0x303030, 0x303030);
        gridHelper.position.set(0, - 0.04, 0);
        scene.add(gridHelper);

        // stats
        stats = new Stats();
        container.appendChild(stats.dom);

        // model
        var manager = new THREE.LoadingManager();
        manager.onProgress = function (item, loaded, total) {

            console.log(item, loaded, total);

        };

        var onProgress = function (xhr) {

            if (xhr.lengthComputable) {

                var percentComplete = xhr.loaded / xhr.total * 100;
                console.log(Math.round(percentComplete, 2) + '% downloaded');

            }

        };

        var onError = function (xhr) {

            console.error(xhr);

        };

        var loader = new THREE.FBXLoader(manager);
        loader.load('models/fbx/accient_2_full.fbx', function (object) {

            //object.mixer = new THREE.AnimationMixer(object);
            //mixers.push(object.mixer);

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

            scene.add(object);


        }, onProgress, onError);

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

            scene.add(object);

        }, onProgress, onError);

        renderer = new THREE.WebGLRenderer();
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000);
        container.appendChild(renderer.domElement);

        // controls, camera
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.target.set(0, 12, 0);
        camera.position.set(2, 18, 28);
        controls.update();

        window.addEventListener('resize', onWindowResize, false);

        light = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0);
        light.position.set(0, 1, 0);
        scene.add(light);

        light = new THREE.DirectionalLight(0xffffff, 1.0);
        light.position.set(0, 1, 0);
        scene.add(light);

        //animate();

    }

    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    //

    function animate() {

        requestAnimationFrame(animate);

        if (mixers.length > 0) {

            for (var i = 0; i < mixers.length; i++) {

                mixers[i].update(clock.getDelta());

            }

        }

        stats.update();

        render();

    }

    function render() {

        renderer.render(scene, camera);

    }
</script>

`

@jostschmithals can you give me a correct solution for this. I'm also deactive the animate code

@adam-clarey I've tested it, and the reason that you can't see the cube is that it sits under the ground plane (if you orbit it with the camera you should see it). Besides this all is working fine for me with your code.

@takahirox: The mesh inside the group created by FBXLoader is translated and rotated, so that the pivot point is not placed in the center of the cube like in the original model, but in the center of its upper side. This seems to be a minor bug?

(the image is correctly displayed on top though ...)

@hmtri1011 You have deactivated your animate() function. Therefore your scene is not rendered at all 😉

(It should be sufficient in this case to deactivate only the lines you already commented out.)

@jostschmithals tks :D it works now

Good spot @jostschmithals, thanks.

Should it matter what binary version the file is? I've got fbx files with version 7400 that render fine, but one with version 7500 and it errors out.

"FBXLoader: Unknown property type "
where the variable 'type' is an empty string

@adam-clarey I have no detailed knowledge of fbx. I only joined this thread because I found the question interesting whether/how image data could be baked into the model file. So I would like to forward this question to @takahirox.

I know the specification of >=7500 is a bit different from < 7500, and
am working on that to support >= 7500.
Can you share the binary model data of version 7500 for the test?

So after more testing, 7200 and 7500 seem to be fine.

However, 6100 and 7300 dont render.
house_fs.fbx.zip
DutchHouse.FBX.zip

Would you share the ascii version files?
We can clarify if the issue is binary specific or not.

And I hope we close this issue because FBXLoader supports binary now (maybe not perfect yet tho).
Let's make another issue for FBXLoader improvement.

@takahirox Sounds good!

@adam-clarey
I think i got this bug.

"FBXLoader: Unknown property type "
where the variable 'type' is an empty string

in FBXLoader.js
change to

            while ( ! this.endOfContent( reader ) ) {

                var node = this.parseNode( reader, version );
                if ( node !== null ) 
                    allNodes.add( node.name, node );
                else
                    break;

            }

11956

Hello everyone,
I noticed that FBXLoader just supports FBX file to be >= 7.0.
Now I want to load fbx file below 7.0, please tell how to do this?
Here is my fbx files https://github.com/nxhoang/Three.js-Fxb-and-Textures/tree/master/models/fbx
Thanks a lot.

@nxhoang as we discussed here, we only support FBX versions above 6100 (Binary) or 7000 (ASCII).

If you need to use older FBX files you'll need to update them (best to load them into 3ds max or Maya to do this), or convert them to another format.

Was this page helpful?
0 / 5 - 0 ratings