bUseIrradiancePhotons

bUseIrradiancePhotons

#Overview

name: bUseIrradiancePhotons

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 21 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of bUseIrradiancePhotons is to enable the use of irradiance photons in the photon mapping process for global illumination calculations in Unreal Engine’s Lightmass system.

This setting variable is primarily used in the Lightmass module, which is responsible for the offline global illumination calculations in Unreal Engine. It’s part of the photon mapping subsystem within Lightmass.

The value of this variable is set in the Lightmass configuration file (GLightmassIni). It’s read from the configuration file in the FLightmassExporter::WriteSceneSettings function.

Several other variables interact with bUseIrradiancePhotons:

  1. bCacheIrradiancePhotonsOnSurfaces: This setting determines whether to cache irradiance photon calculations on surfaces.
  2. bUsePhotonDirectLightingInFinalGather: This affects how irradiance photons are used in the final gathering step.
  3. DirectIrradiancePhotonFraction and IndirectIrradiancePhotonFraction: These control the proportion of direct and indirect photons that become irradiance photons.

Developers should be aware that:

  1. Enabling this feature can significantly impact performance and memory usage, as it involves storing and processing additional photon data.
  2. It affects the accuracy and quality of indirect lighting calculations, particularly for multi-bounce lighting.
  3. Its effectiveness can vary depending on the scene complexity and lighting conditions.

Best practices when using this variable include:

  1. Use it in conjunction with bCacheIrradiancePhotonsOnSurfaces for optimal performance.
  2. Adjust the DirectIrradiancePhotonFraction and IndirectIrradiancePhotonFraction to balance quality and performance.
  3. Consider disabling it for simpler scenes where the additional accuracy may not be noticeable.
  4. Test thoroughly with and without this feature enabled to determine the best setting for your specific project.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseLightmass.ini:170, section: [DevOptions.PhotonMapping]

#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:2353

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bVisualizeCachedApproximateDirectLighting"), bConfigBool, GLightmassIni));
		Scene.PhotonMappingSettings.bVisualizeCachedApproximateDirectLighting = bConfigBool;
		VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bUseIrradiancePhotons"), bConfigBool, GLightmassIni));
		Scene.PhotonMappingSettings.bUseIrradiancePhotons = bConfigBool;
		VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bCacheIrradiancePhotonsOnSurfaces"), bConfigBool, GLightmassIni));
		Scene.PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces = bConfigBool;
		VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bVisualizePhotonPaths"), bConfigBool, GLightmassIni));
		Scene.PhotonMappingSettings.bVisualizePhotonPaths = bConfigBool;
		VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PhotonMapping"), TEXT("bVisualizePhotonGathers"), bConfigBool, GLightmassIni));
		Scene.PhotonMappingSettings.bVisualizePhotonGathers = bConfigBool;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/FinalGather.cpp:1466

Scope (from outer to inner):

file
namespace    Lightmass
function     FFinalGatherSample FStaticLightingSystem::CachePointIncomingRadiance

