Logarithmic depth buffers seem to be gaining wider adoption with our customers lately. The idea stemmed from an article by Outerra on how they preserved depth resolution at both near and far distances. Like Outerra, many of our customers need to render something like a cockpit close to the eyepoint, while at the same time rendering distant terrain hundreds of kilometers away. Conventional depth buffers cannot handle such a wide difference between your near and far clip planes, without producing artifacts from depth buffer resolution (“z-fighting.”)
While Outerra’s original article on log depth buffers covered the basic idea, it wasn’t refined until 2013 in this update. This newer article is much more explicit about what needs to go into your vertex programs in order to change how your depth buffer values are written, and it produces good results. All you have to do is add this snippet of code, plus one uniform value, into all of your vertex programs (and maybe a few of your fragment programs, too.)
Sounds simple enough – until you realize you also need to get any middleware you’re using to also write depth values in this manner. Fortunately, the extensible shader framework in the SilverLining Sky, 3D Clouds, and Weather SDK and the Triton Ocean SDK let you do this without too much trouble.
Make sure you’re using at least SilverLining version 4.004 and Triton version 3.28, as those are the versions that have what you need.
In Triton, there is a user-vert-functions.glsl file in the Resources folder of the SDK. At the bottom, you’ll find this function:
// Provides a point to override the final value of gl_Position.
// Useful for implementing logarithmic depth buffers etc.
vec4 overridePosition(in vec4 position)
This gives you a hook to adjust the final clip positions on everything Triton draws, so this is where you want to adjust the depth value. If you’re going by Outerra’s algorithm, it would look like this:
vec4 overridePosition(in vec4 position)
{
vec4 adjustedClipPosition = position;
if ( Fcoef > 0.0 )
{
adjustedClipPosition.z = (log2(max(1e-6, position.w+1.0))*Fcoef - 1.0) * position.w;
}
return adjustedClipPosition;
}
Fcoef needs to be added as a uniform at the top of user-vert-functions.glsl:
uniform float Fcoef;
According to the paper, Fcoef = 2.0 / log2(farplane + 1.0). So your application needs to set this uniform whenever your far clip distance changes. Triton gives you access to its underlying shader programs via the Triton::Ocean::GetShaderObject() method (there are several different programs you’ll need to retrieve,) which you may then use with glGetUniformLocation and glUniform1f to set the Fcoef uniform in each program.
In SilverLining, it’s the same idea. The Resources/Shaders/UserFunctions.glsl file also contains a overridePosition() function you may use in the same manner. The only difference is in how you retrieve the shader program ID’s for setting the Fcoef uniform from your application. In SilverLining, you’ll use the GetSkyShader(), GetBillboardShader(), GetBillboardShaderInstanced(), GetStarShader(), GetPrecipitationShader(), and GetActivePlanarCloudShaders() methods on SilverLining::Atmosphere to retrieve all of the relevant program ID’s.
Depth buffer resolution is especially a problem when you have water approaching coastlines in the distance, as so many of our customers do – even if you’re using height maps with Triton to help with this. I hope this article gives you a good way to solve that problem, if you’re faced with it.