First-person Camera

How to 3D

Chapter 7: Camera and Terrain

First-person Camera

The Matrix4.look method is handy when we want to fix the eye at an arbitrary location in the world. However, if we want the viewer to be able to navigate a scene, we need a more sophisticated abstraction that has behaviors for moving and turning. Let's build a FirstPersonCamera class that manages the viewer's state.

State

The FirstPersonCamera class must track its position and orientation. Some of the state we have seen as parameters that we'll need to pass to Matrix4.look. It also holds on to some derived state, like the eyeFromWorld matrix, which will be frequently accessed by the renderer or other camera methods.

Insert this code in lib/first-person-camera.ts in your project.

Behaviors

The FirstPersonCamera class provides several behaviors for initializing the camera, moving and turning it, and building the eyeFromWorld matrix.

Constructor

The constructor receives the camera's position and focal point and the world's up vector. It directly initializes all but its eyeFromMatrix and right variables. Note that we receive the focal point—which is a position. The forward vector is more immediately useful and more flexible, so we store it instead.

The eyeFromWorld matrix must be rebuilt whenever the camera's position or rotation changes. Instead of duplicating that logic, we factor out a helper reorient method and call it at the end of the constructor.

Reorient

The reorient method is called whenever the camera moves or turns. It derives the eyeFromWorld matrix and right vector from the camera state using the look method we defined earlier.

Strafe

We want the camera to move as the viewer interacts with the renderer. One common camera motion in games is the strafe, in which the player sidesteps to the left or right without turning. We strafe the camera by pushing its position some distance along its right vector and then rebuilding the camera's transformation matrix.

If the distance is negative, the camera moves left.

Advance

Another common motion is for the camera to advance forward or backward. We advance the camera by pushing its position along the forward vector.

If the distance is negative, the camera moves backward.

Rotation

Imagine we are piloting an airplane and a flight controller tells us to turn 30 degrees. This isn't a helpful command because we have many possible turns to choose from. We could yaw, which is turning left or right. We could pitch, which is turning the nose up or down. We could roll, which is turning about the nose. Or we could rotate around some non-standard axis.

Cameras are like airplanes in that they may be turned in many directions. Users typically make them yaw and pitch in order to look at nearby objects in the scene. Outside of flight simulators, rolling isn't common.

We yaw the camera by rotating the forward direction around the world's up vector, which is a matrix-vector multiplication. What rotation matrix do we use? Currently our Matrix4 class only has methods for rotating around the x-, y-, and z-axes. The world's up axis could be anything. Let's assume for the moment we have a more general Matrix4.rotateAround(axis, degrees) method.

We similarly pitch the camera by rotating the forward direction around the right vector.

Since rolling is uncommon, we won't add a method for it.

Put all this code in your FirstPersonCamera class. We're almost ready to test it out in a renderer. We just need a rotateAround method.

← Look MatrixRotate Around →