Floating point depth buffers

Published December 31, 2009
Advertisement
I had always thought that using a floating point depth buffer on modern hardware would solve all the depth buffer problems, in a similar way than the logarithmic depth buffer but without requiring any changes in the shader code, and having no artifacts and potential performance losses in their workarounds. So I was quite surprised when swiftcoder mentioned in this thread that he had found that the floating point depth buffer had insufficient resolution for a planetary renderer.

The value that gets written into the Z-buffer is value of z/w after projection, and it has an unfortunate shape that gives enormous precision to a very narrow part close to the near plane. In fact, almost half of the possible values lie within two times the distance of the near plane. In the picture below it's the red "curve". The logarithmic distribution (blue curve), on the other hand, is optimal with regards to object sizes that can be visible at given distance.


Floating point depth buffer should be able to handle the original z/w curve because the exponent part corresponds to the logarithm of the number.

However, here's the catch. Depth buffer values converge towards value of 1.0, or in fact most of the depth range gives values very close to it. The resolution of floating point around 1.0 is entirely given by the mantissa, and it's approximately 1e-7. That is not enough for planetary rendering, given the ugly shape of z/w.

However, the solution is quite easy. Swapping the values of far and near plane and changing the depth function to "greater" inverts the z/w shape so that it iterates towards zero with rising distance, where there is a plenty of resolution in the floating point.

I've also found an earlier post by Humus where he says the same thing, and also gives more insight into the old W-buffers and various Z-buffer properties and optimizations.

Update


I tried to compute the depth resolution of various Z-buffers for whole range from 0 to 10,000 kilometers. Here's the result (if I didn't make a mistake), showing the resolution at given distance (lower is better):




The red curve shows resolution of the logarithmic Z-buffer. It scales linearly with distance, what means that in the screen space it's constant. That's also the ideal behavior.

The blue curve shows the resolution of 32 bit floating point depth buffer with swapped far and near plane. The spikes are formed with each decrement of the exponent. Floating point depth buffer has worse resolution than the logarithmic one, but it should be still sufficient. The green line is for an ideal Z-buffer that has depth resolution of 0.12 millimeters at one kilometer. It also happens to be the worst case bound for the floating point depth buffer.
0 likes 4 comments

Comments

patrickvl
Did you notice InfinityAdmin / Ysaneya quoted you, and instead proposes a much simpler solution?
See
Tip of the day: logarithmic zbuffer artifacts fix
for more details.
January 05, 2010 07:06 AM
patrickvl
How does this compare to your previous post on the Logarithmic Depth Buffer, and Ysaneya's ideas on the subject?
January 05, 2010 07:24 AM
cameni
Quote:Original post by patrickvl
How does this compare to your previous post on the Logarithmic Depth Buffer, and Ysaneya's ideas on the subject?
I haven't tested it thoroughly yet, but as far as I can tell the floating point depth buffer with the reversed planes should be almost on par with the logarithmic one with respect to the resolution. It's also simpler to use, without bringing in the near-plane artifacts or eliminating fast-z by writing the depth in pixel shader as in the workaround.
But I shall test it more complexly later, and I also hope someone will evaluate it in their environment too.
January 05, 2010 01:20 PM
swiftcoder
I will slap this into my planetary renderer once I get back home - would likely simplify my codebase quite a bit.
January 10, 2010 07:53 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement