I know when we use Z-buffer to eliminate the hidden faces, the polygons can be in any order. But my teacher said that this does not mean that two images generated by sending polygons in different orders will have identical values in their z-buffers and in their frame buffers. How does this happen? And if this is the case, When or how will the z-buffers and the frame buffers have the same values even if polygons are sent in different order?
-
$\begingroup$ TL;DR - the Z-buffer holds the depth of the closest polygon to the camera. At the end of the frame, all other things being equal, the closest poly is the closest poly, so the depth buffer value will be the same regardless of draw order. $\endgroup$– 3DaveCommented Oct 5, 2016 at 22:51
-
$\begingroup$ At the end of the render the frame buffer may contain different values but, provided you haven't played with the Z test mode, the Z buffer should be consistent. $\endgroup$– Simon FCommented Oct 6, 2016 at 11:27
4 Answers
What your teacher means is that at the end of the frame, once all polygons in the scene have been drawn, the z-buffer will have the same values. This is because the z-buffer keeps the minimum Z within each pixel, over all the polygons drawn to that pixel, and the minimum doesn't depend on the order.
If you look at the z-buffer in the middle of the frame, when some polygons, but not all, have been drawn, then naturally the contents of the z-buffer will depend on what's been drawn so far, which would depend on the order in general.
With regard to the color buffer, the same things are true if all the Z values within each pixel are distinct. However there's one case where the results do depend on the order: when multiple polygons have the same Z value at a given pixel. This could happen if the same polygons are rendered twice with different colors, or some such. Then, the behavior depends on the setting of the depth test (i.e. glDepthFunc
in OpenGL). If it's strictly "less", then the first polygon drawn that has the minimum Z will "win" and its color will end up in the color buffer at the end. But if the depth test is set to "less-equal", then each polygon that has the minimum Z will overwrite the one before it, and the last one drawn will end up in the color buffer at the end. So in that case, the order of drawing polygons, and the state of the depth test, do make a difference.
-
1$\begingroup$ I wonder if his teacher was referring to non determinism of the floating point operations? Not sure if that actually happens on the GPU but I could see it possibly happening. A pretty obscure thing though, so maybe not likely what was being talked about? $\endgroup$ Commented Oct 6, 2016 at 2:00
-
$\begingroup$ @AlanWolfe That could happen with a floating-point render target, I suppose. Not sure if it's an issue for integer formats (even with blending). $\endgroup$ Commented Oct 6, 2016 at 2:35
If you use alpha blending, then the order of rendered polygons matters even if you use depth writes & tests. E.g. imagine you render two triangles A (red) and B (blue) with 50% opacity where the smaller triangle B is in front of A. If you render A before B then the B will appear purple, but if you render B before A then B will appear dark blue (pixels for A are not rendered where the triangles overlap).
However, if you use opaque rendering, then the frame buffer values will be the same regardless of the rendering order, except in the special case Nathan mentioned where the depth values are equal for the two triangles.
Only thing where the rendering order matters for the z-buffer result that comes to mind is if you use a specific stencil test & ops. E.g. when rendering A the stencil test passes and writes a value to the stencil buffer which causes B to fail and results in only triangle A being visible. But if you render B before A, then you see B in front of A. This will naturally influence also frame buffer values.
This is the basic implementation of the z-buffer algorithm .
Suppose the depth buffer is a matrix d[][];
for(each polygon P)
{
for(each pixel (X, Y) on the polygon)
{
depth_variable = depth of P at (X, Y);
if(depth < d[X][Y])
{
color_variable = color of P at (X, Y);
set the pixel color at (X, Y) to color_variable;
d[X][Y] = depth_variable;
}
}
}
As we can see while iterating through polygons we only store the new pixel value if the new depth is less (or less than equal to depending on the setting as mentioned by Mr. Nathan Reed) than the stored one in the depth buffer, so it doesn't matter in which order you render the polygons.
The only thing that matters is the fact which polygon has the least depth at a particular pixel.
Though polygons can be sent in any order some polygons may lie in the same plane. Their respective zs can be calculated using the formula z=(-Ax-By-D)/C, and if the two polygon surfaces are at same depth then they can have same value of z.