0
\$\begingroup\$

I have trouble applying early depth test in my engine, to prevent fragment shader to be (fully) executed for fragments that will be overwritten anyway, because other fragments, drawn later, will be in front of them.

First, I do a depth only pass and write its result to a texture. This step seems correct (I already use it for SSAO).

Second, I do the main rendering pass. Here, each fragment shader begins by comparing the current depth value to the early depth test value, every fragment being further than the early depth test value being discarded.

My implementation (see below) makes me loose performance, and wrongly discards fragments depending of the epsilon used to compare the depth values. Any idea of what I do wrong?

I use OpenGL 3.3, in a forward rendering engine.

Relevant fragment shader code:

float linearize_depth(float depth,float near,float far)
{
  float ndc = depth * 2.0 - 1.0;
  float linearDepth = (2.0 * near * far) / (far + near - ndc * (far - near));
  return linearDepth;
}

void earlyDepthTest(vec2 fragPos, vec2 screenRes)
{
  vec2 res = gl_FragCoord.xy / vec2(800, 800); 

  float earlyDepthNormalized = linearize_depth(texture(cameraDepthMapTexture, res).r, 0.1, 1024.0);
  float currentDepthNormalized = linearize_depth(gl_FragCoord.z, 0.1, 1024.0);
  float depthDifference = currentDepthNormalized - earlyDepthNormalized;

  if(depthDifference > 0.1)
    discard;
}

void main()
{
  earlyDepthTest(gl_FragCoord.xy, vec2(800, 800));
  
  // All fragment shader processing
}
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

It sounds like you're using a technique called "Z pre-pass".

This is usually not implemented in the fragment shader. Instead, we re-use the depth buffer from the first depth-only pass as the depth buffer for the actual rendering pass. (ie. make sure you don't clear the depth between passes, or that you copy the old depth buffer over if you're rendering to a new destination)

We then set the render state's depth test, something like...

glEnable(GL_DEPTH_TEST);  
glDepthFunc(GL_LEQUAL);  

This is enough for the rasterization pipeline to perform the depth threshold on our behalf, before the fragment shader is even invoked, and abort further processing of whole 2x2 quads of fragments that end up being occluded.

Note that if your fragment shader outputs a modified depth (using gl_FragDepth), that can disable early depth testing, since the GPU doesn't know the depth it should use for testing until after the fragment shader runs.

\$\endgroup\$

You must log in to answer this question.

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