Only change color on Hover three.js

Viewed 574

I am trying to make a rectangle change color on hover with three.js but I can only get it to do it at all times, without the mouse making any difference. I am following the guide on the three.js documentation for using Raycaster.

Here's my code

var scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);

var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
function onMouseMove(event) {
    // calculate mouse position in normalized device coordinates
    // (-1 to +1) for both components

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.PlaneGeometry(2, 2);
var material = new THREE.MeshBasicMaterial({ color: 0xbbbbbb, side: THREE.DoubleSide });
var plane = new THREE.Mesh(geometry, material);
plane.rotation.z = Math.PI/3;
plane.rotation.x = -Math.PI/3;
scene.add(plane);

camera.position.z = 5;
function render() {
    // update the picking ray with the camera and mouse position
    raycaster.setFromCamera(mouse, camera);

    // calculate objects intersecting the picking ray
    var intersects = raycaster.intersectObjects(scene.children);

    for (var i = 0; i < intersects.length; i++) {
        
        intersects[i].object.material.color.set(0xff0000);

    }

    renderer.render(scene, camera);
}
window.addEventListener('mousemove', onMouseMove, false);
window.requestAnimationFrame(render);

Any help would be appreciated.

1 Answers

There are a few issues in your code:

  • The call of requestAnimationFrame() must happen inside the animation loop.
  • Since your object is in the middle, you have to init the mouse vector with (-1, -1). Otherwise the first tests (until the cursor is above the canvas) assume the mouse is in the center of the screen and thus directly produce an intersection with your object.
  • You have to update the world matrix of the camera once so the first intersection test is correct.

var scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);

var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(-1, -1);

function onMouseMove(event) {
  // calculate mouse position in normalized device coordinates
  // (-1 to +1) for both components

  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

}

document.addEventListener('mousemove', onMouseMove, false);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.PlaneGeometry(2, 2);
var material = new THREE.MeshBasicMaterial({
  color: 0xbbbbbb,
  side: THREE.DoubleSide
});
var plane = new THREE.Mesh(geometry, material);
plane.rotation.z = Math.PI / 3;
plane.rotation.x = -Math.PI / 3;
scene.add(plane);

camera.position.z = 5;
camera.updateMatrixWorld();

function render() {

  requestAnimationFrame(render);

  // update the picking ray with the camera and mouse position
  raycaster.setFromCamera(mouse, camera);

  // calculate objects intersecting the picking ray
  var intersects = raycaster.intersectObjects(scene.children);

  if (intersects.length > 0) {

    intersects[0].object.material.color.set(0xff0000);

  } else {

    material.color.set(0xbbbbbb);

  }

  renderer.render(scene, camera);
}

render();
body {
  margin: 0;
}
canvas {
  display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.118.3/build/three.js"></script>

Related