OpenGL draws primitives according to a user-definable camera model. You can specify a camera in very intuitive terms: position, aperture, and so on, and the geometry will automatically use that camera. Several cameras might be used. For example, a mini-map in the corner of a screen can use different camera parameters as the main scene. Additionally, you can select between different projection schemes: Perspective and orthographic are available, so you can choose your desired viewing algorithm. You can also completely override the camera and thus draw in window coordinates. This is especially useful when drawing in two dimensions, doing overlays for menus or interface elements, and so on.
An OpenGL camera is nothing but a series of transforms. The full scene is rotated according to the camera's orientation, then translated so the viewpoint is placed correctly, and an optional perspective transform is applied. But hand coding these transforms would be troublesome and prone to errors. Thus, the Open GL Utility Library (GLU) provides easy-to-use calls that take care of the camera operation. Overall, only two calls are required. The first call allows us to specify camera projection properties (aperture, aspect ratio, type of projection, and so on). The second is used to directly place the camera in our 3D world.
Let's now see how we can specify the camera's projection properties. Here is the call for perspective projection:
gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble znear, GLdouble zfar);
The first parameter indicates the field of view, in degrees, in the Y direction. The second parameter specifies the ratio between width and height. For example, a value of 1.3 implies that the camera's snapshot of the world is 1.3 times wider than it is tall. The last two parameters are used to initialize the Z-buffer. Both are strictly positive double values, specifying at which distance (in Z) the near and far clipping planes should be. Overall, these four parameters allow us to specify a view frustum completely, as shown in Figure B.4.
Figure B.4. Camera parameters and their geometric interpretation under OpenGL.
However, we need to place our 3D camera in space. This is easily achieved by using the call:
gluLookAt ( GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz);
Although the parameter list looks impressive, this is a really straightforward call. The first three parameters indicate where the camera actually is. Then, the second triplet is used to specify the point in space the camera is pointing at. Notice we do not provide angles of rotation, but a target instead. The last triplet is used to specify a vector pointing up relative to the camera's orientation. This vector will be mapped to the vertical axis in the viewport and allows us to represent rolling cameras, like a plane in a twisting trajectory along its line of advance.
Now, it is essential that you realize that gluPerspective and gluLookAt are nothing more than a series of transforms encapsulated into comfortable calls. Thus, they affect the currently selected matrix as any glTranslate, glRotate, or glMultMatrix would do. As a result, you must be careful about the order of operations and the currently selected matrix. Failing to do so results in wrong textures, lighting, and so on. The following code is the way to properly initialize a camera under OpenGL:
glMatrixMode(GL_PROJECTION); glLoadIdentity() ; gluPerspective(...) ; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(...);
Again, remember that gluPerspective implements a projection model, whereas gluLookAt effectively places the camera, which is nothing but rotating and translating the scene accordingly.