openglglslnvidiaatishadow-mapping

Shadow acne on Nvidia graphics card


A partner and I are working on a small demo in OpenGL. We are doing simple shadow mapping. He uses an ATI and Intel HD graphics 4000 and everything works fine. I use a GTX 560 TI and get shadow acne although we use the same code. enter image description here

When I'm moving the whole shadow is flickering. To set up the depth buffer of our framebuffer we do the following:

glBindTexture(GL_TEXTURE_2D,_t_depth->name());
  glTexImage2D(
    GL_TEXTURE_2D,0,
    GL_DEPTH_COMPONENT32,
    width,height,
    0, GL_DEPTH_COMPONENT, GL_FLOAT,0);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
  glBindTexture(GL_TEXTURE_2D,0);
  glFramebufferTexture(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,_t_depth->name(),0);

The relevant part of the vertex shader is:

uniform mat4 u_lightspace_MVP;
layout(location=0) in vec3 v_position;
...
vec4 shadowcoord_x=u_lightspace_MVP*vec4(v_position,1.0);
shadowcoord_x/=shadowcoord_x.w;

The relevant part of the fragment shader is:

 if (texture(s_shadowMap,shadowcoord_x.xy).r>shadowcoord_x.z-0.0001)

I have tried different bias values but either it doesn't affect the acne or there is no shadow at all. I also tried to use sampler2DShadow with textureProj() and texture() as the lookup function. Nothing seems to work. This issue doesn't only affect the shadows but also the volumetric lighting effect where shadowmaps are also used. On the other hand clipping with gl_ClipDistance works fine on my Nvidia but not on his graphic cards.


Solution

  • After further trial and error approaches I finally got rid of the acne. The only thing I had to do was to halve the precision of the shadow map from 32bit to 16bit. The initialization looks like this now:

    glBindTexture(GL_TEXTURE_2D,_t_depth->name());
      glTexImage2D(
        GL_TEXTURE_2D,0,
        GL_DEPTH_COMPONENT16,
        width,height,
        0, GL_DEPTH_COMPONENT, GL_FLOAT,0);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
      glBindTexture(GL_TEXTURE_2D,0);
      glFramebufferTexture(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,_t_depth->name(),0);
    

    Now I'm also using sampler2DShadow and textureProj() in the fragment shader for depth testing and everything works fine. Still I'm curious why it didn't work with 32 bit on my Nvidia but on an ATI.