Raycasting not working on imported OBJ model,but working on object created with the program

Viewed 34

I am new to three.js, and i am trying to use raycasting, i am quite confused with how raycasting would work on imported 3d models. Here i imported an obj model, and when i try to detect whether i touch with the imported 3D model, the funciton is not working as i expect. But when i change it to detect a box object i create with three.js, is working as i expected, can someone help with this problem?

import * as THREE from 'https://unpkg.com/three@0.126.1/build/three.module.js';

import { OrbitControls } from 'https://unpkg.com/three@0.126.1/examples/jsm/controls/OrbitControls.js';

import {OBJLoader} from "https://unpkg.com/three@0.126.1/examples/jsm/loaders/OBJLoader.js";

import {MTLLoader} from "https://unpkg.com/three@0.126.1/examples/jsm/loaders/MTLLoader.js";

import * as GUI from "https://unpkg.com/dat.gui@0.7.7/build/dat.gui.module.js";

//Set Up Enviroment for 3D model
const renderer = new THREE.WebGLRenderer();

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

document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();



//Set up Lighting
var keyLight = new THREE.DirectionalLight(new THREE.Color('hsl(30,100%,75%)'),1.0);
var fillLight = new THREE.DirectionalLight(new THREE.Color('hsl(240,100%,75%)'),0.75);
var backLight = new THREE.DirectionalLight(0xffffff,1.0);

keyLight.position.set(-100,0,100);
fillLight.position.set(100,0,100);
backLight.position.set(100,0,-100).normalize();

scene.add(keyLight);
scene.add(fillLight);
scene.add(backLight);



//Set up Camera
const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth/window.innerHeight,
    0.1,
    1000
);

const orbit = new OrbitControls(camera,renderer.domElement);
camera.position.set(0,2,7.5);
orbit.update();



//Set up base
const planeGeometry = new THREE.PlaneGeometry(100,100);
const planeMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    wireframe: false,
    side: THREE.DoubleSide
});

var plane = new THREE.Mesh(planeGeometry,planeMaterial);
scene.add(plane);
plane.rotation.x = -0.5 * Math.PI;



//Model for testing
const boxGeometry = new THREE.BoxGeometry(10,10,10);
const boxMaterial = new THREE.MeshBasicMaterial({color: 0x0000ff})

var box = new THREE.Mesh(boxGeometry,boxMaterial);
scene.add(box);
box.position.x += 20;


//Set up GUI for controlling base 
const gridHelper = new THREE.GridHelper(100);
scene.add(gridHelper);

const gui = new GUI.GUI();
const options = {
    planeColor: '#ffea00',
    wireframe: false 
};

gui.addColor(options,'planeColor').onChange(function(e){
    plane.material.color.set(e);
});

gui.add(options,'wireframe').onChange(function(e){
    plane.material.wireframe = e;
});


//Set up Background image
const textureLoader = new THREE.TextureLoader();

textureLoader.load(
    '../img/doge.jpg',
    function ( texture ) {
        scene.background = texture;
    },
    undefined,
    function ( err ) {
        console.error( 'An error happened.' );
    }
);


//Import obj and mtl file to build 3D model
var building;

const mtlLoader = new MTLLoader();
mtlLoader.load(
    '../source/building_04.mtl',
    (materials)=>{
        materials.preload();
        console.log(materials);

        const objLoader = new OBJLoader()
        objLoader.setMaterials(materials)
        objLoader.load(
            '../source/building_04.obj',
            (object)=>{
                scene.add(object)
                building = object;
                object.position.y +=1;
            },
            (xhr) => {
                console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
            },
            (error) => {
                console.log("Object error")
            }
        )
    },
    (xhr) => {
        console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
    },
    (error) => {
        console.log("Material Eror")
    }
)



//Set up raycasting environment
const raycaster = new THREE.Raycaster();
const mousePosition = new THREE.Vector2();

window.addEventListener('mousemove', function(e){
    mousePosition.x = (e.clientX/this.window.innerWidth)*2 - 1;
    mousePosition.y = -(e.clientY/this.window.innerHeight)*2 + 1;
});

//Function making sure everything to be up to date
function animate(){
    //Raycasting
    raycaster.setFromCamera( mousePosition, camera );

    const intersects = raycaster.intersectObjects( scene.children,true);

    if(intersects.length > 0){
        for ( let i = 0; i < intersects.length; i ++ ) {
            if(building != undefined){
                if(intersects[0].object.id === building.id){
                    console.log("Touched!");
                }
                else{
                    console.log("did not touch!");
                }
            }
            else{
                console.log("Not reeady!");
            }
            console.log(intersects[i].object.id);
        }
    }
    else{
        console.log("did not touched")
    }
    console.log("finished")



    renderer.render(scene,camera);
}
renderer.setAnimationLoop(animate);



//Make the screen to resize following the browser size
window.addEventListener('resize',function(){
    camera.aspect = window.innerWidth/this.window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth,window.innerHeight);
});
1 Answers

The problem is that the object you get from OBJLoader and assign to your building variable is an instance of THREE.Group. Groups do not have an own geometry or material. They are more or less containers holding other 3D objects (like meshes, point clouds, lines or other groups) and representing them as a logical group.

That means they are never the result of a raycasting evaluation which means if(intersects[0].object.id === building.id) always fails.

I suggest you do this after the loading process which tags your objects:

building.traverse( function( object ) {

    object.userData.tag = 'building';

} );

You can then use the tag property in your raycasting routine for detecting the building.

Related