z = log(C*z + 1) / log(C*Far + 1) * wWhere C is constant that determines the resolution near the camera, and the multiplication by w undoes in advance the implicit division by w later in the pipeline.
log(C*Far + 1) Res =  2^n * C/(C*x+1)
1m 10m 100m 1km 10km 100km 1Mm 10Mm  C=1 1.9e6 1.1e5 9.7e5 0.001 0.01 0.096 0.96 9.6 [m] C=0.001 0.0005 0.0005 0.0006 0.001 0.006 0.055 0.549 5.49 [m]
Tyler Glaiel 
12 Aug 2009 at 3:08 pm PST

I'd love to see what it looks like as the camera flys forward at high speed across the terrain.
I was considering something like this once. Is there an easy way to add this into traditional graphics libraries like opengl or directx via a shader? 


Brano Kemen 
There's an older video with the terrain at http://vimeo.com/2385874
The code for logarithmic zbuffer is easy to add to shaders, it's actually the oneline expression mentioned above. 


Stephen Northcott 
There is another method which I discuss here, based on an article I link to also..
http://www.arcnebula.com/devBlog/2008/07/howtosetthenearclip pingdistancetozero2/ That method is great, except when your viewpoint passes into surfaces.. But in planet and landscape rendering engines it's fairly easy in my experience to isolate those as special cases. 


Aurelio Reis 
This is a nice way to go about it but keep in mind that modifying depth values in a shader has the potential to dramatically degrade performance due to the way in which the graphics pipeline rejects pixels early.
Extending this to work by just modifying the projection matrix would make it immensely more useful. Thoughts? 


Brano Kemen 
This method modifies the depth in vertex shader, just after you multiply the position with modelviewproj matrix, so that's OK from the performance point of view.
However there are artifacts near the camera when one or more face vertices lie behind the near plane. The problem is not so much in the values of Z being negative  lower C linearizes the function well enough so that this would not be problem. Problem is that the rasterizer interpolates Z/W and 1/W linearly and computes perpixel z by dividing the two values. It does this to obtain perspective correct values. The value written to Zbuffer could be a different thing from this all, but actually it's taken from this. Anyway, the problem is that we are premultiplying Z with values of W at the vertices, to get rid of inherent 1/W. Basically then, even when the logarithmic function is linear enough in +200m range, we are also linearly interpolating between values of W. But since the rasterizer interpolates 1/W, the corresponding values of W are quite different there. I'm using the pixel shader computed depth (which may impair the performance by disabling earlyZ and hierarchicZ) only for the objects intersecting the near plane. But I didn't see any slowdown in my app anyway. 


Thatcher Ulrich 
This is a great post.
There's a formulation I like a little better, which is: z = log(z / zn) / log(zf / zn) That keeps relative precision constant through the whole zn to zf range, which is how I'm used to thinking about it. 

