NumAdaptiveRefinementLevels

NumAdaptiveRefinementLevels

#Overview

name: NumAdaptiveRefinementLevels

The value of this variable can be defined or overridden in .ini config files. 4 .ini config files referencing this setting variable.

It is referenced in 16 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of NumAdaptiveRefinementLevels is to control the number of recursive levels allowed for adaptive refinement in importance tracing, which is a technique used in global illumination calculations. This setting has a significant impact on both the quality of the lighting results and the build time of the lightmaps.

NumAdaptiveRefinementLevels is primarily used in the Lightmass subsystem of Unreal Engine, which is responsible for precomputed lighting calculations. It is part of the FImportanceTracingSettings struct, which suggests it’s specifically used for importance tracing in the global illumination process.

The value of this variable is set in the Lightmass configuration file (GLightmassIni). It can be adjusted based on the quality settings of the lightmap build process, as seen in the WriteSceneSettings function in Lightmass.cpp.

This variable interacts with other importance tracing settings, such as AdaptiveBrightnessThreshold and AdaptiveFirstBouncePhotonConeAngle. It’s also influenced by the IndirectLightingQuality setting, which can increase the number of refinement levels for higher quality settings.

Developers should be aware that increasing NumAdaptiveRefinementLevels will significantly increase build times but can also improve the quality of indirect lighting. It’s important to balance this setting with performance considerations.

Best practices when using this variable include:

  1. Start with lower values and incrementally increase if needed, as higher values dramatically increase build times.
  2. Consider the project’s requirements for lighting quality versus build time when adjusting this value.
  3. Use in conjunction with other importance tracing settings for optimal results.
  4. Be aware that very high values (beyond 4 or 5) may yield diminishing returns in terms of visual quality improvement.
  5. Test the impact of changes in a controlled environment before applying to a full production build.

Remember that this setting is part of the advanced lightmass configuration and should be adjusted with care and understanding of its impact on the lighting build process.

#Setting Variables

#References In INI files

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

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

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

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

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

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		Scene.ImportanceTracingSettings.bUseStratifiedSampling = bConfigBool;
		VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.ImportanceTracing"), TEXT("NumHemisphereSamples"), Scene.ImportanceTracingSettings.NumHemisphereSamples, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.ImportanceTracing"), TEXT("NumAdaptiveRefinementLevels"), Scene.ImportanceTracingSettings.NumAdaptiveRefinementLevels, GLightmassIni));
		float MaxHemisphereAngleDegrees;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.ImportanceTracing"), TEXT("MaxHemisphereRayAngle"), MaxHemisphereAngleDegrees, GLightmassIni));
		Scene.ImportanceTracingSettings.MaxHemisphereRayAngle = MaxHemisphereAngleDegrees * (float)PI / 180.0f;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.ImportanceTracing"), TEXT("AdaptiveBrightnessThreshold"), Scene.ImportanceTracingSettings.AdaptiveBrightnessThreshold, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.ImportanceTracing"), TEXT("AdaptiveFirstBouncePhotonConeAngle"), Scene.ImportanceTracingSettings.AdaptiveFirstBouncePhotonConeAngle, GLightmassIni));
		VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.ImportanceTracing"), TEXT("AdaptiveSkyVarianceThreshold"), Scene.ImportanceTracingSettings.AdaptiveSkyVarianceThreshold, GLightmassIni));

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

Scope (from outer to inner):

file
function     void FLightmassExporter::WriteSceneSettings

Source code excerpt:

		Scene.IrradianceCachingSettings.AngleSmoothFactor *= IrradianceCacheSmoothFactor;

		VERIFYLIGHTMASSINI(GConfig->GetInt(QualitySectionNames[QualityLevel], TEXT("NumAdaptiveRefinementLevels"), Scene.ImportanceTracingSettings.NumAdaptiveRefinementLevels, GLightmassIni));

		float AdaptiveBrightnessThresholdScale;
		VERIFYLIGHTMASSINI(GConfig->GetFloat(QualitySectionNames[QualityLevel], TEXT("AdaptiveBrightnessThresholdScale"), AdaptiveBrightnessThresholdScale, GLightmassIni));
		Scene.ImportanceTracingSettings.AdaptiveBrightnessThreshold = Scene.ImportanceTracingSettings.AdaptiveBrightnessThreshold * AdaptiveBrightnessThresholdScale;

		float AdaptiveFirstBouncePhotonConeAngleScale;

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::CalculateVolumeSampleIncidentRadiance

