Three.js camera on path

@phil_crowther
and an example with env map…

camera.rotation.z = 0;

camera.rotation.z = 0.5;

am i missing something you mean?

1 Like

Very interesting!

I tried inserting camera.rotation.z into one of my programs and it still didn’t work - until I removed the command: camera.lookAt(scene.position).

That is a very handy command that I have been using forever and that you can use to make the camera look at the center of the scene or at an object. Apparently that command overrides camera.rotation.z. So my previous advice may only apply if you want to use that particular command.

If will see if I can avoid that limitation by putting the object in the center of the scene and switching to camera.lookAt(object).

EDIT: I tried camera.lookAt(0,0,0) and it also prevented Z-rotation. So it looks like I will have to find/create an alternative function which serves the same purpose.

Thanks!

1 Like

@phil_crowther Ahh yes I get you now, would a way round that be to attach a child to the camera that looks at the scene position and set the camera x and y rotation to the rotation of said child so you still have explicit control over camera.rotation.z?

Let me take a look at your example and see what happens if I add a Skybox. I don’t want to lead you (or me) down the wrong path.

One other factor that will come into play is whether you want to look left or right as you are moving along. This will affect the amount of camera.rotation.z. For example, if you are moving straight and bank your vehicle while looking right or left, there will be no z rotation, only x rotation (up/down).

My program handles that. But I am curious if the method that you are using will turn out to be better and faster.

1 Like

Okay, I added a simple Skybox to the scene. It looks pretty neat.

However, it appears that there is no camera z rotation. (It’s kind of hard to tell because the program does all the banking when looking up or down, not at the horizon.)

I am guessing that the reason is that the program includes a variation of the “dreaded” “lookAt” command which cancels out any camera z rotation. Or it could be that you are using OrbitControls which - in the examples I have seen - do not provide for camera z rotation.

So this particular example looks okay without camera z rotation - because of the path you are following. However, if you if you want camera z rotation, it appears that you have to either:

  1. Use the method I described in my first message; or
  2. Find a substitute for the “lookAt” command.

This looks like an interesting project, so I encourage you to keep working on it.

EDIT:

As I took one last look at the string, I realized that this is not your project - that, like me, you were merely trying to help. So I would be interested in hearing whether you agree with my conclusions.

As I was considering whether to revise what I have done, I realized that even if I figure out how to rotate the camera on the z-axis, I am going to have to find a way to prevent it from rotating my object, e.g. the cockpit. That’s one nice thing about the method I developed - the cockpit does not move. Only the external objects move. So I don’t have to undo any rotation.

1 Like

@phil_crowther

Yes I agree and i do see the conundrum now i realise you meant…

camera.rotate.z

in conjunction with

camera.lookAt();

i keep thinking there must be a simple way round the issue, i made an example this morning to get your feedback, thoughts and likely find the holes in an approach like this…

https://3dpk.co.uk/examples/rotateznew/rotatez.html

i’ve set up 2 cameras, one is a ghost used to lookAt(mesh); and the main has camera.rotation.x and y to update to the ghost camera’s x and y rotation, this means we can rotate the z axis as we want on the main camera which would be the z axis copied from a banking fuselage in the case mentioned…

let me know what you think i’m probably being really silly and missing something quite important as you seem to have been through this and found a viable and solid solution.

cheers.

1 Like

I actually didn’t realize (or had forgotten) that lookAt was preventing camera.rotate.z from working. So this has been helpful.

And I do have some situations where my solution does not work. For example, I have some aircraft that have reflective surfaces. My solution does not handle reflections - which I believe requires multiple cameras.

So I am definitely interested in a solution, like the one you are suggesting, that would allow me to use the default Skybox. I will take a look at it since it seems to do a good job of “looking at” the object.

1 Like

@phil_crowther
yeah it might need a bit of fixing up and figuring out with long term logic…

i guess the ghost camera would lookAt(things) and translate xyz transforms and rotation x and y axis to the main camera?

for example have the main camera.position set to the ghost camera.position.x y and z and the main camera.rotation x and y set to that of the ghost camera?

then if you put conventional orbit controls in the scene, you can assign them to the ghost camera so that main camera follows suit an it’s camera.rotation.z is always free to assign to?

if you also needed the camera to then follow a moving target you would simply have the ghost cameras position follow the target meaning the main camera would in turn follow the ghost camera?

does it make sense or can you see bugs in this approach?

1 Like

I would need two different kinds of view. In the cockpit view, I would need a camera locked to the airplane that would look out. In the external view, I would need a camera that orbits the airplane and looks at the airplane. While many of the same challenges apply the latter is probably more challenging since the camera has to move and always look at the airplane.

My basic camera routine is very simple, moving the mouse vertically changes the latitude while moving the mouse horizontally changes the longitude. One challenge is that, if the aircraft banks, the “equator” banks so that both the camera location and rotation will be affected. (I believe that the formula which describes the behavior will be an ellipse.) If you are straight behind the aircraft, there will be no change in position and the rotation will be entirely on the z-axis. If you are straight off the left or right wing, your position will change vertically and the rotation will be entirely on the x-axis. I should be able to compute these changes using math. However, if you are able to do the same thing using a ghost camera, that is even better.

