3

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.

Stan
  • 721
  • 10
  • 24
  • When you used sampler2DShadow, did you switch your glTexParameteri to use GL_LINEAR instead of GL_NEAREST? – fluffels May 17 '14 at 10:14
  • Yes, I have tried this already. It seems OpenGL does some interpolation on the shadow map, although GL_NEAREST for both filters has been chosen. – Stan May 17 '14 at 10:23
  • Well, GL_NEAREST won't work for normal shadow mapping. The reason is your filtering depths, which doesn't really make sense. If you implement a PCF shadow mapping algorithm, then GL_LINEAR makes sense, since you're filtering the results of a depth test. It *might* help in your situation. I can't see anything else wrong with your code. – fluffels May 17 '14 at 15:22
  • What does the depth buffer look like after the light pass? It might be a good way to debug... – fluffels May 17 '14 at 15:23
  • 1
    The depth buffer looks fine when I display it, there are no artifacts or anything else which could cause this acne. The strange thing about it is, that it is working on ATI graphic cards, even on an Intel it works without problems. – Stan May 17 '14 at 17:58
  • For one thing, your bias is in the wrong direction... – Andon M. Coleman May 17 '14 at 19:09
  • @fluffels: Nearest filtering (point sampling) works just fine with shadow maps, regardless what texture lookup you use. – Andon M. Coleman May 17 '14 at 19:12
  • 1
    Have you considered doing the perspective divide in the fragment shader and/or using `noperspective` interpolation? That may give you more consistent results. – Andon M. Coleman May 17 '14 at 21:12
  • Sorry, meant to say GL_LINEAR. – fluffels May 19 '14 at 07:35

1 Answers1

1

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.

Stan
  • 721
  • 10
  • 24