ShadowMap Flickering


#1

Hello out there,

I am new to cinder. I started developing a little game. I used the ShadowMappingBasicExample from samples folder.

I get some strange flickering only on my ci::geom::Cube, when they should be bright.

Any ideas, how to resolve these issues?

Video of bug can be found here: https://www.youtube.com/watch?v=GpwpnPV57Ek

Vertex shader

#version 330

uniform mat4 ciModelViewProjection;
uniform mat4 ciViewMatrixInverse;
uniform mat4 ciModelView;
uniform mat3 ciNormalMatrix;
uniform mat4 ciModelMatrix;

uniform vec2 uResolution = vec2(10.0f);

uniform mat4 uShadowMatrix;
uniform vec3 uShadowLightPosition;

in vec4 ciPosition;
in vec3 ciNormal;
in vec3 ciTangent;
in vec2 ciTexCoord0;

out vec4 vVertexPosition;
out vec2 vTextureCoordinates;
out mat3 TBN;
out vec4 vViewPos;

void main(void) {
    
    vec3 wcNormal = (ciModelMatrix * vec4(ciNormal, 0)).xyz;
    vec3 wcTangent = (ciModelMatrix * vec4(ciTangent, 0)).xyz;
    vec3 wcBitangent = cross(wcNormal, wcTangent);

    TBN = inverse(mat3(wcTangent, wcBitangent, wcNormal));
    
    vVertexPosition = ciModelMatrix * ciPosition;
    vTextureCoordinates = ciTexCoord0 * uResolution;
    
    gl_Position = ciModelViewProjection * ciPosition;
    
    vViewPos = gl_Position;

}

Fragment shader
#version 330

uniform mat4 ciProjectionMatrix;

uniform sampler2D uTexDiffuse;
uniform sampler2D uTexNormal;
uniform sampler2DShadow uShadowTexture;

uniform mat4 uShadowMatrix;
uniform vec3 uShadowLightPosition;

uniform vec3 uLightColor;

uniform vec3 uWcLightPosition;
uniform vec3 uWcCameraPosition;

uniform vec3 uAmbientColor;
uniform vec3 uAmbientAttentuation;

uniform vec3 uSpecularColor = vec3(1.0);
uniform int uShininess = 256;

uniform float uEmissiveThreshold = 0.8f;

uniform float uFogStart = 8.0f;
uniform float uFogEnd = 10.0f;

uniform float uAttentuationConstant = 0.9f;
uniform float uAttentuationLinear = 0.5f;
uniform float uAttentuationQuadratic = 0.4f;

in mat3 TBN;
in vec4 vVertexPosition;
in vec3 vNormalDirection;
in vec2 vTextureCoordinates;
in vec4 vViewPos;

const mat4 biasMatrix = mat4( 0.5, 0.0, 0.0, 0.0,
							  0.0, 0.5, 0.0, 0.0,
							  0.0, 0.0, 0.5, 0.0,
							  0.5, 0.5, 0.5, 1.0 );

layout (location = 0) out vec4 oColor0;
layout (location = 1) out vec4 oColor1;

vec3 phong(vec3 n, vec3 v, vec3 l, float dist) {
    
    vec3 ambientColor = uAmbientColor * uAmbientAttentuation;
    
    if (dot(n, v) < 0)
        return vec3(0);
    
    float ndotl = dot(n, -l);
    if (ndotl < 0)
        return vec3(0);
    
    vec3 diffuseColor = texture(uTexDiffuse, vTextureCoordinates).rgb * uLightColor * ndotl;
    
    vec3 r = reflect(l, n);
    float rdotv = max(dot(r, v), 0.0f);
    vec3 specularColor = uSpecularColor * uLightColor * pow(rdotv, uShininess);
    
    float attentuation = 2 / (uAttentuationConstant + uAttentuationLinear * dist + uAttentuationQuadratic * pow(dist, 2));
    
    vec4 sCoord = biasMatrix * uShadowMatrix * vVertexPosition;
    vec4 shadowCoord = sCoord / sCoord.w;
    float shadow = 1.0f;
    if (shadowCoord.z > -1 && shadowCoord.z < 1) {
        shadow = textureProj(uShadowTexture, shadowCoord, -0.00005f);
    }
    
    return ambientColor + diffuseColor * shadow * attentuation + specularColor  * attentuation * shadow;
}

vec3 decode(vec3 normal) {
    return normalize((normal * vec3(2, 2, 1) - vec3(1, 1, 0)) * vec3(-1, -1, 1));
}

void main(void) {

    vec3 wcLightDirection = uWcLightPosition - vVertexPosition.xyz;
    vec3 wcViewDirection = uWcCameraPosition - vVertexPosition.xyz;

    vec3 tsLightDirection = TBN * -wcLightDirection;
    vec3 tsViewDirection = TBN * wcViewDirection;
    
    float dist = length(wcLightDirection);

    vec3 n = normalize(decode(texture(uTexNormal, vTextureCoordinates).rgb));
    vec3 v = normalize(tsViewDirection);
    vec3 l = normalize(tsLightDirection);
    
    vec3 color = phong(n, v, l, dist);

    // fog
    float distToEnd = abs(vViewPos.z);
    float fogFactor = clamp((uFogEnd - distToEnd) / (uFogEnd - uFogStart), 0, 1);

    oColor0 = vec4(color, fogFactor);
    
    float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
    if (luminance >= uEmissiveThreshold) {
        oColor1 = vec4(color, fogFactor);
    } else {
        oColor1 = vec4(vec3(0), fogFactor);
    }

}

All setup is equal to the shadowmapping basic example.


#2

a temporary fix for me is to rotate cubes and torus by at least 2° degrees.

The flickering is gone. But why the hell does this even happen?


#3

Okay. Solution was setting

shadowMapFormat.setInternalFormat(GL_DEPTH_COMPONENT16);

instead of

shadowMapFormat.setInternalFormat(GL_DEPTH_COMPONENT32F);


#4

Hi,

the flickering is caused by self-shadowing, which is a very common artifact of shadow mapping. It’s simply due to the depth map precision. You already have noticed that the problem is (mostly) gone when using a higher precision map and also when rotating the cubes a little (because in that case the pixels each have a different depth value and the effect is less apparent… but it is still there!).

There are several techniques that reduce the artifacts, but sadly there is no one-fix-to-rule-them-all. You’ll have to tweak settings for your scene, based on camera position, light position, object size, etc. See the link for more general information.

-Paul