With regard to the cockpit view, you would like to have a camera mounted on the head of the pilot. The initial camera (“ghost camera”?) should bank, pitch or change heading along with the aircraft. The secondary camera which is mounted on top of the initial camera only has to pitch and change heading (x-axis and y-axis). No z-axis rotation is required. And since it is outward looking, it doesn’t have to “lookAt” anything.

Can that kind of stacking be done with cameras?

Thanks.

EDIT

It looks like you can create the cockpit view by creating a pivot, e.g.:

pivot = new THREE.Object3D();
pivot.add(camera);
scene.add(pivot);|
pivot.rotation.set(0,0,15 * DegRad); // bank the pivot

You can then rotate the camera on the x-axis, using, e.g.:

ypos = ypos + .01;
camera.rotation.set(0, ypos, 0);

I’m not sure if/how you could use this method for the external camera.

1 Like

Okay, I got it.

As mentioned, my camera set up is very simple with vertical mouse (Y) movements changing latitude and horizontal mouse (X) movements changing longitude. I use the latitude and longitude angles to position the camera. So all I have to do to look back at the aircraft is to set the camera rotation to the reverse of the latitude and longitude. To work properly, the rotation order has to be “YXZ”. No need for lookAt.

To handle aircraft bank and pitch, I attached the camera to a pivot, which - like the airplane - is located at 0,0,0 and which has a rotation order of “YXZ”. I then adjusted my thinking so that the latitude and longitude are relative to the aircraft, not the outside world. (The equator is level with the wings.) This only changed the heading. For example, zero is the nose of the aircraft rather than north. I then set gave the pivot the same rotation as the aircraft and Voila! She works perfectly!

So I owe you a big debt of gratitude for questioning my unqualified statement that there is no camera z rotation. This new method should vastly simplify my program and allow me to use the features of the standard skybox, such as reflective surfaces.

Incidentally, I took a look at the values produced by the lookAt function. Even though I was inputting only x and y rotations, the function computed x, y and z camera rotations. (I assume that this is the result of some kind of quaternion calculation.) So, to work right, the function had to override any existing x, y, or z camera rotations.

1 Like

Ah neat! Sounds ideal for your use case!! Would this work on an object offset from its origin of 0 0 0?

1 Like

I believe so. The formula that I use rotates the camera around a center point based on the distance from the center point and the latitude and longitude. This changes the camera position.xyz. Since I have linked the camera to the pivot, that camera position should be relative to the pivot. So if you change the position of the pivot, the camera absolute position should also change. And the camera will continue to look at the pivot. The camera is like a moon orbiting a planet and which is always facing the planet.

Here is the code I used (including subroutines). Not very long. I suspect that three.js has a built-in routine that I could use in place of my RotVec (Rotate Vector) subroutine:

// Camera and Pivot
var camera = new THREE.PerspectiveCamera(45, width/height, 1, SkyLim);
camera.rotation.order = “YXZ”;
var pivot = new THREE.Object3D();
pivot.add(camera);
scene.add(pivot);
pivot.rotation.order = “YXZ”;

// Rotate and Move Camera
function moveCamera() {
// Camera Relative to Aircraft
var cx = Mod360(CamLat) * DegRad;
var cy = Mod360(CamLon) * DegRad;
RotVec(CamDst, cx, cy); // Returns XYZValues
camera.position.set(XValue, YValue, ZValue);
// Camera Rotation (order = YXZ)
camera.rotation.set(-cx, cy, 0);
// Pivot Rotation (order = YXZ)
var px = Mod360(ACPtch) * DegRad; // Pitch
var py = Mod360(-ACHead) * DegRad; // Heading
var pz = Mod360(360-ACBank) * DegRad; // Bank
pivot.rotation.set(px, py, pz);
}

/* Rotate Vector */
// For given vector and XY radians
// Computes rotated XYZ point values
function RotVec(Dst,XRd,YRd) {
// Pitch
YValue = Dst * Math.sin(XRd);
ZValue = Dst * Math.cos(XRd);
// Heading
XValue = ZValue * Math.sin(YRd);
ZValue = ZValue * Math.cos(YRd);
}

/* Converts degrees to 360 */
function Mod360(deg) {
if (deg < 0) deg = deg + 360;
else if (deg == 360 || deg > 360) deg = deg - 360;
return deg;}

EDIT
Changes to above:

  1. Added the setup for the camera and pivot
  2. Streamlined the moveCamera subroutine.
1 Like

Okay, I changed my flight simulation demo to eliminate lookAt and to use camera Z-rotation.
Flight Demo

The internal view works as expected. The pivot remains at 0,0,0 and you position the camera at the location of the pilot’s head. (My version was a little more complex because I also use model animations to change the aircraft pitch.)

So now I am back to using the standard three.js skybox, which will allow for things like reflections. And it simplifies my computations since I don’t have to rotate everything around me.

So thanks for challenging my statement that you can’t bank the camera!

1 Like