Source code excerpt:

		{
			// Use irradiance photons for indirect lighting
			if (PhotonMappingSettings.bUseIrradiancePhotons)
			{
				FLinearColor Irradiance = FLinearColor::Black;

				if (PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces)
				{
					// Trace a ray into the texel to get a good representation of what the final gather will see,

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:906

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings

Source code excerpt:

	}
#if LIGHTMASS_DO_PROCESSING
	if (!InScene.PhotonMappingSettings.bUseIrradiancePhotons)
#endif
	{
		InScene.PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces = false;
	}
	InScene.PhotonMappingSettings.FinalGatherImportanceSampleFraction = FMath::Clamp(InScene.PhotonMappingSettings.FinalGatherImportanceSampleFraction, 0.0f, 1.0f);
	if (InScene.ImportanceTracingSettings.NumHemisphereSamples * (1.0f - InScene.PhotonMappingSettings.FinalGatherImportanceSampleFraction) < 1)

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:988

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings
function     void FStaticLightingSystem::DumpStats

Source code excerpt:

		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)
		{
			SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs    Mark %.3f million Irradiance Photons\n"), 100.0f * Stats.IrradiancePhotonMarkingTime / TotalStaticLightingTime, Stats.IrradiancePhotonMarkingTime, Stats.NumIrradiancePhotons / 1000000.0f);
			if (PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces)
			{
				SolverStats += FString::Printf( TEXT("%4.1f%%%8.1fs    Cache %.3f million Irradiance Photon Samples on surfaces\n"), 100.0f * Stats.CacheIrradiancePhotonsTime / TotalStaticLightingTime, Stats.CacheIrradiancePhotonsTime, Stats.NumCachedIrradianceSamples / 1000000.0f);
			}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1037

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings
function     void FStaticLightingSystem::DumpStats

Source code excerpt:

		}

		if (PhotonMappingSettings.bUseIrradiancePhotons)
		{
			if (PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces
				// Only log Irradiance photon caching stats if it was more than 2 percent of the total time
				&& Stats.CacheIrradiancePhotonsTime / TotalStaticLightingTime > .02)
			{
				SolverStats += FString::Printf( TEXT("\n") );

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:1208

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings
function     void FStaticLightingSystem::DumpStats

Source code excerpt:

		SolverStats += FString::Printf( TEXT("%.3f million Photon Gathers, %.3f million Irradiance Photon Gathers\n"), Stats.NumPhotonGathers / 1000000.0f, Stats.NumIrradiancePhotonMapSearches / 1000000.0f);
		SolverStats += FString::Printf( TEXT("%.3f million Importance Photons found, %.3f million Importance Photon PDF calculations\n"), Stats.TotalFoundImportancePhotons / 1000000.0f, Stats.NumImportancePDFCalculations / 1000000.0f);
		if (PhotonMappingSettings.bUseIrradiancePhotons && Stats.IrradiancePhotonCalculatingTime / TotalStaticLightingTime > .02)
		{
			SolverStats += FString::Printf( TEXT("%.3f million Irradiance Photons, %.1f%% Direct, %.1f%% Indirect, %.3f million actually found\n"), Stats.NumIrradiancePhotons / 1000000.0f, 100.0f * Stats.NumDirectIrradiancePhotons / Stats.NumIrradiancePhotons, 100.0f * (Stats.NumIrradiancePhotons - Stats.NumDirectIrradiancePhotons) / Stats.NumIrradiancePhotons, Stats.NumFoundIrradiancePhotons / 1000000.0f);
			const float IterationsPerSearch = Stats.CalculateIrradiancePhotonStats.NumSearchIterations / (float)Stats.CalculateIrradiancePhotonStats.NumIterativePhotonMapSearches;
			if (Stats.CalculateIrradiancePhotonStats.NumIterativePhotonMapSearches > 0)
			{
				SolverStats += FString::Printf( TEXT("%.1f Irradiance calculating search iterations per search (%.3f million searches, %.3f million iterations)\n"), IterationsPerSearch, Stats.CalculateIrradiancePhotonStats.NumIterativePhotonMapSearches / 1000000.0f, Stats.CalculateIrradiancePhotonStats.NumSearchIterations / 1000000.0f);

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:158

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitPhotons

Source code excerpt:

	LogSolverMessage(FString::Printf(TEXT("EmitIndirectPhotons complete, %.3f million photons emitted in %.1f seconds"), Stats.NumSecondPassPhotonsEmitted / 1000000.0f, Stats.EmitIndirectPhotonsTime));

	if (PhotonMappingSettings.bUseIrradiancePhotons)
	{
		// Process all irradiance photons and mark ones that have direct photons nearby,
		// So that we can search for those with a smaller radius when using them for rendering.
		// This allows more accurate direct shadow transitions with irradiance photons.
		MarkIrradiancePhotons(ImportanceVolumeBounds, mIrradiancePhotons);
		const double EndMarkIrradiancePhotonsTime = FPlatformTime::Seconds();

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:304

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitDirectPhotons

Source code excerpt:

			}

			if (PhotonMappingSettings.bUseIrradiancePhotons && PhotonMappingSettings.bUsePhotonDirectLightingInFinalGather)
			{
				for (int32 PhotonIndex = 0; PhotonIndex < CurrentOutput.IrradiancePhotons->Num(); PhotonIndex++)
				{
					// Add the irradiance photons to an octree
					IrradiancePhotonMap.AddElement(FIrradiancePhotonElement(PhotonIndex, *CurrentOutput.IrradiancePhotons));
				}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:349

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitDirectPhotons

Source code excerpt:

			|| PhotonMappingSettings.bUseFinalGathering && GeneralSettings.ViewSingleBounceNumber == 1)
		{
			if (PhotonMappingSettings.bUseIrradiancePhotons)
			{
				int32 NumDirectIrradiancePhotons = 0;
				for (int32 ArrayIndex = 0; ArrayIndex < IrradiancePhotons.Num(); ArrayIndex++)
				{
					NumDirectIrradiancePhotons += IrradiancePhotons[ArrayIndex].Num();
				}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:480

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitDirectPhotonsWorkRange

Source code excerpt:

		Output.IndirectPathRays[LightIndex].Empty(WorkRange.TargetNumIndirectPhotonPaths);
	}
	if (PhotonMappingSettings.bUseIrradiancePhotons)
	{
		// Attempt to preallocate irradiance photons based on the percentage of photons that go into the irradiance photon map.
		// The actual number of irradiance photons is based on probability.
		Output.IrradiancePhotons->Empty(FMath::TruncToInt(DirectIrradiancePhotonFraction * DirectPhotonEfficiency * WorkRange.NumDirectPhotonsToEmit));
	}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:586

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitDirectPhotonsWorkRange

Source code excerpt:

				Output.DirectPhotons.Add(NewPhoton);
				Output.NumPhotonsEmittedDirect = Output.NumPhotonsEmitted;
				if (PhotonMappingSettings.bUseIrradiancePhotons 
					// Create an irradiance photon for a fraction of the direct photons
					&& RandomStream.GetFraction() < DirectIrradiancePhotonFraction)
				{
					const FIrradiancePhoton NewIrradiancePhoton(PathIntersection.IntersectionVertex.WorldPosition, PathIntersection.IntersectionVertex.WorldTangentZ, true);
					Output.IrradiancePhotons->Add(NewIrradiancePhoton);
				}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:781

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotons

Source code excerpt:

			}

			if (PhotonMappingSettings.bUseIrradiancePhotons)
			{
				for (int32 PhotonIndex = 0; PhotonIndex < CurrentOutput.IrradiancePhotons->Num(); PhotonIndex++)
				{
					// Add the irradiance photons to an octree
					IrradiancePhotonMap.AddElement(FIrradiancePhotonElement(PhotonIndex, *CurrentOutput.IrradiancePhotons));
				}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:831

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotons

Source code excerpt:

#if ALLOW_LIGHTMAP_SAMPLE_DEBUGGING
	if (PhotonMappingSettings.bVisualizePhotonPaths
		&& PhotonMappingSettings.bUseIrradiancePhotons 
		&& GeneralSettings.ViewSingleBounceNumber != 0)
	{
		int32 NumIndirectIrradiancePhotons = 0;
		for (int32 RangeIndex = NumPhotonWorkRanges; RangeIndex < IrradiancePhotons.Num(); RangeIndex++)
		{
			NumIndirectIrradiancePhotons += IrradiancePhotons[RangeIndex].Num();

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:930

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotonsWorkRange

Source code excerpt:

	Output.FirstBounceEscapedPhotons.Empty(FMath::TruncToInt(WorkRange.NumIndirectPhotonsToEmit * .6f * IndirectPhotonEfficiency * PhotonMappingSettings.GeneratePhotonSegmentChance));
	Output.SecondBouncePhotons.Empty(FMath::TruncToInt(WorkRange.NumIndirectPhotonsToEmit * .4f * IndirectPhotonEfficiency));
	if (PhotonMappingSettings.bUseIrradiancePhotons)
	{
		// Attempt to preallocate irradiance photons based on the percentage of photons that go into the irradiance photon map.
		// The actual number of irradiance photons is based on probability.
		Output.IrradiancePhotons->Empty(FMath::TruncToInt(IndirectIrradiancePhotonFraction * IndirectPhotonEfficiency * WorkRange.NumIndirectPhotonsToEmit));
	}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:1070

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotonsWorkRange

Source code excerpt:

#if ALLOW_LIGHTMAP_SAMPLE_DEBUGGING
					if (PhotonMappingSettings.bVisualizePhotonPaths
						&& !PhotonMappingSettings.bUseIrradiancePhotons
						&& (GeneralSettings.ViewSingleBounceNumber < 0
						|| PhotonMappingSettings.bUseFinalGathering && GeneralSettings.ViewSingleBounceNumber > 1 
						|| !PhotonMappingSettings.bUseFinalGathering && GeneralSettings.ViewSingleBounceNumber > 0))
					{
						FScopeLock DebugOutputLock(&DebugOutputSync);
						if (StartupDebugOutput.IndirectPhotons.Num() == 0)

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:1084

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::EmitIndirectPhotonsWorkRange

Source code excerpt:

#endif
					// Create an irradiance photon for a fraction of the deposited photons
					if (PhotonMappingSettings.bUseIrradiancePhotons 
						&& bShouldCreateIrradiancePhoton
						&& RandomStream.GetFraction() < IndirectIrradiancePhotonFraction)
					{
						const FIrradiancePhoton NewIrradiancePhoton(NewPhoton.GetPosition(), PathIntersection.IntersectionVertex.WorldTangentZ, false);
						Output.IrradiancePhotons->Add(NewIrradiancePhoton);
					}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:1218

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::MarkIrradiancePhotons

Source code excerpt:

void FStaticLightingSystem::MarkIrradiancePhotons(const FBoxSphereBounds3f& ImportanceBounds, TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons)
{
	check(PhotonMappingSettings.bUseIrradiancePhotons);
	GSwarm->SendMessage( NSwarm::FTimingMessage( NSwarm::PROGSTATE_Preparing2, 0 ) );

	// Setup work ranges for processing the irradiance photons
	IrradianceMarkWorkRanges.Empty(IrradiancePhotons.Num());
	for (int32 WorkRange = 0; WorkRange < IrradiancePhotons.Num(); WorkRange++)
	{

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:1349

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::CalculateIrradiancePhotons

Source code excerpt:

void FStaticLightingSystem::CalculateIrradiancePhotons(const FBoxSphereBounds3f& ImportanceBounds, TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons)
{
	check(PhotonMappingSettings.bUseIrradiancePhotons);
	//@todo - add a preparing stage for the swarm visualizer
	//GSwarm->SendMessage( NSwarm::FTimingMessage( NSwarm::PROGSTATE_Preparing2, 0 ) );

	if (!PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces)
	{
		// Without bCacheIrradiancePhotonsOnSurfaces, treat all irradiance photons as found since we'll have to calculate irradiance for all of them.

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp:651

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::FinalizeSurfaceCacheTextureMapping

Source code excerpt:

				if ((GeneralSettings.ViewSingleBounceNumber < 0 || GeneralSettings.ViewSingleBounceNumber >= 2)
					&& !ImportanceTracingSettings.bUseRadiositySolverForLightMultibounce
					&& PhotonMappingSettings.bUseIrradiancePhotons)
				{
					const FIrradiancePhoton* NearestPhoton = TextureMapping->CachedIrradiancePhotons[SurfaceCacheIndex];

					if (NearestPhoton)
					{
						// The irradiance photon contains 2nd and up bounce lighting for point / spot / directional lights (since they emit photons)

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/TextureMapping.cpp:2771

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::CalculateDirectLightingTextureMappingPhotonMap

Source code excerpt:

				FStaticLightingVertex CurrentVertex = TexelToVertex.GetVertex();

				if (PhotonMappingSettings.bUseIrradiancePhotons)
				{
					FLinearColor DirectLighting;

					const FIrradiancePhoton* NearestPhoton = NULL;
					if (PhotonMappingSettings.bCacheIrradiancePhotonsOnSurfaces)
					{

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h:586

Scope (from outer to inner):

file
namespace    Lightmass
class        class FPhotonMappingSettings

Source code excerpt:


	/** Debugging - whether to use the optimization of caching irradiance calculations in deposited photons (called Irradiance photons). */
	bool bUseIrradiancePhotons;

	/** 
	* Debugging - whether to cache the result of the search for the nearest irradiance photon on surfaces. 
	* This results in a constant time lookup at the end of each final gather ray instead of a photon map search.
	* Only visible photons are cached, which reduces light leaking.
	*/