Saturday, June 4, 2011

How to create a view matrix

When I started with 3D I had this really handy function in the GLUT library called gluLookAt(...) which helps you position the viewer (camera) inside your scene.What this matrix does is to transform points from world space into camera space - or in other words in it answers this question: "What would be the coordinate of a world point if the camera was the origin of a new world coordinate system?". WebGL does not have it in its API, so let's create our own from scratch then.

You need three things to construct a view matrix:

  • eye of the camera -  position of the camera specified in world coordinates.
  • target point indicates the target of the camera (where we want to look).
  • up vector - defines which direction is up

You also need to remember that the up vector must not be parallel to the line of sightvector from the eye to the target point!

Eye, target and up vector in the scene.
Eye, target and up vector.

And here is the pseudo-code for constructing the view matrix:

    Matrix lookAt(Vector3 eye, Vector3 target, Vector3 up) {
         Vector3 vz= normalize(eye - target);
         Vector3 vx = normalize(crossProduct(up, vz));
         // vy doesn't need to be normalized because it's a cross
         // product of 2 normalized vectors
         Vector3 vy = crossProduct(vz, vx);
         Matrix inverseViewMatrix = new Matrix(new Vector4(vx, 0),
                                                                                              new Vector4(vy, 0),
                                               new Vector4(vz, 0),
                                                                                              new Vector4(eye, 1));
        return inverseViewMatrix.getInverse();

First of all two important assumptions I have in this code:

  • eye, target and up are 3-component vectors - this is not the general case
  • I assume that the matrix mode is row-major - the matrix mode only affects in which order you multiply matrices and vectors, the result stays the same
Depending on your specific application or convention, fit this code to your needs. I guess everything should be straight forward except maybe the return line - why do we need the inverse? Well, you remember we want our camera to be the origin of the coordinate system? To achieve that we have to apply the inverse of the computed matrix to all our objects so they get transform to camera space. If you want more info on this topic, visit check out this tutorial.