Raycasting is functioning properly on objects created within the program, however, it seems to be ineffective on imported OBJ models

As a newcomer to three.js, I am currently exploring raycasting and encountering some confusion regarding its functionality with imported 3D models. Specifically, when I import an obj model and attempt to determine if there is contact with the imported 3D model, the function does not behave as expected. However, when I switch to detecting a box object created within three.js, everything works as anticipated. Can anyone provide assistance in resolving this issue?

import * as THREE from 'https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8efae6fcebebcebea0bfbcb8a0bf">[email protected]</a>/build/three.module.js';

import { OrbitControls } from 'https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="43372b31262603736d7271756d72">[email protected]</a>/examples/jsm/controls/OrbitControls.js';

import {OBJLoader} from "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d4a0bca6b1b194e4fae5e6e2fae5">[email protected]</a>/examples/jsm/loaders/OBJLoader.js";

import {MTLLoader} from "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="42362a30272702726c7370746c73">[email protected]</a>/examples/jsm/loaders/MTLLoader.js";

import * as GUI from "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="385c594c165f4d517808160f160f">[email protected]</a>/build/dat.gui.module.js";

//Setting Up the 3D Model Environment
const renderer = new THREE.WebGLRenderer();

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

document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();



//Configuring 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);



//Configuring 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();



//Creating the 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;


//GUI Setup for Controlling the 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;
});


//Background Image Setup
const textureLoader = new THREE.TextureLoader();

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


//Importing obj and mtl files to build the 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 Error")
    }
)



//Setting up Raycasting Environment
const raycaster = new THREE.Raycaster();
const mousePosition = new THREE.Vector2();

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

//Function to Ensure Everything is 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 ready!");
            }
            console.log(intersects[i].object.id);
        }
    }
    else{
        console.log("Did not touch")
    }
    console.log("Finished")


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



//Resize Screen Based on Browser Size
window.addEventListener('resize',function(){
    camera.aspect = window.innerWidth/this.window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth,window.innerHeight);
});

Answer №1

The issue lies in the fact that the object returned by OBJLoader and stored in your building variable is of type THREE.Group. Unlike meshes, groups do not have their own geometry or material. They essentially act as containers for other 3D objects such as meshes, point clouds, lines, or other groups, grouping them together logically.

As a result, they cannot be directly targeted by raycasting evaluations, causing the condition if(intersects[0].object.id === building.id) to always return false.

My recommendation is to assign tags to your objects after the loading process using the following code snippet:

building.traverse( function( object ) {

    object.userData.tag = 'building';

} );

By tagging your objects in this way, you can then utilize the tag property in your raycasting logic to accurately detect the building.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am interested in running JavaScript code on a page that has been loaded through AJAX

I am struggling to execute the Javascript loaded within an ajax page. Here is the link to my loaded ajax page: https://jsfiddle.net/4dsbry7j/ JS : var xmlhttp = new XMLHttpRequest(); var url = "http://localhost/ajax/find2.php"; xmlhttp.onreadystatechang ...

Error occurs when attempting to clear the cache storage

useEffect(async () => { caches.open('my-cache') }, [token, user_id]) Upon trying to log out of the application, const logoutFunc = () => { localStorage.clear() caches.keys().then((list) => list.map((key) => { ...

How can I use JavaScript to retrieve information from a different webpage?

I am trying to extract data from another webpage using JavaScript, jQuery, or Ajax without using PHP. I came across a helpful example on Stack Overflow (link here). However, when I implement these codes in my index.html file, it doesn't seem to work. ...

When trying to access the page via file://, the cookies are not functioning properly

My HTML code is functioning properly in Firefox and even on the W3Schools website when tested using their editor in Chrome. However, when I run my code in Chrome from Notepad++, it doesn't seem to work. It appears that the body onload event is not tri ...

Trigger the useEffect Hook once the condition has been satisfied

Within my component, I am utilizing the useEffect hook to monitor updates of a specific value. I have implemented a condition to prevent the useEffect function from triggering after the initial rendering. However, I noticed that each time the button is c ...

What is the best way to halt a JavaScript function originating from embedded iframe content?

When I embed another website using iframe, there is a javascript function on their page that I do not want to run on my own page. Here it is: if (top.location != location) { top.location.href = document.location.href; } I attempted a solution but it ende ...

Trigger an event in jQuery when the focus moves away from a set of controls

Within a div, I have three textboxes and am looking for a way to trigger an event when focus leaves one of these inputs without transitioning to another one of the three. If the user is editing any of the three controls, the event should not be triggered. ...

I am encountering an issue while developing a JavaScript filtering system

Hey everyone, I need help with coding a filter in JavaScript and I'm running into an error (Uncaught TypeError: todos.forEach is not a function) that I can't figure out. Can someone assist me in resolving this issue? const todoFilter = docume ...

Searching for an individual MongoDB document using Express

I recently started working with MongoDB and express. I am trying to authenticate a user based on their username and password, but my code seems to always execute the "else statement" even when the correct credentials are entered. Below is the JavaScript f ...

How can you transfer array elements to a new array using JavaScript?

I have a task to transform the fields of an array received from one server so that they can be understood by another server for upload. My approach involves first retrieving and displaying the original field names from the initial server's array to al ...

What is the best way to incorporate progress updates into a rendered jade page?

I am currently working on a small express.js application with a form. When the form is submitted, it triggers a python script that takes approximately 5 minutes to run and outputs messages to the console while it is running. At the moment, I am able to cal ...

With Ionic, you can use one single codebase for both iPad and iPhone

I currently have a complete app developed using ionic and angularjs that is functioning well on iPads and Android devices. Now we are looking to launch it for iPhones and Android smartphones with some design modifications. Is there a method to achieve th ...

Nightwatch.js feature not functioning properly in a 'closing' manner

I'm facing an issue where I need to execute a function at the beginning of my test before proceeding with the rest of the test steps. Here is the custom command I am using, named internalAdviceLinksHtml: const solr = require('solr-client') ...

What is the advantage of using multiple states compared to a single state object in React?

When working with a functional component that requires the use and manipulation of multiple state items, I often find myself in a dilemma. Should I group all the states together in one object and set them with one method, or should I declare and set each s ...

Extracting JavaScript variable data to PHP using Ajax technology

I've been trying to save latitude and longitude values in PHP variables, but I'm having trouble. Here is the code I'm using. Can anyone please help me figure out why these values are not being stored in PHP variables: Code: <!DOCTYPE h ...

Include a Class into a label using jQuery

I am having an issue where I need to specifically add the error class to a <label> with the name attribute set to choice_16_0. However, when I try to achieve this using my code, it ends up changing all labels on the page to <label for="choice_16_0 ...

utilizing jQuery to create dynamic data changes based on JSON file

<div id="rightside"> <h1>John Doe</h1> <p>1980 - 2020 <p><a href="johnswebsite.com">Visit Website</a> <p>Lorem ipsum dolor sit amet, consectetur adi ...

Using .done(), .then(), and .when() in jQuery for sequencing ajax requests in a specific order

After diving into the world of Promises in jquery and trying to avoid "callback hell" when dealing with multiple ajax requests, I still find myself without a clear answer on which method to use - whether it's .done(), .then(), or .when() - for chainin ...

What is the best method to determine if a text box is filled or empty?

I need to verify whether a text box is populated with a name. If it is empty, an alert message should be shown upon clicking the submit button, and the page should not proceed with submitting the blank value. If there is a value in the text box, then that ...

Best locations for placing files when integrating Javascript into Wordpress

I have been struggling to make JavaScript work and determine the correct location to place the files. After attempting various methods, I am now wondering what the most logical approach would be. Despite spending a week on this task, the lack of a tutoria ...