The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Message from discussion 3D position to transformed depth value.

From:
To:
Cc:
Followup To:
Subject:
 Validation: For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon.

More options Oct 31 2012, 6:23 pm
Newsgroups: comp.graphics.api.opengl
From: Nobody <nob...@nowhere.com>
Date: Wed, 31 Oct 2012 22:23:49 +0000
Local: Wed, Oct 31 2012 6:23 pm
Subject: Re: 3D position to transformed depth value.

On Tue, 30 Oct 2012 23:56:30 +0000, VelociChicken wrote:
>> Also, it's not linear, it's reciprocal; specifically: a+(b/z), where a and
>> b are such that the near and far planes map to -1 and +1 respectively.

> So I can't get the real distance to a point without 'unprojecting' it?

It's easier to just keep an unprojected copy, i.e. as well as:

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

position = gl_ModelViewMatrix * gl_Vertex;

In theory, it's possible to reconstruct the latter from gl_FragCoord,
gl_ProjectionMatrix and the viewport (which isn't available via a built-in

If you do want to reconstruct it from gl_FragCoord, gl_FragCoord.w is the
reciprocal of the interpolated value of gl_Position.w, which will normally
just be the negative of the unprojected z coordinate (the standard
perspective matrix has [0 0 -1 0] in the bottom row).

So, for the standard gluPerspective() matrix:

nx = 2 * (gl_FragCoord.x - viewport_x) / viewport_width - 1;
ny = 2 * (gl_FragCoord.y - viewport_y) / viewport_height - 1;
nz = 1.0/gl_FragCoord.w;
x = nz * nx * aspect / f;       // f = 1/tan(fovy/2)
y = nz * ny / f;
z = -nz;
distance = length(vec3(x,y,z));

Note that zNear and zFar aren't relevant, as we're using gl_FragCoord.w
rather than gl_FragCoord.z.