# Is placing z value of vertex in w enough to achieve perspective projection in OpenGL?

I have been learning about projection matrix in OpenGL and I am finding it really hard to understand. All I know is that there are other configurations in the projection matrix besides placing z in w for perspective projection. What are those other numbers and why are they there? Thanks.

• Considering (0, 0) as the center of the screen. If we divide any point we want to place on that screen by z it will get infinitely closer to (0, 0). This creates that vanishing effect. Farther back it goes, the larger the z, the more it vanishes. This is essentially what perspective projection is doing despite all the confusing notation, matrices, and what not. It also handles all the other transformations. Certain scalings and translations must be applied to get a point into screen coordinates. Jul 21, 2017 at 21:29

The projection matrix distorts the view frustum (the volume the camera can see) into a unit cube. So everything with all coordinates in the range -1 to 1 after projection is potentially visible, and everything else can be clipped.

To make things further away look smaller, we need to divide by their Z distance. We can't put this value directly into the matrix since it is different for each point we want to project, so instead we place each point's Z into its projected W, giving (X, Y ,Z ,1) -> (X', Y', Z', Z), known as clip coordinates. This is then divided by the new W to give (X'/Z, Y'/Z, Z'/Z, 1), known as normalized device coordinates. On the GPU this division happens automatically after the vertex shader and before clipping and rasterization.

The general form of a projection matrix is

A 0 0 0
0 B 0 0
0 0 C D
0 0 1 0


The A and B terms relate to the field of view, higher values give a narrower view. Specifically, B is the cotangent of half the vertical view angle, and A is B/aspect ratio.

The C and D terms are bias and scale terms which map the near plane to -1 (0 in DirectX), and the far plane to 1. These are used for writes to the depth buffer to determine which objects occlude others. The depth mapping is actually a function of 1/Z, rather than Z, since this gives better precision close to the near plane, and allows perspective-correct interpolation.

Also note that in OpenGL, W' is -Z rather than Z, since we are using a right-handed coordinate system, with negative Z pointing into the screen.

• Thanks for the answer. tell me If I am wrong here that we map frustum ranges to [-1,1] because OpenGL expects them to be in that range(because OpenGL performs clipping) so that clipping can occur properly. Am I correct? Jul 22, 2017 at 11:19
• That's about right. The clipping occurs in automatic hardware on the GPU, so it's broadly the same across different graphics APIs. Some specify -1 for the near plane and some specify 0. 0 is actually better for depth precision, for reasons Nathan Reed explains at reedbeta.com/blog/depth-precision-visualized
– russ
Jul 22, 2017 at 13:37
• @russ thanks for this concise and clear answer. One point I would like clarification on - Suppose I have a small mesh, say a cylinder. Are the occluded faces of this cylinder outside the unit cube after projection? Basically I am trying to map (x,y) touchscreen space on a mobile device to find the point in 3d space visible to the camera - however I am trying to ignore points that the camera doesn't see. Are you saying I can test for visibility of a vertex in the vertex shader by checking to make sure the bounds for XYZ are all -1 to 1 after projection? Sep 15, 2021 at 19:40