4.4. Shadow Artefacts

There are certain things that can go wrong with dynamic shadow implementations like the ones used in Grit. There are some things to avoid when modelling objects, in order to avoid problems.

4.4.1. Holes in shadows

Since the shadows are calculated by rendering the scene from the sun (or moon) you have to make sure that your geometry, when viewed from this direction, appears to be opaque. This means cliffs must have polygons around the back facing the sun, in order to the sun shining through them to the front. A more expensive alternative is to turn on the rendering of backfaces in the material.

If your map is an island that drops below sealevel in all directions, you don't have to worry about this. But if your map is surrounded by some sort of "wall", then you do.

4.4.2. Shadow Texture Stretch

Shadow texture stretch occurs where polygons do not face the light.

Since the shadow texture is projected onto the scene from the light, surfaces that are perpendicular to the light (e.g. flat ground at sunset) will experience very bad texture stretch. This causes aliasing artefacts. Because of the LiSPSM perspective transformation, the artefacts have a very nasty sawtooth appearance, instead of the square pixelation that usually occurs with aliasing artefacts.

To visualise the aliasing, we can use the following, which renders just the projection of the shadow map onto the scene, with equal intensitity for all triangles:

debug_cfg.falseColour = "SHADOWYNESS"

A small fern on the edge of a cliff is projecting a shadow downhill away from the edge of the cliff. The shadow is very elongated because of the low sun. One can see the sawtooth artefacts in the stretched part of the shadow. When animated, the moving sun causes these sawtooth artefacts to crawl in a very distracting way.

Shadow texture stretch is usually hidden by the lighting equation.

Luckily these areas should receive very much light due to the diffuse lighting equation. E.g. if the light is incident at 15 degrees then the amount of lighting would only be 25% (i.e. sin(15)) of the amount of light that it would receive at 90 degrees. This means the shadow is much less distinct in these areas. The following falseColour value shows the actual shadow, i.e. incorporating the diffuse lighting component as well as the shadow map:

debug_cfg.falseColour = "SHADOW_MASK"

In the next section, we can see how this effect can be disrupted by certain kinds of assets.

4.4.3. Normal Bending

If your mesh has sharp edges between polys (an angle of more than 20 degrees for example) and is smooth shaded, then for some pixels, the normals interpolated across that mesh will be considerably different to the 'true' normal of that face (i.e. the normal you would calculate using the positions of the 3 vertexes). For example, if you model a cube and use smooth shading then the normals of each face will be orthogonal, but the normals will be smoothly interpolated around the cube causing a huge amount of normal bending at the edges and corners.

Normal Bending
Shadow artefacts caused by normal bending.

Normal bending is usually OK, but causes a problem with shadows. This is because shadow stretch occurs in places where the true normal of the polygon is close to perpendicular to the light source, however light attenuation uses the interpolated normal, which can be pointing closer to the light than the true normal. This kind of artefact often occurs on sharp terrain like cliffs. It causes areas to be illuminated when they would not otherwise be, and therefore causes shadow artefacts to appear that would ordinarily be hidden in the darkness. If the face is in-line with the light, e.g. cliffs at noon, and there is significant normal bending, then the polygon may be almost fully lit, even though the polygon is nearly at 90 degrees to the sun.

There used to be a material property shadowObliqueCutoff for controlling this effect, but it is no-longer implemented since the switch to deferred shading. The technique was to attenuate shadows more aggressively on surfaces rendered with the material in question. However doing this on a per- material basis causes areas of the mesh that do not have normal bending to be subject to the same attenuation of shadows. The preferred solution is to calculate the amount the amount required at each vertex and store that in the vertex as an attribute. This can be fully automated in the asset generation pipeline. However it is not yet implemented. Please ignore the artifacts for now.

4.4.4. Shadow Acne

Shadow Acne Diagram
An illustration of shadow acne.

Imprecision in the shadow map, which records the distance of each occluder from the light, causes the shadow to fluctuate, causing unpleasant high frequency transitions from 'in shadow' to 'not in shadow' on every surface that faces the light. The engine will avoid shadow acne by adding a certain amount of bias to the depth of hte caster during the shadow casting phase. Thus, the shadow is pushed away from the light by enough in order to avoid the noise being an issue. The following image illustrates the problem and how the depth bias solves it, the screen shot is of a natural gas tank, but the diagram below is for a wall on flat ground.

The engine tries to use the minimal amount of bias to avoid shadow acne, by using the normal of the casting surface and a small constant offset on everything. Thus, you don't need to worry about this as a modeller, unless your surfaces are so thin that even this small amount of bias is too much.

4.4.5. Additional Bias

Unwanted Shadow Fidelity
Unwanted self-shadowing.

You can add additional bias yourself, in the material, in order to get rid of other artefacts. For example here there are unwanted shadows on the tank. There is simply not enough fidelity in the dynamic shadows to properly render shadows for such detailed geometry. We would rather there were no shadows at all.

One way to avoid this is to avoid these kind of nooks and crannies in the geometry of the object. However since these contribute greatly to the appearance of objects, this may be unacceptable. Another solution is to add another 0.1m to the depth bias during shadow casting (on top of the small amount calculated by the engine), in order to push the shadow far enough away from the object to hide shadows on the high detail parts of the mesh.

4.4.6. Shadow Disconnection

Shadow Disconnection
Too much bias causes the shadow to disconnect from the base of the object.

Too much bias can cause a problem in itself though. If the bias is increased enough, the shadow will move so far from the object that there will be a 'gap' where the object meets the ground. This gives the unwelcome appearance that the object is 'floating' above the ground, as seen with this table. If you want a lot of bias, you may have to thicken the geometry of your model.

The bias automatically used by the engine is carefully chosen to be as small as it can be. However as a modeller you must also make sure your additional bias is not too large as well.