Source code excerpt:

	MappingContext.Stats.VolumetricLightmapDirectLightingTime += EndUpperDirectLightingTime - EndGatherTime;

	int32 NumSampleAdaptiveRefinementLevels = ImportanceTracingSettings.NumAdaptiveRefinementLevels;
	float SampleAdaptiveRefinementBrightnessScale = 1.0f;
	FLightingCacheGatherInfo UpperGatherInfo;

	FFinalGatherSample3 UpperHemisphereSample = IncomingRadianceAdaptive<FFinalGatherSample3>(
		NULL, 
		RepresentativeVertex, 

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

Scope (from outer to inner):

file
namespace    Lightmass
class        class FUniformHemisphereRefinementGrid
function     void RefineIncomingRadiance

Source code excerpt:

		EHemisphereGatherClassification GatherClassification,
		bool bGatheringForCachedDirectLighting,
		int32 NumAdaptiveRefinementLevels,
		float BrightnessThresholdScale,
		const TArray<FVector4f, TInlineAllocator<30> >& TangentImportancePhotonDirections,
		const TArray<FSphere3f>& PortalBoundingSpheres,
		FStaticLightingMappingContext& MappingContext,
		FGatherHitPoints* HitPointRecorder,
		FLMRandomStream& RandomStream,

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

Scope (from outer to inner):

file
namespace    Lightmass
class        class FUniformHemisphereRefinementGrid
function     void RefineIncomingRadiance

Source code excerpt:

		// Operate on all cells at a refinement depth before going deeper
		// This is necessary for the neighbor comparisons to work right
		for (int32 RefinementDepth = 0; RefinementDepth < NumAdaptiveRefinementLevels; RefinementDepth++)
		{
			FLinearColor TotalLighting = FLinearColor::Black;

			// Recalculate total lighting based on the refined results
			for (int32 ThetaIndex = 0; ThetaIndex < NumThetaSteps; ThetaIndex++)
			{

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

Scope (from outer to inner):

file
namespace    Lightmass
function     SampleType FStaticLightingSystem::IncomingRadianceAdaptive

Source code excerpt:

	EFinalGatherRayBiasMode RayBiasMode,
	EHemisphereGatherClassification GatherClassification,
	int32 NumAdaptiveRefinementLevels,
	float BrightnessThresholdScale,
	const TArray<FVector4f>& UniformHemisphereSamples,
	const TArray<FVector2f>& UniformHemisphereSampleUniforms,
	float MaxUnoccludedLength,
	const TArray<FVector4f>& ImportancePhotonDirections,
	FStaticLightingMappingContext& MappingContext,

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

Scope (from outer to inner):

file
namespace    Lightmass
function     SampleType FStaticLightingSystem::IncomingRadianceAdaptive

Source code excerpt:

			GatherClassification,
			bGatheringForCachedDirectLighting,
			NumAdaptiveRefinementLevels,
			BrightnessThresholdScale,
			TangentSpaceImportancePhotonDirections,
			Scene.Portals,
			MappingContext,
			GatherInfo.HitPointRecorder,
			RandomStream,

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

Scope (from outer to inner):

file
namespace    Lightmass
function     FFinalGatherSample FStaticLightingSystem::CachePointIncomingRadiance

Source code excerpt:

					RBM_ConstantNormalOffset,
					GLM_FinalGather,
					ImportanceTracingSettings.NumAdaptiveRefinementLevels,
					1.0f,
					CachedHemisphereSamples,
					CachedHemisphereSampleUniforms,
					CachedSamplesMaxUnoccludedLength,
					ImportancePhotonDirections, 
					MappingContext, 

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ValidateSettings

Source code excerpt:

	if (InScene.GeneralSettings.IndirectLightingQuality > 50)
	{
		InScene.ImportanceTracingSettings.NumAdaptiveRefinementLevels += 2;
	}
	else if (InScene.GeneralSettings.IndirectLightingQuality > 10)
	{
		InScene.ImportanceTracingSettings.NumAdaptiveRefinementLevels += 1;
	}

	InScene.ShadowSettings.NumShadowRays = FMath::TruncToInt(InScene.ShadowSettings.NumShadowRays * FMath::Sqrt(InScene.GeneralSettings.IndirectLightingQuality));
	InScene.ShadowSettings.NumPenumbraShadowRays = FMath::TruncToInt(InScene.ShadowSettings.NumPenumbraShadowRays * FMath::Sqrt(InScene.GeneralSettings.IndirectLightingQuality));

	InScene.ImportanceTracingSettings.NumAdaptiveRefinementLevels = FMath::Min(InScene.ImportanceTracingSettings.NumAdaptiveRefinementLevels, MaxNumRefiningDepths);
}

/** Logs solver stats */
void FStaticLightingSystem::DumpStats(float TotalStaticLightingTime) const
{
	FString SolverStats = TEXT("\n\n");

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

Scope (from outer to inner):

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

Source code excerpt:

		uint64 TotalNumRefiningSamples = 0;

		for (int i = 0; i < ImportanceTracingSettings.NumAdaptiveRefinementLevels; i++)
		{
			TotalNumRefiningSamples += Stats.NumRefiningFinalGatherSamples[i];
		}

		SolverStats += FString::Printf( TEXT("Final Gather: %.1fs on %.3f million base samples, %.1fs on %.3f million refining samples for %u refinement levels. \n"), Stats.BaseFinalGatherSampleTime, Stats.NumBaseFinalGatherSamples / 1000000.0f, Stats.RefiningFinalGatherSampleTime, TotalNumRefiningSamples / 1000000.0f, ImportanceTracingSettings.NumAdaptiveRefinementLevels);
		
		if (TotalNumRefiningSamples > 0)
		{
			SolverStats += FString::Printf( TEXT("   %.1f%% due to brightness differences, %.1f%% due to importance photons, %.1f%% other reasons, Samples at depth: "), 100.0f * Stats.NumRefiningSamplesDueToBrightness / TotalNumRefiningSamples, 100.0f * Stats.NumRefiningSamplesDueToImportancePhotons / TotalNumRefiningSamples, 100.0f * Stats.NumRefiningSamplesOther / TotalNumRefiningSamples);

			for (int i = 0; i < ImportanceTracingSettings.NumAdaptiveRefinementLevels; i++)
			{
				SolverStats += FString::Printf(TEXT("%.1f%%, "), 100.0f * Stats.NumRefiningFinalGatherSamples[i] / TotalNumRefiningSamples);
			}

			SolverStats += FString::Printf(TEXT("\n"));
		}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.h:2345

Scope (from outer to inner):

file
namespace    Lightmass
class        class FStaticLightingSystem

Source code excerpt:

		EFinalGatherRayBiasMode RayBiasMode,
		EHemisphereGatherClassification GatherClassification,
		int32 NumAdaptiveRefinementLevels,
		float BrightnessThresholdScale,
		const TArray<FVector4f>& UniformHemisphereSamples,
		const TArray<FVector2f>& UniformHemisphereSampleUniforms,
		float MaxUnoccludedLength,
		const TArray<FVector4f>& ImportancePhotonDirections,
		FStaticLightingMappingContext& MappingContext,

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Radiosity.cpp:305

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::RadiositySetupTextureMapping

Source code excerpt:

						TArray<FVector4f> ImportancePhotonDirections;
						FLightingCacheGatherInfo GatherInfo;
						const int32 NumAdaptiveRefinementLevels = GeneralSettings.IndirectLightingQuality <= 10 ? 1 : 2;

						if (bCacheFinalGatherHitPoints)
						{
							GatherHitPoints.GatherHitPointRanges.Add(FArrayRange(GatherHitPoints.GatherHitPointData.Num()));
							GatherInfo.HitPointRecorder = &GatherHitPoints;
						}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Radiosity.cpp:322

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::RadiositySetupTextureMapping

Source code excerpt:

							RBM_ConstantNormalOffset,
							GLM_GatherLightEmitted, /* Gather sky light and emissive only */
							NumAdaptiveRefinementLevels,
							1.0f,
							CachedHemisphereSamplesForRadiosity[0],
							CachedHemisphereSamplesForRadiosityUniforms[0],
							1,
							ImportancePhotonDirections, 
							MappingContext, 

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Radiosity.cpp:580

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::RadiosityIterationTextureMapping

Source code excerpt:

		const int32 DestRadiosityBufferIndex = 1 - SourceRadiosityBufferIndex;

		int32 NumAdaptiveRefinementLevels = PassIndex == 0 ? 1 : 0;

		if (GeneralSettings.IndirectLightingQuality > 10)
		{
			NumAdaptiveRefinementLevels++;
		}

		const int32 RadiositySampleSet = FMath::Min<int32>(PassIndex, UE_ARRAY_COUNT(CachedHemisphereSamplesForRadiosity) - 1);

		TLightingCache<FFinalGatherSample> RadiosityCache(TextureMapping->Mesh->BoundingBox, *this, 1);
	

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/Radiosity.cpp:634

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::RadiosityIterationTextureMapping

Source code excerpt:

							RBM_ConstantNormalOffset,
							GatherClassification, 
							NumAdaptiveRefinementLevels,
							1.0f,
							CachedHemisphereSamplesForRadiosity[RadiositySampleSet],
							CachedHemisphereSamplesForRadiosityUniforms[RadiositySampleSet],
							1,
							ImportancePhotonDirections, 
							MappingContext, 

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

Scope (from outer to inner):

file
namespace    Lightmass
class        class FImportanceTracingSettings

Source code excerpt:


	/** Number of recursive levels allowed for adaptive refinement.  This has a huge impact on build time but also quality. */
	int32 NumAdaptiveRefinementLevels;

	/** 
	 * Largest angle from the sample normal that a hemisphere sample direction can be. 
	 * Useful for preventing rays nearly perpendicular to the normal which may self intersect a flat surface due to imprecision in the normal.
	 */
	float MaxHemisphereRayAngle;