1
\$\begingroup\$

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);
}
\$\endgroup\$
4
\$\begingroup\$

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

\$\endgroup\$
4
  • 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\$ 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\$ 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\$
    – Krupip
    Sep 12 '19 at 22:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .