Three.js - How to update object position for Raycaster and Intersection - javascript

I've this glTF face model which successfully 'looks' at the position of the mouse. I got the tracking working on the full window, even outside the canvas (which is needed). Since the canvas will not be full screen.
Now I'll run into an issue where the face direction doesn't align with the mouse location. E.g. this issue happens when I place the canvas inside a column on the right, the object thinks the canvas is still originated from the top left corner of the window. I'm using this code to track the mouse movement:
var plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), -10);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var pointOfIntersection = new THREE.Vector3();
document.addEventListener("mousemove", onMouseMove, false);
function onMouseMove(event) {
mouse.x = (event.clientX / canvas.clientWidth) * 2 - 1;
mouse.y = - (event.clientY / canvas.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
scene.lookAt(pointOfIntersection);
}
I don't really know how to approach this problem. How do I update the new object position relative to the screen so the raycaster and pointOfIntersection align the face direction accordingly to it's position?

const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ( ( event.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
Kudos to Mugen87 for making this possible :)

Related

three.js first person camera rotation

I've looked for help of first player rotation on three.js for a while but most of the answers are outdated with functions which currently don't exist in the updated library.
I'm trying to make my code run so that the camera will rotate around it's own axis according to the position of the mouse on the screen.
The current rotation code is:
var scale = 10;
function viewKeys(){
document.addEventListener("mousemove", MouseMove, true);
function MouseMove(event) {
mouseX = event.clientX - divOffsetWidth;
mouseY = event.clientY - divOffsetHeight;
}
}
divOffset variables make the mouse positions read relative to the center of the HTML div.
function viewAnimate(){
camera.rotation.x = -((3/2)*(Math.PI*mouseY)) / (scale);
camera.rotation.y = -(2*(Math.PI*mouseX)) / (scale);
}
The viewKeys() function is called in the init() function and the viewAnimate() function is called within the animate() function.
Currently the code can rotate normally when the camera's position is (0,0,0) but if I move to a different position it looks as if the camera is rotating relative to the whole environment's axis.
I am aware that there are lots of control librarys for three.js but I would like to understand how to be able to rotate something on its own axis myself.
How do you suppose I change the rotation so that it works correctly?
If you want to rotate the camera yourself via the mouse, you will have to understand how Euler rotations work in three.js. See this answer.
One way to implement what you want is by using a pattern like so:
var scale = 1;
var mouseX = 0;
var mouseY = 0;
camera.rotation.order = "YXZ"; // this is not the default
document.addEventListener( "mousemove", mouseMove, false );
function mouseMove( event ) {
mouseX = - ( event.clientX / renderer.domElement.clientWidth ) * 2 + 1;
mouseY = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
camera.rotation.x = mouseY / scale;
camera.rotation.y = mouseX / scale;
}
I agree with you that experimenting with this would be a good learning experience.
three.js r.89

ThreeJS, get vector towards clicked direction

What I'm trying to achieve is to make a specific mesh move towards a specific vector until it will eventually be stopped by the player.
So far I have managed to get the XY coordinates of the clicked canvas and project them in 3d using the following piece of code. Unfortunately I'm not sure what approach to take in order to get the direction towards the clicked position.
var vector = new THREE.Vector3();
vector.set(
( event.clientX / window.innerWidth ) * 2 - 1,
+ ( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
vector.unproject( camera );
var dir = vector.sub( camera.position ).normalize();
var distance = + camera.position.z / dir.z;
var pos = camera.position.clone().add( dir.multiplyScalar( distance ) );
This assumes a target Vector3 and a maximum distance to be moved per frame of .01.
var vec1 = target.clone(); // target
vec1.sub(mesh.position); // target - position
var dist = Math.min(vec1.length(), .01); // assume .01 is maximum movement
if (dist > 0) {
vec1.setLength(dist); // this will be the movement
mesh.position.add(vec1); // this moves the messh
}

convert mouse click to 3d space with orthographic camera

Three.js : rev 73
I'm using the following construct to find intersection of mouse click with objects in the 3d world (orthographic setup):
function onDocumentMouseDown(event) {
event.preventDefault();
console.log("Click");
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
var raycaster = new THREE.Raycaster();
// update the picking ray with the camera and mouse position
raycaster.setFromCamera(mouse, camera);
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects(scene.children);
console.log("intersects: " + intersects.length);
for (var i = 0; i < intersects.length; i++) {
console.log(intersects[i].point);
}
}
However, the intersection is very inaccurate. Intersection is captured when I click near the top left of the box only.
jsFiddle: Can someone please help me understand why is this misbehaving ?
Also, if no object is being selected, I want to find out where is the click in 3d world relative to the box - left, right, below the box ? Can I use the ray itself to compute this ?
you have to get accurate mouse position for ray-casting :-
mouse.x = ( (event.clientX -renderer.domElement.offsetLeft) / renderer.domElement.width ) * 2 - 1;
mouse.y = -( (event.clientY - renderer.domElement.offsetTop) / renderer.domElement.height ) * 2 + 1;
you have to fire event listener when window resize
i update the fiddle again check it now .
add new function for window resize...
code is self explaintory ...hope you got it .
Check Update Fiddle now
updated fiddle :-
http://jsfiddle.net/gc1v0rza/5/

Sprite not moving with cusor in three.js r71

When I move the cursor, the sprite is visible but not properly moving along with the cursor point. It is moving in opposite direction. Please help.
sprite1.position.set( event.clientX *(-.4) , event.clientY *(.4) , 1 );
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
Whenever something is "moving in opposite direction" in the 3d world, it is useful negating whatever that is:
mouse.x = ( event.clientX / window.innerWidth );
mouse.y = ( event.clientY / window.innerHeight );
//mouse is now somewhere between 0..1 for both x and y
//if you want this to go in the opposite direction
mouse.x = 1 - mouse.x;
mouse.y = 1 - mouse.y;
//if it goes from -1 to 1 you scale it:
mouse.x = mouse.x * 2 - 1; //first it goes from 0..2 then -1...1
//reversing this is
mouse.x = -mouse.x;
this on the other hand:
sprite1.position.set( event.clientX *(-.4) , event.clientY *(.4)
will be hard to achieve. It seems you are projecting your screen coordinates in pixels, to some world units (otherwise i'm not sure you'd get them to show up). If you are working only in the positive range, flipping -4 to 4 will move it offscreen. You'd need to do add an offset, so subtract 8 for example.

Detect clicked object in THREE.js

I have a THREE.js scene where a lot of elements appear, and I need to detect what object the user is clicking on.
What I have done so far is the following. The camera does not move to much - it only changes the vertical position by a limited amount, always looking towards the same point. My approximate method is the following:
I take the coordinates if the click relative to the canvas
I translate them into horizontal and vertical coordinates in the webGL scene by means of a simple rescaling, and add a Z coordinate which is sufficiently far away.
I take a horizontal ray starting from the point above, constructed by THREE.Ray()
I use ray.intersectObjects() to find the first element along the ray.
This method approximately works, but it is sometimes a few pixels away from the actual point.
Is there a more reliable technique to find out the object where a user has clicked?
Depends on what kind of camera are you using.
1) PerspectiveCamera: is ok link that Mr.doob provides.
2) OrthographicCamera: is quite different:
var init = function() {
camera = new THREE.OrthographicCamera( SCREEN_WIDTH / - 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, NEAR, FAR);
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}
function onDocumentMouseDown( e ) {
e.preventDefault();
var mouseVector = new THREE.Vector3();
mouseVector.x = 2 * (e.clientX / SCREEN_WIDTH) - 1;
mouseVector.y = 1 - 2 * ( e.clientY / SCREEN_HEIGHT );
var raycaster = projector.pickingRay( mouseVector.clone(), camera );
var intersects = raycaster.intersectObject( TARGET );
for( var i = 0; i < intersects.length; i++ ) {
var intersection = intersects[ i ],
obj = intersection.object;
console.log("Intersected object", obj);
}
}
Check out this one:
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);
var object; //your object
document.addEventListener('mousedown', onMouseDown, false);
function onMouseDown(e) {
var vectorMouse = new THREE.Vector3( //vector from camera to mouse
-(window.innerWidth/2-e.clientX)*2/window.innerWidth,
(window.innerHeight/2-e.clientY)*2/window.innerHeight,
-1/Math.tan(22.5*Math.PI/180)); //22.5 is half of camera frustum angle 45 degree
vectorMouse.applyQuaternion(camera.quaternion);
vectorMouse.normalize();
var vectorObject = new THREE.Vector3(); //vector from camera to object
vectorObject.set(object.x - camera.position.x,
object.y - camera.position.y,
object.z - camera.position.z);
vectorObject.normalize();
if (vectorMouse.angleTo(vectorObject)*180/Math.PI < 1) {
//mouse's position is near object's position
}
}
Checks for intersection of the mouse and any of the Cubes in 3d space and alters it's color. Maybe this help you.
I ran into problems trying to implement this for a canvas which does not take up the entire width and height of the screen. Here is the solution I found works quite well.
Initialize everything on an existing canvas:
var init = function() {
var canvas_model = document.getElementById('model')
var viewSize = 50 // Depending on object size, canvas size etc.
var camera = new THREE.OrthographicCamera(-canvas_model.clientWidth/viewSize, canvas_model.clientWidth/viewSize, canvas_model.clientHeight/viewSize, -canvas_model.clientHeight/viewSize, 0.01, 2000),
}
Add an event listener to the canvas:
canvas_model.addEventListener('click', function(event){
var bounds = canvas_model.getBoundingClientRect()
mouse.x = ( (event.clientX - bounds.left) / canvas_model.clientWidth ) * 2 - 1;
mouse.y = - ( (event.clientY - bounds.top) / canvas_model.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
// Do stuff
}
}, false)
Or for a 'touchstart' event, change the lines calculating the mouse.x and mouse.y into:
mouse.x = ( (event.touches[0].clientX - bounds.left) / canvas_model.clientWidth ) * 2 - 1;
mouse.y = - ( (event.touches[0].clientY - bounds.top) / canvas_model.clientHeight ) * 2 + 1;

Categories

Resources