Brynn Mahsman Brynn Mahsman - 2 months ago 13
C++ Question

How do you calculate the transformation matrix for a camera?

I have a camera with the position, forward, right, and down vectors defined as class members

, and
. For the rotation part of the problem, I simply load the rows of the destination coordinate system (view space) with
, and
and then apply a rotation matrix to go into "OpenGL" view space.

Before that I translate by the negative of
. Is this correct, or do I need to do more math to determine the actual translation to pre- or post- multiply by my rotation?

Below is the code I have that doesn't seem to work. Specifically, I am rendering an object (a small quad facing down the z-axis) at the origin of world space and when I run the program that object appears distorted. (Note that the mat4 constructor takes elements in ROW major order though it stores them in column major internally).

mat4 Camera::matrix() const
0.0f, 0.0f, -1.0f, 0.0f,
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f) *
_forward.x, _forward.y, _forward.z, 0.0f,
_right.x, _right.y, _right.z, 0.0f,
_down.x, _down.y, _down.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f) *

Here is the code for the look at function that is being used before the above.

void Camera::look_at(const vec3& position, const vec3& point)
_position = position;
_forward = normalize(point - position);
_right = cross(_forward, vec3(0.0f, 1.0f, 0.0f));
_down = cross(_forward, _right);

In my initialization, I use this code:

camera.look_at(vec3(1.0f, 1.0f, 1.0f), vec3(0.0f, 0.0f, 0.0f));
view = camera.matrix();
proj = perspective(60.0f, SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.001f, 100.0f);
view_proj = proj * view;


I'd suggest to use glm::lookAt() for convenience.

For more info refer

But here is how one would construct it from position, target and up vectors.

note this is same as the lookAt() function.

//creates a lookat matrix
mat4 lookAt(Vec3 eye, Vec3 center, Vec3 up)
    Vec3 left, up2, forward;

    // make rotation matrix

    // forward vector
    forward = center - eye;

    // up2 vector (assuming up is normalized)
    up2 = up;

    // left vector = up2 cross forward
    left = up2.Cross(forward);

    // Recompute up2 = forward cross left (in case up and forward were not orthogonal)
    up2 = forward.Cross(left);

    // cross product gives area of parallelogram, which is < 1.0 for
    // non-perpendicular unit-length vectors; so normalize left, up2 here

        left.x, left.y, left.z, left.Dot(-eye),
        up2.x, up2.y, up2.z, up2.Dot(-eye),
        -forward.x, -forward.y, -forward.z, -forward.Dot(-eye),
        0.0f, 0.0f, 0.0f, 1.0f)


note that up2 = up in case up and forward were orthogonal, else up2 is an orthogonal up vector to forward.