12
\$\begingroup\$

I read the response here:

What does the graphics card do with the fourth element of a vector as the final position?

"The fourth component is a trick to keep track of perspective projection. When you do a perspective projection, you want to divide by z: x' = x/z, y' = y/z, but this isn't an operation that can be implemented by a 3x3 matrix operating on a vector of x, y, z. The trick that has become standard for doing this is to append a fourth coordinate, w, and declare that x, y, z will always be divided by w after all transformations are applied and before rasterization. "

but I didn't understand why couldn't we divide by z using a 3x3 matrix?

can't we just multiply by

1/z 0 0
0 1/z 0
0 0 1/z

to get [x/z y/z 1]

?

\$\endgroup\$
  • \$\begingroup\$ Try to express a transformation (or composition of transformations) that includes translation somewhere in the chain. Without a w value, you can't express it in a single matrix. \$\endgroup\$ – DMGregory Jul 9 '15 at 19:50
  • \$\begingroup\$ I do understand the translation part but I just didn't understand how adding a fourth coordinate will help or is a a trick to divide by z \$\endgroup\$ – nevermind Jul 9 '15 at 20:18
  • \$\begingroup\$ For what it's worth you totally can do what you said. Dividing x and y by z is a valid method for converting from 3d coordinates to a 2d screen space with projection where distant objects get smaller. The w is a homogeneous coordinate to take it up to the fourth dimension to be able to do translation. \$\endgroup\$ – Alan Wolfe Jul 10 '15 at 3:07
15
\$\begingroup\$

Because if you only divide [x, y, z] by z you get [x/z, y/z, 1] and you lost the actual value of z, which is actually useful if you want to do near/far plane clipping or fill a Z-buffer.

The best way to keep some information about z, at least on the GPU, is therefore to use 4 components instead of 3. In practice, what is actually in the last two vector components before the perspective division depends on what kind of projection and effects you want.

For instance, in the case of a perspective projection, this is the resulting 4-component vector:

| a 0 0 0 |   | x |   |   ax   |
| 0 b 0 0 |   | y |   |   by   |
| 0 0 c d | × | z | = | cz + d |
| 0 0 1 0 |   | 1 |   |    z   |

After perspective divide the vector becomes:

|  ax/z   |
|  by/z   |
| c + d/z |
|    1    |

And the c + d/z part leaves us with enough information to fill the Z buffer.

\$\endgroup\$
  • \$\begingroup\$ You could divide only the X and Y by Z, yielding [x/z, y/z, z]. The GPU doesn't have to do vector division, it could have been designed to do any calculation. \$\endgroup\$ – immibis Jul 10 '15 at 2:59
4
\$\begingroup\$

Technically, you could do that. But why bother? By the time you have that final z, you could either:

  • construct a 3x3 matrix as you described, wasting 9 * sizeof(float) bytes of space, spending cycles to compute 1/z (one division) and then doing nine multiplies and six adds to get your final vertex, or
  • you can do three divisions, as the modern pipeline currently does

One of these seems far more optimal to me, and it's not the first one. Even if optimized hardware exists for the matrix multiply, as it most certainly does, it's still conceptually more complex than a simple division.

Plus, a 3x3 matrix cannot encode a translation, and so a 4x4 matrix (and thus the fourth w coordinate) is used earlier in the pipeline anyway. This means you already have that fourth component sitting there so you may as well use it to transport a useful value and do your division with it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.