depth buffer values


I’m reading the depth buffer to enable me to calculate the range to any pixel in the screen. I’m want to ajust the z values from [0,1] to real-world depths. I can then multiply these by the corresponding precomputed scale factor to give the range. Can anyone tell me how these depth buffer values could be adjusted to real-world depths? Am I right to assume that 0.0 is coincident with the near clipping plane and 1.0 with the far clipping plane - thus I simply need to multiply by (far-near)?

// read the depth map from the framebuffer normalizing on the way
glPixelTransferf(GL_DEPTH_SCALE, 1.0);
glPixelTransferf(GL_DEPTH_BIAS, 0.0);
glReadPixels(x, y, dx, dy, GL_DEPTH_COMPONENT, GL_FLOAT, depthMap);

Cheers for any pointers.

[This message has been edited by thelamberto (edited 07-22-2002).]

I’m pretty sure that’s the way it works.


no, that’s not how it works. the depth map is exponential, not linear.

ie, the values from near to far are stored like

z’ <- (z-n)/(f-n)

so, z` becomes 0 when z == n and it becomes 1 when z==f, but it doesn’t become 0.5 when z=(f+n)/2

you’ll need to compute the reverse of the projection matrix (found in the back of the red book), or use gluUnProject (which does this for you).


Originally posted by john:
[b]… the values from near to far are stored like

z’ <- (z-n)/(f-n)

so, z` becomes 0 when z == n and it becomes 1 when z==f, but it doesn’t become 0.5 when z=(f+n)/2

Hmmm, you’d better go back and relearn algebra. If z = (f+n)/2 and z’ = (z-n)/(f-n), then z’ = 0.5

you’re right.

hmm. maybe i was thinking of something else, then, without thinking it through properly


you’re right about the poorly thought out analogy. but, then it clicked. z’ is divided by w’ when stored in the depth buffer, yes? Maybe it isn’t. I’m pretty sure it is, in which case:

octave:1> f=10
f = 10
octave:2> n=10
n = 10
octave:3> f=100
f = 100
octave:4> z=55
z = 55
octave:5> za=-(fn)/(f-n)-(2.0f*n)/(f-n)
za = -33.333
octave:6> zb=-z
zb = -55
octave:7> za/zb
ans = 0.60606

Hi Guys,

I think I’ve nailed it - the transformation is not linear. Many thanks to Kevin Dennen for pointing this out.

By Kevin Dennen
Taken from “The Hidden Charms of Z-buffer” by Kurt Akeley, IRIS Universe ( 11 )

dcp = FarClip - NearClip
scp = FarClip + NearClip
a = -1.0 * ( FarClip * NearClip / dcp )
b = scp/ ( 2.0 * dcp ) + 0.5

ans = a / ( zval - b )

Depending on your far and near clip values, you may not see a big change until the 0.9## decimal values as this transformation is not linear. For example:
for Near Clip = 10 and Far Clip = 10000, zval =0.9 range = 99.1
zval =0.99 range = 909
zval = 0.999 range = 5002

[This message has been edited by thelamberto (edited 07-23-2002).]

Also got this:

From “ABCs of th Z-Buffer”, published Jan/Feb 1991, Pipeline Volume 2, Number 1, Revision 1.1.

When the projection matrix is defined by

    perspective (fovy, aspect, near, far);

and the z viewport transformation is defined by

    lsetdepth (near  ,far  );
                       vp    vp

then z    and z       are related by the following:
      eye      screen

                              far near(far   - near  )
                                           vp       vp
                                    far - near
z    = ------------------------------------------------------------------
 eye             (far + near) (far   - near  )     far   + near
                                       vp       vp            vp       vp
       z       - -----------------------------  -  --------------
        screen          2 (far - near)                           2

Most of the time far_vp and near_vp are 1 and 0 respectively so equation simplifies to that posted above. Remember z is negative into the screen and this is “corrected” in the previous post.

EDIT: Equation got messed up - sorted.

[This message has been edited by thelamberto (edited 07-24-2002).]