Search code examples
openglglslshaderfragment-shadershadow-mapping

Small artifacts with simple hard shadow mapping technique using OpenGL and GLSL


I have a strange behaviour with my hard shadows I have never seen before because of the somber color of the textures I used (these artifacts was not visible). Here's some screenshots of my problem with 3 different shadowmap resolutions:

1) Shadowmap 160 * 120

enter image description here

As you can see, there are kind of teeth on the surface of the cube.

Here's the view of the scene from light position:

enter image description here

Here's the shadowmap:

enter image description here

2) Shadowmap 640 * 480

enter image description here

With a higher resolution the artifacts are less visible because the shadow map brings more precision.

Here's the view of the scene from light position:

enter image description here

Here's the shadowmap:

enter image description here

I tried with higher other resolution. Of course the artifacts are smaller and smaller but if you zoom on the surface they are still visible.

Here's the code I use in my fragment shader during the second pass:

[...]

uniform sampler2DShadow ShadowSampler[MAX_LIGHT_COUNT];

[...]

float GetDynamicShadowBias(vec3 normalDir_cs, vec3 lightDir_cs)
{
    float cosTheta = clamp(dot(normalDir_cs, lightDir_cs), 0.0f, 1.0f);
    float bias = 0.005f * tan(acos(cosTheta));

    return (clamp(bias, 0.0f, 0.01f));
}

float GetBiased_Hard_ShadowFactor(vec3 normalDir, vec3 lightDir, int idx)
{    
    if (ShadowCoords[idx].w > 0.0f)
    {
        float bias = GetDynamicShadowBias(normalDir, lightDir);

        float LightToOccluderClipDist = texture(
            ShadowSampler[idx], ShadowCoords[idx].xyz/ShadowCoords[idx].w);

        float LightToVertexClipDist = (ShadowCoords[idx].z - bias)/ShadowCoords[idx].w;

        if (LightToOccluderClipDist < LightToVertexClipDist)
            return (0.0f);
    }
    return (1.0f);
}

So I wonder if it's possible to remove these artifacts on the edges of the cube. I tried to play with the shadow bias without real success (for information I use FRONT_FACE culling during the first pass (filling of the depth texture)).


Solution

  • There are 2 things going on here. One is that this is a limitation of standard shadow maps. Because the shadow of any given object will take up some potentially smaller number of pixels in the map, when you then cast that map onto the scene, those parts can get re-enlarged and you'll get aliasing.

    The second thing that appears to be happening is that your shadows are essentially 1 bit, it appears. They're either black or white. If you were to in some way antialias the map while creating it (say supersampling or some other technique), it would be less noticeable (though it wouldn't go away completely in my experience).

    There are some techniques that build on classic shadow maps. One is Subpixel Shadow Mapping from SIGGRAPH 2013. (There were some other shadow papers that year, too.) I've also seen ray-casted shadows implemented in realtime via GLSL recently. (Sorry, can't find the link! I'll post later if I can dig it up.)