Brynn Mahsman - 1 year ago 71
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

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

Before that I translate by the negative of
`_position`
. 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
{
return
mat4(
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) *
mat4(
_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) *
translate(
-_position.x,
-_position.y,
-_position.z
);
}
``````

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.

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;
forward.Normalize();

// 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.Normalize();
up2.Normalize();

mat4(
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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download