# 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. – Andrew Wilson Jul 21 '17 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? – Ankit singh kushwah Jul 22 '17 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 '17 at 13:37