Calculating the z eye-coordinate from the z-buffer value?

The question is, how to do it. What I need is an equation that can calculate the actual z coordinate in eye(camera) coordinates from a z buffer value. This is not as simple as it sounds since the precision i the z-buffer changes over it’s spectrum, i.e. less precision when draw something far away. So if I have say, a near plane at 1.0 and a far plane at 10.0, what actual z-coordinate, in eye-space, would a z-buffer value of 0.5 be?
If someone has the general equation for this or knows where to find it, please post it.

Thanks

From what I know, z buffer values range from 0.0 to 1.0, so a z buffer value of 0.5 in your case would be 4.5. I guess a general equation would be (zFar - zNear) * zBufferValue.

A Z-buffer value of 0.5 does not mean in the middle of the near and far clipping plane, that is if you use perspective projection. In orthographic projection, it does. As Anders mentioned, the Z-buffer values are not linearly spread out in the Z-buffer. So th forumla you gave is correct for orthographic projection, but not for perspective projection.

Yeah, I forgot about that. I don’t have an easy formula off the top of my head, but I can explain how you can derive one. You’ll have to back track through all of the transformations. So if you have a z-buffer range of 0.0 <-> 1.0, get that back to a range of -1.0 <-> 1.0 by subtracting 0.5 and then multiplying by 2.0. Now when you have your new range, then you will have to multiply by the w component of your vertex, which you can calculate by multiplying it by the modelview and projection matrices. I know it’s not a general equation, but I don’t think it would be too hard to figure it out.

[This message has been edited by thebamaman (edited 01-10-2002).]

Since noone gave a clear formula, I sat down with a piece of paper, and came up with this.

// -------------------------------
// n: distance to near clip plane
// f: distance to far clip plane
// z: value in depth buffer
// -------------------------------
double convertZ(double n, double f, double z)
{
// Convert Z from [0, 1] to [-1, 1]
double wz = (2.0 * z) - 1.0;

double a = -(f - n) / (2.0 * f * n);
double b = (f + n) / (2.0 * f * n);

return -1.0 / (wz * a + b);
}

Tried it some times, and it seems to give OK results. You can try using gluUnProject, with an identity modelview matrix. Something like this.

double p[3];
gluUnProject(x, y, z, mv, pr, vp, p+0, p+1, p+2);

x and y can be anything, as long as z is the value from the depth buffer.
mv is the modelview matrix, and should be the indentity.
pr is the projection matrix, and should be the one you get from glPerspective/glFrustum.
vp is the viewport, can be anything, but keep it valid, so the viewport transform doesn’t mess up.

p[2] will hold the result you are after, and if you are lucky, convertZ() should give you the same result.