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

我只是一个虾纸丫 提交于 2019-11-30 02:28:38

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].

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.

As

gl_FragCoord.w = 1.0 / gl_Position.w

And (likely) your projection matrix gets w from -z (if the last column is 0,0,-1,0) then;

float distanceToCamera = 1.0 / gl_FragCoord.w;
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!