Search code examples
three.jswavefront

Three.js OBJLoader parse method not working


I would like to render my user generated obj instead of loading from file. In my example below, objString represents a cube. The browser just show a dark screen. I'm expecting the display of a green cube rotating.

I wonder what I'm missing

import React from 'react';
import * as THREE from "three";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader"

class App extends React.Component {
    componentDidMount() {
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

        let loader = new OBJLoader();

        // obj string below represents a cube
        var objString = `
            v 0.000000 2.000000 2.000000
            v 0.000000 0.000000 2.000000
            v 2.000000 0.000000 2.000000
            v 2.000000 2.000000 2.000000
            v 0.000000 2.000000 0.000000
            v 0.000000 0.000000 0.000000
            v 2.000000 0.000000 0.000000
            v 2.000000 2.000000 0.000000
            f 1 2 3 4
            f 8 7 6 5
            f 4 3 7 8
            f 5 1 4 8
            f 5 6 2 1
            f 2 6 7 3
        `;

        var cube = loader.parse(objString);
        scene.add( cube );

        // var geometry = new THREE.BoxGeometry( 1, 1, 1 );
        // var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
        // var cube = new THREE.Mesh( geometry, material );
        // scene.add( cube );

        camera.position.z = 5;
        var animate = function () {
            requestAnimationFrame( animate );
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
            renderer.render( scene, camera );
        };
        animate();
    }

    render() {
        return (
            <div></div>
        );
    }
}

export default App;

Solution

  • OBJLoader actually works fine. The problem is that the loader returns meshes with MeshPhongMaterial which is a lit material. Since you don't have any lights in your scene, you just have a black screen. Try it like so:

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
    
    var scene = new THREE.Scene();
    
    var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
    camera.position.z = 5;
    
    let loader = new THREE.OBJLoader();
    
    // obj string below represents a cube
    var objString = `
    v 0.000000 2.000000 2.000000
    v 0.000000 0.000000 2.000000
    v 2.000000 0.000000 2.000000
    v 2.000000 2.000000 2.000000
    v 0.000000 2.000000 0.000000
    v 0.000000 0.000000 0.000000
    v 2.000000 0.000000 0.000000
    v 2.000000 2.000000 0.000000
    f 1 2 3 4
    f 8 7 6 5
    f 4 3 7 8
    f 5 1 4 8
    f 5 6 2 1
    f 2 6 7 3
    `;
    
    var cube = loader.parse(objString);
    scene.add( cube );
    
    var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
    hemiLight.position.set( 0, 20, 0 );
    scene.add( hemiLight );
    
    var dirLight = new THREE.DirectionalLight( 0xffffff );
    dirLight.position.set( - 3, 10, - 10 );
    scene.add( dirLight );
    
    
    var animate = function () {
        requestAnimationFrame( animate );
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render( scene, camera );
    };
    
    animate();
    body {
        margin: 0px;
    }
    canvas {
      display: block;
    }
    <script src="https://cdn.jsdelivr.net/npm/three@0.116.1/build/three.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.116.1/examples/js/loaders/OBJLoader.js"></script>