This post is about coordinate transformations which I was confused with so much!

Geometrically, coordinate system (or frame) consists of an origin and basis - a set of three vectors. Bases are not necessarily orthonormal, but it is assumed that bases are orthonormal because it is convenient. Let p p the origin, {u,v,w} \{u,v,w\} bases, and (a,b,c) the coordinates, then we can describe point like this:

p+ua+vb+wc p + u * a + v * b + w * c

In canonical coordinates, the origin is o(0,0,0) o(0, 0, 0) and bases are X(1,0,0)T X(1, 0, 0)^T , Y(0,1,0)T Y(0, 1, 0)^T , Z(0,0,1)T Z(0, 0, 1)^T . We can use another origin and basis - e,{U,V,W} e, \{U, V, W\} . The point P P can be described in different coordinates.

P=(Px,Py,Pz)o+PxX+PyY+PzZ P = (P_x, P_y, P_z) \equiv o + P_x*X + P_y*Y + P_z*Z

P=(Pu,Pv,Pw)e+PuU+PvV+PwW P = (P_u, P_v, P_w) \equiv e + P_u*U + P_v*V + P_w*W

As e,{U,V,W} e, \{U,V,W\} are described in canonical coordinates too, we can express this relationship using matrix.

[PxPyPz1]=[100ex010ey001ez0001][UxVxWx0UyVyWy0UzVzWz00001][PuPvPw1]=[UxVxWxexUyVyWyeyUzVzWzez0001][PuPvPw1] \begin{bmatrix} P_x \\ P_y \\ P_z \\ 1 \end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & e_x \\ 0 & 1 & 0 & e_y \\ 0 & 0 & 1 & e_z \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} U_x & V_x & W_x & 0 \\ U_y & V_y & W_y & 0 \\ U_z & V_z & W_z & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} P_u \\ P_v \\ P_w \\ 1 \end{bmatrix} = \begin{bmatrix} U_x & V_x & W_x & e_x \\ U_y & V_y & W_y & e_y \\ U_z & V_z & W_z & e_z \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} P_u \\ P_v \\ P_w \\ 1 \end{bmatrix}

This 4x4 matrix is a coordinate transformation matrix from an arbitrary frame to the canonical coordinate system.

Then we can obtain transformation matrix in the other direction. The transformation matrix is the inverse of the matrix above - translation and then rotation. When basis vectors are orthonormal, it is simply transposed matrix.

[PuPvPw1]=[UxVxWx0UyVyWy0UzVzWz00001]T[100ex010ey001ez0001][PxPyPz1] \begin{bmatrix} P_u \\ P_v \\ P_w \\ 1 \end{bmatrix} = \begin{bmatrix} U_x & V_x & W_x & 0 \\ U_y & V_y & W_y & 0 \\ U_z & V_z & W_z & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}^T * \begin{bmatrix} 1 & 0 & 0 & -e_x \\ 0 & 1 & 0 & -e_y \\ 0 & 0 & 1 & -e_z \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} P_x \\ P_y \\ P_z \\ 1 \end{bmatrix}

Now we know how to transform coordinate system! Next we can derive ’gluLookAt’ function using matrices described above. The function changes the world coordinate from the camera coordinate.

gluLookAt( eye, center, up );

//eye - the position of eye point
//center - the reference point
//up - the direction of the up vector

When we use gluLookAt, three points are given, eye - the position of the camera, center - the viewing direction, and up - the view-up vector. Using three points, we can create the camera frame (coordinate system). The camera is located at eye, viewing at -Zc Z^c (OpenGL coordinate), with upward-orientation Yc Y^c .

Zc=normalize(eyeat) Z^c = normalize(eye-at)

Xc=normalize(Zc×up) X^c = normalize(Z_c \times up)

Yc=normalize(Zc×Xc) Y^c = normalize(Z_c \times X_c)

So we now have a transformation matrix from the world coordinates the camera coordinates. Remember it is from canonical coordinates to a new coordinate.

[X0cY0cZ0c0X1cY1cZ1c0X2cY2cZ2c00001]T[100eyex010eyey001eyez0001]=[X0cX1cX2c0Y0cY1cY2c0Z0cZ1cZ2c00001][100eyex010eyey001eyez0001] \begin{bmatrix} X^c_0 & Y^c_0 & Z^c_0 & 0 \\ X^c_1 & Y^c_1 & Z^c_1 & 0 \\ X^c_2 & Y^c_2 & Z^c_2 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}^T * \begin{bmatrix} 1 & 0 & 0 & -eye_x \\ 0 & 1 & 0 & -eye_y \\ 0 & 0 & 1 & -eye_z \\ 0 & 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} X^c_0 & X^c_1 & X^c_2 & 0 \\ Y^c_0 & Y^c_1 & Y^c_2 & 0 \\ Z^c_0 & Z^c_1 & Z^c_2 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} * \begin{bmatrix} 1 & 0 & 0 & -eye_x \\ 0 & 1 & 0 & -eye_y \\ 0 & 0 & 1 & -eye_z \\ 0 & 0 & 0 & 1 \end{bmatrix}

Yay! Now we can write our own gluLookAt function.