[HowTo] Perspective Projection Matrix in OpenGL

Here is a small function to create a perspective projection matrix. This function does not use OpenGL calls to initialize the matrix. This routine is nice because it can be used either with Direct3D (requires a little ogl to d3d matrix conversion – will be posted in another HowTo) or with the upcoming Larrabee too. And this function will be very useful to all coders that will need to produce OpenGL 3.1 compliant code because with OpenGL 3.1, you must have your own matrices functions!
void BuildPerspProjMat(float *m, float fov, float aspect,
float znear, float zfar)
{
float xymax = znear * tan(fov * PI_OVER_360);
float ymin = -ymax;
float xmin = -xmax;
float width = xymax - xmin;
float height = xymax - ymin;
float depth = zfar - znear;
float q = -(zfar + znear) / depth;
float qn = -2 * (zfar * znear) / depth;
float w = 2 * znear / width;
w = w / aspect;
float h = 2 * znear / height;
m[0] = w;
m[1] = 0;
m[2] = 0;
m[3] = 0;
m[4] = 0;
m[5] = h;
m[6] = 0;
m[7] = 0;
m[8] = 0;
m[9] = 0;
m[10] = q;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = qn;
m[15] = 0;
}
and here is how to use it in an OpenGL 1 / OpenGL 2 code:
float m[16] = {0};
float fov=60.0f; // in degrees
float aspect=1.3333f;
float znear=1.0f;
float zfar=1000.0f;
BuildPerspProjMat(m, fov, aspect, znear, zfar);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m);
// okay we can switch back to modelview mode
// for all other matrices
glMatrixMode(GL_MODELVIEW);
...
With a real OpenGL 3.0 code, we must use GLSL shaders and uniform variables to pass and exploit the transformation matrices:
glUseProgram(shaderId);
glUniformMatrix4fv("projMat", 1, GL_FALSE, m);
RenderObject();
glUseProgram(0);
Related posts:












glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m);
THese functions are both depricated in OGL 3.0 and up
You can cut down the number of calculations (and eliminate the multiplactions by -1) but simplifying the terms:
{
const float h = 1.0f/tan(fov*PI_OVER_360);
float neg_depth = zNear-zFar;
m[0] = h / aspect;
m[1] = 0;
m[2] = 0;
m[3] = 0;
m[4] = 0;
m[5] = h;
m[6] = 0;
m[7] = 0;
m[8] = 0;
m[9] = 0;
m[10] = (zFar + zNear)/neg_depth;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = 2.0f*(zNear*zFar)/neg_depth;
m[15] = 0;
}
The “how to use it” code is confusing; the GL Matrix functions are supposed to be removed in ogl 3.1. Maybe i’m wrong but i think that you must provide the matrix to the shaders using parameters ?!
Regards
Thanks guys for your feedbacks!
Luuk and Damien > you’re both right. In a proper GL 3.1 code, we must use a glsl shader to render an object and tranformation matrices must be passed with uniforms. But I wanted to give a simple GL 2 code. I update a bit the post…
Zenja > thanks for the optimization
Thanks for the nice code example.
I have used matrices, in school, in the distant past, but have only
recently started using OpenGL, OpenCV, etc.
Over the past few days I have spent a lot of time trying to
learn about matrices, perspective projection, homogeneous
coordinates, and related topics.
I see that the matrix presented in your code is similar to that
for the perspective projection presented at:
http://www.songho.ca/opengl/gl_projectionmatrix.html
except that your example has it this way:
m[8] = 0;
m[9] = 0;
m[10] = q;
m[11] = -1;
m[12] = 0;
m[13] = 0;
m[14] = qn;
m[15] = 0;
and the other web site does it like this:
m[8] = 0;
m[9] = 0;
m[10] = q;
m[11] = qn;
m[12] = 0;
m[13] = 0;
m[14] = -1;
m[15] = 0;
Why is that?
I think that the answer probably lies in the use of
homogeneous coordinates but I don’t understand it yet.
Can you help me with this?
Thanks,
Lars