Rotating the camera

I’m looking at adding @natpryce’s stick controller to a variation on the 3D demo. I’m having a bit of trouble correctly turning the controller’s steer vector into a new camera position, though. Note that I’m only doing movement in the x and z axes, with y being at a fixed height.

I’m using the x component of the vector to update an Angle variable, and the y component to adjust the camera’s position forward or backward, based on the Angle.

But I guess I also need to change the camera’s eye coordinates to so that the camera is ‘looking towards’ some point in the distance based on the Angle. I’m not sure how to do this though! I’m presuming something like work out a normalised vector and then project it to a point in the distance?

Any help would be greatly appreciated!

Sorry, I hate bumping topics, but just double checking whether anyone has any ideas on this?

My way of thinking about this is to think of the eye-and-camera system as a vector going from the camera to the eye. So when I’m trying to work out what’s going on, or how I want to turn the camera, then I try to visualise what’s happening to this vector.

But there are lots of ways to move a vector. If we assume, for simplicity, that it is of fixed length, then still we get 5 degrees of freedom: the position of the anchor (the camera in this case) and the direction of the vector (the displacement of the eye from the camera).

For example, in the roller coaster program then I want the camera to be looking at the person in the cart (this is in the newer version of the code, not the one included with Codea). So I work out the position of the cart, and that’s my eye vector. Then I want the camera looking at that point along the line of the track so I work out the tangent to the path at that point and move back in that direction by a fixed distance. This becomes my camera position. Finally, I use the normal to the track for the “up”.

I’m not completely clear as to what you want to achieve. In particular, should moving in the y-direction move the camera along the line it is currently looking along, or along some line fixed for all time? I’ll assume the former.

So we have a camera at a position c looking at a position e. These are in the xz-plane so I’ll write them as 2-vectors. The “up” direction is always assumed to be the y-direction. The user moves the controller by (x,y) and we want to interpret the x as an adjustment to the angle and the y as a forward/backward.

The first question is whether the adjustment to the angle should move the camera or move the eye. In the latter, we regard the camera as fixed but can rotate. In the former, we keep looking at the same point but move around it. I think that the latter makes most sense. So c doesn’t change, but e should transform by a rotation with angle x. Thus

e.x,e.z = math.cos(x)*e.x + math.sin(x)e.z, -math.sin(x)*e.x + math.cos(x)*e.z

If that’s rotating stuff the wrong way, change the signs of the sines. If you decide to do the assignments in two statements then you’ll need to use dummy variables as you must be sure to use the old values for e.x and e.z in the computations for the new ones.

The y-value is to be used to move the camera forward or backward along its current line of sight. Again, there’s a choice to be made. We could keep the eye fixed, or translate that as well. I’ll do the code for the latter. To do the translation, we need to add a vector to both the camera and eye position that is in the direction of the eye from the camera. Thus

e,c = e + y*(e - c),c + y*(e - c)

Again, if doing this in two statements then use dummy variables. To just move the camera then only update c.

I hope I’ve interpreted what you want correctly.

Wow! Thanks so much for the detailed response, @Andrew_Stacey. Your explanation of how to think about the camera and eye is really useful. I still don’t entirely understand the calculations for determining the new eye and camera co-ordinates, however! :slight_smile:

I think I get the translations - simply moving the eye and camera by a percentage of the distance between them (very roughly speaking)?

As for e.x and e.z… I know my basic trigonometry, and I can use it to do movements and rotations in 2D, but I’m afraid I can’t quite follow it here. Why do you compute sin and cos for both x and z and add them?

Anyway, I’ve tried plugging this into my example and I can’t get it to do what I’m after. If you’d like to take a look, it’s in this .codea project:

All the calculations are done in the Main draw() method. However, I just realised after posting this that I’ve foolishly used my joystick’s steer.x property as an angle in e.x and e.z calculations, which is nonsense.

Essentially, the ‘effect’ I’m trying to produce is a general 3D ‘first person’ movement - think DOOM or Wolfenstein, really.

Okay, I got a couple of things wrong. Mainly, I rotated the eye about the origin, not the camera.

Here’s an attempt with your code. Put the following in setup replacing the existing controller definition.

controller = VirtualStick {
        moved = function(v) angvel = v.x speed = v.y/100 end,
        released = function(v) angvel = 0 speed = 0 end
    angle = 0
    angvel = 0
    speed = 0

In the draw function, put the following for updating the eye and camera:

angle = angle + DeltaTime*angvel
    e = c - 600*vec3(-math.sin(angle),0,math.cos(angle))
    e,c = e + speed*(e - c),c + speed*(e - c)

Is that close to what you are after?

Fantastic! This is almost exactly what I’m after. Thanks so much. I think I can mostly understand what’s going on here :slight_smile:

All I need to do is tweak the turn speed and movement speed to get the ‘feel’ I’m after.