Rylan Schaeffer
Rylan Schaeffer

Reputation: 2705

Three JS - Rotate arrow in 3D to track mouse

I'm learning Three Js and I have the following problem: I have an arrow of a fixed length r centered at position (x, y, z) and I want the arrow to rotate to track the mouse. If the mouse is further away from the center than r, I want the z component of the arrow to be 0, but if the mouse is within distance r from the center, I want the arrow's z component to be set to the remaining length i.e. Math.sqrt((arrowLength * arrowLength) - (dx*dx) - (dy*dy)).

How do I do this?

My question is similar to this question but the key difference is that I don't know the dz component in advance.

Upvotes: 0

Views: 462

Answers (1)

prisoner849
prisoner849

Reputation: 17596

You can use .unproject() method of Vector3() to cast a vector from camera's NDC space to world space.

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/[email protected]";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 1).setLength(6);
let renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(innerWidth, innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", onWindowResize);

let pointer = new THREE.Vector3();
let lookAt = new THREE.Vector3();
window.addEventListener("pointermove", event => {
  pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
  pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
  lookAt.copy(pointer).unproject(camera).setLength(5);
  o.lookAt(lookAt);
})

let g = new THREE.ConeGeometry(0.2, 2, 32);
g.translate(0, 1, 0);
g.rotateX(Math.PI * 0.5);
let m = new THREE.MeshNormalMaterial();
let o = new THREE.Mesh(g, m);
scene.add(o);

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
});

function onWindowResize() {

  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);

}

</script>

Upvotes: 3

Related Questions