ShowFlag.VolumeLightingSamples

ShowFlag.VolumeLightingSamples

#Overview

name: ShowFlag.VolumeLightingSamples

This variable is created as a Console Variable (cvar).

It is referenced in 17 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of ShowFlag.VolumeLightingSamples is to visualize volume lighting samples used for Global Illumination (GI) on dynamic objects in Unreal Engine 5. This setting variable is primarily related to the rendering system, specifically for debugging and visualizing lighting information.

The Unreal Engine subsystems and modules that rely on this setting variable include:

  1. The Renderer module
  2. The Lighting system
  3. The Static Lighting system
  4. The Lightmass system (for pre-computed lighting)

The value of this variable is typically set in the engine’s configuration files or through the editor’s UI. It can be toggled on or off to enable or disable the visualization of volume lighting samples.

This variable interacts with other lighting-related variables and systems, such as:

  1. The Indirect Lighting Cache
  2. Precomputed Light Volumes
  3. Dynamic object lighting settings

Developers should be aware of the following when using this variable:

  1. It is primarily intended for debugging and visualization purposes.
  2. Enabling this flag may impact performance, especially in complex scenes with many lighting samples.
  3. It is fixed in shipping builds, meaning it cannot be toggled in release versions of the game.

Best practices when using this variable include:

  1. Use it during development and lighting setup to ensure proper placement and distribution of volume lighting samples.
  2. Disable it in production builds to avoid performance overhead.
  3. Combine it with other visualization tools to get a comprehensive understanding of the scene’s lighting.

Regarding the associated variable VolumeLightingSamples:

The purpose of VolumeLightingSamples is to store and manage the actual volume lighting sample data used for Global Illumination on dynamic objects. This variable is used in various parts of the engine, including:

  1. The Lightmass processor for importing volume samples
  2. The Static Lighting system for generating and processing volume samples
  3. The Lightmass solver for exporting volume lighting samples

The value of this variable is set during the lightmass computation process and is used throughout the rendering pipeline.

Developers should be aware that:

  1. This variable contains important lighting data and should be handled carefully.
  2. It is used in both editor-time lightmass calculations and runtime rendering.
  3. The data stored in this variable can be significant in size, especially for large and complex scenes.

Best practices for working with VolumeLightingSamples include:

  1. Ensure proper memory management when working with large datasets.
  2. Optimize the number and distribution of volume lighting samples to balance quality and performance.
  3. Use the visualization tools (like ShowFlag.VolumeLightingSamples) to verify the correctness and efficiency of the volume lighting samples.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:329

Scope: file

Source code excerpt:

SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeVolumetricLightmap, SFG_Visualize, NSLOCTEXT("UnrealEd", "VisualizeVolumetricLightmapSF", "Volumetric Lightmap"))
/** Visualize volume lighting samples used for GI on dynamic objects */
SHOWFLAG_FIXED_IN_SHIPPING(0, VolumeLightingSamples, SFG_Visualize, NSLOCTEXT("UnrealEd", "VolumeLightingSamplesSF", "Volume Lighting Samples"))
/** Render Paper2D sprites, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Paper2DSprites, SFG_Advanced, NSLOCTEXT("UnrealEd", "Paper2DSpritesSF", "Paper 2D Sprites"))
/** Visualization of distance field AO */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeDistanceFieldAO, SFG_Visualize, NSLOCTEXT("UnrealEd", "VisualizeDistanceFieldAOSF", "Distance Field Ambient Occlusion"))
/** Mesh Distance fields */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeMeshDistanceFields, SFG_Visualize, NSLOCTEXT("UnrealEd", "MeshDistanceFieldsSF", "Mesh DistanceFields"))

#Associated Variable and Callsites

This variable is associated with another variable named VolumeLightingSamples. They share the same value. See the following C++ source code.

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

Scope (from outer to inner):

file
function     void FLightmassProcessor::ImportVolumeSamples

Source code excerpt:

			if (Channel >= 0)
			{
				ReadArray(Channel, GDebugStaticLightingInfo.VolumeLightingSamples);
				Swarm.CloseChannel(Channel);
			}
		}

		const FString ChannelName = Lightmass::CreateChannelName(Lightmass::PrecomputedVolumeLightingGuid, Lightmass::LM_VOLUMESAMPLES_VERSION, Lightmass::LM_VOLUMESAMPLES_EXTENSION);
		const int32 Channel = Swarm.OpenChannel( *ChannelName, LM_VOLUMESAMPLES_CHANNEL_FLAGS );

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingDebug.cpp:623

