Camera Tutorial

Hamburg (Germany), the 25th May 1998. Written by Nils Pipenbrinck aka Submissive/Cubic & $eeN

Introduction

Doing a 3D-engine without a camera is quite easy. If you are writing your first 3D-engine or have never dealt with the camera stuff you might have problems figuring out how to do the camera transformation. As usual it turns out to be very simple.

How to define the Camera

We don't need that much information to define a camera. The only values are:

  1. The position of the camera itself
  2. The camera's look-at point
  3. the roll angle (rotation) of the camera around it's view axis

I made myself a structure which looks like this:

struct tcamera
{
  tvector position;
  tvector target;
  float   roll;
};

The Camera Transformation

Now, how do we calculate something useful out of these informations? First we have to move the entire world so that the position of the camera becomes the origin of the world coordinate system. This is done by translating by the tcamera.position scaled by -1. Then we have to find 3 vectors that form our new coordinate system. The three vectors must all have a length of one, and must not be colinear.
The first vector which can be calculated is our new y-vector. It's the vector that will point to the top of our screen. Calculate it by rotating a y-vector around the z-axis by the roll-value:

Up.x = sin(roll);
Up.y = -cos(roll);
Up.z = 0;

Now we calculate the new z-vector. This vector has the same direction as the camera look direction, but it must be normalized to get the length = 1.

Forward.x = Look_at.x - Position.x
Forward.y = Look_at.y - Position.y;
Forward.z = Look_at.z - Position.z;

normalize_vector (Forward);

The third vector can be calculated by the cross-product of Up and Forward. It'll result in a vector pointing to the right of our screen, or - speaking in our new coordinate system - to the positive x-axis. Normalize this vector, since it's not guaranteed that up and forward are collinear.

Right = crossproduct(up, forward);

normalize_vector (Right);

We're almost finished now... But there is still one thing: It's not guaranteed that the up-vector and the direction-vector are colinear. (think about a camera that'll look at the sky). To avoid distortion we have to recalculate the Up vector again:

Up = crossproduct (Right, forward);

Again, normalize this vector (just in case, it doesn't hurt).

Making a camera-matrix

How do we build a rotation-matrix out of these three vectors? We only have to put the vectors into the three rows of our rotation-matrix.

| right.x    right.y      right.z   |
| up.x       up.y         up.z      |     ; (rotation3x3)
| forward.x  forward.y    forward.z |

If you like 4x4 matrices (as I do) you might use:

| right.x    right.y      right.z    0 |
| up.x       up.y         up.z       0 |
| forward.x  forward.y    forward.z  0 |  ; (rotation4x4)
| 0          0            0          1 |

We also know the Camera translation matrix (which can only be built if you use 4x4 matrices since translation can not be expressed as a 3x3 matrix):

| 1   0   0   -position.x |
| 0   1   0   -position.y |
| 0   0   1   -position.z |
| 0   0   0    1          |

The final Camera matrix is simply the translation multiplied with the rotation:

matrixmul (final, translation, rotation);

How to use the Matrix

Assuming that you use 4x4 matrices for your object transformation you can just concatenate (multiply) your object matrix with the camera matrix. That's all. If however you still use 3x3 matrices you have something more to do:

The resulting point can then be clipped and projected. I think this is a good example of why 4x4 matrices are better than 3x3 matrices. Transforming points using 3x3 matrices is almost three times as expensive as using 4x4 matrices. Of cause the setup-costs (4 matrix-multiplications per object) are higher when you use 4x4 matrices. If you want to rotate a bunch of cubes 3x3 might be the better choice. (anyway, who draws cubes these days?).

Final Words

I hope you learned something. Well, there might still be a bug in the math. It's possible that this camera model will mirror on some axis (I haven't tested it). If so you only have to change the order of the crossproduct somewhere. And as usual there are hundreds of typos in the text.. You know: foreign languages are difficult languages. Instead of flaming me you might press the »Save As« button, fix the typos and send it back to me... thank you. Maybe I'll add a tutorial which explains 4x4 matrices in detail. I think there are still a lot of folks out there who don't see the advantage and only use them cause they're state of the art.


Colinear

colinear means, that a vector can not be expressed as the scaled summ of any other vectors. For example the vector (1,0,0) can not be expressed by either (0,1,0) or (0,0,1). Three vectors that are colinear form a basis for a 3d coordinate system.


© by submissive