javascripthtmlthree.jsobjloader

Cant seem to add my obj to the scene: THREE.Object3D.add: object not an instance of THREE.Object3D


I am new to using three.js. I used to use a JSON file as my 3D model but the actual 3D file has some issues when I export it from Blender so I am switching to obj. The actual model is fine now but I have no idea how to switch from JSON to obj. This is as far as I can get but I keep getting the error: THREE.Object3D.add: object not an instance of THREE.Object3D.

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

camera.position.z = 100;
camera.position.y = 10;

var renderer = new THREE.WebGLRenderer({
  alpha: true
});
var manager = new THREE.LoadingManager(loadModel);

manager.onProgress = function(item, loaded, total) {
  console.log(item, loaded, total);
};

var wrapper = new THREE.Object3D();
var textureloader = new THREE.TextureLoader();

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

var light = new THREE.DirectionalLight(0xffffff, 1.0);

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

light2.position.set(-100, 100, -100);
scene.add(light2);

function onError() {}

function onProgress(xhr) {
  if (xhr.lengthComputable) {
    var percentComplete = (xhr.loaded / xhr.total) * 100;
    console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
  }
}
var head;
var loader = new THREE.OBJLoader2(manager);

loader.load(
  "http://trhidouan309.barzalou.com/site_web/js/profil.obj",
  function(obj) {
    head = obj;
  },
  onProgress,
  onError
);

function loadModel() {
  setTimeout(function() {
    wrapper.add(head);
    scene.add(wrapper);
  }, 10);
}

material.opacity = 0.6;

var hiddenPlane = new THREE.Mesh(planeGeometry, material);

hiddenPlane.position.set(0, 0, 50);
scene.add(hiddenPlane);

var mouse = new THREE.Vector2(0, 0);
var point = new THREE.Vector3(0, 0, 0);
var raycaster = new THREE.Raycaster();

camera.lookAt(scene.position);
window.addEventListener("mousemove", onMouseMove, false);
window.addEventListener("resize", onWindowResize, false);

function onMouseMove(event) {
  event.preventDefault();
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  raycaster.setFromCamera(mouse, camera);
  var intersects = raycaster.intersectObject(hiddenPlane);
  if (intersects.length > 0) {
    point = intersects[0].point;
  }
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  wrapper.lookAt(point);
  renderer.render(scene, camera);
}

window.onload = function() {
  document.getElementById("scene3d").appendChild(renderer.domElement);
};

animate();
<script src="js/LoaderSupport.js"></script>
<script src="js/OBJLoader2.js"></script>
<script src="js/index.js"></script>

The 3D model seems to load but I don't think its able to be added in the scene


Solution

  • You are having issues with the timing of the calls to load the obj file and render it. You are calling loadModel through the loading manager which contains a call to the object named head before it is initialized by loader.load() function. Additionally you are calling loader.load() asynchronously which would cause further timing issues.

    One way to fix this would be calling loader.load() synchronously by passing the correct arguments as mentioned in the docs OBJLoader2 ThreeJS (see below) and moving the call to loader.load to be before the loading manager so that it would load before the object named head gets used.

    From objloader2 doc setting useAsync to false causes the loader to load synchronously:

    .load ( url : String, onLoad : Function, onProgress : Function, onError : Function, onMeshAlter : Function, useAsync : boolean ) : null
    

    This way ensures the obj object is not used before the .obj file is loaded.

    See code snippet below:

     var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 1000);
        camera.position.z = 100;
        camera.position.y = 10;
        var renderer = new THREE.WebGLRenderer({
            alpha: true
        });
    
        //Moved loader.load and passed correct sync args
        var head;
        var loader = new THREE.OBJLoader2(manager);
        loader.load('http://trhidouan309.barzalou.com/site_web/js/profil.obj', function (obj) {
            head = obj;
        }, onProgress, onError, null, false);
    
        var manager = new THREE.LoadingManager(loadModel);
        manager.onProgress = function (item, loaded, total) {
            console.log(item, loaded, total);
        };
        var wrapper = new THREE.Object3D;
        var textureloader = new THREE.TextureLoader();
        renderer.setSize(window.innerWidth, window.innerHeight);
        var light = new THREE.DirectionalLight(0xffffff, 1.0);
        light.position.set(100, 100, 100);
        scene.add(light);
        var light2 = new THREE.DirectionalLight(0xffffff, 1.0);
        light2.position.set(-100, 100, -100);
        scene.add(light2);
    
        function onError() {}
    
        function onProgress(xhr) {
            if (xhr.lengthComputable) {
                var percentComplete = xhr.loaded / xhr.total * 100;
                console.log('model ' + Math.round(percentComplete, 2) + '% downloaded');
            }
        }
    
        function loadModel() {
            setTimeout(function () {
                wrapper.add(head);
                scene.add(wrapper);
            }, 10);
        }
        material.opacity = 0.6;
        var hiddenPlane = new THREE.Mesh(planeGeometry, material);
        hiddenPlane.position.set(0, 0, 50);
        scene.add(hiddenPlane);
        var mouse = new THREE.Vector2(0, 0);
        var point = new THREE.Vector3(0, 0, 0);
        var raycaster = new THREE.Raycaster();
        camera.lookAt(scene.position);
        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('resize', onWindowResize, false);
    
        function onMouseMove(event) {
            event.preventDefault();
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(mouse, camera);
            var intersects = raycaster.intersectObject(hiddenPlane);
            if (intersects.length > 0) {
                point = intersects[0].point;
            }
        };
    
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
    
        function animate() {
            requestAnimationFrame(animate);
            render();
        }
    
        function render() {
            wrapper.lookAt(point);
            renderer.render(scene, camera);
        }
        window.onload = function () {
            document.getElementById("scene3d").appendChild(renderer.domElement);
        }
    
        animate();

    PS: there seems to be another issue with material.opacity = 0.6; lacking correct declaration that might cause the scene to not render properly.