Reputation: 1355
The GLM maths library for openGL gives this implementation for the construction of lookAt matrix
.
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
{
vec<3, T, Q> const f(normalize(center - eye));
vec<3, T, Q> const s(normalize(cross(up, f)));
vec<3, T, Q> const u(cross(f, s));
mat<4, 4, T, Q> Result(1);
Result[0][0] = s.x;
Result[1][0] = s.y;
Result[2][0] = s.z;
Result[0][1] = u.x;
Result[1][1] = u.y;
Result[2][1] = u.z;
Result[0][2] = f.x;
Result[1][2] = f.y;
Result[2][2] = f.z;
Result[3][0] = -dot(s, eye); //#this
Result[3][1] = -dot(u, eye); //#this
Result[3][2] = -dot(f, eye); //#this
return Result;
}
Everything is fine and okay except for the translation factors that is done in the last three lines I've marked with //#this
. The translation had to be done for the camera's world position x, y and z
but instead it's done for the dot product of the camera's local coordinate and the direction vector, which can't possibly be equal.
Consider one case where the vector 2*eye
(eye being the camera's position) is passed as the vector center
(center being the target position) then the camera's local z-axis would coincide with the direction vector giving us the translation factor for the camera as [0,0,1]
, so we'd basically be moving along the world along only the z-axis
(since we don't move the camera we'd be moving the world along just z axis in the negative direction) which is something we wouldn't want. Where am I missing the point or why is this being done for the translation?
Upvotes: 3
Views: 1037
Reputation: 211230
glm::lookAt
defines the view matrix. The view matrix transforms vertex coordinates from world space to view space.
eye
, center
and up
are positions respectively vectors in world space, which define the the position and orientation of the camera in world space. eye
, center
and up
define the view space. If you would setup a matrix by this vectors, then the matrix would transform from view space to world space.
Since the view matrix has to do the opposite (world space -> view space), the view matrix is the inverse matrix of that matrix which is defined by eye
, center
and up
. glm::lookAt
is a optimized algorithm for computing an inverse matrix in this spacial case.
Note s
, u
, f
are transposed when they are assigned to the matrix.
The translation of the inverse matrix is not the negative translation of the matrix. The translation of the inverse matrix has to consider the orientation (rotation). Because of that the translation vector has to be rotated. The rotation of a (3d) vector by a 3x3 Rotation matrix can be computed by (is the same as) the 3 Dot products of the axis vectors and the direction vector. (s
, u
, f
) define a 3x3 rotation matrix and eye
is transformed by this matrix.
What the code actually dose is to concatenate a rotation by transposed (s
, u
, f
) and a translation by -eye
(very simplified pseudo code):
viewmatrix = transpose(rotation(s, u, f)) * translation(-eye)
Upvotes: 4
Reputation: 198
The dot product of one vector, a, with another normalized vector, n, can be thought of as the projection of a onto n. So, all that's happening here is that the eye
vector is being projected onto f
, s
, and u
, which are the basis vectors of the rotated coordinate frame. With these projections, we can learn the x, y, and z coordinates of eye
in the f-s-u coordinate frame.
Upvotes: 1