Search code examples
three.jspointprojectionmouse-coordinates

Mouse / Canvas X, Y to Three.js World X, Y, Z


I've searched around for an example that matches my use case but cannot find one. I'm trying to convert screen mouse co-ordinates into 3D world co-ordinates taking into account the camera.

Solutions I've found all do ray intersection to achieve object picking.

What I am trying to do is position the center of a Three.js object at the co-ordinates that the mouse is currently "over".

My camera is at x:0, y:0, z:500 (although it will move during the simulation) and all my objects are at z = 0 with varying x and y values so I need to know the world X, Y based on assuming a z = 0 for the object that will follow the mouse position.

This question looks like a similar issue but doesn't have a solution: Getting coordinates of the mouse in relation to 3D space in THREE.js

Given the mouse position on screen with a range of "top-left = 0, 0 | bottom-right = window.innerWidth, window.innerHeight", can anyone provide a solution to move a Three.js object to the mouse co-ordinates along z = 0?


Solution

  • You do not need to have any objects in your scene to do this.

    You already know the camera position.

    Using vector.unproject( camera ) you can get a ray pointing in the direction you want.

    You just need to extend that ray, from the camera position, until the z-coordinate of the tip of the ray is zero.

    You can do that like so:

    var vec = new THREE.Vector3(); // create once and reuse
    var pos = new THREE.Vector3(); // create once and reuse
    
    vec.set(
      ( event.clientX / window.innerWidth ) * 2 - 1,
      - ( event.clientY / window.innerHeight ) * 2 + 1,
      0.5,
    );
        
    vec.unproject( camera );
        
    vec.sub( camera.position ).normalize();
        
    var distance = - camera.position.z / vec.z;
        
    pos.copy( camera.position ).add( vec.multiplyScalar( distance ) );
    

    The variable pos is the position of the point in 3D space, "under the mouse", and in the plane z=0.


    EDIT: If you need the point "under the mouse" and in the plane z = targetZ, replace the distance computation with:

    var distance = ( targetZ - camera.position.z ) / vec.z;
    

    three.js r.98