[References]
1. "gl_FragCoord, from stackoverflow.com and OpenGL 4.3 core profile specification"
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
is1 / clip.w (Always 1/clip.w in fragment shader.)
- where
clip.w
is the W component of the clip-space position (ie: what you wrote togl_Position
).
gl_FragCoord.z
is generated by the following process, assuming the usual transforms:- Camera-space to clip-space transform, via projection matrix multiplication in the vertex shader.
clip.z = (projectionMatrix * cameraPosition).z
- Transform to normalized device coordinates.
ndc.z = clip.z / clip.w
- Transform to window coordinates, using the
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
andB
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
andB
terms directly from that matrix.A = projectionMatrix[2][2]
, andB = projectionMatrix[3][2]
.
...
[References]
You can refer to chapter 2.13 "Coordinate Transformations" of OpenGL specs, and to the fact, that gl_FragCoord.w in fragment shader is always 1/clp_w.
The path of eye_z in pipeline is as follows:
1. from eye-space to clip-space: clp_z = (gl_ProjectionMatrix * eye_pos).z;
1. from clip-space to normalized device coordinates: ndc_z = clp_z/clp_w;
2. from ndc to window space: wnd_z = ndc_z * (dfar-dnear)/2 + (dfar+dnear)/2, where dfar and dnear are parameters from glDepthRange and mostly equal to 0 and 1, so for simplicity let's assume gl_FragCoord.z = wnd_z = (clp_z/clp_w)/2 + 0.5. Thus, when you divide this by gl_FragCoord.w (which is equal to multiply by clp_w) you will get clp_z/2 + clp_w/2;
Now let's have a look at what is clp_z and clp_w. If you look at projection matrix, and especially at it's 3rd row (which is responsible for calculation of clp_z), it's clearly seen that clp_z is the product of scale and shift operations upon eye_z: from [eye_near..eye_far] range to [-1..1] range, while clp_w is equal to -eye_z (4th row); That way, you can write your equation (clp_z/2 + clp_w/2) as: (A*eye_z + B)/2 - eye_z/2 = C*eye_z + D - which is not equal to eye_z in common case, but is linear combination of it with constant coefficients.
So you can use it as a measure to compare depths, or as a parameter in any formula that have linear dependency from eye_z and etc., but not as direct measure of eye_z. For that purpose you need inversion of projection matrix, or simply store eye_z in vertex shader and send it to fragment shader as a varying;
....
...
No comments:
Post a Comment