javascript3dthree.jsvrml

Three.js coloring the wrong side of a VRML object's faces


Here's a VRML file that I'm trying to display with three.js. When I preview that file in a standalone viewer like view3dscene, it looks correct:

3D rendering of a bolt

However, in Three.js using the example VRMLLoader, the insides of the faces are colored instead of the outsides:

Rendering of the same bolt, but the outside is transparent, revealing the concave back side

Looks clear to me that three.js is reading the correct color information, just applying it to the faces incorrectly. But I'm very new to working with 3D, so I'm not sure where the discrepancy lies or what I can do to fix it.

I'm not doing anything fancy with loading the file; it's just as in the example code:

loader.load('https://75thtrombone.com/links/stack-exchange/2016-09/' + model, function(geometry) {
    scene.add(geometry);
});

Here's a fiddle with my code and a view of the problem. (Zoom in with the mouse wheel, drag to rotate.) Any help, insight, direction towards something to read to learn more, or any other clues at all would be wonderful.


Solution

  • @Radio is correct. Your winding order is backwards, which causes the faces to point in the wrong direction. It only appears that some of the faces are correct because of the threading on the object.

    Here is a fiddle (code below) demonstrating one way to correct the winding order without altering your original object: https://jsfiddle.net/TheJim01/3nr7rakk/

    I merely add a function which recurses the object returned by the loader, and forces all materials to draw the back-side of the triangle, rather than the front-side. This only happens once, so it may be good enough in cases of small geometry, but you'll see this slow down as you use larger geometry sets, and complex objects may throw stack errors if they're large enough.

    One thing I did not do (as an exercise for the asker) was test this with the latest THREE.js. JSFiddle uses a very old version of THREE.js (JSFiddle uses r54, the current is r80). I recommend either configuring the fiddle to use the latest version and try again, or host the code locally with the latest version. There may be fixes to the VRML loader which resolve the issue you're seeing.

    You can use this page as an example of how to link JSFiddle to the latest THREE.js: http://jsfiddle.net/TheJim01/kb7e88vr/ Feel free to fork and modify it.

    Updated code: My code is the same as @75th Trombone's except I added/changed the following:

    function sideReplacer(obj){
        if(obj.material){
            obj.material.side = THREE.DoubleSide;
        }
        if(obj.children && obj.children.length > 0){
            for(var i in obj.children){
                sideReplacer(obj.children[i]);
            }
        }
    }
    
    loader.load('https://75thtrombone.com/links/stack-exchange/2016-09/' + model, function(geometry) {
        sideReplacer(geometry);
        scene.add(geometry);
    });