Avoiding artifacts in shadow maps

posted in Merc Tactics
Published May 08, 2024
Advertisement

My game Merc Tactics uses a simple shadow map to create shadows, but I had a lot of trouble getting it to work without artifacts. In particular peter panning and acne were a big problems.

the shader code looks like this:

		uniform sampler2DShadow sShadow; 
		uniform sampler2D sampler2d;
		in mediump vec2 uvOutA;
		in highp vec4 shadowCoord;
		in lowp vec4 outColor;
		out vec4 fragColor;
		uniform lowp vec2 invShadowSize;
 		uniform lowp float ambientLight;

		float offset_lookup(sampler2DShadow sShadow, vec4 loc, vec2 offset)
		{
			return textureProj(sShadow, vec4(loc.xy + offset * invShadowSize * loc.w,
				loc.z, loc.w));
		}
		void main(void)
		{
			// for soft shadows I sample 4 values from shadow texture using a random offset
			// and use the average value
			lowp float shadow;
			vec2 offset = vec2(0, 0);
			if (fract(shadowCoord.x * 0.5) > 0.25) offset.x = 1;
			if (fract(shadowCoord.y * 0.5) > 0.25) offset.y = 1;
			offset.y += offset.x;  // y ^= x in floating point
			if (offset.y > 1.1) offset.y = 0;
			shadow = (offset_lookup(sShadow, shadowCoord, offset + vec2(-1.5, 0.5)) +
				offset_lookup(sShadow, shadowCoord, offset + vec2(0.5, 0.5)) +
				offset_lookup(sShadow, shadowCoord, offset + vec2(-1.5, -1.5)) +
				offset_lookup(sShadow, shadowCoord, offset + vec2(0.5, -1.5)) ) * 0.25;

			lowp vec4 texColor = texture(sampler2d, uvOutA);  
			float light = shadow  + ambientLight; 
			lowp vec3 color = texColor.rgb * light;
			fragColor = vec4(color, texColor.a*outColor.a);

		}

This simple shader produces a nice soft shadow, but there is shadow acne:

Acne

I needed to use polygon offset to get rid of the acne:

	glEnable(GL_POLYGON_OFFSET_FILL);   
	glPolygonOffset(m_offset, m_offsetSlope);	// using values m_offset = 3.4f, m_offsetSlope = 4.0f

Polygon offset fixes the acne problem, but it also creates peter panning. You can now see there is a gap between the shadow and the wall:

peter panning

I adjusted the values of polygon offset and the offset slope to minimise both the acne and peter panning, but there is no values that will remove both. To the solve the problem completely this I rendered the shadow map using front face culling (glCullFace(GL_FRONT) )and render everything else using back face culling:

Now, it's nearly perfect:

artifact free

I needed to use a very big shadow texture as well (8192x8192). Using anything smaller and I get small amounts of peter panning.

Also, there are still some cases where acne appears, but they are rare enough, so this solution is good enough.

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement