Hovering over objects in Three.js does not function as effectively as clicking on them

Just getting into Three.js

I'm attempting to load a GLTF model and add mouseover and mouseout events. The goal is for the color of the GLTF model to change on mouseover and revert back to the original on mouseout.

I have had some success with this, but there seems to be a problem as shown in this video. It only changes the color when the mouse pointer directly enters the GLTF model without passing through the black background first.

The code I'm currently using:

const loader = new GLTFLoader();
loader.load('models/box.glb', function (gltf) {
    gltf.scene.traverse(function (child) {
        if (child.isMesh) {
            let m = child;
            m.receiveShadow = true;
            m.castShadow = true;
            m.material.flatShading = true;
            sceneMeshes.push(m);
        }
        if (child.isLight) {
            let l = child;
            l.castShadow = true;
            l.shadow.bias = -.003;
            l.shadow.mapSize.width = 2048;
            l.shadow.mapSize.height = 2048;
        }
    });
    scene.add(gltf.scene);
    console.log(gltf.scene);
}, (xhr) => {
    console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
    console.log(error);
});
const raycaster = new THREE.Raycaster();
const sceneMeshes = new Array();
renderer.domElement.addEventListener('mouseover', onMouseMove, false);
renderer.domElement.addEventListener('mouseout', onMouseOut, false);
function onMouseMove(event) {
    const mouse = {
        x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
        y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
    };
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(sceneMeshes, false);
    if (intersects.length > 0) {
        intersects[0].object.material.color.set(0xffff00);
    }
}
function onMouseOut(event) {
    const mouse = {
        x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
        y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
    };
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(sceneMeshes, false);
    if (intersects.length > 0) {
        intersects[0].object.material.color.set(0xff0000);
    }
}

Any suggestions on what might be causing this issue?

Answer №1

Give this simplified code a try:

let camera, scene, renderer, mesh;
let raycaster, mouse;

let currentIntersection = null;

init();
animate();

function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
  camera.position.z = 4;

  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2();

  scene = new THREE.Scene();

  const geometry = new THREE.BoxBufferGeometry();
  const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );

  mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  renderer.domElement.addEventListener('pointermove', onMouseMove, false);

}

function animate() {

  requestAnimationFrame(animate);

  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.02;

  renderer.render(scene, camera);

}

function onMouseMove(event) {
  mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
  mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObject(scene, true);
  if (intersects.length > 0) {
    currentIntersection = intersects[0].object;
    currentIntersection.material.color.set(0xffff00);
  } else {
    if (currentIntersection !== null) {
      currentIntersection.material.color.set(0xff0000);
      currentIntersection = null;
    }
  }
}
body {
  margin: 0;
}

canvas {
  display: block;
}
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8afee2f8efefcabaa4bbb8baa4bb">[email protected]</a>/build/three.js"></script>

A pointermove event listener is typically enough to create a "hover" effect.

Answer №2

My issue was resolved by implementing the mousemove event, along with the code snippet below within the onMouseMove event:

if (intersects.length > 0) {
    INTERSECTED = intersects[0].object;

    if (intersects[0].object) {
        INTERSECTED.material.color.set(0xff0000);
        console.log("Touching")
    }
        
} else {
    INTERSECTED.material.color.set(0xfff000);
    console.log("Not touching")
}

Essentially, my mistake was placing the else statement incorrectly - it should have been right after the if statement (intersects[0].object)

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

Passing PHP array to JavaScript in a specific format