Scope (from outer to inner):

file
function     void DrawStaticLightingDebugInfo

Source code excerpt:

		}

		for (int32 SampleIndex = 0; SampleIndex < GDebugStaticLightingInfo.VolumeLightingSamples.Num(); SampleIndex++)
		{
			const FDebugVolumeLightingSample& CurrentSample = GDebugStaticLightingInfo.VolumeLightingSamples[SampleIndex];
			PDI->DrawPoint(FVector4(CurrentSample.Position), CurrentSample.AverageIncidentRadiance * GEngine->LightingOnlyBrightness, 12.0f, SDPG_World);
		}

		for (int32 RayIndex = 0; RayIndex < GDebugStaticLightingInfo.PrecomputedVisibilityRays.Num(); RayIndex++)
		{
			const FDebugStaticLightingRay& CurrentRay = GDebugStaticLightingInfo.PrecomputedVisibilityRays[RayIndex];

#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/StaticLightingSystem/StaticLightingPrivate.h:525

Scope: file

Source code excerpt:

	TArray<FDebugPhoton> GatheredImportancePhotons;
	TArray<FDebugOctreeNode> GatheredPhotonNodes;
	TArray<FDebugVolumeLightingSample> VolumeLightingSamples;
	TArray<FDebugStaticLightingRay> PrecomputedVisibilityRays;
	bool bDirectPhotonValid;
	FDebugPhoton GatheredDirectPhoton;
	FVector4f TexelCorners[NumTexelCorners];
	bool bCornerValid[NumTexelCorners];
	float SampleRadius;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/ImportExport/Exporter.cpp:44

Scope (from outer to inner):

file
namespace    Lightmass
function     void FLightmassSolverExporter::ExportVolumeLightingSamples

Source code excerpt:

			if( ErrorCode >= 0 )
			{
				WriteArray(DebugOutput.VolumeLightingSamples);
				Swarm->CloseCurrentChannel();
			}
			else
			{
				UE_LOG(LogLightmass, Log, TEXT("Failed to open volume sample debug output channel!"));
			}

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ExportNonMappingTasks

Source code excerpt:

			VolumeBounds.Origin, 
			VolumeBounds.BoxExtent, 
			VolumeLightingSamples);

		// Release volume lighting samples unless they are being used by the lighting threads for shading
		if (!DynamicObjectSettings.bVisualizeVolumeLightInterpolation)
		{
			VolumeLightingSamples.Empty();
		}

		// Tell Swarm the task is complete (if we're not in debugging mode).
		if ( !IsDebugMode() )
		{
			FLightmassSwarm* Swarm = GetExporter().GetSwarm();

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

Scope (from outer to inner):

file
namespace    Lightmass
class        class FStaticLightingSystem

Source code excerpt:

	volatile int32 NumVolumeSampleTasksOutstanding;
	volatile int32 bShouldExportVolumeSampleData;
	/** Bounds that VolumeLightingSamples were generated in. */
	FBoxSphereBounds3f VolumeBounds;
	/** Octree used for interpolating the volume lighting samples if DynamicObjectSettings.bVisualizeVolumeLightInterpolation is true. */
	FVolumeLightingInterpolationOctree VolumeLightingInterpolationOctree;
	/** Map from Level Guid to array of volume lighting samples generated. */
	TMap<FGuid,TArray<FVolumeLightingSample> > VolumeLightingSamples;

	/** All precomputed visibility cells in the scene.  Some of these may be processed on other agents. */
	TArray<FPrecomputedVisibilityCell> AllPrecomputedVisibilityCells;

	/** Threads must acquire this critical section before reading or writing to CompletedStaticShadowDepthMaps. */
	FCriticalSection CompletedStaticShadowDepthMapsSync;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:216

Scope (from outer to inner):

file
namespace    Lightmass
function     void FVolumeSamplePlacementRasterPolicy::ProcessPixel

Source code excerpt:

				if (NumBackfacingHits < .3f * UniformHemisphereSamples.Num() * 2)
				{
					TArray<FVolumeLightingSample>* VolumeLightingSamples = System.VolumeLightingSamples.Find(LevelGuid);
					check(VolumeLightingSamples);
					// Add a new sample for this layer
					VolumeLightingSamples->Add(FVolumeLightingSample(FVector4f(SamplePosition, SampleRadius)));
					// Add the sample to the proximity octree so we can avoid placing any more samples nearby
					ProximityOctree.AddElement(FVolumeSampleProximityElement(VolumeLightingSamples->Num() - 1, *VolumeLightingSamples));
					if (System.DynamicObjectSettings.bVisualizeVolumeLightInterpolation)
					{
						System.VolumeLightingInterpolationOctree.AddElement(FVolumeSampleInterpolationElement(VolumeLightingSamples->Num() - 1, *VolumeLightingSamples));
					}
				}
			}
		}
	}
}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:280

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::BeginCalculateVolumeSamples

