camerathree.jsloaderrhino

Rhino obj to Three.js visualisation problems


While testing the import/export between Rhino and Three, I have encountered some problems while visualising a fairly complicated obj file. I exported the obj from Rhino after triangulating the Mesh.

The problem shows indipendently from the material: with no material, with a material or/and with a texture applied within Three.

Jpeg of the geometry I try to import from Rhino vs the result on Three.js: enter image description here

As you can see, there are some weird depth problems, especially depending on the camera position. I made a long research on the topic without finding a solution. I'll append some other topics on StackOverflow that I already have followed.

On my own, I tried also to check and flip the normals within Rhino, with no success.

My script (updated with Gaitat advice):

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - loaders - OBJ loader</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #000;
                color: #fff;
                margin: 0px;
                overflow: hidden;
            }
            #info {
                color: #fff;
                position: absolute;
                top: 10px;
                width: 100%;
                text-align: center;
                z-index: 100;
                display:block;
            }
            #info a, .button { color: #f00; font-weight: bold; text-decoration: underline; cursor: pointer }
        </style>
    </head>

    <body>
        <div id="info">
        <a href="http://threejs.org" target="_blank">three.js</a> - OBJLoader test
        </div>

        <script src="../build/three.min.js"></script>
        <script src="js/loaders/OBJLoader.js"></script>

        <script>

            var container;

            var camera, scene, renderer;

            var mouseX = 0, mouseY = 0;

            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;


            init();
            animate();


            function init() {

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

                camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 1, 2500 );
                camera.position.z = 50;

                // scene

                scene = new THREE.Scene();

                var ambient = new THREE.AmbientLight( 0x101030 );
                scene.add( ambient );

                var directionalLight = new THREE.DirectionalLight( 0xffeedd );
                directionalLight.position.set( 0, 0, 1 );
                scene.add( directionalLight );

                // texture

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

                    console.log( item, loaded, total );

                };

                var texture = new THREE.Texture();

                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 ) {
                };


                var loader = new THREE.ImageLoader( manager );
                loader.load( 'textures/UV_Grid_Sm.jpg', function ( image ) {

                    texture.image = image;
                    texture.needsUpdate = true;

                } );

                // model

                loader = new THREE.OBJLoader( manager );
                loader.load( 'obj/RU_obj/testTriangulated_again.obj', function ( object ) {

                    object.traverse( function ( child ) {

                        if ( child instanceof THREE.Mesh ) {

                            child.material.map = texture;

                        }

                    } );

                    object.position.y = - 30;
                    object.scale.x = 0.5;
                    object.scale.y = 0.5;
                    object.scale.z = 0.5;

                    scene.add( object );

                }, onProgress, onError );

                //

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

                document.addEventListener( 'mousemove', onDocumentMouseMove, false );

                //

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

            }

            function onWindowResize() {

                windowHalfX = window.innerWidth / 2;
                windowHalfY = window.innerHeight / 2;

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

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

            }

            function onDocumentMouseMove( event ) {

                mouseX = ( event.clientX - windowHalfX ) / 2;
                mouseY = ( event.clientY - windowHalfY ) / 2;

            }

            //

            function animate() {

                requestAnimationFrame( animate );
                render();

            }

            function render() {

                camera.position.x += ( mouseX - camera.position.x ) * .05;
                camera.position.y += ( - mouseY - camera.position.y ) * .05;
                camera.lookAt( scene.position );

                renderer.render( scene, camera );

            }

        </script>

    </body>
</html>

And here it is my obj file: https://www.dropbox.com/s/di157kddzw5tasr/testTriangulated.obj?dl=0.

Thanks in advance.


Solution

  • Replace this code:

    loader.load('obj/RU_obj/testTriangulated.obj', function(geometry) {
        var material =  new THREE.MeshPhongMaterial( { color: 0x00ff00 } );
        geometry.position.y = 0;
        geometry.material = material;
        scene.add(geometry);
    });
    

    with

    var material = new THREE.MeshPhongMaterial( { color: 0x00ff00 } );
    loader.load('obj/RU_obj/testTriangulated.obj', function(object) {
        scene.add( new THREE.Mesh (object.geometry, material) );
    });
    

    You cannot assign the material as you did. What I am doing is using the geometry of the loaded object and creating a new mesh which I then add to the scene.

    Update

    Your object is actually inside out so what you are seeing is the inside of it. So in Rhino you have to change the normals or change the orientation of your polygons. The fix here is to use double sided material. This code has the fix:

    <body>
        <div id="info">
        <a href="http://threejs.org" target="_blank">three.js</a> - OBJLoader test
        </div>
    
        <script src="../build/three.min.js"></script>
        <script src="js/loaders/OBJLoader.js"></script>
        <script src="js/controls/TrackballControls.js"></script>
    
        <script>
    
            var container;
            var camera, scene, renderer, controls;
            var mouseX = 0, mouseY = 0;
    
            init();
            animate();
    
            function init()
            {
                container = document.createElement( 'div' );
                document.body.appendChild( container );
    
                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
                camera.position.z = 100;
    
                // scene
    
                scene = new THREE.Scene();
    
                // lights
    
                var ambient = new THREE.AmbientLight( 0x101030 );
                scene.add( ambient );
    
                var directionalLight = new THREE.DirectionalLight( 0xffeedd );
                directionalLight.position.set( 0, 0, 1 );
                scene.add( directionalLight );
    
                // texture
    
                var manager = new THREE.LoadingManager();
                manager.onProgress = function ( item, loaded, total ) { };
    
                var texture = new THREE.Texture();
    
                var loader = new THREE.ImageLoader( manager );
                loader.load( 'textures/UV_Grid_Sm.jpg', function ( image )
                {
                    texture.image = image;
                    texture.needsUpdate = true;
                } );
    
                // model
    
                var loader = new THREE.OBJLoader( manager );
                loader.load( 'testTriangulated.obj', function ( object )
                {
                    object.traverse( function ( child )
                    {
                        if ( child instanceof THREE.Mesh )
                        {
                            child.material.map = texture;
                            child.material.side = THREE.DoubleSide;
                        }
                    } );
    
                    scene.add( object );
                } );
    
                //
    
                renderer = new THREE.WebGLRenderer();
                renderer.setPixelRatio( window.devicePixelRatio );
                renderer.setSize( window.innerWidth, window.innerHeight );
                container.appendChild( renderer.domElement );
    
                // controls
                controls = new THREE.TrackballControls (camera, renderer.domElement);
                controls.rotateSpeed = 1.0;
                controls.zoomSpeed = 1.2;
    
                window.addEventListener( 'resize', onWindowResize, false );
            }
    
            function onWindowResize()
            {
    
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
    
                renderer.setSize( window.innerWidth, window.innerHeight );
            }
    
            function animate()
            {
                requestAnimationFrame( animate );
                controls.update();
                renderer.render( scene, camera );
            }
    
        </script>
    
    </body>