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.
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.
Share Improve this question edited Jun 4, 2014 at 10:48 James Milner asked Jun 4, 2014 at 10:38 James MilnerJames Milner 8992 gold badges12 silver badges16 bronze badges5 Answers
Reset to default 9As 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.
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;
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.
Use event.OffsetX and event.OffsetY if you are using ClientX and ClientY.
Because I am not using the full screen resolution as the size of my WebGL canvas, I needed to do an alternate calculation to subtract the distance between the window and the canvas, to define where my mouse actually was hovering..
function onDocumentMouseMove( event ) {
mouseVector.x = (event.offsetX / (window.innerWidth - 240)) * 2 - 1;
mouseVector.y = -(event.offsetY / (window.innerHeight - 100)) * 2 + 1;
}
// when the mouse moves, call the given function
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
Once my mouse coordinates were calculated correctly for the canvas size, objects inside it reacted more accurately. (This solution does not manipulate the camera, just the mouse coordinates returned.)
Hope this helps.