Perspective Matrix implementation


im currently trying to implement perspective view with matrix but its not working. so this is what i did:

  1. i got a screen with width and height 800
  2. i implement the drawing, transformation, culling etc and it works perfectly. but the z-translation did not work. its fine because i havent implement the perspective view.
  3. i implement the perspective by multiplying it with a matrix that shown in the redbook when implementing glFulstrum.
    so here is my matrix
	Matrix4 m(-2.0f*n/(r-l), 0, (r+l)/(r-l), 0,
				0, -2.0f*n/(t-b), (t+b)/(t-b), 0,
				0, 0, (f+n)/(f-n), -2.0f*(f*n)/(f-n),
				0, 0, -1, 0);

but it simply does not work. i called it with this line:

perspectiveView(-400, 400, -400, 400, -400, 400);

l, r, t, b, n, f respectively.

is there something wrong?

“simply does not work” is always the best explanation. what is the problem? what does not work? how does it look like?
one thing that comes to mind is your near/far values. -400,+400 is weird for a perspective setup. +1,+400 would be better.

the perspective view is not working. i cant have a z-translation. but other non z related transformation (x and y) is working. its like having an orthogonal projection on my scene

i tried to understand perspective matrices long time ago. what helped me along with tutorials is to call gluPerspective with values then retrieve the matrix with glGet to see what was in there. same with glOrtho and the like. maybe a look on gluPerspective will help you more.

If you had read carefully the glFrustum function specification, the near and far values must be positive and at 1st sight you are actually using the matrix set by glFrustum.

I notice some problem:
Solving the computation with your parameter you get this matrix:

400	0	(0)/(r-l)	0
0	400	(0)/(t-b)	0
0	0	(0)/(f-n)	-160000
0	0	-1		0

… so when you multiply your camera space vertex you don’t have any Z transformation (all Z are flattened to -1) and no screen ratio preservation. :-
Both your parameter and computation are wrong.

this article explain very well the prospective matrix:

Basically you want a matrix that take coordinates in camera space and transform them in a -1.0 < p < 1.0 cube in homogeneous coord.

The first row should take the X coord and based on your (X)FOV should scale it.
Should be something like that

2*near/(right-left)	0	0	0

the right and left value are referred to how wide is your near plane. a Near plane of 800 is HUGE.
The other number should be 0 cause I don’t wont the X to be modified by the Y o Z (or even W) coord.
You can say… wait… I want my X to become smaller when the Z became bigger to have a prospective. :slight_smile:
No, cause the normalization pass should take care of this.

The second row is like the first, but now we are working on the Y. Nothing new…

0	2*near/(top-bottom)	0	0

Now let’s take care of the Z.
You want the z that stay on the near plane to become -1.0 and the z that stay on the far plane to become 1.0
That easy…

0	0	(far+near)/(far-near)	-2.0 * far* near /(far-near)

Now if I have a vertex in (0.0, 0.0, near) it will became
00 + 00 + near (far+near) / (far-near) + 1 * (-2.0 * far near /(far-near))=
near * (far-near) / (far-near) = near
Wow… It don’t work, we still need to add something.
Of course!! The normalization… :slight_smile:
After this pass the coordinates are divided by W so we need a W that is -Z.
Here it is, the last row is

0	0	-1	0

now we have a matrix like this:

2*near/(right-left)		0	0		0
0	2*near/(top-bottom)	0			0
0	0			(far+near)/(far-near)	-2.0 * far* near /(far-near)
0	0			-1			0

And now my vertex in (0, 0, near, 1) will go in (0.0, 0.0, -1.0)
and my vertex in (0, 0, far, 1) will go in (0.0, 0.0, 1.0).

The computation is correct but the parameter are not very intuitive… and here it come the glutPerspective.
glutPerspective compute the right parameter based on the (Y)fov and the screen ratio.

Hope this’ll help.

Rosario, thats the best explanation of the glFrustum matrix i’ve seen yet. Very useful.

I would think a more practical perspective matrix would be one expressed in terms of camera field-of-view and viewport size.
At least it would be easier to understand.

Taken from here:

void BuildPerspProjMat(float *m, float fov, float aspect, float znear, float zfar)
  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;


Actually, viewport transformation has nothing common with projection. They are 2 different transformations. MVP, then homogenous division, then viewport transformation. So don’t mess them up! :slight_smile: