0

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

Anas Abu Farraj
  • 1,540
  • 4
  • 23
  • 31
TahaInc
  • 45
  • 1
  • 6
  • data loading is asynchromous; so you cannot do `head = obj` and then later on add `head` to the scene. Try doing `wrapper.add(head)` in the `load()` function. – gaitat Jan 21 '19 at 20:05
  • @gaitat Do you mean like this? Because I just tried and it's still giving me the same error: loader.load('http://trhidouan309.barzalou.com/site_web/js/profil.obj', function (obj) { head = obj; wrapper.add(head); scene.add(wrapper); }); – TahaInc Jan 21 '19 at 23:14
  • yes thats how I meant. Can you try using `OBJLoader` instead of `OBJLoader2` just to verify? – gaitat Jan 22 '19 at 01:19
  • @gaitat I used to use that instead of OBJLoader2 and I had too many errors with it (like trackGeometry.computeCentroids(); trackGeometry.computeFaceNormals(); trackGeometry.computeVertexNormals(); ) So i looked around and found that the new version would fix it – TahaInc Jan 22 '19 at 21:08
  • @gaitat Alright so I used the answer below to help me and now theres no error but I get this warning message (object_group "obj_" was defined with unresolvable material "material_0"! Assigning "defaultMaterial") and also nothing displays. – TahaInc Jan 22 '19 at 21:13
  • 1
    if you used the answer below you should mark it as correct. then if you still have issues post a new question. – gaitat Jan 23 '19 at 00:52

1 Answers1

0

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.

Amr Aly
  • 386
  • 1
  • 14
  • Sorry can't comment above because I don't have enough rep points. "Alright so I used the answer below to help me and now theres no error but I get this warning message (object_group "obj_" was defined with unresolvable material "material_0"! Assigning "defaultMaterial") and also nothing displays" This is likely caused because you don't use THREE.MTLLoader() to preload your materials take a look at https://threejs.org/docs/#examples/loaders/MTLLoader – Amr Aly Jan 23 '19 at 21:48