ZBuffering is a very handy graphics algorithm. Invented by Catmull in '79, it allows us to paint objects to the screen without sorting, without performing intersection calculations where objects interpenetrate, to paint in whatever order we like, and to paint any kind of object we like. But there is one big problem with it: unless in hardware, its slow and inefficient. But you might as well add it to your engine, its very useful. A ZBuffer type system is also used in Radiosity, if you are calculating form-factors in the hemicube algorithm.
[size="5"]How It Works
The basic idea behind zbuffer is very simple: If the pixel we are currently painting is the closest yet painted, write it. If not, don't write it. To identify if the pixel is the nearest, we need a memory buffer - the Z buffer. Here we store the Z of each pixel painted so far. Pseudo-code for a naive implementation of this would be:
Clear Z-Buffer to a certain value
For every polygon
For every scanline of that polygon
For every pixel
If this is nearest pixel {
Write Pixel
Write Z into zbuffer
}
End
End
End
Note that we needn't be using solely polygons. The implementation could equally be:
Clear Z-Buffer to a certain value
For every primitive
For every scanline of that primitive
For every pixel
If this is nearest pixel {
Write Pixel
Write Z into zbuffer
}
End
End
End
However, there are four main problems with the z-buffer:
- Clearing the zbuffer
- Re-writing pixels that have already been written (overdraw)
- Z-compression with distant objects
- Jumping at every pixel!
[size="5"]Improvements
There are a number of improvements we can make to the z-buffer algorithm. The first is to use 1/z values. Such values are linear in screen space, are always in the range -1 to +1, and do not suffer from z-compression. Clearing the zbuffer simply becomes a case of memset(zbuffer, 0, zbuffersize), because 0 in floating point is 00000000h. We must however invert our condition, from:
If CurrentZ <= ZBuffer[y][x]
To:
If CurrentZ >= ZBuffer[y][x]
The penalty of clearing the Z-buffer can be improved with dirty rectangles. The idea behind this is that you just clear the part of your screen (and Z-buffer) that you have written to. However, this is not much use if you're doing full screen animation. Alternatively, you can try adding some value to your Z every frame. Eg if you are using a 32-bit integer zbuffer, try adding on a value greater than the far clipping limit; for example 65536. Apparently, using this technique, you can avoid clearing the frame buffer. I think pseudo code would go something like:
// Init Stuff...
zadd = 0
ClearZBuffer()
for(;;) { // Render loop
Project, Transform, Light Polygons etc...
Clear Screen
Add "zadd" to every Z value to be interpolated
Render to zbuffer
Add 65536 to zadd
if zadd overflows {
ClearZBuffer
zadd = 0
}
}