DirectPhotonDensity
DirectPhotonDensity
#Overview
name: DirectPhotonDensity
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 20
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of DirectPhotonDensity is to control the density of direct photons emitted by lights in the scene for photon mapping calculations. It is used in the lighting and rendering system of Unreal Engine 5, specifically for global illumination and photon mapping.
This setting variable is primarily used by the Lightmass subsystem, which is responsible for precomputed lighting in Unreal Engine. It’s part of the photon mapping settings and is used in both the editor (UnrealEd) and the Lightmass standalone application.
The value of this variable is typically set in the Lightmass configuration file (GLightmassIni). It can be modified through the engine’s configuration system or potentially through in-editor settings.
DirectPhotonDensity interacts with several other variables, including:
- DirectIrradiancePhotonDensity
- IndirectPhotonDensity
- OutsideImportanceVolumeDensityScale
Developers should be aware that:
- This variable significantly impacts the quality and performance of light baking.
- Higher values will result in more accurate lighting but will increase baking time and memory usage.
- The value is in photons per million surface area units, so it scales with scene size.
Best practices when using this variable include:
- Adjust it based on the scale and complexity of your scene.
- Balance it with other photon mapping settings for optimal results.
- Start with default values and incrementally adjust as needed.
- Consider using different values for different quality levels of lightmaps.
- Be mindful of the performance impact when increasing this value, especially for large scenes.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseLightmass.ini:191, section: [DevOptions.PhotonMapping]
- INI Section:
DevOptions.PhotonMapping
- Raw value:
350
- 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:2381
Scope (from outer to inner):
file
function void FLightmassExporter::WriteSceneSettings
Source code excerpt:
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PhotonMapping"), TEXT("NumImportanceSearchPhotons"), Scene.PhotonMappingSettings.NumImportanceSearchPhotons, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("OutsideImportanceVolumeDensityScale"), Scene.PhotonMappingSettings.OutsideImportanceVolumeDensityScale, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("DirectPhotonDensity"), Scene.PhotonMappingSettings.DirectPhotonDensity, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PhotonMapping"), TEXT("DirectIrradiancePhotonDensity"), Scene.PhotonMappingSettings.DirectIrradiancePhotonDensity, GLightmassIni));
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));
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:2450
Scope (from outer to inner):
file
function void FLightmassExporter::WriteSceneSettings
Source code excerpt:
float NumDirectPhotonsScale;
VERIFYLIGHTMASSINI(GConfig->GetFloat(QualitySectionNames[QualityLevel], TEXT("NumDirectPhotonsScale"), NumDirectPhotonsScale, GLightmassIni));
Scene.PhotonMappingSettings.DirectPhotonDensity = Scene.PhotonMappingSettings.DirectPhotonDensity * NumDirectPhotonsScale;
Scene.PhotonMappingSettings.DirectIrradiancePhotonDensity = Scene.PhotonMappingSettings.DirectIrradiancePhotonDensity * NumDirectPhotonsScale;
float DirectPhotonSearchDistanceScale;
VERIFYLIGHTMASSINI(GConfig->GetFloat(QualitySectionNames[QualityLevel], TEXT("DirectPhotonSearchDistanceScale"), DirectPhotonSearchDistanceScale, GLightmassIni));
Scene.PhotonMappingSettings.DirectPhotonSearchDistance = Scene.PhotonMappingSettings.DirectPhotonSearchDistance * DirectPhotonSearchDistanceScale;
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:536
Scope (from outer to inner):
file
namespace Lightmass
function void FScene::ApplyStaticLightingScale
Source code excerpt:
// Scale surface densities in world units
const float ScaleSquared = SceneConstants.StaticLightingLevelScale * SceneConstants.StaticLightingLevelScale;
PhotonMappingSettings.DirectPhotonDensity /= ScaleSquared;
PhotonMappingSettings.DirectIrradiancePhotonDensity /= ScaleSquared;
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));
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:704
Scope (from outer to inner):
file
namespace Lightmass
function int32 FDirectionalLight::GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
int32 FDirectionalLight::GetNumDirectPhotons(float DirectPhotonDensity) const
{
int32 NumDirectPhotons = 0;
if (ImportanceBounds.SphereRadius > DELTA)
{
// The importance volume is valid, so only gather enough direct photons to meet DirectPhotonDensity inside the importance volume
const float ImportanceDiskAreaMillions = (float)PI * FMath::Square(ImportanceBounds.SphereRadius) / 1000000.0f;
checkSlow(SceneBounds.SphereRadius > ImportanceBounds.SphereRadius);
const float OutsideImportanceDiskAreaMillions = (float)PI * (FMath::Square(SceneBounds.SphereRadius) - FMath::Square(ImportanceBounds.SphereRadius)) / 1000000.0f;
NumDirectPhotons = FMath::TruncToInt(ImportanceDiskAreaMillions * DirectPhotonDensity + OutsideImportanceDiskAreaMillions * OutsideImportanceVolumeDensity);
}
else
{
// Gather enough photons to meet DirectPhotonDensity everywhere in the scene
const float SceneDiskAreaMillions = (float)PI * FMath::Square(SceneBounds.SphereRadius) / 1000000.0f;
NumDirectPhotons = FMath::TruncToInt(SceneDiskAreaMillions * DirectPhotonDensity);
}
return NumDirectPhotons == appTruncErrorCode ? INT_MAX : NumDirectPhotons;
}
/** Generates a direction sample from the light's domain */
void FDirectionalLight::SampleDirection(FLMRandomStream& RandomStream, FLightRay& SampleRay, FVector4f& LightSourceNormal, FVector2f& LightSurfacePosition, float& RayPDF, FLinearColor& Power) const
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:994
Scope (from outer to inner):
file
namespace Lightmass
function int32 FPointLight::GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
int32 FPointLight::GetNumDirectPhotons(float DirectPhotonDensity) const
{
// Gather enough photons to meet DirectPhotonDensity at the influence radius of the point light.
const float InfluenceSphereSurfaceAreaMillions = 4.0f * (float)PI * FMath::Square(Radius) / 1000000.0f;
const int32 NumDirectPhotons = FMath::TruncToInt(InfluenceSphereSurfaceAreaMillions * DirectPhotonDensity);
return NumDirectPhotons == appTruncErrorCode ? INT_MAX : NumDirectPhotons;
}
/**
* Tests whether the light affects the given bounding volume.
* @param Bounds - The bounding volume to test.
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:1495
Scope (from outer to inner):
file
namespace Lightmass
function int32 FSpotLight::GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
int32 FSpotLight::GetNumDirectPhotons(float DirectPhotonDensity) const
{
const float InfluenceSphereSurfaceAreaMillions = 4.0f * (float)PI * FMath::Square(Radius) / 1000000.0f;
const float ConeSolidAngle = 2.0f * float(PI) * (1.0f - CosOuterConeAngle);
// Find the fraction of the sphere's surface area that is inside the cone
const float ConeSurfaceAreaSphereFraction = ConeSolidAngle / (4.0f * (float)PI);
// Gather enough photons to meet DirectPhotonDensity on the spherical cap at the influence radius of the spot light.
const int32 NumDirectPhotons = FMath::TruncToInt(InfluenceSphereSurfaceAreaMillions * ConeSurfaceAreaSphereFraction * DirectPhotonDensity);
return NumDirectPhotons == appTruncErrorCode ? INT_MAX : NumDirectPhotons;
}
/** Generates a direction sample from the light's domain */
void FSpotLight::SampleDirection(FLMRandomStream& RandomStream, FLightRay& SampleRay, FVector4f& LightSourceNormal, FVector2f& LightSurfacePosition, float& RayPDF, FLinearColor& Power) const
{
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:1640
Scope (from outer to inner):
file
namespace Lightmass
function int32 FRectLight::GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
int32 FRectLight::GetNumDirectPhotons(float DirectPhotonDensity) const
{
const float InfluenceSphereSurfaceAreaMillions = 4.0f * (float)PI * FMath::Square(Radius) / 1000000.0f;
// Find the fraction of the sphere's surface area that is inside the cone
const float SurfaceAreaSphereFraction = 0.25f;
// Gather enough photons to meet DirectPhotonDensity on the spherical cap at the influence radius of the spot light.
const int32 NumDirectPhotons = FMath::TruncToInt(InfluenceSphereSurfaceAreaMillions * SurfaceAreaSphereFraction * DirectPhotonDensity);
return NumDirectPhotons == appTruncErrorCode ? INT_MAX : NumDirectPhotons;
}
/** Validates a surface sample given the position that sample is affecting. */
void FRectLight::ValidateSurfaceSample(const FVector4f& Point, FLightSurfaceSample& Sample) const
{}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.cpp:2198
Scope (from outer to inner):
file
namespace Lightmass
function int32 FMeshAreaLight::GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
int32 FMeshAreaLight::GetNumDirectPhotons(float DirectPhotonDensity) const
{
// Gather enough photons to meet DirectPhotonDensity at the influence radius of the mesh area light.
// Clamp the influence radius to the importance or scene radius for the purposes of emitting photons
// This prevents huge mesh area lights from emitting more photons than are needed
const float InfluenceSphereSurfaceAreaMillions = 4.0f * (float)PI * FMath::Square(FMath::Min(ImportanceBounds.SphereRadius, InfluenceRadius)) / 1000000.0f;
const int32 NumDirectPhotons = FMath::TruncToInt(InfluenceSphereSurfaceAreaMillions * DirectPhotonDensity);
return NumDirectPhotons == appTruncErrorCode ? INT_MAX : NumDirectPhotons;
}
/** Initializes the mesh area light with primitives */
void FMeshAreaLight::SetPrimitives(
const TArray<FMeshLightPrimitive>& InPrimitives,
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:138
Scope (from outer to inner):
file
namespace Lightmass
class class FLight : public FLightData
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const = 0;
/**
* Tests whether the light affects the given bounding volume.
* @param Bounds - The bounding volume to test.
* @return True if the light affects the bounding volume
*/
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:249
Scope (from outer to inner):
file
namespace Lightmass
class class FDirectionalLight : public FLight, public FDirectionalLightData
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const;
/** Generates a direction sample from the light's domain */
virtual void SampleDirection(FLMRandomStream& RandomStream, FLightRay& SampleRay, FVector4f& LightSourceNormal, FVector2f& LightSurfacePosition, float& RayPDF, FLinearColor& Power) const;
/** Gives the light an opportunity to precalculate information about the indirect path rays that will be used to generate new directions. */
virtual void CachePathRays(const TArray<FIndirectPathRay>& IndirectPathRays);
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:346
Scope (from outer to inner):
file
namespace Lightmass
class class FPointLight : public FLight, public FPointLightData
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const;
/**
* Tests whether the light affects the given bounding volume.
* @param Bounds - The bounding volume to test.
* @return True if the light affects the bounding volume
*/
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:440
Scope (from outer to inner):
file
namespace Lightmass
class class FSpotLight : public FPointLight, public FSpotLightData
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const;
/** Generates a direction sample from the light's domain */
virtual void SampleDirection(FLMRandomStream& RandomStream, FLightRay& SampleRay, FVector4f& LightSourceNormal, FVector2f& LightSurfacePosition, float& RayPDF, FLinearColor& Power) const;
/** Generates a direction sample from the light based on the given rays */
virtual void SampleDirection(
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:469
Scope (from outer to inner):
file
namespace Lightmass
class class FRectLight : public FPointLight, public FRectLightData
Source code excerpt:
virtual FLinearColor GetDirectIntensity(const FVector4f& Point, bool bCalculateForIndirectLighting) const override;
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const override;
virtual void ValidateSurfaceSample(const FVector4f& Point, FLightSurfaceSample& Sample) const override;
virtual FVector4f LightCenterPosition(const FVector4f& ReceivingPosition, const FVector4f& ReceivingNormal) const override;
virtual bool AffectsBounds(const FBoxSphereBounds3f& Bounds) const override;
virtual bool BehindSurface(const FVector4f& TrianglePoint, const FVector4f& TriangleNormal) const override;
virtual FVector4f GetDirectLightingDirection(const FVector4f& Point, const FVector4f& PointNormal) const override;
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:507
Scope (from outer to inner):
file
namespace Lightmass
class class FSkyLight : public FLight, public FSkyLightData
function virtual int32 GetNumDirectPhotons
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const
{ checkf(0, TEXT("GetNumDirectPhotons is not supported for skylights")); return 0; }
/** Generates a direction sample from the light's domain */
virtual void SampleDirection(FLMRandomStream& RandomStream, class FLightRay& SampleRay, FVector4f& LightSourceNormal, FVector2f& LightSurfacePosition, float& RayPDF, FLinearColor& Power) const
{ checkf(0, TEXT("SampleDirection is not supported for skylights")); }
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/LightmassScene.h:606
Scope (from outer to inner):
file
namespace Lightmass
class class FMeshAreaLight : public FLight
Source code excerpt:
/** Returns the number of direct photons to gather required by this light. */
virtual int32 GetNumDirectPhotons(float DirectPhotonDensity) const;
/** Initializes the mesh area light with primitives */
void SetPrimitives(
const TArray<FMeshLightPrimitive>& InPrimitives,
float EmissiveLightFalloffExponent,
float EmissiveLightExplicitInfluenceRadius,
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.cpp:496
Scope (from outer to inner):
file
namespace Lightmass
function FStaticLightingSystem::FStaticLightingSystem
Source code excerpt:
Scene.PhotonMappingSettings.IndirectPhotonEmitDiskRadius,
Scene.SceneConstants.LightGridSize,
Scene.PhotonMappingSettings.DirectPhotonDensity,
Scene.PhotonMappingSettings.DirectPhotonDensity * Scene.PhotonMappingSettings.OutsideImportanceVolumeDensityScale);
Lights.Add(&InScene.DirectionalLights[LightIndex]);
}
// Initialize lights and add them to the solver's Lights array
for (int32 LightIndex = 0; LightIndex < InScene.PointLights.Num(); LightIndex++)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:42
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::InitializePhotonSettings
Source code excerpt:
for (int32 LightIndex = 0; LightIndex < Lights.Num(); LightIndex++)
{
Stats.NumFirstPassPhotonsRequested += Lights[LightIndex]->GetNumDirectPhotons(PhotonMappingSettings.DirectPhotonDensity);
}
NumDirectPhotonsToEmit = FMath::Min<uint64>(Stats.NumFirstPassPhotonsRequested, (uint64)MaxNumDirectPhotonsToEmit);
if (NumDirectPhotonsToEmit == MaxNumDirectPhotonsToEmit)
{
LogSolverMessage(FString::Printf(TEXT("Clamped the number of direct photons to emit to %.3f million, from %.3f million requested."), MaxNumDirectPhotonsToEmit / 1000000.0f, Stats.NumFirstPassPhotonsRequested / 1000000.0f));
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:52
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::InitializePhotonSettings
Source code excerpt:
}
DirectIrradiancePhotonFraction = FMath::Clamp(Scene.PhotonMappingSettings.DirectIrradiancePhotonDensity / Scene.PhotonMappingSettings.DirectPhotonDensity, 0.0f, 1.0f);
// Calculate numbers of photons to gather based on the scene using the given photon densities, the scene's surface area and the importance volume's surface area
float SceneSurfaceAreaMillionUnits = FMath::Max(AggregateMesh->GetSurfaceArea() / 1000000.0f, DELTA);
float SceneSurfaceAreaMillionUnitsEstimate = FMath::Max(4.0f * (float)PI * SceneBounds.SphereRadius * SceneBounds.SphereRadius / 1000000.0f, DELTA);
float SceneSurfaceAreaMillionUnitsEstimateDiff = SceneSurfaceAreaMillionUnitsEstimate > DELTA ? ( SceneSurfaceAreaMillionUnits / SceneSurfaceAreaMillionUnitsEstimate * 100.0f ) : 0.0f;
LogSolverMessage(FString::Printf(TEXT("Scene surface area calculated at %.3f million units (%.3f%% of the estimated %.3f million units)"), SceneSurfaceAreaMillionUnits, SceneSurfaceAreaMillionUnitsEstimateDiff, SceneSurfaceAreaMillionUnitsEstimate));
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PhotonMapping.cpp:211
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::EmitDirectPhotons
Source code excerpt:
{
const FLight* CurrentLight = Lights[LightIndex];
const int32 LightNumDirectPhotons = CurrentLight->GetNumDirectPhotons(PhotonMappingSettings.DirectPhotonDensity);
LightDistribution.LightPDFs.Add(LightNumDirectPhotons);
}
if (Lights.Num() > 0)
{
// Compute the Cumulative Distribution Function for our step function of light powers
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h:667
Scope (from outer to inner):
file
namespace Lightmass
class class FPhotonMappingSettings
Source code excerpt:
* Density of direct photons to emit per light, in number of photons per million surface area units.
*/
float DirectPhotonDensity;
/** Density of direct photons which have irradiance cached at their position, in number of photons per million surface area units. */
float DirectIrradiancePhotonDensity;
/** Distance to use when searching for direct photons. */
float DirectPhotonSearchDistance;