Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does (gl_FragCoord.z / gl_FragCoord.w) represent?

Tags:

opengl

glsl

I want actual world space distance, and I get the feeling from experimentation that

(gl_FragCoord.z / gl_FragCoord.w)

is the depth in world space? But I'm not too sure.

EDIT I've just found where I had originally located this snippet of code. Apparently it is the actual depth from the camera?

like image 885
Engineer Avatar asked Dec 04 '12 20:12

Engineer


2 Answers

This was asked (by the same person) and answered elsewhere. I'm paraphrasing and embellishing the answer here:

As stated in section 15.2.2 of the OpenGL 4.3 core profile specification (PDF), gl_FragCoord.w is 1 / clip.w, where clip.w is the W component of the clip-space position (ie: what you wrote to gl_Position).

gl_FragCoord.z is generated by the following process, assuming the usual transforms:

  1. Camera-space to clip-space transform, via projection matrix multiplication in the vertex shader. clip.z = (projectionMatrix * cameraPosition).z
  2. Transform to normalized device coordinates. ndc.z = clip.z / clip.w
  3. Transform to window coordinates, using the glDepthRange near/far values. win.z = ((dfar-dnear)/2) * ndc.z + (dfar+dnear)/2.

Now, using the default depth range of near=0, far=1, we can define win.z in terms of clip-space: (clip.z/clip.w)/2 + 0.5. If we then divide this by gl_FragCoord.w, that is the equivalent of multiplying by clip.w, thus giving us:

(gl_FragCoord.z / gl_FragCoord.w) = clip.z/2 + clip.w/2 = (clip.z + clip.w) / 2

Using the standard projection matrix, clip.z represents a scale and offset from camera-space Z component. The scale and offset are defined by the camera's near/far depth values. clip.w is, again in the standard projection matrix, just the negation of the camera-space Z. Therefore, we can redefine our equation in those terms:

(gl_FragCoord.z / gl_FragCoord.w) = (A * cam.z + B -cam.z)/2 = (C * cam.z + D)

Where A and B represent the offset and scale based on near/far, and C = (A - 1)/2 and D = B / 2.

Therefore, gl_FragCoord.z / gl_FragCoord.w is not the camera-space (or world-space) distance to the camera. Nor is it the camera-space planar distance to the camera. But it is a linear transform of the camera-space depth. You could use it as a way to compare two depth values together, if they came from the same projection matrix and so forth.

To actually compute the camera-space Z, you need to either pass the camera near/far from your matrix (OpenGL already gives you the range near/far) and compute those A and B values from them, or you need to use the inverse of the projection matrix. Alternatively, you could just use the projection matrix directly yourself, since fragment shaders can use the same uniforms available to vertex shaders. You can pick the A and B terms directly from that matrix. A = projectionMatrix[2][2], and B = projectionMatrix[3][2].

like image 93
2 revs Avatar answered Oct 10 '22 02:10

2 revs


According to the docs:

Available only in the fragment language, gl_FragDepth is an output variable that
is used to establish the depth value for the current fragment. If depth buffering
is enabled and no shader writes to gl_FragDepth, then the fixed function value
for depth will be used (this value is contained in the z component of
gl_FragCoord) otherwise, the value written to gl_FragDepth is used.

So, it looks like gl_FragDepth should just be gl_FragCoord.z unless you've set it somewhere else in your shaders.

like image 22
Xymostech Avatar answered Oct 10 '22 04:10

Xymostech