Three.js Projector and Ray objects
3d, javascript, three.js
Solution
Basically, you need to project from the 3D world space and the 2D screen space.
Renderers use `projectVector` for translating 3D points to the 2D screen. `unprojectVector` is basically for doing the inverse, unprojecting 2D points into the 3D world. For both methods you pass the camera you're viewing the scene through.
So, in this code you're creating a normalised vector in 2D space. To be honest, I was never too sure about the `z = 0.5` logic.
mouse3D.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse3D.y = -(event.clientY / window.innerHeight) * 2 + 1;
mouse3D.z = 0.5;
Then, this code uses the camera projection matrix to transform it to our 3D world space.
projector.unprojectVector(mouse3D, camera);
With the mouse3D point converted into the 3D space, we can now use it for getting the direction and then use the camera position to throw a ray from.
var ray = new THREE.Ray(camera.position, mouse3D.subSelf(camera.position).normalize());
var intersects = ray.intersectObject(plane);
Problem
I have been trying to work with the Projector and Ray classes in order to do some collision detection demos. I have started just trying to use the mouse to select objects or to drag them. I have looked at examples that use the objects, but none of them seem to have comments explaining what exactly some of the methods of Projector and Ray are doing. I have a couple questions that I am hoping will be easy for someone to answer. What exactly is happening and what is the difference between Projector.projectVector() and Projector.unprojectVector()? I notice that it seems in all the examples using both projector and ray objects the unproject method is called before the ray is created. When would you use projectVector? I am using the following code in this demo to spin the cube when dragged on with the mouse. Can someone explain in simple terms what exactly is happening when I unproject with the mouse3D and camera and then create the Ray. Does the ray depend on the call to unprojectVector() ``` /** Event fired when the mouse button is pressed down */ function onDocumentMouseDown(event) { event.preventDefault(); mouseDown = true; mouse3D.x = mouse2D.x = mouseDown2D.x = (event.clientX / window.innerWidth) * 2 - 1; mouse3D.y = mouse2D.y = mouseDown2D.y = -(event.clientY / window.innerHeight) * 2 + 1; mouse3D.z = 0.5; /** Project from camera through the mouse and create a ray */ projector.unprojectVector(mouse3D, camera); var ray = new THREE.Ray(camera.position, mouse3D.subSelf(camera.position).normalize()); var intersects = ray.intersectObject(crateMesh); // store intersecting objects if (intersects.length > 0) { SELECTED = intersects[0].object; var intersects = ray.intersectObject(plane); } } /** This event handler is only fired after the mouse down event and before the mouse up event and only when the mouse moves */ function onDocumentMouseMove(event) { event.preventDefault(); mouse3D.x = mouse2D.x = (event.clientX / window.innerWidth) * 2 - 1; mouse3D.y = mouse2D.y = -(event.clientY / window.innerHeight) * 2 + 1; mouse3D.z = 0.5; projector.unprojectVector(mouse3D, camera); var ray = new THREE.Ray(camera.position, mouse3D.subSelf(camera.position).normalize()); if (SELECTED) { var intersects = ray.intersectObject(plane); dragVector.sub(mouse2D, mouseDown2D); return; } var intersects = ray.intersectObject(crateMesh); if (intersects.length > 0) { if (INTERSECTED != intersects[0].object) { INTERSECTED = intersects[0].object; } } else { INTERSECTED = null; } } /** Removes event listeners when the mouse button is let go */ function onDocumentMouseUp(event) { event.preventDefault(); /** Update mouse position */ mouse3D.x = mouse2D.x = (event.clientX / window.innerWidth) * 2 - 1; mouse3D.y = mouse2D.y = -(event.clientY / window.innerHeight) * 2 + 1; mouse3D.z = 0.5; if (INTERSECTED) { SELECTED = null; } mouseDown = false; dragVector.set(0, 0); } /** Removes event listeners if the mouse runs off the renderer */ function onDocumentMouseOut(event) { event.preventDefault(); if (INTERSECTED) { plane.position.copy(INTERSECTED.position); SELECTED = null; } mouseDown = false; dragVector.set(0, 0); } ```