Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve depth value invariance between two passes?

Tags:

opengl

glsl

I have two geometry passes. In the first pass, I write the fragment's depth value to a float texture with glBlendEquation(GL_MIN), similar to dual depth peeling. In the second pass I use it for early depth testing in the fragment shader.

However, for some fragments the depth test fails unless I slightly offset the min depth value (eps below):

enter image description here

Setting up the texture:

glBindTexture(GL_TEXTURE_2D, offscreenDepthMapTextureId);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG32F, screenWidth, screenHeight);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, offscreenDepthMapFboId);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
  offscreenDepthMapTextureId, 0);

Note that the texture is used as a color attachment, not the depth attachment. I have disabled GL_DEPTH_TEST in both passes, since I can't use it in the final pass.

Vertex shader, used in both passes:

#version 430

layout(location = 0) in vec4 position;

uniform mat4 mvp;
invariant gl_Position;

void main()
{
  gl_Position = mvp * position;
}

First pass fragment shader, with offscreenDepthMapFboId bound, so it writes the depth as color to the texture. Blending makes sure that only the min value ends up in the red component.

#version 430

out vec4 outputColor;

void main()
{
  outputColor.rg = vec2(gl_FragCoord.z, -gl_FragCoord.z);
}

Second pass, writing to the default framebuffer. The texture is used as depthTex.

#version 430

out vec4 outputColor;

uniform sampler2D depthTex;

void main()
{
  vec2 zwMinMax = texelFetch(depthTex, ivec2(gl_FragCoord.xy), 0).rg;
  float zwMin = zwMinMax.r;
  float zwMax = -zwMinMax.g;
  float eps = 0;// doesn't work
  //float eps = 0.0000001; // works
  if (gl_FragCoord.z > zwMin + eps)
    discard;
  outputColor = vec4(1, 0, 0, 1);
}

The invariant qualifier in the vertex shader didn't help. Using eps = 0.0000001 seems like a crude workaround as I can't be sure that this particular value will always work. How do I get the two shaders to produce the exact same gl_FragCoord.z? Or is the depth texture the problem? Wrong format? Are there any conversions happening that I'm not aware of?

like image 736
Andreas Haferburg Avatar asked Nov 12 '22 02:11

Andreas Haferburg


1 Answers

Have you tried glDepthFunc(GL_EQUAL) instead of your in-shader-comparison-approach? Are you reading and writing to the same depth-texture in the same pass?

Im not sure if gl_FragCoord's format and precision is correlated with the one of the depth-buffer. Also it might be a driver glitch, but glDepthFunc(GL_EQUAL) should work as expected.

like image 114
Marius Avatar answered Jan 04 '23 02:01

Marius