Direct Lighting Injection

Next is the Direct Lighting injection phase, which can be seen as a deferred lighting process in Card space, which also includes shadow calculation.

Tile-based Lighting

Before performing lighting calculations, it is necessary to organize the relationship between the light source and the page, that is, to determine the list of light sources that actually affect each area. This is the process of Tiled-based Lighting in many engines.

image

Relationships between LightSources, Tiles, CardPages, and Cards:

image

The size of a tile is an important consideration in the design of a display or screen. The standard size of a tile is 8 x 8 pixels. The total pixel number is obviously 64.

Tiles are often used in combination with lights, which have a many-to-many relationship with tiles. This combination is typically calculated in a program or system called LightTiles.

One key feature of tiles is their ability to store light sources. In fact, each tile can store up to 8 light sources.

Additionally, there is a function that is used to determine whether a light source affects the tile. This function is called DoesLightAffectCardPageUVRange, and it plays a crucial role in ensuring that the display is accurate and visually appealing.

Shadow

Compared to shadow calculation under the standard Camera view, Card space needs to deal with a special issue:

  • VSM and other shadow mapping systems are designed to cull based on the Camera view. Therefore, areas outside the view may not contain shadow information.
  • However, Lumen Card still needs this information to produce correct shadows during light calculation, otherwise it will result in light leaking.

This issue leads to the direct lighting calculation stage of Lumen Card being divided into three parts:

  • Shadow calculation using shadow maps
    • Before 5.2 official release, this was true, but it is not true now. Please check below.
  • Offscreen Shadow calculation using distance field tracing.
  • Finally, based on the shadow information, material information captured by SurfaceCache, and information from the light source itself, the Tile is illuminated by the light source.

Calculation of Visible Area Shadow

ℹ️
/Engine/Private/Lumen/LumenSceneDirectLightingShadowMask.usf

Here, the Card and Page data from Lumen is being read to rebuild the SurfaceCacheData of the Card. The most important data for this is the WorldPositionand WorldNormal.

These two pieces of data are generated and copied during the Card Capture phase.

After this, the visible area does not actually sample the shadow map, but rather marks the affected area.

ShadowMaskRay.ShadowFactor = 1.0f;
ShadowMaskRay.bShadowFactorComplete = false;

Afterwards, the task of shadow calculation was left to the off-screen shadow calculation.

ℹ️
If you have read some other articles analyzing Lumen, you may have seen the sampling VSM or SM at this step in their analysis. Their analysis is also correct, but there was a code change between UE5.2 preview and 5.2 release that removed the sampling of VSM and SM. Readers interested in this change can refer to this link:Lumen - removed shadow map reuse from HWRT surface cache lighting pat… · EpicGames/UnrealEngine@63d6f08 (github.com)

Off-screen shadow calculation

ℹ️
/Engine/Private/Lumen/LumenSceneDirectLightingSoftwareRayTracing.usf

The basic steps of this step are consistent with the previous content:

  • Each thread obtains the information it needs to perform shadow Trace, reconstruct the spatial information of the Surface Cache, etc.

Off-screen shadow calculation is performed by tracing the Global Signed Distance Field.

Global Signed Distance Field

GSDF is divided and stored by page in a way similar to Virtual Texture. It is important to note that this is a Texture3D rather than a 2D texture.

image
🛠
SDF encoding?

Lighting Combination

image
ℹ️
/Engine/Private/Lumen/LumenSceneDirectLighting.usf

The final result will merge direct lighting, emissive, and indirect lighting.

In fact, this is divided into 2 steps:

Direct Lighting

image

Once again, pull the information related to the light tiles and combine it with the previously calculated shadow information. If the current area is not within the shadow, calculate the light intensity using the GetIrradianceForLight function. Output the following buffer:

image

Combine Indirect Lighting

image

Blend with the previously accumulated Indirect Lighting Buffer using the function CombineFinalLighting.

FinalLighting = (DirectLighting + IndirectLighting) * Diffuse_Lambert(Albedo) + Emissive;

The final buffer:

image