i'm trying to recreate this app, and it is currently working now. But i can't click the corner of the text perfectly, it always need to be offset.
https://jsfiddle.net/naonvl/ecdxfkbm/3/
right now, it's hard to scale the text. i think the getRealPosition is not correct so the mouse X and Y also not precise.
Does anyone know how to fix this?
The problem is i set getIntersects like this
var getIntersects = function (point, objects) {
mouse.set(point.x * 2 - 0.97, -(point.y * 2) + 0.97);
raycaster.setFromCamera(mouse, camera);
return raycaster.intersectObjects(objects);
};
compare to three.js example here https://threejs.org/examples/#webgl_raycast_texture
function getIntersects( point, objects ) {
mouse.set( ( point.x * 2 ) - 1, - ( point.y * 2 ) + 1 );
raycaster.setFromCamera( mouse, camera );
return raycaster.intersectObjects( objects, false );
}
i miss calculate the mouse.set there, i change the calculation and tweak X and Y position of mouse by adding 3 to each of them, and it raycasted perfectly in the center of mouse pointer
Related
I'm setting up a world map on a curved plane that the user can rotate and highlight countries. When a country is clicked, I determine what exactly was clicked and then show a tooltip with some information about the selected country, like on the screenshot below:
The map itself is generated in three, but the tooltip is a regular old div. The thing is, I'd like the tooltip to stay glued to that particular point of the texture, even if the plane is rotated. The original positioning of the tooltip is based on the information from the raycaster. As such, I'd want the app to return the current position of that precise point, relative to the container (or window) - based on uv coordinate for instance. How can I achieve that?
Basing on the link provided by #prisoner849, I've implemented the following solution:
a) on mouseup event I set a new tooltip 3D origin point (only if there was no significant delta in mouse position, to discern between clicking and dragging the camera)
b) every frame, the following function is fired, which converts the 3D coords to 2D and calculates the position of the tooltip:
function setTooltipOrigin( camera, renderer, tooltip, lastClickPoint ) {
var canvas = renderer.domElement,
point = new THREE.Vector3();
point.x = lastClickPoint.x,
point.y = lastClickPoint.y,
point.z = lastClickPoint.z,
point.project( camera );
point.x = Math.round(( 0.5 + point.x / 2 ) * ( canvas.width / window.devicePixelRatio ));
point.y = Math.round(( 0.5 - point.y / 2 ) * ( canvas.height / window.devicePixelRatio ));
point.x -= 14; //small adjustment to the position, so the line points to the click point
point.y -= (tooltip.scrollHeight * 0.7); //same for y
tooltip.style.transform = 'translate(' + point.x + 'px, ' + point.y + 'px)';
}
This one is bugging me quite a bit.
I'm trying to achieve rotation of a Cannon.Body based on the mouse input.
By using the (Cannon) Three FPS example to demonstrate, you can see what the issue is.
https://codepen.io/Raggar/pen/EggaZP
https://github.com/RaggarDK/Baby/blob/baby/pl.js
When you run the code and enable pointerlockcontrols by clicking on the "click to play" area and press W for 1 second to get the sphere into the view of the camera, you'll see that the sphere moves according to the WASD keys by applying velocity. If you move the mouse, the quaternion is applied to the Body, and the proper velocity is calculated.
Now turn 180 degrees, and the rotation on the X axis is now negated somehow.
When moving the mouse up, the sphere rotates down.
How would one fix such issue? Maybe I'm doing something wrong elsewhere, that might mess with the quaternion?
Maybe I should mention, in the playercontroller(pl.js), I'm applying the rotation to the sphereBody, instead of the yaw- and pitchObjects.
Relevant code from pl.js (Line 49):
var onMouseMove = function ( event ) {
if ( scope.enabled === false ) return;
var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
cannonBody.rotation.y -= movementX * 0.002;
cannonBody.rotation.x -= movementY * 0.002;
cannonBody.rotation.x = Math.max( - PI_2, Math.min( PI_2, cannonBody.rotation.x ) );
//console.log(cannonBody.rotation);
};
And (Line 174):
euler.x = cannonBody.rotation.x;
euler.y = cannonBody.rotation.y;
euler.order = "XYZ";
quat.setFromEuler(euler);
inputVelocity.applyQuaternion(quat);
cannonBody.quaternion.copy(quat);
velocity.x = inputVelocity.x;
velocity.z = inputVelocity.z;
Inside the animate() function, codepen (Line 305):
testballMesh.position.copy(sphereBody.position);
testballMesh.quaternion.copy(sphereBody.quaternion);
The problem is the way you assign angles to and from the Quaternions. The quaternion x,y,z,w properties are not directly compatible with angles, so you need to convert.
This is how to set the angle around a given axis for a CANNON.Quaternion:
var axis = new CANNON.Vec3(1,0,0);
var angle = Math.PI / 3;
body.quaternion.setFromAxisAngle(axis, angle);
Extracting the Euler angles from quaternions is probably not be the best way to attack the second part of the problem. You could instead just store the rotation around X and Y axes when the user moves the mouse:
// Declare variables outside the mouse handler
var angleX=0, angleY=0;
// Inside the handler:
angleY -= movementX * 0.002;
angleX -= movementY * 0.002;
angleX = Math.max( - PI_2, Math.min( PI_2, angleX ) );
And then to get the rotation as a quaternion, use two quaternions separately (one for X angle and one for Y) and then combine them to one:
var quatX = new CANNON.Quaternion();
var quatY = new CANNON.Quaternion();
quatX.setFromAxisAngle(new CANNON.Vec3(1,0,0), angleX);
quatY.setFromAxisAngle(new CANNON.Vec3(0,1,0), angleY);
var quaternion = quatY.mult(quatX);
quaternion.normalize();
To apply the quaternion to your velocity vector:
var rotatedVelocity = quaternion.vmult(inputVelocity);
Pro tip: don't use Euler angles if you can avoid them. They usually cause more problems than they solve.
I have several randomly generated boxes that I want to rotate towards the mouse position. I tried to get the mouse position and then use lookAt(mouse3D)to rotate the boxes towards the mouse coordinates, but they don't change their rotation at all. I don't even want them to rotate towards the mouse position within the 3D space, simply towards the mouse position as it is on the screen.
Currently I get the mouse position like this:
function onDocumentMouseMove( event ) {
mouse3D = new THREE.Vector3(
( event.clientX / window.innerWidth ) * 2 - 1,
- ( event.clientY / window.innerHeight ) * 2 + 1,
camera.position.z );
}
Here's an example I found which I wasn't able to apply to my problem: http://mrdoob.github.io/three.js/examples/misc_lookat.html
I created JSFiddle with my current approach:
https://jsfiddle.net/nrub93m7/
I just added this method to your jsfiddle link:
function onDocumentMouseMove( event )
{
mouse3D = new THREE.Vector3( event.clientX, event.clientY, 0);
}
I've created a near exact implementation of the Three.js Draggable Cubes example, except that my implementation ignores the z axis for movement in 2D. The example can be found here: http://threejs.org/examples/#webgl_interactive_draggablecubes
While I am able to click and move around my object, if I move the mouse too fast, the object will lag behind; the mouse pointer will move to it's location and then the object will follow the mouses path to the location. This issue is also noticeable in the Three.js example. Try dragging one of the cubes at anything beyond a moderate speed.
I've tried a few things to get the object to be directly under the mouse pointer but none have worked. The closest I think I might have come to a solution was by changing the mouse position update in the MouseMove event. However, it appears that the Three.js implementation of the code returns values between 1 and -1 rather than the screen X and Y coordinates, which leads me to wonder if the original implementation is causing the lag.
//Original Implementation - Works With Lag
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
console.log(mouse.x + "," + mouse.y); //Output: -0.9729166666666667,0.8596858638743455
//My Implementation - Does Not Work
mouse.x = event.clientX - (window.innerWidth / 2);
mouse.y = event.clientY - (window.innerHeight / 2);
console.log(mouse.x + "," + mouse.y); //Output: -934,-410.5
//Update Function
void Update()
{
var vector = new THREE.Vector3(mouse.x, mouse.y, 1);
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObject(plane);
meshToMove.position.x = intersects[0].point.x;
meshToMove.position.y = intersects[0].point.y;
}
//Main Loop
function Loop()
{
Update();
Render();
requestAnimationFrame(Loop);
}
Q: How can I update the three.js Draggable Cubes example so that objects don't lag behind the mouse during a click and drag?
I already asked this question over there:
https://github.com/mrdoob/three.js/issues/2070#issuecomment-6372113
But I did not really get it right now.
Here is my problem again:
i am using this function to calculate the screen position (x,y) of my Vector3.
this.toScreenXY = function(position, camera, canvas)
{
var pos3D = position.clone();
var pos2D = projector.projectVector( pos3D, camera );
return {
x : ((pos2D.x + 1) * canvas.domElement.width / 2 + canvas.domElement.offsetLeft),
y : ((-pos2D.y + 1) * canvas.domElement.height / 2 + canvas.domElement.offsetTop)
};
};
But when I got the correct screen position, turn the camera by 180 degree (about the y-axis), I got the same x,y values even if the real Vector3 is behind the Cameras view.
Any idea how to check wether the Vector3 is in Cameras view or not?
Thank you for your help!