# Projection Matrix

This topic is 5200 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I need to build the projection matrix (with a fov value) to transform my geometry in a software renderer. I'm using a right-handed coordinate system. The x, y values need to be clamped to [-1,1] and the z values need to be clamped to [0,1]. The result of the transformation is completely wrong and I really don't understand why... With a far plane at 10000 and a near plane at 1, a z values of about 5000 should be transformed into ~= 0.5, right? The matrix I build is: w 0 0 0 0 h 0 0 0 0 q qn 0 0 -1 0 with: q = -zFarPlane/(zFarPlane-zNearPlane) qn = -zFarPlane*zNearPlane/(zFarPlane-zNearPlane) Here are the 2 functions I wrote that build the projection matrix and transform a 3D Vector:
Matrix4 Matrix4::Perspective(real32 fov, real32 aspectRatio, real32 zNearPlane, real32 zFarPlane)
{
Matrix4 mat;
real32 fHeight = 1.0 / tan(DEGTORAD(fov) * 0.5);
real32 fWidth = fHeight / aspectRatio;

mat._00 = 2.0*zNearPlane/fWidth;
mat._01 = 0.0;
mat._02 = 0.0;
mat._03 = 0.0;

mat._10 = 0.0;
mat._11 = 2.0*zNearPlane/fHeight;
mat._12 = 0.0;
mat._13 = 0.0;

mat._20 = 0.0;
mat._21 = 0.0;
mat._22 = -zFarPlane / (zFarPlane-zNearPlane);
mat._23 = -zFarPlane*zNearPlane / (zFarPlane-zNearPlane);

mat._30 = 0.0;
mat._31 = 0.0;
mat._32 = -1.0;
mat._33 = 0.0;

return mat;
}

inline Vector3 Matrix4::Transform(const Vector3& v) const
{
Vector3 vecNew;

real fInvW = 1.0 / (m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3]);

vecNew.x = (m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3]) * fInvW;
vecNew.y = (m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3]) * fInvW;
vecNew.z = (m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]) * fInvW;

return vecNew;
}


Any help would be greatly appreciated! Thanks [Edited by - Deckards on July 28, 2005 9:39:12 AM]

##### Share on other sites
This word document describes how the OpenGL projection matrix is calculated. It may contain useful information...

Tom

##### Share on other sites
Thanks the link. My matrix is a bit different from the OpenGL one because I need to clamp the Z values to [0.1] instead of [-1,1].
Unfortunately, I still don't understand why my results are wrong :(

##### Share on other sites
Quote:
 Original post by DeckardsWith a far plane at 10000 and a near plane at 1, a z values of about 5000 should be transformed into ~= 0.5, right?

This may be the source of your confusion: the world Z values are not mapped linearly into [0,1] space. Generally most of the [0,1] range will be taken up by the area very near to the camera. I haven't done the math for this case but I wouldn't be surprised if the Z buffer value at 5000 ends up > .99. What actual value did you get?

Your functions look correct from a cursory glance.

##### Share on other sites
Quote:
 Original post by ganchmaster This may be the source of your confusion: the world Z values are not mapped linearly into [0,1] space. Generally most of the [0,1] range will be taken up by the area very near to the camera.

Yes, the Z values aren't mapped linearly into [0,1] space, but as [0,1] is the view volume between the near and far plane, all the vertices that have a Z value in the [near,far] range should have their transformed value in the [0,1] range, right?

I get the following homogeneous values with those properties:
near=0.1 far=10000 fov=90 aspect=1.33
Those are negative values because the camera looks down the Z axis.

-10000 -> 1.0
-5000 -> 0.99
-5 -> 0.98
-2 -> 0.95
-0.1 -> ~0

[Edited by - Deckards on July 28, 2005 11:11:19 AM]

##### Share on other sites
Quote:
 Original post by DeckardsYes, the Z values aren't mapped linearly into [0,1] space, but as [0,1] is the view volume between the near and far plane, all the vertices that have a Z value in the [near,far] range should have their transformed value in the [0,1] range, right?

Yeah, that is correct. So I guess what I stated earlier is not the problem.

It looks like the sign of your mat._23 term is incorrect. Usually people have +1 as the _32 parameter, and the signs of the _22 and _23 terms are + and -, respectively. Since you have -1 as _32, probably the signs of _22 and _23 should be - and +.

##### Share on other sites
Quote:
 Original post by DeckardsI get the following homogeneous values with those properties:near=0.1 far=10000 fov=90 aspect=1.33Those are negative values because the camera looks down the Z axis.-10000 -> 1.0-5000 -> 0.99-5 -> 0.98-2 -> 0.95-0.1 -> ~0
Those values are correct. Read this.

From the calculator on that page, with a 24 bit depth buffer...
z-distance     value      value scaled to [0,1]10000          16777216   1.00000005960464832810451555875045000           16777048   0.999990046023729206545901688689095              16441836   0.980009852648368635676421861435292              15938514   0.950009521842570414696360510370760.1            0          0.0
Your near value is way too close, push it out as far as possible.

EDIT: There's a slight bug (rounding bug I assume) in that calculator, the max value for 24-bits is 16777215, that's why the scaled value for 10000 is slightly larger than 1.0

##### Share on other sites
Thank you very much!
I thought those values were weird but thanks to this calculator, I now undersand that it was alright :)

[Edited by - Deckards on July 30, 2005 4:47:31 PM]

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 16
• 9
• 15
• 9
• 11