OpenGL Projection Matrix
Related Topics: OpenGL Transformation
Overview
A computer monitor is a 2D surface. We need to transform 3D scene into 2D image in order to display it. GL_PROJECTION matrix is for this projection transformation . This matrix is used for converting from the eye coordinates to the clip coordinates. Then, this clip coordinates are also transformed to the normalized device coordinates (NDC) by divided with w component of the clip coordinates.
Therefore, we have to keep in mind that both clipping and NDC transformations are integrated into GL_PROJECTION matrix. The following sections describe how to build the projection matrix from 6 parameters; left , right , bottom , top , near and far boundary values.
Perspective Projection
In perspective projection, a 3D point in a truncated pyramid frustum (eye coordinates) is mapped to a cube (NDC); the x-coordinate from [l, r] to [-1, 1], the y-coordinate from [b, t] to [-1, 1] and the z-coordinate from [n, f] to [-1, 1].
Note that the eye coordinates are defined in right-handed coordinate system, but NDC uses left-handed coordinate system. That is, the camera at the origin is looking along -Z axis in eye space, but it is looking along +Z axis in NDC. Since glFrustum() accepts only positive values of near and far distances, we need to negate them during construction of GL_PROJECTION matrix.
In OpenGL, a 3D point in eye space is projected onto the near plane (projection plane). The following diagrams shows how a point (xe , ye , ze ) in eye space is projected to (xp , yp , zp ) on the near plane.
From the top view of the projection, the x-coordinate of eye space, xe is mapped to xp , which is calculated by using the ratio of similar triangles;
From the side view of the projection, yp is also calculated in a similar way;
Note that both xp and yp depend on ze ; they are inversely propotional to -ze . It is an important fact to construct GL_PROJECTION matrix. After an eye coordinates are transformed by multiplying GL_PROJECTION matrix, the clip coordinates are still a homogeneous coordinates . It finally becomes normalized device coordinates (NDC) divided by the w-component of the clip coordinates. (See more details on OpenGL Transformation . )
,
Therefore, we can set the w-component of the clip coordinates as -ze . And, the 4th of GL_PROJECTION matrix becomes (0, 0, -1, 0).
Next, we map xp and yp to xn and yn of NDC with linear relationship; [l, r] ⇒ [-1, 1] and [b, t] ⇒ [-1, 1].
Then, we substitute xp and yp into the above equations.
Note that we make both terms of each equation divisible by -ze for perspective division (xc /wc , yc /wc ). And we set wc to -ze earlier, and the terms inside parentheses become xc and yc of clip coordiantes.
From these equations, we can find the 1st and 2nd rows of GL_PROJECTION matrix.
Now, we only have the 3rd row of GL_PROJECTION matrix to solve. Finding zn is a little different from others because ze in eye space is always projected to -n on the near plane. But we need unique z value for clipping and depth test. Plus, we should be able to unproject (inverse transform) it. Since we know z does not depend on x or y value, we borrow w-component to find the relationship between zn and ze . Therefore, we can specify the 3rd row of GL_PROJECTION matrix like this.
In eye space, we equals to 1. Therefore, the equation becomes;
To find the coefficients, A and B , we use (ze , zn ) relation; (-n, -1) and (-f, 1), and put them into the above equation.
To solve the equations for A and B , rewrite eq.(1) for B;
Substitute eq.(1') to B in eq.(2), then solve for A;
Put A into eq.(1) to find B ;
We found A and B . Therefore, the relation between ze and zn becomes;
Finally, we found all entries of GL_PROJECTION matrix. The complete projection matrix is;
This projection matrix is for general frustum. If the viewing volume is symmetric, which is and ,.then it can be simplified as;
Before we move on, please take a look at the relation between ze and zn , eq.(3) once again. You notice it is a rational function and is non-linear relationship between ze and zn . It means there is very high precision at the near plane, but very little precision at the far plane. If the range [-n, -f] is getting larger, it causes a depth precision problem (z-fighting); a small change of ze around the far plane does not affect on zn value. The distance between n and f should be short as possible to minimize the depth buffer precision problem.
Orthographic Projection
Constructing GL_PROJECTION matrix for orthographic projection is much simpler than perspective mode.
All xe , ye and ze components in eye space are linearly mapped to NDC. We just need to scale a rectangular volume to a cube, then move it to the origin. Let's find out the elements of GL_PROJECTION using linear relationship.
Since w-component is not necessary for orthographic projection, the 4th row of GL_PROJECTION matrix remains as (0, 0, 0, 1). Therefore, the complete GL_PROJECTION matrix for orthographic projection is;
It can be further simplified if the viewing volume is symmetrical, and .