How do I place an element in front of the camera, facing it regardless of where it is? - three.js

I have this simple scene with a "tooltip" entity composed of some data, I'd like to know how to position it in front of the camera. The tooltip will have to face certain points a few meters away so the user can see it. It must obey camera direction (it can be gathered by calculating it from previousPoint to nextPoint where the camera will move), but only y axis (can't be tilted or anything like that).I tried digging through math but couldn't understand good enough to employ a solution for this little project; I appreciate all the help!
setTimeout(function(){
var camera = document.getElementById("cameraS");
var tt = document.getElementById("ttS");
var cameraPos = camera.getAttribute('position');
var ttPos = tt.getAttribute('position');
tt.setAttribute('position', cameraPos);
tt.setAttribute('rotation', {'y': -90});
}, 5000);
JSFiddle
EDIT
I made an image showing what I'm after: http://imgur.com/a/eDhqE
I have point A and point B; the camera will play an animation moving from previous point to the next, and upon reaching there the tooltip will be displayed a few meters away from the point (box) so we can see it. It must take camera orientation into consideration but it must be perpendicular to the ground (can't be tilted).

There is a command THREE.Object.lookAt(THREE.Vector3); that will rotate an object (assuming (0.0,1.0,0.0) is up) to face a vector. You can use this to have it face your camera.
If you only want Y rotation, you can copy the current rotation, then do look at, then copy the rotation.x and rotation.z from the previous frame rotation copy - so that way it'll only correct the y with .lookAt because you reset x and z.

Related

Convert screen space X,Y position into perspective projection with a specific z position

I'm using ThreeJS, but this is a general math question.
My end goal is to position an object in my scene using 2D screen space coordinates; however, I want a specific z position in the perspective projection.
As an example, I have a sphere that I want to place towards the bottom left of the screen while having the sphere be 5 units away from the camera. If the camera were to move, the sphere would maintain its perceived size and position.
I can't use an orthographic camera because the sphere needs to be able to move around in the perspective projection. At some point the sphere will be undocked from the screen and interact with the scene using physics.
I'm sure the solution is somewhere in the camera inverse matrix, however, that is beyond my abilities at the current moment.
Any help is greatly appreciated.
Thanks!
Your post includes too many questions, which is out of scope for StackOverflow. But I’ll try to answer just the main one:
Create a plane Mesh using PlaneGeometry.
Rotate it to face the camera, place it 5 units away from the camera.
Add it as a child with camera.add(plane); so whenever the camera moves, the plane moves with it.
Use a Raycaster’s .setfromCamera(cords, cam)
then
.intersectObject(plane)
method to convert x, y screen cords into an x, y, z world position where it
intersects the plane. You can read about it in the docs.
Once it’s working, make the plane invisible with visible = false
You can see the raycaster working in this official example: https://threejs.org/examples/#webgl_geometry_terrain_raycast

Flipping (orthographic) camera axes

It seems possible to flip an axes of an orthographic camera in three, e.g. by the following code:
var tmp = camera.right;
camera.right = camera.left;
camera.left = tmp;
camera.updateProjectionMatrix();
However, this screws up the lighting, so it seems to not be supported (at least not with built in materials). Is this so? Is there another way to achieve this?
The use case I currently have is a scientific scene (loads of spheres and lines) that can be seen from either positive or negative Z direction. The requirement is that the X and Y axis point the same direction (e.g. right and up) no matter which Z-direction you are looking in. Is there an alternative solution if flipping left/right is not the way to go?
For an example of what I am talking about, see this fiddle: https://jsfiddle.net/mt0bpwcz/1/ Try double clicking the scene to switch the camera. Afterwards the lighting will be very strange (especially visible in the specular highlights).

How to find nearest object with three.js

I have a bunch of data and I know their lat/lon position (circles on the image). Now I have a camera in three.js and I know it's position, rotation and which way is north from it's perspective.
I want to go on top of these circles on mouse click but I'd like that the program would choose the closest one to the player and it should also be in the current field of view.
I've tried finding the angle between camera look direction and circle's position but it still moves quite randomly.
Any ideas where to start with this?
I'm not totally sure what you're asking regarding the "going on top of the circles and mouse click" part but here's a utility function for getting the distance between a camera and a point you know the x, y, z coordinates for.
var getCameraDistanceFrom = function(camera,x,y,z) {
var cameraDistance = new THREE.Vector3();
var target = new THREE.Vector3(x,y,z);
cameraDistance.subVectors(camera.position, target);
return cameraDistance.length();
};
This answer seems to have a good way to check if an object is in the camera's field of view: Determine if a mesh is visible on the viewport according to current camera

Three.js & OrbitControls.js - pan camera parallel to ground plane (like Google Earth)

I'm working on a simple Three.js demo that uses OrbitControls.js.
I'd like to change the behavior of panning in OrbitControls. Currently, when you pan the camera, it moves the camera in a plane that is perpendicular to the viewing direction. I'd like to change it so that the camera stays a constant distance from the ground plane and moves parallel to it. Google Earth uses a similar control setup.
Edit: I should have mentioned this detail in the first place, but I'd also like the point where you click and start dragging to remain directly under the cursor throughout the entire drag. There needs to be that solid connection between the mouse movement and what the user expects to happen on the screen. Otherwise, it feels as though I'm 'slipping' when I try to move around the scene.
Can someone give me a high-level explanation of how this might be done (with or without OrbitControls.js)?
EDIT: OrbitControls now supports panning parallel to the "ground plane", and it is the default.
To pan parallel to screen-space (the legacy behavior), set:
controls.screenSpacePanning = true;
Also available is MapControls, which has an API similar to that of Google Earth.
three.js r.94
Some time ago I was working on exactly this issue, i.e. adaptation of OrbitControls.js to map navigation.
Here's the code of MapControls.js.
Here's the demo of the controls.
I figured it out. Here's the overview:
Store the mousedown event somewhere.
When the mouse moves, get the new mousedown event.
For each of those points, find the points on the plane where those clicks are located (You'll need to put the points into camera space, transform them into world space, then fire a ray from the camera through each point to find their intersections with the plane. This page explains the ray-plane intersection test).
Subtract the world-space start intersection point from the world-space end intersection point to get the offset.
Subtract that offset from the camera's target point and you're done!
In the case of OrbitControl.js, the camera always looks at the target point, and its position is relative to that point. So when you change the target, the camera moves with it. Since the target always lies on the plane, the camera moves parallel to that plane (as long as you're panning).
You should set your camera 'up' to z axe:
camera.up.set(0,0,1)
And then, the main problem with OrbitControl is its panUp() function. It should be fixed.
My pull request : https://github.com/mrdoob/three.js/pull/12727
y axe is relative to camera axes and should be relative to a fixed plan in the world. To define the expected y axe, make a 90° rotation of camera x axe, based on world z axe.
v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
v.applyAxisAngle( new THREE.Vector3( 0, 0, 1 ), Math.PI / 2 );
v.multiplyScalar( distance );
panOffset.add( v )
Enjoy!

libGDX: How to let the camera point to moving sprite?

I'm new to libGDX and android game dev. And I want to achieve this:
I have a Screen and within it, a ball sprite that is moving along the X axis. Now I want to center the viewport to the sprite when it moves. Just like in Angry birds, where the camera follows the bird flying across the sky.
How can I implement that within my game using OrthographicCamera?
This took me a while of Googling and testing, but I just found something and I think others may appreciate it.
To move the camera (and if you are using a spriteBatch), make sure to call setProjectionMatrix.
Ex:
camera.position.y += 5; // or whatever you want to change y by...
camera.position.x += 5;
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
Hope this helps someone!
In case you haven't figured this out yet, you need to convert the ball position to the camera position using
camera.unproject(ballPosition)
This converts the screen coordinates into world coordinates. Then call
camera.position(ballPosition)
to set the camera position to your ball's location in the world.
The
camera.translate(...);
function translates all of the involved attributes the camera by the given data. After the operation you need to call
camera.update();
to calculate the new matrices of the camera. This will push the camera to the direction you want.

Resources