After running the code provided, I find that the data returned is in an array format but unfortunately not easily referenced. AJAX: $.ajax({ url: './FILE.php', type: 'post', data: {'action': 'allfolders'}, ...

The function and if-else statement are experiencing malfunctions

Currently in the early stages of learning coding, I've been focusing on building a solid foundation by practicing with CodeWars. Utilizing this platform for practice has been beneficial because it offers solutions for guidance. While attempting to wor ...

What's the Secret Behind the Mysterious Parameter in setState?

Currently enrolled in a TypeScript + React course where I am working on developing a todo list application. However, my query is related to a specific feature of React. Within the function for adding a new Todo item, there is a statement declaring a funct ...

Retrieve information and functions from one component in a separate component

I currently have two components: ContainerSidebar.vue <!-- Sidebar --> <div id="b-sidebar"> <div class="change-image"> <img :src="profile.avatar != null ? profile.avatar+'#&apo ...

How to efficiently store data using ajax and php techniques

I'm currently working on sending data via ajax for the user_question and language input fields. Can anyone help me with the correct way to include this element in the ajax JavaScript code so that I can save the table element value in my database? Tha ...

Tips for validating a text input field depending on the selected value in a dropdown menu using AngularJS

When a user selects from the dropdown menu, they can choose between Number and Decimalnumber. If the user selects Number, the text box should only allow whole numbers (e.g. 22, 33, 444, 345436). The user should not be able to enter decimal values like 22 ...

What is the best way to compare the previous and next values in React?

When working with the code snippet below to send a list of values to another component - React.createElement("ul", null, this.state.stock.map(function (value){ return (React.createElement(Price, { price: value })) }) ) the values are then sent t ...

Node server encountering issue with undefined data in POST request

I have been working on an Angular2/Node.js application. Everything seems to be working fine when I retrieve an object from the Node server, but I'm facing an issue when trying to post data to the server. The request.body always shows as undefined. Can ...

I desire for both my title and navigation bar to share a common border-bottom

As I embark on my journey into the world of HTML and CSS, my knowledge is still limited. Despite trying various solutions from similar queries, none seem to resolve my specific issue. What I yearn for is to have both my title and navigation bar share the s ...

dynamically import a variety of components in vue.js and nuxt depending on certain conditions

Is there a way to implement dynamic imports for all 3 components in this scenario? Each component has different props, so using the switch option in the computed method is not feasible. I have come across solutions for using a single component dynamically ...

What could be causing the invalid hooks error to appear in the console?

I'm completely stumped as to why this error is popping up when I try to use mutations with React Query. Any insights or advice would be greatly appreciated. Note: I'm implementing this within a function component in React, so it's puzzling ...

Discovering the Nearest Point to the Mouse Cursor using Three JS Ray Casting

Three.js version r85 While using raycasting in Three JS, a list of points is generated, and I am interested in identifying the point closest to the cursor. It appears that the first point returned is typically the one nearest to the camera. Is there a me ...

What makes it possible for Vue v3 to handle variables that are undefined?

We are in the process of developing a web application that monitors analytical changes and updates them in real time. While this may not be crucial information, we thought it would be worth mentioning. If you visit Vue.js's official website at https: ...

What is causing this unique component to be positioned outside of the <tr> tag?

table.vue ... <tbody class="table-body"> <slot></slot> </tbody> ... TableCellRow.vue <template> <td class="table-row-cell" :class="this.class"> <s ...

What is the best way to style HTML content with MathJax following its retrieval with jQuery.load?

I recently encountered an issue while using jQuery.load to load a new page. The content on the original page is being treated strangely in some way. Specifically, I have code on the original page that formats LaTeX commands with MathJax: <script type=" ...

Create a unique jQuery script for a gallery that allows you to dynamically pass a CSS class as a parameter

Hey there! I'm a newbie in the world of JavaScript and programming, and I'm struggling to find an efficient solution for a script that assigns parameters to multiple photo galleries. The script is functional, but I believe it can be simplified to ...

Is it possible to utilize AJAX to load the URL and then extract and analyze the data rather than

I had originally created a web scraping method using PHP, but then discovered that the platform I was developing on (iOS via phone gap) did not support PHP. Fortunately, I was able to find a solution using JS. $(document).ready(function(){ var container ...

The most efficient method for handling a vast amount of data in NodeJS

My database consists of 4 million numbers and I need to quickly check if a specific number exists in it. Example of the database: [177,219,245,309,348,436,...] I initially tried using a MySQL table for this task, but it took a lengthy 1300ms just to chec ...

Prevent users from selecting elements on the mobile site

Hey there! I'm currently working on preventing users from selecting items on my mobile site. While I've been successful in doing so on a regular website using the CSS class below .unselectable { -moz-user-select: -moz-none; -khtml-user-s ...

how to load CSS and JS files on certain views in Laravel 5.2

Currently, I am facing a situation where I need to ensure that the CSS and JS files are loaded only on specific views in Laravel 5.2. Due to my boss's decision to eliminate RequireJS for loading JS files on our blade templates, we are now exploring a ...