0

I'm a complete beginner at threejs and I just finished my first tutorial. I've been toying around with what I've learned but have run into an issue/query. My goal is to hover my mouse pointer over a basic cube shape, and have the cube shape grow in scale then when my pointer leaves the cube shape it returns to it's original size (Or at least shrinks). I figure an If Statement would be the way to go, but I can't find any documentation or examples of how to create an If Statement to create an on-hover effect on a shape in threejs. Here's my code:

// Scene and Camera settings
var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
camera.position.z = 5;

// Renderer settings
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor("#e5e5e5");
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//Prevent malforming of renderer when resizing browser
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;

  camera.updateProjectionMatrix();
});

//Raycaster and mouse to detect intersections
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

//Cube settings
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
  color: 0xFFCC00
});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.set(0, 1.75, 0);
scene.add(mesh);

//Light settings
var light = new THREE.PointLight(0xFFFFFF, 1, 500);
light.position.set(10, 0, 25);
scene.add(light);

//Render
var render = function() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

//onMouseOver event

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.intersectObjects(scene.children, true);

  for (var i = 0; i < intersects.length; i++) {
    this.tl = new TimelineMax();
    this.tl.to(intersects[i].object.scale, 1, {
      x: 2,
      ease: Expo.easeOut
    });
  }

}

render();

window.addEventListener('mousemove', onMouseMove);
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>

I've tried referencing the 0 index of 'intersects' and registering an If Statement that says if intersects[0] is Intersected, then increase scale, else decrease scale 1-to-1. However it didn't work. I've also tried implementing similar code I found online to try and mould it to fit the purpose but again no results. Any help will be appreciated, even if it's just a link to a tutorial on threejs If statement functionality.

1

1 Answer 1

0

If you have only a single object that is hovered and scaled, a simple flag ishovering = true|false could do the trick. If there are more than one object, it is better to reference the object that got intersected on mouse hover and scaled, such that it can also get scaled down again, when the first intersection is suddenly another object.

I made some adjustments to your code snippet. I don't think that you need a for loop. Usually, one want to highlight only the most upfront object (intersects[0]) the mouse is hovering. With a for loop you would also scale all objects behind the first object. If that is really the case, you'll have to reference all scaled objects in an array.

Below is the relevant code snippet, only the upfront object is scaled:

if (!intersects[0] && hoverObj || hoverObj && intersects[0] && intersects[0].object !== hoverObj) {
        
  // reset scale of old hover object
  new TimelineMax().to(hoverObj.scale, 1, { x: 1, y: 1, z: 1, ease: Expo.easeOut });
  hoverObj = null;
        
}
      
if (intersects[0] && !hoverObj) {
      
  // set scale of new hover object
  hoverObj = intersects[0].object;
  new TimelineMax().to(hoverObj.scale, 1, { x: 1.2, y: 1.2, z: 1.2, ease: Expo.easeOut });
        
}

Complete code snippet:

// Scene and Camera settings
var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
camera.position.z = 5;

// Renderer settings
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor("#e5e5e5");
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//Prevent malforming of renderer when resizing browser
window.addEventListener('resize', () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;

  camera.updateProjectionMatrix();
});

//Raycaster and mouse to detect intersections
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();

//Cube settings
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshLambertMaterial({
  color: 0xFFCC00
});
var mesh1 = new THREE.Mesh(geometry, material);
mesh1.rotation.set(0, 1.75, 0);
scene.add(mesh1);
var mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.set(-1.5, 0, 0);
scene.add(mesh2);

//Light settings
var light = new THREE.PointLight(0xFFFFFF, 1, 500);
light.position.set(10, 0, 25);
scene.add(light);

//Render
var render = function() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}

var hoverObj = null;

//onMouseOver event
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.intersectObjects(scene.children, true);
  
  if (!intersects[0] && hoverObj || hoverObj && intersects[0] && intersects[0].object !== hoverObj) {
    
    // reset scale of old hover object
    new TimelineMax().to(hoverObj.scale, 1, { x: 1, y: 1, z: 1, ease: Expo.easeOut });
    hoverObj = null;
    
  }
  
  if (intersects[0] && !hoverObj) {
  
    // set scale of new hover object
    hoverObj = intersects[0].object;
    new TimelineMax().to(hoverObj.scale, 1, { x: 1.2, y: 1.2, z: 1.2, ease: Expo.easeOut });
    
  }

}

render();

window.addEventListener('mousemove', onMouseMove);
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

Ups, I haven't looked at the link posted by @prisoner849 . So, my answer is probably redundant.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.