A camera represents the perspective from which a scene is rendered. Scenes, implemented through instances of the Clairvoyance SceneManager class, emulate three dimensional environments and can contain any number of camera references. While a scene can exist independently of a camera, it is only made visible by defining an active camera to render it with.
A Scene has member references to both an active viewport and active camera. When building a client application, a user adds a default viewport to the window and specifies which camera will render to it. Different cameras can be added thereafter. A scene and its cameras represent a one-to-many relationship. While a camera can be attached only to one scene at a time, a scene may have references to multiple cameras.
A camera is responsible for generating the projection and view matrices used to generate the final model view projection matrix. The Camera class extends the Frustum class, which in turn extends the MovableObject class. When a camera receives calls to rotate or translate, it delegates matrix updates to its frustum, and recalculates the relevant matrices. The Scene will then pass these matrices to the active vertex shader at render time.
Clairvoyance handles the creation of a window through the Windows API. As such, it does not use any pre-existing libraries such as GLUT to control window events or user interactivity. When building a client application off of Clairvoyance, users can choose a programming interface to add runtime user input support. In testing, we found it favourable to use the Simple DirectMedia Layer (SDL) API. SDL’s keyboard and mouse handling made it easy to define camera controls.
In FPS game in development, you can use a camera to represent the view of the player. Like many traditional FPS games, keyboard controls and mouse movement are both used to control the player. To implement this, we used a simple node hierarchy to organize the player’s relationship to the camera:
- A scene node represents the 3D transformations of the player in world space, tracking his position and orientation.
- A camera is then attached to the player scene node and positioned at head height. As a child to the node, the camera derives its position and orientation from the player by calculating its final transformations with respect to its local transformations.
- Mouse movements along the Y axis control the camera’s pitch, while movements along the X axis rotate the player node (and thus rotating the camera). Keyboard controls translate the player node with respect to its local transforms. Separating the camera’s pitch from the player node prevents unwanted translations upward.
- SDL locks the mouse to the centre of the screen at the start of the frame. By calculating the change in position, we can generate a rotation matrix that we apply to the player node.
When rendering the scene, a camera uses a few optimizations to keep the scene running smoothly. Largely, this pertains to frustum culling. The camera culls objects outside the frustum as well as ignores the dynamic lights that do not affect the final rendering.