Source code excerpt:


		//@todo - can this be presized more accurately?
		VolumeLightingSamples.Empty(FMath::Max<int32>(5000, LandscapeEstimateNum));
		FStaticLightingMappingContext MappingContext(nullptr, *this);
		// Octree used to keep track of where existing samples have been placed
		FVolumeLightingProximityOctree VolumeLightingOctree(VolumeBounds.Origin, VolumeBounds.BoxExtent.GetMax());
		// Octree used for interpolating lighting for debugging
		VolumeLightingInterpolationOctree = FVolumeLightingInterpolationOctree(VolumeBounds.Origin, VolumeBounds.BoxExtent.GetMax());
		// Determine the resolution that the scene should be rasterized at based on SurfaceLightSampleSpacing and the scene's extent

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

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::BeginCalculateVolumeSamples

Source code excerpt:

			{
				// Create a new LevelId array if necessary
				if (!VolumeLightingSamples.Find(CurrentMesh->LevelGuid))
				{
					VolumeLightingSamples.Add(CurrentMesh->LevelGuid, TArray<FVolumeLightingSample>());
				}
				// Tell the rasterizer we are adding samples to this mesh's LevelId
				Rasterizer.SetLevelGuid(CurrentMesh->LevelGuid);
				// Rasterize all triangles in the mesh
				for (int32 TriangleIndex = 0; TriangleIndex < CurrentMesh->NumTriangles; TriangleIndex++)
				{

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:422

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::BeginCalculateVolumeSamples

Source code excerpt:

							// Place the sample in the intersected level, or the persistent level if there was no intersection
							const FGuid LevelGuid = Intersection.bIntersects ? Intersection.Mesh->LevelGuid : FGuid(0,0,0,0);
							TArray<FVolumeLightingSample>* VolumeLightingSampleArray = VolumeLightingSamples.Find(LevelGuid);
							if (!VolumeLightingSampleArray)
							{
								VolumeLightingSampleArray = &VolumeLightingSamples.Add(LevelGuid, TArray<FVolumeLightingSample>());
							}

							// Add a sample and set its radius such that its influence touches a diagonal sample on the 3d grid.
							VolumeLightingSampleArray->Add(FVolumeLightingSample(FVector4f(SamplePosition, DetailVolumeSpacing * FMath::Sqrt(3.0f))));
							VolumeLightingOctree.AddElement(FVolumeSampleProximityElement(VolumeLightingSampleArray->Num() - 1, *VolumeLightingSampleArray));
							if (DynamicObjectSettings.bVisualizeVolumeLightInterpolation)

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:448

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::BeginCalculateVolumeSamples

Source code excerpt:

		Stats.NumDynamicObjectSurfaceSamples = SurfaceSamples;

		TArray<FVolumeLightingSample>* UniformVolumeSamples = VolumeLightingSamples.Find(FGuid(0,0,0,0));
		if (!UniformVolumeSamples)
		{
			UniformVolumeSamples = &VolumeLightingSamples.Add(FGuid(0,0,0,0), TArray<FVolumeLightingSample>());
		}

		const float VolumeSpacingCubed = DynamicObjectSettings.VolumeLightSampleSpacing * DynamicObjectSettings.VolumeLightSampleSpacing * DynamicObjectSettings.VolumeLightSampleSpacing;
		int32 RequestedVolumeSamples = FMath::TruncToInt(8.0f * VolumeBounds.BoxExtent.X * VolumeBounds.BoxExtent.Y * VolumeBounds.BoxExtent.Z / VolumeSpacingCubed);
		RequestedVolumeSamples = RequestedVolumeSamples == appTruncErrorCode ? INT_MAX : RequestedVolumeSamples;
		float EffectiveVolumeSpacing = DynamicObjectSettings.VolumeLightSampleSpacing;

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:540

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ProcessVolumeSamplesTask

Source code excerpt:

	float MaxUnoccludedLength = (CombinedVector / UniformHemisphereSamples.Num()).Size3();

	TArray<FVolumeLightingSample>& CurrentLevelSamples = VolumeLightingSamples.FindChecked(Task.LevelId);

	for (int32 SampleIndex = Task.StartIndex; SampleIndex < Task.StartIndex + Task.NumSamples; SampleIndex++)
	{
		FVolumeLightingSample& CurrentSample = CurrentLevelSamples[SampleIndex];

		if (GeneralSettings.NumIndirectLightingBounces > 0 

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/SampleVolume.cpp:571

Scope (from outer to inner):

file
namespace    Lightmass
function     void FStaticLightingSystem::ProcessVolumeSamplesTask

Source code excerpt:

			FSHVectorRGB3 IncidentRadiance;
			CurrentSample.ToSHVector(IncidentRadiance);
			VolumeLightingDebugOutput.VolumeLightingSamples.Add(FDebugVolumeLightingSample(CurrentSample.PositionAndRadius, IncidentRadiance.CalcIntegral() / FSHVector2::ConstantBasisIntegral));
		}
#endif
	}

	MappingContext.Stats.TotalVolumeSampleLightingThreadTime += FPlatformTime::Seconds() - VolumeSampleStartTime;
}

#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/ImportExport.h:484

Scope (from outer to inner):

file
namespace    Lightmass

Source code excerpt:

	struct FVolumeLightingDebugOutput
	{
		TArray<FDebugVolumeLightingSample> VolumeLightingSamples;
	};

	/** Guid used by Unreal to determine when the volume lighting debug channel with the same Guid can be opened. */
	static const FGuid VolumeLightingDebugOutputGuid = FGuid(0x1e8119ff, 0xa46f48f8, 0x92b18d49, 0x172c5832);
	/** Guid used by Unreal to determine when the volume lighting sample channel with the same Guid can be opened. */
	static const FGuid PrecomputedVolumeLightingGuid = FGuid(0xce97c5c3, 0xab614fd3, 0xb2da55c0, 0xe6c33fb4);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:329

Scope: file

Source code excerpt:

SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeVolumetricLightmap, SFG_Visualize, NSLOCTEXT("UnrealEd", "VisualizeVolumetricLightmapSF", "Volumetric Lightmap"))
/** Visualize volume lighting samples used for GI on dynamic objects */
SHOWFLAG_FIXED_IN_SHIPPING(0, VolumeLightingSamples, SFG_Visualize, NSLOCTEXT("UnrealEd", "VolumeLightingSamplesSF", "Volume Lighting Samples"))
/** Render Paper2D sprites, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Paper2DSprites, SFG_Advanced, NSLOCTEXT("UnrealEd", "Paper2DSpritesSF", "Paper 2D Sprites"))
/** Visualization of distance field AO */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeDistanceFieldAO, SFG_Visualize, NSLOCTEXT("UnrealEd", "VisualizeDistanceFieldAOSF", "Distance Field Ambient Occlusion"))
/** Mesh Distance fields */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeMeshDistanceFields, SFG_Visualize, NSLOCTEXT("UnrealEd", "MeshDistanceFieldsSF", "Mesh DistanceFields"))

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/IndirectLightingCache.cpp:596

Scope (from outer to inner):

file
function     void FIndirectLightingCache::FinalizeUpdateInternal_RenderThread

Source code excerpt:

	}	

	if (GCacheDrawLightingSamples || Renderer.ViewFamily.EngineShowFlags.VolumeLightingSamples || GCacheDrawDirectionalShadowing)
	{
		FViewElementPDI DebugPDI(&Renderer.Views[0], nullptr, &Renderer.Views[0].DynamicPrimitiveCollector);

		for (int32 VolumeIndex = 0; VolumeIndex < Scene->PrecomputedLightVolumes.Num(); VolumeIndex++)
		{
			const FPrecomputedLightVolume* PrecomputedLightVolume = Scene->PrecomputedLightVolumes[VolumeIndex];