I am trying to write a simple GLSL shader that just renders the real (not normalized) depth of a fragment as a floating point value.

So far, I've figured out how to get the depth of a vertex, and just interpolate across the fragments, but I'm starting to realize that this is not going to give me the correct depth of each fragment, is it?

Here's what I have so far:

Vertex shader:

uniform mat4 world;
uniform mat4 view;
uniform mat4 projection;
attribute vec3 position;
attribute vec3 color;
varying float distToCamera;
void main()
    vec4 cs_position =  view * world * vec4(position, 1.0);
    distToCamera = -cs_position.z;
    gl_Position = projection * cs_position;

Fragment shader:

varying float distToCamera;

void main()
    gl_FragColor = vec4(distToCamera, distToCamera, distToCamera, 1.0);

Yes, your Z value, distToCamera, will be correct at each triangle's vertices, but won't be anywhere else (except between vertices of matching Z-value), because of linear interpolation.

Edit: In current GLSL, the default interpolation is "in perspective", where gl_Position/gl_FragCoord is taken into account for interpolating. This can be overridden (you won't want to for your case) as a type qualifier, like:

noperspective out float distToCamera;  // vertex shader
noperspective in float distToCamera;  // fragment shader

Alternatively, you can get it recover it from gl_FragCoord...

In a fragment shader, gl_FragCoord contains (x, y, z, 1/w) in window coordinates. x, y, and z have already been divided by w.

So, you can recover your vertex shader output, gl_Position.z, interpolated correctly in 3d, as

float originalZ = gl_FragCoord.z / gl_FragCoord.w;

(Depending how you've done your vertex shader projection matrix, this might not be your world Z, of course.)

| improve this answer | |
  • 1
    \$\begingroup\$ perfect. I didn't know I could simply divide by w to get it back from normalized coordinates! \$\endgroup\$ – mklingen Jan 28 '15 at 23:18
  • 1
    \$\begingroup\$ ...dividing by (1/w)... :-) \$\endgroup\$ – david van brink Jan 28 '15 at 23:19
  • \$\begingroup\$ I may need to retract or amend this answer -- I think your original approach may work fine, distToCamera (or same as fragcoord.z/fragcoord.w). The default interpolation in current GLSL is, indeed, perspected. On my own test shader, interpolating across viewPosVarying.xyz gives nice straight depth lines. (I use gray=z - floor(z) to visualize the lines.) \$\endgroup\$ – david van brink Jan 28 '15 at 23:30
  • \$\begingroup\$ This does not appear to work, even in the cause this absolutely should (orthogonal projection matrix). Setting an output variable to my fragment shader out vec4 Position; to Position = mvp_matrix * vec4(vertex, 1.0); and checking against depth of anothe rpoint which another matrix with the same projection works (comparing both z values to get vertexes drawn in behind several transparent objects to not draw), when I try to derive Position from gl_FragCoord.z / gl_FragCoord.w; it isn't the same value. Not sure what the deal is. \$\endgroup\$ – whn Sep 12 '19 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.