Resources
Important types
FStaticLightingManager- Manages systemsFStaticLightingSystem- Runs Lightmass processor and handles the start/process/end of applying build data.FLightmassProcessorFStaticLightingBuildContext- Created alongFStaticLightingSystemUMapBuildDataRegistry- Per level, the actual asset you can see in the Content Browser.FMeshMapBuildDataFLightMap2D(andFLightMap)FShadowMap2D(andFShadowMap)ULightMapTexture2DFLightmapResourceClusterFStaticLightingTextureMapping
Important functions
UWorld::GetLightMapsAndShadowMaps
Important delegates
FEditorDelegates::OnLightingBuildStarted- Called when a lighting build has startedFEditorDelegates::OnLightingBuildKept- Called when a lighting build has been keptFEditorDelegates::OnLightingBuildFailed- Called when a lighting build has failed (maybe called twice if cancelled)FEditorDelegates::OnLightingBuildSucceeded- Called when a lighting build has succeeded
Static Lighting
Core
The FStaticLightingManager always exists as its Get method creates an instance if none exists.
FStaticLightingManager::CreateStaticLightingSystem is used to create new FStaticLightingSystem instances. The only usage I found is in UEditorEngine::BuildLighting. FStaticLightingBuildContext is also created there.
Building
Start
To build light UEditorEngine::BuildLighting is called.
One of the paths to run it is ULevelEditorSubsystem::BuildLightMaps.
After creating a new FStaticLightingSystem, FStaticLightingSystem::BeginLightmassProcess is called.
Inside this function a lot of process is done, Lights array is filled by getting all ULightComponentBase that is contained in the built world.
The light component also needs to be affecting the world, as well as allowing static shadowing or static lightening.
FStaticLightingSystem::GatherStaticLightingInfo is also called inside.
FStaticLightingSystem::GatherScene is later called as well as FStaticLightingSystem::InitiateLightmassProcessor.
Running
On each UEditorEngine::UpdateBuildLighting call, FStaticLightingManager::UpdateBuildLighting runs FStaticLightingSystem::UpdateLightingBuild on the active system.
UEditorEngine::UpdateBuildLighting is called from multiple places, including UUnrealEdEngine::Tick and ULevelEditorSubsystem::BuildLightMaps in a while loop (the one after calling UEditorEngine::BuildLighting, using UEditorEngine::IsLightingBuildCurrentlyRunning).
End
At the end of the lightmass process, FStaticLightingManager::ProcessLightingData is called.
This will run FStaticLightingSystem::FinishLightmassProcess on the system.
This function does a number of important things:
1.FStaticLightingSystem::InvalidateStaticLighting - Invalidates the lighting of the current levels so new lighting can be applied.
It iterates all levels for the Lighting context world, if it should update the static Lighting data it will call ULevel::ReleaseRenderingResources and clear MapBuildData using UMapBuildDataRegistry::InvalidateStaticLighting.
Some others miscellaneous stuff is done inside the function.
0.5FLightmassProcessor::CompleteRun
A lot of things happens inside, here I will only mention that it can eventually call FLightmassProcessor::ProcessMapping which calls FStaticLightingSystem::ApplyMapping that internally calls the Apply virtual of FStaticLightingMapping. In most cases it will be an FStaticMeshStaticLightingTextureMapping if its a SM.
All of this dive to say that UMapBuildDataRegistry::AllocateMeshBuildData will be executed to add a MeshBuildData entry with an defaulted (“empty”) FMeshMapBuildData.
2.FStaticLightingSystem::CompleteDeterministicMappings
Uses the Mappings array of item type FStaticLightingMapping.
The Mappings variable is used if we have sorting enabled (GLightmassDebugOptions.bSortMappings). Otherwise UnSortedMappings is used, which its item type is FStaticLightingMappingSortHelper.
In my testing this was skipped so I can’t tell much on what it does, check source code for more info.
3.FStaticLightingSystem::EncodeTextures - After importing, textures need to be encoded to be used.
This will run FLightMap2D::EncodeTextures and FShadowMap2D::EncodeTextures.
This is also where the ULightMapTexture2D are created (see FLightMapPendingTexture::CreateUObjects).
4.FStaticLightingSystem::ApplyNewLightingData - Pushes newly collected lightmaps on to the level.
For each considered level, this will:
- Loop 1:
- Call
ULevel::OnApplyNewLightingData(only updatesLightBuildLevelOffset) - If persistent level call
UpdateSceneonPrecomputedVisibilityHandlerandPrecomputedVolumeDistanceField. - For each actor:
- Get
UMapBuildDataRegistryusingFStaticLightingBuildContext::GetOrCreateRegistryForActor. - For each light component:
- If
UMapBuildDataRegistry::GetLightBuildDatafails it callsUMapBuildDataRegistry::FindOrAllocateLightBuildData
- If
- For each sky atmosphere component:
- If
UMapBuildDataRegistry::GetSkyAtmosphereBuildDatafails it callsUMapBuildDataRegistry::FindOrAllocateSkyAtmosphereBuildData.
- If
- Get
- Call
- Loop 2:
- Get
UMapBuildDataRegistryusingFStaticLightingBuildContext::GetRegistryForLevel - Runs
UMapBuildDataRegistry::SetupLightmapResourceClusterson the registry. - Runs
ULevel::InitializeRenderingResources
- Get
More on UMapBuildDataRegistry
So now our UMapBuildDataRegistry holds our built data. Such as an array MeshBuildData holding FMeshMapBuildData, and an array LightBuildData of holding FLightComponentMapBuildData.
An FMeshMapBuildData holds data such as a FLightMapRef and a FShadowMapRef.
The FLightMap2D holds an array of Textures of type ULightMapTexture2D.
The first entry is a High Quality (HQ) lightmap and the second is a Low Quality (LQ) lightmap (When loading up a level with Static Lighting you can see a rough quality change after a few seconds when the editor is loading the HQ after using the LQ).
Usage
So … how is this used ?
On UMapBuildDataRegistry::PostLoad the clusters are created and sent to the render thread (see UMapBuildDataRegistry::SetupLightmapResourceClusters and check FLightmapResourceCluster section below).
In my simulation (empty world with point light and floor SM), here is how light maps are queried:
By the Spot Light:
ULightComponent::CreateRenderState_Concurrentis called.- This internally calls
FScene::AddLighton the world scene, which callsUPointLightComponent::CreateSceneProxy - Inside the
FLightSceneProxyconstructorULightComponent::GetLightComponentMapBuildDatais called. This runs theUMapBuildDataRegistry::Getoverload using a Actor Component, which internally uses the one using a Level and World as input if you aren’t using World Partition. If the light component was previously built this will return a validFLightComponentMapBuildDataptr (usingUMapBuildDataRegistry::GetLightBuildData).
By the floor Static Mesh:
UStaticMeshComponent::CreateStaticMeshSceneProxyis called.- Inside the
FStaticMeshSceneProxyconstructorUStaticMeshComponent::IsPrecomputedLightingValidwill be called to set a bool. - This will call
UStaticMeshComponent::GetMeshMapBuildData, which will use theFGuid MapBuildDataIdstored in the LOD to get the Mesh Build Data.
Miscs
FStaticLightingDescriptors
Descriptors is created in FStaticLightingBuildContext::FStaticLightingBuildContext IF the world is using World Partition.
FLightmapResourceCluster
A bundle of lightmap resources which are referenced by multiple components.
Comment on FLightmapResourceCluster::TryInitializeUniformBuffer.
// Two stage initialization of FLightmapResourceCluster
// 1. when UMapBuildDataRegistry is post-loaded and render resource is initialized
// 2. when the level is made visible (ULevel::InitializeRenderingResources()), which calls UMapBuildDataRegistry::InitializeClusterRenderingResources() and fills FeatureLevel
// When both parts are provided, TryInitialize() creates the final UB with actual content
// Otherwise UniformBuffer is created with empty parametersThis seems to be what is used by the render thread to know what to use.
World Settings displayed “Lightmaps”
In the world settings panel, the “Lightmaps” row in the Advanced area isn’t a variable but a custom row injected from FLightmapCustomNodeBuilder.
The text is formatted from FLightmapCustomNodeBuilder::GetLightmapCountText, which uses the LightmapItems array.
The array is recreated on each FLightmapCustomNodeBuilder::RefreshLightmapItems call.
The light maps and shadow maps are queried by using UWorld::GetLightMapsAndShadowMaps.
More on UWorld::GetLightMapsAndShadowMaps
UWorld::GetLightMapsAndShadowMaps works by getting all ULightMapTexture2D, UShadowMapTexture2D and ULightMapVirtualTexture2D objects.
More on ULevel
In ULevel there is MapBuildData of type UMapBuildDataRegistry.