Learning to Love your Z-buffer. |
the letter 'Z' as "zed" - but Americans pronounce it "zee".
...although that's just to make |
Many of the early 3D adaptors for the PC have a 16 bit Z buffer, some others have 24 bits - and the very best have 32 bits. If you are lucky enough to have a 32 bit Z buffer, then Z-precision may not seem to be an issue for you. However, if you expect your program to be portable, you'd better give it some thought.
The precision of Z matters because the Z buffer determines which objects are hidden behind which others - and if you don't have enough precision to resolve the distance between two nearby objects, they will randomly show through each other - sometimes in large zig-zags, sometimes in stripes.
This is commonly called 'flimmering' or 'Z-fighting' and it's very disturbing to the user.
Some graphics programmers call zNear 'hither' and zFar 'yonder'.
Beginners frequently place zNear at a very short distance because they don't want polygons close to the eye to be clipped against the near plane - and because it isn't obvious why you'd want to do anything else.
Positioning of zNear too close to the eye is the cause of flimmering (in almost every case) - and the remainder of this document explains why that is.
z_buffer_value = (1<<N) * ( a + b / z ) Where: N = number of bits of Z precision a = zFar / ( zFar - zNear ) b = zFar * zNear / ( zNear - zFar ) z = distance from the eye to the object ...and z_buffer_value is an integer.This means that Z (and hence the precision of Z) is proportional to the reciprocal of the z_buffer_value - and hence there is a LOT of precision close to the eye and very little precision off in the distance.
This reciprocal behaviour is somewhat useful because you need objects that are close to the eye to be rendered in great detail - and you need better Z precision for detailed objects.
However, an undesirable consequence of this is that many of your Z buffer's bits are wasted - storing insanely fine detail close to the near clip plane. If you pull the near clip closer to your eye, then ever more bits are dedicated to the task of rendering things that are that close to you, at considerable cost to the precision a bit further out.
It follows that in most cases, flimmering can be greatly reduced - or even eliminated by moving the near clip plane further from your eye.
Instead we have to think about the ratio of distances to objects in your scene to the value of zNear.
This equation applies:
delta = z * z / ( zNear * (1<<N) - z ) Where: N = number of bits of Z precision zNear = distance from eye to near clip plane z = distance from the eye to the object delta = the smallest resolvable Z separation at this range.This equation is approximate - it only applies if zNear is much smaller than zFar - which is true for nearly all applications.
For another way to think about this, suppose we choose to think about the range at which there is a n% error in Z due to the precision of the Z buffer. For ease of discussion, I'll call the ratio of that range to the value of zNear 'Zn%'.
Hence, Z5% is the "range at which there is a 5% error in Z" divided by zNear.
For a 16 bit Z buffer, the value of Z5% is about 3500. It varies *slightly* depending on the value of zFar, and for very small values of zFar, it does get a little bigger - but for practical applications, 3500 is a good rule-of-thumb.
What this means in practice, is that if you place zNear at 1 meter (in whatever units your database uses), then when an object is at 3,500 meters, there will be a 5% error in it's Z value.
For 16 bit Z: Z10% = ~8000 * Z5% = 3500 Z1% = 666 Z0.1% = 66 Z0.01% = 6
The table tell us that value for Z1% is 666 and Z10% is ~8000. So with our 1 meter zNear, we can expect better than 1% precision below 666 meters, better than 5% precision below 3500 meters and better than 10% at under 8000 meters.
Now, if your zNear is at 10cm, you'll see a 5% error at just 350 meters (3500*0.1m)- and out at 3.5km meters, the error will be around 33% - over a kilometer in error. An airplane flying behind a huge mountain could suddenly pop into view in front of it when we are are only a couple of miles away!
You can see that the placement of zNear is really critical in a 16 bit Z system.
For a 24 bit Z buffer, the ratios are 256 times larger so Z1% is ~170,000, and Z5% is about a million.
For a 32 bit Z buffer, even Z1% is about 45 million and we are unlikely to care about Z5% and Z10% metrics!
Some machines offer alternative depth buffering algorithms. These tend to fall into two catagories: