IndirectPhotonDensity

IndirectPhotonDensity

#Overview

name: IndirectPhotonDensity

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

#Summary

#Usage in the C++ source code

The purpose of IndirectPhotonDensity is to control the density of indirect photons in the photon mapping system used for global illumination calculations in Unreal Engine’s Lightmass.

This setting variable is primarily used in the Lightmass subsystem, which is responsible for precomputed lighting in Unreal Engine. It is part of the photon mapping settings that control how indirect lighting is calculated and stored.

The value of this variable is typically set in the Lightmass configuration file (GLightmassIni). It’s read from the “DevOptions.PhotonMapping” section of this configuration file.

IndirectPhotonDensity interacts with several other variables in the photon mapping system:

  1. It’s scaled by NumIndirectPhotonsScale, which allows for quality-based adjustments.
  2. It’s used in conjunction with IndirectIrradiancePhotonDensity to determine the fraction of indirect photons that should store irradiance information.
  3. It’s affected by the StaticLightingLevelScale, which adjusts the density based on the overall scale of the level.

Developers should be aware that:

  1. This variable directly affects the number of indirect photons emitted during the lighting build process. Higher values will result in more accurate indirect lighting but will increase build times and memory usage.
  2. The actual number of photons emitted is capped to prevent excessive memory usage.
  3. The density is applied differently depending on whether an importance volume is used in the scene.

Best practices when using this variable include:

  1. Adjust it based on the scale and complexity of your scene. Larger scenes may require lower densities to keep build times reasonable.
  2. Use it in conjunction with importance volumes to focus photon density in areas where it’s most needed.
  3. Be prepared to experiment with different values to find the right balance between lighting quality and build performance for your specific project.
  4. Consider the relationship between this value and other photon mapping settings for optimal results.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseLightmass.ini:197, 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:2385

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("DirectPhotonSearchDistance"), Scene.PhotonMappingSettings.DirectPhotonSearchDistance, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("IndirectPhotonPathDensity"), Scene.PhotonMappingSettings.IndirectPhotonPathDensity, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("IndirectPhotonDensity"), Scene.PhotonMappingSettings.IndirectPhotonDensity, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("IndirectIrradiancePhotonDensity"), Scene.PhotonMappingSettings.IndirectIrradiancePhotonDensity, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("IndirectPhotonSearchDistance"), Scene.PhotonMappingSettings.IndirectPhotonSearchDistance, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("PhotonSearchAngleThreshold"), Scene.PhotonMappingSettings.PhotonSearchAngleThreshold, GLightmassIni));
		float IrradiancePhotonSearchConeAngle;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("IrradiancePhotonSearchConeAngle"), IrradiancePhotonSearchConeAngle, GLightmassIni));
		Scene.PhotonMappingSettings.MinCosIrradiancePhotonSearchCone = FMath::Cos((90.0f - FMath::Clamp(IrradiancePhotonSearchConeAngle, 1.0f, 90.0f)) * (float)PI / 180.0f);

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:2463

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		float NumIndirectPhotonsScale;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(QualitySectionNames[QualityLevel], TEXT("NumIndirectPhotonsScale"), NumIndirectPhotonsScale, GLightmassIni));
		Scene.PhotonMappingSettings.IndirectPhotonDensity = Scene.PhotonMappingSettings.IndirectPhotonDensity * NumIndirectPhotonsScale;

		float NumIndirectIrradiancePhotonsScale;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(QualitySectionNames[QualityLevel], TEXT("NumIndirectIrradiancePhotonsScale"), NumIndirectIrradiancePhotonsScale, GLightmassIni));
		Scene.PhotonMappingSettings.IndirectIrradiancePhotonDensity = Scene.PhotonMappingSettings.IndirectIrradiancePhotonDensity * NumIndirectIrradiancePhotonsScale;

		float RecordRadiusScaleScale;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:540

Scope (from outer to inner):

file
namespace    Lightmass
function     void FScene::ApplyStaticLightingScale

Source code excerpt:

	PhotonMappingSettings.DirectPhotonSearchDistance *= SceneConstants.StaticLightingLevelScale;
	PhotonMappingSettings.IndirectPhotonPathDensity /= ScaleSquared;
	PhotonMappingSettings.IndirectPhotonDensity /= ScaleSquared;
	PhotonMappingSettings.IndirectIrradiancePhotonDensity /= ScaleSquared;
	PhotonMappingSettings.IndirectPhotonSearchDistance *= SceneConstants.StaticLightingLevelScale;
	*/
}

//----------------------------------------------------------------------------
//	Light base class
//----------------------------------------------------------------------------
void FLight::Import( FLightmassImporter& Importer )
{
	Importer.ImportData( (FLightData*)this );
	Importer.ImportArray( LightTextureProfileData, FLightData::LightProfileTextureDataSize );

	// The read above stomps on CachedLightSurfaceSamples since that memory is padding in FLightData
	FMemory::Memzero(&CachedLightSurfaceSamples, sizeof(CachedLightSurfaceSamples));
	
	// Precalculate the light's indirect color
	IndirectColor = FLinearColorUtils::AdjustSaturation(FLinearColor(Color), IndirectLightingSaturation) * IndirectLightingScale;
}

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings

Source code excerpt:

	InScene.GeneralSettings.ViewSingleBounceNumber = FMath::Min(InScene.GeneralSettings.ViewSingleBounceNumber, InScene.GeneralSettings.NumIndirectLightingBounces);

	if (FMath::IsNearlyEqual(InScene.PhotonMappingSettings.IndirectPhotonDensity, 0.0f))
	{
		// Allocate all samples toward uniform sampling if there are no indirect photons
		InScene.PhotonMappingSettings.FinalGatherImportanceSampleFraction = 0;
	}
#if LIGHTMASS_DO_PROCESSING
	if (!InScene.PhotonMappingSettings.bUseIrradiancePhotons)

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::InitializePhotonSettings

Source code excerpt:

#endif
	Stats.NumSecondPassPhotonsRequested = 0;
	// If the importance volume is valid, only emit enough indirect photons to meet IndirectPhotonDensity inside the importance volume
	if (!PhotonMappingSettings.bEmitPhotonsOutsideImportanceVolume && ImportanceBounds.SphereRadius > DELTA)
	{
		Stats.NumSecondPassPhotonsRequested = Scene.PhotonMappingSettings.IndirectPhotonDensity * ImportanceSurfaceAreaMillionUnits;
	}
	else if (ImportanceBounds.SphereRadius > DELTA)
	{
		Stats.NumSecondPassPhotonsRequested = Scene.PhotonMappingSettings.IndirectPhotonDensity * ImportanceSurfaceAreaMillionUnits
			+ Scene.PhotonMappingSettings.OutsideImportanceVolumeDensityScale * Scene.PhotonMappingSettings.IndirectPhotonDensity * SceneSurfaceAreaMillionUnits;
	}
	else
	{
		Stats.NumSecondPassPhotonsRequested = Scene.PhotonMappingSettings.IndirectPhotonDensity * SceneSurfaceAreaMillionUnits;
	}
	NumIndirectPhotonsToEmit = FMath::Min<uint64>(Stats.NumSecondPassPhotonsRequested, (uint64)MaxNumIndirectPhotons);
	if (NumIndirectPhotonsToEmit == MaxNumIndirectPhotons)
	{
		LogSolverMessage(FString::Printf(TEXT("Clamped the number of indirect photons to emit to %.3f million, from %.3f million requested."), MaxNumIndirectPhotons / 1000000.0f, Stats.NumSecondPassPhotonsRequested / 1000000.0f));
	}

	IndirectIrradiancePhotonFraction = FMath::Clamp(Scene.PhotonMappingSettings.IndirectIrradiancePhotonDensity / Scene.PhotonMappingSettings.IndirectPhotonDensity, 0.0f, 1.0f);
}

/** Emits photons, builds data structures to accelerate photon map lookups, and does any other photon preprocessing required. */
void FStaticLightingSystem::EmitPhotons()
{
	const FBoxSphereBounds3f SceneSphereBounds = FBoxSphereBounds3f(AggregateMesh->GetBounds());

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

Scope (from outer to inner):

file
namespace    Lightmass
class        class FPhotonMappingSettings

Source code excerpt:

	 * This should be high because first bounce photons are used to guide the final gather.
	 */
	float IndirectPhotonDensity;

	/** Density of indirect photons which have irradiance cached at their position, in number of photons per million surface area units. */
	float IndirectIrradiancePhotonDensity;

	/** Distance to use when searching for indirect photons. */
	float IndirectPhotonSearchDistance;