3d Camera Control
This page goes into a bit more detail about writing camera controllers.
First Person Camera Controller
Controlling the camera in a “first person” camera controller. This doesn’t necessarily mean there’s a person in the game-object sense, but this also works for freeflight cameras.
Note: Most of this should be trivially implementable with knowledge from the Vectors and Euler Angles pages.
Assuming a camera structure of some sorts exists, with at two floating point values for at least the pitch and yaw and a position vector.
For this bit I’m going to use the following struct:
typedef struct {
vec3 position;
float yaw;
float pitch;
} camera_t;
Note that it doesn’t include any information about the actual view matrix. That’s not something this page is concerned with.
Assume now you want to update the position for the camera, based on a certain key press. This is actually quite easy, the first step is to convert the yaw/pitch into a direction vector $\hat{d}$. This is also where something like a non-flying first person controller comes in, as it only does a partial conversion, leaving out the $y$ component of the new direction vector.
This vector can now be used to add to our position. That’s all. The only difference in the following code is that, when strafing, instead of using the forward vector we take the cross product of said vector and the up-direction, so that we get a new vector that is parallel to the left/right axis from the perspective of the camera.
void move_camera(camera_t *cam)
{
// Contains the direction we want to move in.
vec3 direction = {0};
// Other stuff, like updating the camera rotation, which is just adding to the
// pitch/yaw, multiplied by the delta time, as well as clamping it.
// Note, the following can be changed to
// vec3 forward = { sinf(cam->yaw) * cosf(cam->pitch), 0, cosf(cam->pitch) * cosf(cam->yaw) }
// if you want a floating freecam style camera movement.
vec3 forward = { sinf(cam->yaw), 0, cosf(cam->yaw) }
// `cross_product` would be a function that returns a vec3 with the cross product.
vec3 left = cross_product((vec3){ 0.0f, 1.0f, 0.0f }, forward);
// Assume `IsKeyPressed` returns a boolean that is true if the key is pressed.
// `vec3_add` takes in two vec3s, adds them together and writes the result
// to the third vector, `vec3_sub` does the same thing but for subtraction.
if (IsKeyPressed(KEY_W)) vec3_add(direction, forward, direction);
if (IsKeyPressed(KEY_S)) vec3_sub(direction, forward, direction);
if (IsKeyPressed(KEY_A)) vec3_add(direction, left, direction);
if (IsKeyPressed(KEY_D)) vec3_sub(direction, left, direction);
if (!is_zero(direction))
vec3_normalize(direction)
// Assume `dt` is defined outside of this function and represents the amount
// of seconds since the last frame and `movementSpeed` to be some sort of value
// that determines the movement speed.
vec3_scale(direction, movementSpeed * dt, direction);
// Add the final direction to the position.
vec3_add(cam->position, direction, cam->position);
}