Z & Stencil Buffers Explored - Page 1

Published on 24th May 1999, written by Kristof Beets for Consumer Graphics - Last updated: 28th Apr 2007

If you read a lot about video cards, then you have probably
heard about the Z-buffer. For those who don't know what it does, I will
try to explain it here as best as I can.

Z-buffering is the traditional way to determine the visibility of a rendered
pixel. Traditional renderers are triangle-based at the top level. This
means that they will take one polygon (triangle) and render it, then start
on the next one when it is finished and continue rendering them one at
a time in order. The problem with this process is that the renderer doesn't
know whether the polygon being processed is actually visible in the final
frame since it doesn't know what polygons are still to come. To make sure
that only visible pixels end up in the frame buffer, you need some way
of determining what polygons will be visible in the final frame. This
technique is called Z-buffering. Z-buffering means that each rendered
pixel has a corresponding Z-value (depth value). The best way to explain
how all this works is by using an example:

The dark polygon in the figure above is rendered first. This means that
for each pixel of this first polygon, variables such as texture, shading
and fog are processed to determine the color and the result is written
to the frame buffer together with the depth (Z) value of each pixel. When
the second polygon is rendered (light gray one) you can see that it is
touching some of the same pixels as the first polygon. When the white
pixel is processed, a new color and Z-value is calculated and the system
then reads the old Z-value from the Z-buffer and compares that value with
the new one. If the new Z-value is smaller, meaning that it's closer to
the camera, then the old color value is changed into the new one. If the
Z-value is bigger than the old one, then the already written color value
is the correct one and everything remains unchanged. I hope this example
has given you the basic idea of just what Z-buffering does.

Now let's talk about the stencil buffer. The stencil buffer is like a
scratch pad where the system can make notes for itself. Based on these
notes, further effects can be added at a later time. TNT cards have an
8-bit stencil buffer meaning that they can add 256 different flags to
each pixel on the screen. These flags tell the system what to do to the
image, such as rendering an extra effects layer. Now how do we fill those
8 bits with useful info? Well the stencil buffer kicks in at the very
end of the rendering. Special polygons are sent to the hardware and the
3D accelerator calculates the Z-value of all pixels of these special polygons
and compares them with the Z-values already stored in the Z-buffer. This
comparison consists of equations such as bigger than, smaller than, equal
to, etc. Corresponding values are written to the Z-buffer based on the
results of these comparisons. Assume for a moment that the light gray
triangle (above) is a special stencil polygon. Now if we use the comparison
"smaller than", then all the pixels of the dark gray triangle
would be flagged since they are all behind the gray triangle. This is
what the stencil buffer does. Comparisons are made between the values
already available in the normal Z-buffer and new special values for the
stencil buffer polygons. Based on the comparisons, values are written
to the stencil buffer. What can you do with these values? Well they have
several purposed including the ability to turn on or off a certain effect.
Let's say we want to create a fade between two images. This can be done
using the stencil buffer. Using the special polygons and Z-comparisons
you can fill the stencil buffer with the values one and zero. The pixels
with value one should be deleted, the ones with value zero in the stencil
buffer should remain unchanged (a.k.a. as a picture blend). Now all you
have to do is render a black polygon to the screen using a check with
the stencil values and the rule to draw the black polygon for one, and
not draw for zero.