3D Camera Math

Pages: 123
I'm new to 3D math, and am experimenting with 3D via SFML+OpenGL.

The way my current camera system is set up is I have two 3D vectors (the mathematical vectors), one for the camera position and the other for the camera rotation. That's p.x, p.y, p.z, and r.x, r.y, r.z, respectively. r.x is rotation about the x axis, etc.

The camera controls I want are the ability to pan the screen left, right, up, down, and forward and backward. I have this implemented in terms or r.x and r.y here:
https://github.com/LB--/Recipe-Spelunker/blob/9b67ca6b27ee4479a2305459b7eddaf8d3fef1d1/src/client/main.cpp#L193

However, my implementation seems the hard way to do it, and I only slightly understand why it works - I got it mostly through trial and error. Now, I want to include r.z, rotation about the z axis, and this is proving to be too challenging for me.

Can someone explain the math to me and/or offer a more elegant solution?
I'd like to know how to do this as well.
closed account (o1vk4iN6)
If you need camera "roll" (basically the camera spinning) then you can just use matrices to the extend:

1
2
3
4
5
6
7
8
9
Mat3 camRot;
Mat3 rotX;

// need to transform "rotX" into our camera system so that a basic rotation matrix
// around the x axis will now be a "roll" rotation for our camera.
// then apply that rotation to our camera
// bit rusty tho i think this is sound :P
camRot = camRot * rotX * camRot;


If you don't need rolling then you can just keep what you have and define rotation by 2 angles like you have. You can then just convert those angles into a "forward" vector then calculate the up and left/right vectors using cross product. Those 3 vectors are then used to form the rotation matrix for the camera.

Can see details here (recommend using firefox as it formats the data correctly into matrix notation, chrome doesn't): http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml

In the above case "center*" position would just be camera position + unit vector of two angles (see spherical coordinates). In the formula it calculates it as "F".

Also that is for opengl, so the rotation matrix is already set for it. It uses negative Z as "forward". So if you are using DirectX or w/e it would need to be adjusted.
Last edited on
Why not use one function alone for rotation around an arbitrary axis? The argument of the function gives you the (x,y,z) coordinates of the axis around which you rotate, and the angle of rotation.
@tition: OpenGL already has a function to do this and I am in fact using it, so I don't know what you mean.
The easy way of dealing with rotation of the camera is to use the built in rotation and translation functions. This is extremely fast, as video cards are built to do these kinds of manipulations.

Ex: (will rotate the camera 180 degrees along the y axis and move the camera 3 units forward)
1
2
glRotatef(180.0f, 0.0f, 1.0f, 0.0f); // this will rotate the yaw of the camera
glTranslatef(0.0f, 0.0f, 3.0f); // this will translate everything you draw after this 3 units in positive z (which is into the screen, effectively making the camera go forward) 


If you want code to do everything for you that does work, I have a camera class that I use for the graphics programming that I do, just PM me.

I also hope you know that sin and cos functions are almost always done in radians. Convert degrees to radians with theta*(pi/180)
Last edited on
@J4ke I don't appreciate you completely skipping reading the topic and making assumptions.
I did read the post, the code that I gave you will work exactly. If you rework the system so that the camera rotation is in the form of an angle rather than a vector, the translate function will translate the rotated matrix, making it look as if you move side to side or front to back in any rotation of the matrix.

I look back at my post and see that I worded it wrong, putting emphasis on the rotation of the camera. I meant to say that you should rotate the camera using the rotate function and then use the translate function instead of having to calculate the vector.
Last edited on
Oh, I had not considered making translations again after the rotation. Indeed I misread your post and thought you hadn't read any posts here. I will try it out, thanks!

EDIT: I'm still confused, the current code I have before your recommendation is this:
1
2
3
4
glRotated(r.x, 1.0, 0.0, 0.0);
glRotated(r.y, 0.0, 1.0, 0.0);
glRotated(r.z, 0.0, 0.0, 1.0);
glTranslated(p.x, p.y, p.z);
How should I change it or what should I add?
Last edited on
LB, I'm puzzled on why you're using sin and cos.
To go forward one unit, increase p.z 1 unit, or to go up one unit, increase p.y by -1 units (negative of whatever direction you want to go). You don't have to have all of the stuff that calculates how much to add to p.x, p.y, and p.z, the rotation of the matrix should do that for you.
@J4ke: I think you misunderstood. I want the up, down, left, right, forward, backward to be relative to the camera's current facing.
Why not just increase the position by the vector that represents where you're facing? That way moving forward would move forward relative to where the player is facing, and so on.
Last edited on
position += forward_vector * speed;
Yea, what helios said.
Oh, one more thing: do make sure the forward_vector is normalized before doing that. You can do that by dividing by the norm before adding, or by ensuring that the transformations don't denormalize vectors. I believe there was a quick check you could do on the matrix for that, by my linear algebra is pretty rusty.
The problem is, I don't have a forward vector.
Take a piece of paper and pretend that is you matrix. Then, rotate the paper however you want to and move it a few units north/south/east/west. Did you need to move the paper diagonally at all to achieve the forward effect?

All you need to do is rotate the paper, or matrix in your case, and then translate it back a few units.
You must have. It's the one that determines the line of sight. You use it to transform the view matrix with glRotate*() (although it's not in Cartesian coordinates in your case).
Last edited on
@helios look at the code I linked to (it's just one source file) :p
Pages: 123