Shadows in CryENGINE

Overview

In CryENGINE 1 we had shadow maps and projected shadows per object for the sun shadows. Additionally, as an easier and more efficient solution, light maps for static environments and stencil shadows for point lights were used. For efficient silhouette extraction, the skinning had to be done on the CPU. However, that becomes a performance problem with more detailed/complex objects. Stencil shadows have barely controllable performance characteristics, a hard look and do not support alpha-tested geometry.

Shadow Maps

Shadow maps, especially with hardware support available, have many nice properties:

  • Efficiently supported by hardware.
  • Roughly linear performance, degrading with the number of objects.
  • Roughly linear performance, degrading with the screen resolution (depends a bit on the shadow map resolution).
  • Adjustable quality (texture resolution and per pixel sample count).
  • Support soft shadows.
  • Support alpha test (but not alpha blending).
  • Easy to combine with other techniques (for example, projected colored shadows).
  • Extensible (e.g. PSM, CSM, LiSPM, randomized lookup, variance shadow maps).
  • Work for projected lights, point lights (cube map or unwrapped cube map), and directional lights (CSM).

The bias problem ("shadow acne") can be an issue but by tweaking the parameters and using some tips and tricks (back face shadow maps), shadow maps can be made to look good.

Soft Shadows

Point light sources cast hard shadows. This often looks unnatural since real light sources have some volume which leads to soft shadows. With shadow maps you can mimic soft shadows by filtering the result of the shadow map lookup (Percentage Closer Filtering, often natively supported by graphics hardware). With multiple samples the quality can be further improved but this can slow down rendering. The bigger the area that the samples cover, the bigger the penumbra of the shadows. The size of the penumbra of physically correct soft shadows starts at 0 on the shadow caster and linearly grows over distance. Although this is hard to achieve with shadow maps, it is possible. However, the effect is rarely visible and generally not worth the performance cost. Hence the penumbra size is small but constant and carefully tweaked to look soft without causing performance or quality issues.

Penumbra Tweaking (DX11 only)

r_ShadowsAdaptionSize 0

r_ShadowsAdaptionSize 0.3

r_ShadowsAdaptionSize 1

Randomized Shadow Lookup

Instead of adding more samples, the quality can also be improved by randomizing the shadow map lookups. This introduces high frequency noise but the eye is used to some image noise even in the real world and in movies. A big blur radius should be avoided because then the noise level becomes unacceptable. {Variance Shadow Maps can solve this problem but other trade-offs will need to be made for them.


From left to right: unfiltered shadow map lookup, PCF filtering with a single sample, multiple randomized shadow map lookups

Combining Multiple Shadow Maps

Standard shadow mapping suffers from fixed resolution textures. The resolution remains constant from the perspective of the light but from the viewer's perspective the areas on the screen show different density. If performance and memory are not big issues, the problem can be solved by using high resolution textures. By using a perspective shadow map projection, the shadow map's density can be adjusted to provide more details where needed. Various techniques exist to achieve this. We have tried out perspective shadow maps and trapezoidal shadow maps (another alternative: LiSPM). We achieved good results with these but we found that splitting the shadow maps into several linear projections had nicer properties compared to the perspective projections. This approach works well for point lights and works even better for the sun.

Console Variables

r_ShadowGenGS
DUMPTODISK

Use geometry shader for shadow map generation (DX11 only, don't change at runtime)
Usage: r_ShadowGenGS [0=off, 1=on]


e_ShadowsDebug

0=off, 2=visualize shadow maps on the screen


e_ShadowsMaxTexRes

Set maximum resolution of shadow map
256(faster), 512(medium), 1024(better quality)


r_ShadowJittering

Shadow map jittering radius.
In PC the only use of this cvar is to instantly see the effects of diferent jittering values,
because any value set here will be overwritten by ToD animation (only in PC) as soon as ToD changes.
Usage: r_ShadowJittering [0=off]


r_ShadowTexFormat

0=use R16G16 texture format for depth map, 1=try to use R16 format if supported as render target
2=use R32F texture format for depth map
3=use ATI's DF24 texture format for depth map
4=use NVIDIA's D24S8 texture format for depth map
5=use NVIDIA's D16 texture format for depth map
Usage: r_ShadowTexFormat [0-5]


r_ShadowGen

0=disable shadow map updates, 1=enable shadow map updates