Three.js: How can I find the camera's current plane - three.js

In three.js, when we define the camera we use something like camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far); If the object is moved outside the bounds set by the two planes, far and near then it is clipped.
Suppose now I rotate the object and I zoom in/out.
How can I find the current plane my camera is on please? I am learning three.js, hence I dont know If I am explaining this clear enough.
I thought that it was camera.position.z that would give me this info. In fact, I think it gives the correct value when my camera looks down the z-axis. However when I rotate by 90 degrees, (effectively moving my camera on the x-axis) the value of camera.position.z changes by a lot.
I have added a graph in case it helps. The plane defined by the blue outline cuts through the data and is parallel to the far and near planes. As I zoom in and out, I am moving the plane forward and backward, right? Do I understand this correct or I have totally missed it? I would like to know the value (a float between far and near) indicating how far that blue plane is from the camera. If you rotate that distance shouldn't change
My end goal is to be able to find-out how close the scene is to the viewer. If it gets too close then I will be adding some more elements to the scene. If it is too far these elements will be removed.

Related

ThreeJS position light at angle and distance from center

I'm trying to learn the ThreeJS positioning functions, but I'm not quite getting there.
I have a light and an animation loop. I want this light to be at a fixed angle relative to the camera pointing towards 0,0,0.
I can make the light come from the camera angle itself like so (in animation loop):
rectLight.position.copy(camera.position);
rectLight.lookAt(0,0,0);
But I don't want it to come from the viewer's perspective, I want it to come from somewhere else relative to it, and at a set distance from center.
So I think it's camera angle +/- some degrees/radians, and then a fixed distance.
I've tried adjusting the coordinates relative to the camera position, like y += 25, y *= 3, and such. Everything I try gives me some whacky light placement motion I don't understand. I'm sorry, 8th grade geometry teacher, I should have paid attention.

three.js rotate planes so they are always perpendicular to the camera axis without changing z rotation

I'm trying to add clouds to my scene using the approach in https://codepen.io/teolitto/pen/KwOVvL, which is to make a large number of plane objects at random positions that each rotate continuously around their z axes.
But I would like to be able to move my camera, change its target, etc., and still have the cloud planes look right.
What I need to do is rotate the planes so that as the camera moves and changes target, the cloud planes stay perpendicular to the camera's axis. And I need to do this without changing the planes' rotation around their own z-axis, because otherwise that would break the cloudlike appearance.
I've tried cloudplane.lookAt(camera.position) but of course that doesn't work. It aims all of the planes at the camera, instead of making them all perpendicular to the camera axis. It also sets the object's z-axis, so the clouds don't evolve.
Any advice is appreciated. (I'm new to three.js, so if I have some of the terminology wrong, I apologize for that.)
Edit:
Setting the cloudplane's rotation.x and rotation.y to match the camera's rotation.x and rotation.y seems to get me pretty close, but it doesn't quite get there - its still possible to orbit the camera to a position where the clouds are all invisible because they're all parallel to the camera.

Converting a Vector3 point to screen space (Vector2) using Three.js [73]

I have initialised a perspective camera at a position looking at the origin (0,0,0). Reading around the most common solution to this I've found is the one described here https://stackoverflow.com/a/27412386/1330719.
From my understanding of the project method is, I should get a vector where the x,y coordinates are between -1 and 1. This doesn't seem to be the case at all and I end up getting coordinates that are completely out of bounds.
Furthermore, if the original vector point is at (0,0,0) I seem to get (NaN, NaN) back. If my camera is looking at position (0,0,0) I expect the Vector3 (0,0,0) to return (width/2, height/2).
In case it is needed, this is how I'm initialising my camera:
this.camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 10E5);
this.camera.position.set(0, 500, -500);
this.camera.lookAt(new THREE.Vector3(0,0,0));
this.camera.updateProjectionMatrix();
Does anyone have a reason why this might not be working? Or alternatively a recommended way of mapping a Vector3 point to the screen space given a camera?
A jsfiddle of what I mean:
https://jsfiddle.net/m78wjLyc/
You should also use camera.updateMatrixWorld(true) before projecting.
Usually this is done automatically by renderer, but you don't use any, so the camera.matrixWorld stays untouched after you change the position, and makes the camera project things as if it was at the world origin.

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!

Move the camera along its LookAt axis in Three.js?

I'm new to Three.js, so if this is obvious then apologies upfront.
I set my camera using the LookAt method, and would like to move along that vector when pressing a key on the keyboard.
I've tried mimicking the feature by subtracting the camera vector from the point I'm looking at via subVector, normalized the resulting vector, then did something along the lines of:
camera.position.x += lookAtVector.x
camera.position.y += lookAtVector.y
camera.position.z += lookAtVector.z
...but I appear to be drifting a bit and not moving toward the lookAt point when I do this. How can I move along a lookAt vector in three.js?
The camera is looking down it's negative-Z axis, so you want to do this:
camera.translateZ( - distance );
three.js r.57

Resources