Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js Raycast off from mouse position

I am currently building an application in three.js alongside some jQuery. I am currently raycasting and placing a helper at the location of where the raycast hits. More or less I am trying to achieve this.

I have managed to achieve this, however upon moving the coordinates of my objects and moving the camera to the new location, my raycast, or the helper at least, is off. It seems to be off by around sort of 30 pixels but depends as you change the camera angle as you can see from here

Here is the code for the helper and the onMouseMove event for raycasting.

// RAYCAST HELPER
            var geometry = new THREE.CylinderGeometry( 0, 5, 15, 3 ); // radius at top, radius at bottom, height, segments
            //geometry.applyMatrix( new THREE.Matrix4().makeTranslation( -50, 0, 0 ) );
            geometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );
            helper = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial({ color: 0xEB1515, ambient: 0xEB1515, wireframe: false }) );
            scene.add( helper );
            rays = true;

    function onMouseMove( event ) {
                    //console.log("Mouse moved");
                    $( document ).ready(function() {
                    if ( rays == true ) {

                        cX = event.clientX - $( "#info" ).width()
                        cY = event.clientY - $( "#topbar" ).height()

                        mouseVector.x = 2 * ( cX / canvaswidth ) - 1;
                        mouseVector.y = 1 - 2 * ( cY / canvasheight );
                        mouseVector.z = 1;

                        var raycaster = projector.pickingRay( mouseVector.clone(), camera );

                        for (var i = 0; i < buildingsroofs.length; i++) {
                            var intersects = raycaster.intersectObject( buildingsroofs[i]);

                            // Toggle rotation bool for meshes that we clicked
                            if ( intersects.length > 0 ) {
                                console.log("Intersection");
                                helper.position.set( 0, 0, 0 );
                                helper.lookAt( intersects[ 0 ].face.normal );
                                helper.position.copy(intersects[0].point);
                            } 
                        }
                    } //End of overarching if loop
                }) 
            } //End of onMouse function

Interestingly, I have got it to work here but these objects have the wrong coordinates from what i'm after. You can also see I am adjusting for the height of the top div and the side div, so that does not appear to be the issue as I originally imagined.

like image 873
James Milner Avatar asked Jun 04 '14 10:06

James Milner


4 Answers

As everything else is correct, your mouseVector x and y values (i.e. clientX and clientY) are most likely off as compared with your WebGL canvas (for instance, you may be getting these from some element other than the canvas.

Easiest way to check for this is to place the mouse in the top left corner of your canvas (should be (0, 0) and log out the mouse position on click to see whether your values are off. Apply same for the bottom right corner, checking against your canvas width and height. I solved a similar problem this way. In my case, (cx, cy) were (-10, -10) and this was enough for a substantial error in raycasting.

like image 80
Engineer Avatar answered Sep 23 '22 18:09

Engineer


Oddly enough the issue seemed to resolve itself upon changing the perspective camera near parameter from 0.1 to 1

camera = new THREE.PerspectiveCamera(45, canvaswidth / canvasheight , 0.1, 10000 );

To:

camera = new THREE.PerspectiveCamera(45, canvaswidth / canvasheight , 1, 10000 ); 

I am still not 100% sure why this fixed the issue, but it appears to have worked.

Edit: Changing FOV from 45 to 60 removed the minor distortion in the raycasting that was still occuring after changing the near camera parameter.

like image 39
James Milner Avatar answered Sep 23 '22 18:09

James Milner


Use event.OffsetX and event.OffsetY if you are using ClientX and ClientY.

like image 23
Kanakam Teja Avatar answered Sep 25 '22 18:09

Kanakam Teja


Had many difficulties with this, and still not sure I understand why this works, but this calculation of x and y works for me.

let canvas = document.querySelector('canvas');

let x = (event.offsetX / canvas.clientWidth) * 2 - 1;
let y = -(event.offsetY / canvas.clientHeight) * 2 + 1;
like image 44
cammil Avatar answered Sep 21 '22 18:09

cammil