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
.