bUsePhotonMapping
bUsePhotonMapping
#Overview
name: bUsePhotonMapping
The value of this variable can be defined or overridden in .ini config files. 1
.ini config file referencing this setting variable.
It is referenced in 19
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of bUsePhotonMapping is to control whether photon mapping is used in the lighting calculations within Unreal Engine’s Lightmass system. Photon mapping is a global illumination technique that simulates the way light interacts with surfaces in a scene.
The bUsePhotonMapping variable is primarily used in the Lightmass subsystem, which is responsible for pre-computing static lighting in Unreal Engine. It’s part of the engine’s offline lighting calculation tools rather than the runtime rendering system.
The value of this variable is typically set in the Lightmass configuration files or through the engine’s lighting settings. It interacts with other lighting-related variables, such as bUseFinalGathering and bUseIrradiancePhotons, to determine the specific lighting calculation techniques used.
Developers should be aware that enabling photon mapping can significantly increase lighting calculation times but can also lead to more accurate global illumination results. It’s particularly useful for scenes with complex indirect lighting.
Best practices when using this variable include:
- Only enable it when higher quality indirect lighting is required, as it can substantially increase build times.
- Use it in conjunction with final gathering (bUseFinalGathering) for the best quality results.
- Adjust related settings like the number of photons and gathering samples to balance quality and performance.
- Consider using it selectively in areas of the scene where indirect lighting is most important.
It’s important to note that while photon mapping can produce high-quality results, it may not always be necessary for all projects, especially those with simpler lighting requirements or stricter build time constraints.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseLightmass.ini:166, section: [DevOptions.PhotonMapping]
- INI Section:
DevOptions.PhotonMapping
- Raw value:
True
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:2345
Scope (from outer to inner):
file
function void FLightmassExporter::WriteSceneSettings
Source code excerpt:
}
{
VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bUsePhotonMapping"), bConfigBool, GLightmassIni));
Scene.PhotonMappingSettings.bUsePhotonMapping = bConfigBool;
VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bUseFinalGathering"), bConfigBool, GLightmassIni));
Scene.PhotonMappingSettings.bUseFinalGathering = bConfigBool;
VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bUsePhotonDirectLightingInFinalGather"), bConfigBool, GLightmassIni));
Scene.PhotonMappingSettings.bUsePhotonDirectLightingInFinalGather = bConfigBool;
VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bVisualizeCachedApproximateDirectLighting"), bConfigBool, GLightmassIni));
Scene.PhotonMappingSettings.bVisualizeCachedApproximateDirectLighting = bConfigBool;
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:27
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::GatherVolumeImportancePhotonDirections
Source code excerpt:
bool bDebugThisSample) const
{
if (GeneralSettings.NumIndirectLightingBounces > 0 && PhotonMappingSettings.bUsePhotonMapping && PhotonMappingSettings.bUsePhotonSegmentsForVolumeLighting)
{
TArray<FPhotonSegmentElement> FoundPhotonSegments;
// Gather nearby first bounce photons, which give an estimate of the first bounce incident radiance function,
// Which we can use to importance sample the real first bounce incident radiance function.
// See the "Extended Photon Map Implementation" paper.
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:437
Scope (from outer to inner):
file
function FLinearColor FStaticLightingSystem::FinalGatherSample
Source code excerpt:
GatherClassification,
MappingContext,
bDebugThisTexel && (!PhotonMappingSettings.bUsePhotonMapping || !PhotonMappingSettings.bVisualizePhotonImportanceSamples));
checkSlow(FLinearColorUtils::AreFloatsValid(PathVertexOutgoingRadiance));
Lighting += PathVertexOutgoingRadiance;
#if ALLOW_LIGHTMAP_SAMPLE_DEBUGGING
if (PathVertexOutgoingRadiance.R > DELTA || PathVertexOutgoingRadiance.G > DELTA || PathVertexOutgoingRadiance.B > DELTA)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:485
Scope (from outer to inner):
file
namespace Lightmass
function FLinearColor FStaticLightingSystem::FinalGatherSample
Source code excerpt:
if (bDebugThisTexel
&& GeneralSettings.ViewSingleBounceNumber == BounceNumber
&& (!PhotonMappingSettings.bUsePhotonMapping || !PhotonMappingSettings.bVisualizePhotonImportanceSamples))
{
FDebugStaticLightingRay DebugRay(PathRay.Start, PathRay.End, RayIntersection.bIntersects, bPositiveSample != 0);
if (RayIntersection.bIntersects)
{
DebugRay.End = RayIntersection.IntersectionVertex.WorldPosition;
}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:1461
Scope (from outer to inner):
file
namespace Lightmass
function FFinalGatherSample FStaticLightingSystem::CachePointIncomingRadiance
Source code excerpt:
// If final gathering is disabled, all indirect lighting will be estimated using photon mapping.
// This is really only useful for debugging since it requires an excessive number of indirect photons to get indirect shadows for the first bounce.
if (PhotonMappingSettings.bUsePhotonMapping
&& GeneralSettings.NumIndirectLightingBounces > 0
&& !PhotonMappingSettings.bUseFinalGathering)
{
// Use irradiance photons for indirect lighting
if (PhotonMappingSettings.bUseIrradiancePhotons)
{
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:1547
Scope (from outer to inner):
file
namespace Lightmass
function FFinalGatherSample FStaticLightingSystem::CachePointIncomingRadiance
Source code excerpt:
if (GeneralSettings.NumIndirectLightingBounces > 0)
{
if (PhotonMappingSettings.bUsePhotonMapping)
{
LIGHTINGSTAT(FScopedRDTSCTimer PhotonGatherTimer(MappingContext.Stats.ImportancePhotonGatherTime));
TArray<FPhoton> FoundPhotons;
// Gather nearby first bounce photons, which give an estimate of the first bounce incident radiance function,
// Which we can use to importance sample the real first bounce incident radiance function.
// See the "Extended Photon Map Implementation" paper.
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:1656
Scope: file
Source code excerpt:
if (bDebugThisTexel
&& GeneralSettings.ViewSingleBounceNumber == BounceNumber
&& (!PhotonMappingSettings.bUsePhotonMapping || !PhotonMappingSettings.bVisualizePhotonImportanceSamples))
{
FDebugStaticLightingRay DebugRay(TexelRay.Start, TexelRay.End, Intersection.bIntersects, false);
if (Intersection.bIntersects)
{
DebugRay.End = Intersection.IntersectionVertex.WorldPosition;
}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:610
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::MultithreadProcess
Source code excerpt:
CacheSamples();
if (PhotonMappingSettings.bUsePhotonMapping)
{
// Build photon maps
EmitPhotons();
}
if (ImportanceTracingSettings.bUseRadiositySolverForSkylightMultibounce)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:845
Scope (from outer to inner):
file
namespace Lightmass
function int32 FStaticLightingSystem::GetNumPhotonImportanceHemisphereSamples
Source code excerpt:
int32 FStaticLightingSystem::GetNumPhotonImportanceHemisphereSamples() const
{
return PhotonMappingSettings.bUsePhotonMapping ?
FMath::TruncToInt(ImportanceTracingSettings.NumHemisphereSamples * PhotonMappingSettings.FinalGatherImportanceSampleFraction) : 0;
}
FBoxSphereBounds3f FStaticLightingSystem::GetImportanceBounds(bool bClampToScene) const
{
FBoxSphereBounds3f ImportanceBounds = Scene.GetImportanceBounds();
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:918
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
Source code excerpt:
}
if (InScene.PhotonMappingSettings.bUsePhotonMapping && !InScene.PhotonMappingSettings.bUseFinalGathering)
{
// Irradiance caching currently only supported with final gathering
InScene.IrradianceCachingSettings.bAllowIrradianceCaching = false;
}
InScene.PhotonMappingSettings.ConeFilterConstant = FMath::Max(InScene.PhotonMappingSettings.ConeFilterConstant, 1.0f);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:983
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::DumpStats
Source code excerpt:
}
if (PhotonMappingSettings.bUsePhotonMapping)
{
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs Emit Direct Photons\n"), 100.0f * Stats.EmitDirectPhotonsTime / TotalStaticLightingTime, Stats.EmitDirectPhotonsTime);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs Cache Indirect Photon Paths\n"), 100.0f * Stats.CachingIndirectPhotonPathsTime / TotalStaticLightingTime, Stats.CachingIndirectPhotonPathsTime);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs Emit Indirect Photons\n"), 100.0f * Stats.EmitIndirectPhotonsTime / TotalStaticLightingTime, Stats.EmitIndirectPhotonsTime);
if (PhotonMappingSettings.bUseIrradiancePhotons)
{
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1011
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::DumpStats
Source code excerpt:
LogSolverMessage(SolverStats);
SolverStats = TEXT("");
if (PhotonMappingSettings.bUsePhotonMapping)
{
if (Stats.EmitDirectPhotonsTime / TotalStaticLightingTime > .02)
{
SolverStats += FString::Printf( TEXT("Total Direct Photon Emitting thread seconds: %.1f\n"), Stats.EmitDirectPhotonsThreadTime);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs Sampling Lights\n"), 100.0f * Stats.DirectPhotonsLightSamplingThreadTime / Stats.EmitDirectPhotonsThreadTime, Stats.DirectPhotonsLightSamplingThreadTime);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs Custom attenuation\n"), 100.0f * Stats.DirectCustomAttenuationThreadTime / Stats.EmitDirectPhotonsThreadTime, Stats.DirectCustomAttenuationThreadTime);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1150
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::DumpStats
Source code excerpt:
//@todo - rdtsc is also not dependable if the OS changes which processor the thread gets executed on.
// Use SetThreadAffinityMask to prevent this case.
if (PhotonMappingSettings.bUsePhotonMapping)
{
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs ImportancePhotonGatherTime\n"), 100.0f * Stats.ImportancePhotonGatherTime / IndirectLightingCacheTaskThreadTime, Stats.ImportancePhotonGatherTime);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs CalculateImportanceSampleTime\n"), 100.0f * Stats.CalculateImportanceSampleTime / IndirectLightingCacheTaskThreadTime, Stats.CalculateImportanceSampleTime);
}
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs FirstBounceRayTraceTime for %.3f million rays\n"), 100.0f * Stats.FirstBounceRayTraceTime / IndirectLightingCacheTaskThreadTime, Stats.FirstBounceRayTraceTime, Stats.NumFirstBounceRaysTraced / 1000000.0f);
SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs CalculateExitantRadiance\n"), 100.0f * Stats.CalculateExitantRadianceTime / IndirectLightingCacheTaskThreadTime, Stats.CalculateExitantRadianceTime);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1200
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::DumpStats
Source code excerpt:
LogSolverMessage(SolverStats);
SolverStats = TEXT("");
if (PhotonMappingSettings.bUsePhotonMapping)
{
const float FirstPassEmittedPhotonEfficiency = 100.0f * FMath::Max(Stats.NumDirectPhotonsGathered, NumIndirectPhotonPaths) / Stats.NumFirstPassPhotonsEmitted;
SolverStats += FString::Printf( TEXT("%.3f million first pass Photons Emitted (out of %.3f million requested) to deposit %.3f million Direct Photons and %u Indirect Photon Paths, efficiency of %.2f%%\n"), Stats.NumFirstPassPhotonsEmitted / 1000000.0f, Stats.NumFirstPassPhotonsRequested / 1000000.0f, Stats.NumDirectPhotonsGathered / 1000000.0f, NumIndirectPhotonPaths, FirstPassEmittedPhotonEfficiency);
const float SecondPassEmittedPhotonEfficiency = 100.0f * Stats.NumIndirectPhotonsGathered / Stats.NumSecondPassPhotonsEmitted;
SolverStats += FString::Printf( TEXT("%.3f million second pass Photons Emitted (out of %.3f million requested) to deposit %.3f million Indirect Photons, efficiency of %.2f%%\n"), Stats.NumSecondPassPhotonsEmitted / 1000000.0f, Stats.NumSecondPassPhotonsRequested / 1000000.0f, Stats.NumIndirectPhotonsGathered / 1000000.0f, SecondPassEmittedPhotonEfficiency);
SolverStats += FString::Printf( TEXT("%.3f million Photon Gathers, %.3f million Irradiance Photon Gathers\n"), Stats.NumPhotonGathers / 1000000.0f, Stats.NumIrradiancePhotonMapSearches / 1000000.0f);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1221
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::DumpStats
Source code excerpt:
if (IrradianceCachingSettings.bAllowIrradianceCaching)
{
const int32 NumIrradianceCacheBounces = PhotonMappingSettings.bUsePhotonMapping ? 1 : GeneralSettings.NumIndirectLightingBounces;
for (int32 BounceIndex = 0; BounceIndex < NumIrradianceCacheBounces; BounceIndex++)
{
const FIrradianceCacheStats& CurrentStats = Stats.Cache[BounceIndex];
if (CurrentStats.NumCacheLookups > 0)
{
const float MissRate = 100.0f * CurrentStats.NumRecords / CurrentStats.NumCacheLookups;
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1358
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ValidateSettings
function void FStaticLightingSystem::CacheSamples
Source code excerpt:
int32 NumUniformHemisphereSamples = 0;
if (PhotonMappingSettings.bUsePhotonMapping)
{
const float NumSamplesFloat =
ImportanceTracingSettings.NumHemisphereSamples
* GeneralSettings.IndirectLightingQuality;
NumUniformHemisphereSamples = FMath::TruncToInt(NumSamplesFloat);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:548
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ProcessVolumeSamplesTask
Source code excerpt:
if (GeneralSettings.NumIndirectLightingBounces > 0
// Calculating incident radiance for volume samples requires final gathering, since photons are only stored on surfaces.
&& (!PhotonMappingSettings.bUsePhotonMapping || PhotonMappingSettings.bUseFinalGathering))
{
const bool bDebugSamples = false;
float BackfacingHitsFraction = 0.0f;
float Unused = 0.0f;
// Sample radius stores the interpolation radius, but CalculateVolumeSampleIncidentRadiance will use this to push out final gather rays (ignore geometry inside the radius)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp:775
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::ProcessTextureMapping
Source code excerpt:
{
const double DirectLightingStartTime = FPlatformTime::Seconds();
const bool bCalculateDirectLightingFromPhotons = PhotonMappingSettings.bUsePhotonMapping && PhotonMappingSettings.bVisualizeCachedApproximateDirectLighting;
// Only continue if photon mapping will not be used for direct lighting
if (!bCalculateDirectLightingFromPhotons)
{
// Iterate over each light that is relevant to the direct lighting of the mesh
for (int32 LightIndex = 0; LightIndex < TextureMapping->Mesh->RelevantLights.Num(); LightIndex++)
{
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h:563
Scope (from outer to inner):
file
namespace Lightmass
class class FPhotonMappingSettings
Source code excerpt:
* Photon mapping benefits many parts of the solver so this is mainly for comparing against other methods.
*/
bool bUsePhotonMapping;
/**
* Debugging - whether to estimate the first bounce lighting by tracing rays from the sample point,
* Which is called final gathering, or by using the density of nearby first bounce photons.
* Final gathering is slow but gets vastly better results than using first bounce photons.
*/