In a raytracer/marcher, you probably have access to the distance from the ray origin (you camera position) to the closest geometry/intersection point. That distance is

**not**what you want to write to the depth buffer, as hardware rasterizers (OpenGL or DirectX) don't store distances to the camera, but the z of the geometry/intersection point. The reason is that this z value is still monotonically increasing with the distance, but has the property of being linear (linear like in "can be interpolated across the surface of a play 3D triangle). So, in your raymarcher, compute the intersection point, and use its z component for writing to the depth buffer.

Well, that will not work just like that. your api of preference will remap your z values to a -1 to 1 range based on the near and far clipping planes you decided to set up. Furthermore, the remapping will probably also transform your z values to some other sort of scale that exploits the properties of perspective (like with a curve that compresses values in the far distance). So you will have to implement the same remapping in your shader before you can merge your raytraced/marched objects with the rest of the polygons.

The mapping is simple, though, and is normally configured by the projection matrix. Grab your OpenGL Redbook, and have a look to the content of a standard projection matrix. The third and fourth row are what we need, since those are the ones that affect the z and w components of your points when transformed from eye to clip space. So, if ze is the z of your intersection point in camera (eye) space, then you can compute the clip space z and w as

zc = -ze*(far+near)/(far-near) - 2*far*near/(far-near)

wc = -ze

The hardware will then do the perspective division and compute the z value in normalized device coordinates before converting it to a 24 bit depth value:

zn = zc/zw = (far+near)/(far-near) + 2*far*near/(far-near)/ze

which you can see it is a formula of the form zn = a + b/ze which produces the desired depth compression. You can check that the boundary conditions are met, by doing

ze = -near -> zn = -1;

ze = -far -> zn = 1;

Yeah, remember that your depths in camera space are negative inwards the screen. So, our raytracing/marching shader should end with something like

float a = (far+near)/(far-near);
float b = 2.0*far*near/(far-near);
gl_FragDepth = a + b/z;

You probably want to upload

*a*and

*b*as uniforms to your shader.

Alternatively, if you don't want mess with all this, you can directly grab the projection parameters from the projection matrix, and do something like

float zc = ( (ModelView)ProjectionMatrix * vec4( intersectionPoint, 1.0 ) ).z;
float wc = ( (ModelView)ProjectionMatrix * vec4( intersectionPoint, 1.0 ) ).w;
gl_FragDepth = zc/wc;

which is a little bit more expensive, but gives the same results...