perspective matrix

Started by
7 comments, last by Quat 18 years, 9 months ago
Could someone give me a quick explanation of what a perspective matrix does? My understanding was that when you multiply a 3d point by it, it can convert it to a 2d location. If this is true, I don't see how it can do that. I thought you basically needed to divide by the z coordinate in order to do that, and there's no way a matrix can do that. Mike C. http://www.coolgroups.com/zoomer
Mike C.http://www.coolgroups.com/zoomer/http://www.coolgroups.com/ez/
Advertisement
You have to be aware that graphics device keeps all 3d points in the XYZW format, where W is 1 . ( It has nothing to do with RHW ! ). Then it is easier to multiply all the matrices which are 4x4, as you know. After that your point is normalized and looks like this : X/W Y/W Z/W . Now, let's look at the identity matrix:

______*
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

If you don't change anything in the last column (*), you always get division by 1 and you can't notice where you can make it depend on Z. Now, let's set Z to 0 and get rid of division by W and change it into the division by Z. Look at the matrix:

______*
1 0 0 0
0 1 0 0
0 0 0 1
0 0 0 0

Now. When the 3d point is multiplied, the result will be: X/Z Y/Z 0 . Try to do all the calculations by yourself to understand better.

If you want to add screen width/height ratio, you need to (1,1) or (2,1) matrix element and get ( i.e. 1.333*X/Z Y/Z 0 or X/Z 0.75Y/Z 0 ) both correct for 800x600 screen ratio.

Notice that (3,4) value of the matrix can be changed slightly in order to get different view angle. Now, you should see some more detailed description. I think that DirectX SDK has a good one.
jid: sebastian.szymanski@jid.pl
What do you mean by set z to 0? And, what do you mean by change it to division by z? If you set z to 0 and change it to division by z, isn't that division by zero?

I'm really not following. If someone could clarify, that would be great.

Mike C.
http://www.coolgroups.com/zoomer
Mike C.http://www.coolgroups.com/zoomer/http://www.coolgroups.com/ez/
The perspective divide is done after the projection transformation using the W value (which is computed by the projection transformation).
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Here is a simple perspective projection transformation matrix for OpenGL (note column vectors). The FOV is 90 degrees, the aspect ratio is 1:1, the near plane is at -1, and the far plane is at -infinity.
 1  0  0  0 0  1  0  0 0  0 -1 -2 0  0 -1  0 
[4, 4, -5, 1] ("view" or "eye" space) is transformed by the projection transformation to [4, 4, 3, 5] ("projection" or "clip" space), which is converted by the perspective divide to [.8, .8, .6] ("normalized device coordinates").
Compare that to other points that would be drawn at the same place on the screen:
[.8, .8, -1, 1] --> [.8, .8, -1, 1] --> [.8, .8, -1]
[1.6, 1.6, -2, 1] --> [.8, .8, 0, 2] --> [.8, .8, 0]
[8, 8, -10, 1] --> [8, 8, 8, 10] --> [.8, .8, .8]
[100, 100, -125, 1] --> [100, 100, 123, 125] --> [.8, .8, .984]
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
it should be 0 becouse there is no Z axis on your screen, is there ? Well, all the points are put on the XY plane ( your screen ). And their Z value is 0 ( presuably 0 is the valid value for DirectX, and OpenGL would like this value to be -1 ).

I think, you have some problems with matrix multipling. As I showed in the previous reply, multiplication of the third column and a 3d point will result in 0 value. Furthermore, your graphic adapter will divide posttransformed points (X,Y,Z) by the result of multiplication of the last column and the point. So, as you can see, it is divided by Z :

W value after transofrmation ( multiplication )

X * 0 + Y * 0 + Z * 1 + W * 0 = Z

Z value after transofrmation

X * 0 + Y * 0 + Z * 0 + W * 0 = 0

of course, there is no problem with dividing 0 with Z value. It always equals 0.

There is something more. If you want to draw whole 3d scenes and use z-buffering, you can't set (3,3) value to 0, but you have to put there a previously calculated fraction which rescale the Z value to the desired range. For instance, 16bit deep z-buffer can contain values from 0 to 65535. We can calculate the fraction using near and far clipping plane. DirectX want values from (0;1) range ( They are converted to integers by the graphics adapter ).

For example, your far clipping plane is 1000.0f form you and your near clipping plane is 4.0f from you. Then the fraction is 1.0f/(1000.0f-4.0f). Points outside this range ( 4.0f ; 1000.0f ) are eficiently rejected by the graphics adapter ).

You can also notice that if you use 24 bit z-buffer, the computations will be more precise.

If somehing is still unclear for you, feel free to ask.
jid: sebastian.szymanski@jid.pl
Seb, I'm pretty sure you got your matrix wrong. This is what you said was a perspective matrix.

1 0 0 0
0 1 0 0
0 0 0 1
0 0 0 0


Take a look at this:

1 0 0 0
0 1 0 0
0 0 0 1
0 0 a 0

I think the a has to be nonzero in order for the dividing by w to turn into division by z. What do you guys think?

Also, one more thing. Let's say you have a z value of 0. How does OpenGL prevent division by 0? Does it just check if z is 0 and not do anything? (i.e. if you try to plot the point x,y,0, OpenGL won't produce a divide by 0 error)

Mike C.
http://www.coolgroups.com/zoomer
Mike C.http://www.coolgroups.com/zoomer/http://www.coolgroups.com/ez/
Quote:Original post by mike74
Let's say you have a z value of 0. How does OpenGL prevent division by 0? Does it just check if z is 0 and not do anything? (i.e. if you try to plot the point x,y,0, OpenGL won't produce a divide by 0 error)


It is culled/clipped by the near plane.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
The perspective matrix does about 3 things:

1. Elements [0][0] and [1][1] scale the x- and y-coordinates to simulate field of views other than 90.

2. It transforms the z-coordinate so that z-values in the range [near, far] are mapped to [0, far]. In this way, when you divide z later by w, you have 0 <= z' <= w ==> 0 <= z' / w <= 1, which is where it needs to be for depth buffering.

3. It copies the original input z-coodinate into the output w-coordinate for later use by the homogeneous divide.
-----Quat

This topic is closed to new replies.

Advertisement