ShowFlag.VisualizeLightCulling

ShowFlag.VisualizeLightCulling

#Overview

name: ShowFlag.VisualizeLightCulling

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

It is referenced in 24 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of ShowFlag.VisualizeLightCulling is to enable a visualization mode for light culling in the Unreal Engine 5 rendering system. This setting variable is used primarily for debugging and optimizing the lighting system, allowing developers to visually inspect how lights are being culled in the scene.

The Unreal Engine subsystems that rely on this setting variable are primarily within the rendering module. Based on the callsites, it’s used in various parts of the renderer, including deferred shading, mobile shading, and post-processing.

The value of this variable is typically set through the engine’s show flags system, which allows toggling various debug visualization modes. It’s not directly set in the code snippets provided, but it’s accessed through ViewFamily.EngineShowFlags.VisualizeLightCulling.

This variable interacts with several other rendering systems and flags. For example, it’s often used in conjunction with other show flags and can affect the behavior of various rendering passes.

Developers should be aware that enabling this flag will change the visual output of the renderer, as it’s designed to show debug information rather than the final, intended visual result. It may also have performance implications, as it can disable certain optimizations or enable additional rendering passes.

Best practices for using this variable include:

  1. Use it primarily for debugging and optimizing light culling.
  2. Be aware that it may affect performance when enabled.
  3. Remember to disable it before final builds or when not actively debugging lighting issues.

The associated variable VisualizeLightCulling appears to be used interchangeably with ShowFlag.VisualizeLightCulling in some parts of the code. It serves the same purpose and is likely just an alternative way to access the same functionality. The same considerations and best practices apply to this associated variable.

#References in C++ code

#Callsites

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

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

Scope: file

Source code excerpt:

SHOWFLAG_ALWAYS_ACCESSIBLE(DistanceCulledPrimitives, SFG_Hidden, NSLOCTEXT("UnrealEd", "DistanceCulledPrimitivesSF", "Distance Culled Primitives"))
/** To visualize the culling in Tile Based Deferred Lighting, later for non tiled as well */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeLightCulling, SFG_Hidden, NSLOCTEXT("UnrealEd", "VisualizeLightCullingSF", "Light Culling"))
/** To disable precomputed visibility */
SHOWFLAG_FIXED_IN_SHIPPING(1, PrecomputedVisibility, SFG_Advanced, NSLOCTEXT("UnrealEd", "PrecomputedVisibilitySF", "Precomputed Visibility"))
/** Contribution from sky light, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(SkyLighting, SFG_LightTypes, NSLOCTEXT("UnrealEd", "SkyLightingSF", "Sky Lighting"))
/** Visualize preview shadow indicator */
SHOWFLAG_FIXED_IN_SHIPPING(0, PreviewShadowsIndicator, SFG_Visualize, NSLOCTEXT("UnrealEd", "PreviewShadowIndicatorSF", "Preview Shadows Indicator"))

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShowFlags.cpp:760

Scope: file

Source code excerpt:

		return VMI_ShaderComplexity;
	}
	else if (EngineShowFlags.VisualizeLightCulling)
	{
		return VMI_LightComplexity;
	}
	else if (EngineShowFlags.LightMapDensity)
	{
		if (EngineShowFlags.Lighting)

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

Scope: file

Source code excerpt:

SHOWFLAG_ALWAYS_ACCESSIBLE(DistanceCulledPrimitives, SFG_Hidden, NSLOCTEXT("UnrealEd", "DistanceCulledPrimitivesSF", "Distance Culled Primitives"))
/** To visualize the culling in Tile Based Deferred Lighting, later for non tiled as well */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeLightCulling, SFG_Hidden, NSLOCTEXT("UnrealEd", "VisualizeLightCullingSF", "Light Culling"))
/** To disable precomputed visibility */
SHOWFLAG_FIXED_IN_SHIPPING(1, PrecomputedVisibility, SFG_Advanced, NSLOCTEXT("UnrealEd", "PrecomputedVisibilitySF", "Precomputed Visibility"))
/** Contribution from sky light, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(SkyLighting, SFG_LightTypes, NSLOCTEXT("UnrealEd", "SkyLightingSF", "Sky Lighting"))
/** Visualize preview shadow indicator */
SHOWFLAG_FIXED_IN_SHIPPING(0, PreviewShadowsIndicator, SFG_Visualize, NSLOCTEXT("UnrealEd", "PreviewShadowIndicatorSF", "Preview Shadows Indicator"))

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/ClusteredDeferredShadingPass.cpp:216

Scope (from outer to inner):

file
function     static void InternalAddClusteredDeferredShadingPass
lambda-function

Source code excerpt:


		FClusteredShadingPS::FPermutationDomain PermutationVector;
		PermutationVector.Set<FClusteredShadingPS::FVisualizeLightCullingDim>(View.Family->EngineShowFlags.VisualizeLightCulling);
		PermutationVector.Set<FClusteredShadingPS::FHairStrandsLighting>(bHairStrands);
		PermutationVector.Set<FClusteredShadingPS::FSubstrateTileType>(bSubstrate ? TileType : 0);
		PermutationVector.Set<FClusteredShadingPS::FRectLight>(bHasRectLights);
		PermutationVector.Set<FClusteredShadingPS::FLightFunctionAtlasDim>(bLightFunctionAtlas);
		TShaderMapRef<FClusteredShadingPS> PixelShader(View.ShaderMap, PermutationVector);
		{

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/CompositionLighting/PostProcessDeferredDecals.cpp:56

Scope (from outer to inner):

file
function     bool AreDecalsEnabled

Source code excerpt:

bool AreDecalsEnabled(const FSceneViewFamily& ViewFamily)
{
	return ViewFamily.EngineShowFlags.Decals && !ViewFamily.EngineShowFlags.VisualizeLightCulling;
}

bool IsDBufferEnabled(const FSceneViewFamily& ViewFamily, EShaderPlatform ShaderPlatform)
{
	return IsUsingDBuffers(ShaderPlatform)
		&& AreDecalsEnabled(ViewFamily)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp:2484

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::Render

Source code excerpt:

		}

		if (ViewFamily.EngineShowFlags.VisualizeLightCulling)
		{
			FRDGTextureRef VisualizeLightCullingTexture = GraphBuilder.CreateTexture(SceneTextures.Color.Target->Desc, TEXT("SceneColorVisualizeLightCulling"));
			AddClearRenderTargetPass(GraphBuilder, VisualizeLightCullingTexture, FLinearColor::Transparent);
			SceneTextures.Color.Target = VisualizeLightCullingTexture;

			// When not in MSAA, assign to both targets.

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/DistanceFieldAmbientOcclusion.cpp:693

Scope (from outer to inner):

file
function     bool ShouldRenderDeferredDynamicSkyLight

Source code excerpt:

		&& Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5
		&& !IsForwardShadingEnabled(Scene->GetShaderPlatform())
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
		&& !ShouldRenderRayTracingSkyLight(Scene->SkyLight, Scene->GetShaderPlatform()); // Disable diffuse sky contribution if evaluated by RT Sky;
}

bool ShouldDoReflectionEnvironment(const FScene* Scene, const FSceneViewFamily& ViewFamily)
{
	const ERHIFeatureLevel::Type SceneFeatureLevel = Scene->GetFeatureLevel();

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/IndirectLightRendering.cpp:876

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::DispatchAsyncLumenIndirectLightingWork

Source code excerpt:

		|| !bAsyncComputeDiffuseIndirect
		|| GLumenVisualizeIndirectDiffuse
		|| ViewFamily.EngineShowFlags.VisualizeLightCulling)
	{
		return;
	}

	// Decals may modify GBuffers so they need to be done first. Can decals read velocities and/or custom depth? If so, they need to be rendered earlier too.
	CompositionLighting.ProcessAfterBasePass(GraphBuilder, InstanceCullingManager, FCompositionLighting::EProcessAfterBasePassMode::OnlyBeforeLightingDecals);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/IndirectLightRendering.cpp:952

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderDiffuseIndirectAndAmbientOcclusion

Source code excerpt:

	extern int32 GLumenVisualizeIndirectDiffuse;
	if ((GLumenVisualizeIndirectDiffuse != 0) != bIsVisualizePass
		|| ViewFamily.EngineShowFlags.VisualizeLightCulling)
	{
		return;
	}

	TRACE_CPUPROFILER_EVENT_SCOPE(FDeferredShadingSceneRenderer::RenderDiffuseIndirectAndAmbientOcclusion);
	RDG_EVENT_SCOPE(GraphBuilder, "DiffuseIndirectAndAO");

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/IndirectLightRendering.cpp:1909

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderDeferredReflectionsAndSkyLighting

Source code excerpt:

{
	extern int32 GLumenVisualizeIndirectDiffuse;
	if (ViewFamily.EngineShowFlags.VisualizeLightCulling 
		|| ViewFamily.EngineShowFlags.RayTracingDebug
		|| ViewFamily.EngineShowFlags.PathTracing
		|| !ViewFamily.EngineShowFlags.Lighting
		|| GLumenVisualizeIndirectDiffuse != 0)
	{
		return;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/IndirectLightRendering.cpp:2183

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderDeferredReflectionsAndSkyLightingHair

Source code excerpt:

void FDeferredShadingSceneRenderer::RenderDeferredReflectionsAndSkyLightingHair(FRDGBuilder& GraphBuilder)
{
	if (ViewFamily.EngineShowFlags.VisualizeLightCulling || !ViewFamily.EngineShowFlags.Lighting)
	{
		return;
	}

	for (FViewInfo& View : Views)
	{

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp:2648

Scope: file

Source code excerpt:

		PermutationVector.Set< FDeferredLightPS::FHairLighting>(0);
		PermutationVector.Set< FDeferredLightPS::FLightingChannelsDim >(View.bUsesLightingChannels);
		PermutationVector.Set< FDeferredLightPS::FVisualizeCullingDim >(View.Family->EngineShowFlags.VisualizeLightCulling);
		PermutationVector.Set< FDeferredLightPS::FVirtualShadowMapMask >(bUseVirtualShadowMapMask);
		PermutationVector.Set< FDeferredLightPS::FSubstrateTileType >(0);
		PermutationVector.Set< FDeferredLightPS::FHairComplexTransmittance >(bNeedComplexTransmittanceSupport);
		PermutationVector.Set< FDeferredLightPS::FLightFunctionAtlasDim >(
			LightFunctionAtlas::IsEnabled(View, ELightFunctionAtlasSystem::DeferredLighting) && LightSceneInfo->Proxy->HasValidLightFunctionAtlasSlot() &&
			LightSceneInfo->Proxy->GetLightFunctionMaterial() != nullptr && !View.Family->EngineShowFlags.VisualizeLightCulling);

		if (bIsRadial)
		{
			PermutationVector.Set< FDeferredLightPS::FSourceShapeDim >(LightProxy->IsRectLight() ? ELightSourceShape::Rect : ELightSourceShape::Capsule);
			PermutationVector.Set< FDeferredLightPS::FSourceTextureDim >(LightProxy->IsRectLight() && LightProxy->HasSourceTexture());
			PermutationVector.Set< FDeferredLightPS::FIESProfileDim >(bUseIESTexture);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp:2743

Scope: file

Source code excerpt:

	// Ensure the light is valid for this view
	const bool bHairRenderingEnabled = HairStrands::HasViewHairStrandsData(View);
	if (!bHairRenderingEnabled || !LightSceneInfo->ShouldRenderLight(View) || View.HairStrandsViewData.VisibilityData.SampleLightingTexture == nullptr || View.Family->EngineShowFlags.VisualizeLightCulling)
	{
		return;
	}
	
	// Sanity check
	check(InTransmittanceMaskData.TransmittanceMask);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp:2810

Scope: file

Source code excerpt:

	PermutationVector.Set< FDeferredLightPS::FLightFunctionAtlasDim >(
		LightFunctionAtlas::IsEnabled(View, ELightFunctionAtlasSystem::DeferredLighting) && LightSceneInfo->Proxy->HasValidLightFunctionAtlasSlot() &&
		LightSceneInfo->Proxy->GetLightFunctionMaterial() != nullptr && !View.Family->EngineShowFlags.VisualizeLightCulling);
	if (bIsDirectional)
	{
		PermutationVector.Set< FDeferredLightPS::FSourceShapeDim >(ELightSourceShape::Directional);
		PermutationVector.Set< FDeferredLightPS::FSourceTextureDim >(false);
		PermutationVector.Set< FDeferredLightPS::FIESProfileDim >(false);
		PermutationVector.Set< FDeferredLightPS::FAtmosphereTransmittance >(IsLightAtmospherePerPixelTransmittanceEnabled(Scene, View, LightSceneInfo));

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightRendering.cpp:2996

Scope: file

Source code excerpt:

	PermutationVector.Set< FDeferredLightPS::FIESProfileDim >(false);
	PermutationVector.Set< FDeferredLightPS::FLightFunctionAtlasDim>(false);
	PermutationVector.Set< FDeferredLightPS::FVisualizeCullingDim >(View.Family->EngineShowFlags.VisualizeLightCulling);
	PermutationVector.Set< FDeferredLightPS::FLightingChannelsDim >(false);
	PermutationVector.Set< FDeferredLightPS::FAnistropicMaterials >(false);
	PermutationVector.Set< FDeferredLightPS::FTransmissionDim >(false);
	PermutationVector.Set< FDeferredLightPS::FHairLighting>(0);
	PermutationVector.Set< FDeferredLightPS::FHairComplexTransmittance>(bNeedComplexTransmittanceSupport);
	PermutationVector.Set< FDeferredLightPS::FAtmosphereTransmittance >(false);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/Lumen/Lumen.cpp:110

Scope (from outer to inner):

file
function     bool Lumen::ShouldHandleSkyLight

Source code excerpt:

		&& Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM5
		&& !IsForwardShadingEnabled(Scene->GetShaderPlatform())
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling;
}

bool ShouldRenderLumenForViewFamily(const FScene* Scene, const FSceneViewFamily& ViewFamily, bool bSkipProjectCheck)
{
	return Scene
		&& Scene->GetLumenSceneData(*ViewFamily.Views[0])

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:546

Scope (from outer to inner):

file
function     void FMobileSceneRenderer::InitViews

Source code excerpt:

		&& !ViewFamily.EngineShowFlags.HitProxies
		&& ViewFamily.EngineShowFlags.Lighting
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
		&& !ViewFamily.UseDebugViewPS()
		&& bRendererOutputFinalSceneColor;

	bRequiresAmbientOcclusionPass = IsUsingMobileAmbientOcclusion(ShaderPlatform)
		&& Views[0].FinalPostProcessSettings.AmbientOcclusionIntensity > 0
		&& (Views[0].FinalPostProcessSettings.AmbientOcclusionStaticFraction >= 1 / 100.0f || (Scene && Scene->SkyLight && Scene->SkyLight->ProcessedTexture && Views[0].Family->EngineShowFlags.SkyLighting))

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:557

Scope (from outer to inner):

file
function     void FMobileSceneRenderer::InitViews

Source code excerpt:

		&& !Views[0].bIsPlanarReflection
		&& !ViewFamily.EngineShowFlags.HitProxies
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
		&& !ViewFamily.UseDebugViewPS()
		&& bRendererOutputFinalSceneColor;

	bShouldRenderVelocities = ShouldRenderVelocities();

	bRequiresShadowProjections = MobileUsesShadowMaskTexture(ShaderPlatform)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:568

Scope (from outer to inner):

file
function     void FMobileSceneRenderer::InitViews

Source code excerpt:

		&& !Views[0].bIsPlanarReflection
		&& !ViewFamily.EngineShowFlags.HitProxies
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
		&& !ViewFamily.UseDebugViewPS()
		&& bRendererOutputFinalSceneColor;

	bShouldRenderHZB = ShouldRenderHZB() && bRendererOutputFinalSceneColor;

	// Whether we need to store depth for post-processing

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:933

Scope (from outer to inner):

file
function     void FMobileSceneRenderer::Render

Source code excerpt:

			&& !Views[0].bIsReflectionCapture
			&& !Views[0].bIsPlanarReflection
			&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
			&& !ViewFamily.UseDebugViewPS()
			&& (CVarDistanceFieldShadowQuality != nullptr && CVarDistanceFieldShadowQuality->GetInt() > 0)
			&& bRendererOutputFinalSceneColor)
		{
			PrepareDistanceFieldScene(GraphBuilder, ExternalAccessQueue);
		}

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:369

Scope (from outer to inner):

file
function     void AddPostProcessingPasses

Source code excerpt:

		VisualizeDepthOfField,
		VisualizeStationaryLightOverlap,
		VisualizeLightCulling,
		VisualizePostProcessStack,
		VisualizeSubstrate,
		VisualizeLightGrid,
		VisualizeSkyAtmosphere,
		VisualizeSkyLightIlluminanceMeter,
		VisualizeLightFunctionAtlas,

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:458

Scope (from outer to inner):

file
function     void AddPostProcessingPasses

Source code excerpt:

	PassSequence.SetNames(PassNames, UE_ARRAY_COUNT(PassNames));
	PassSequence.SetEnabled(EPass::VisualizeStationaryLightOverlap, EngineShowFlags.StationaryLightOverlap);
	PassSequence.SetEnabled(EPass::VisualizeLightCulling, EngineShowFlags.VisualizeLightCulling);
#if DEBUG_POST_PROCESS_VOLUME_ENABLE
	PassSequence.SetEnabled(EPass::VisualizePostProcessStack, EngineShowFlags.VisualizePostProcessStack);
#else
	PassSequence.SetEnabled(EPass::VisualizePostProcessStack, false);
#endif
	PassSequence.SetEnabled(EPass::VisualizeLumenScene, LumenVisualizeMode >= 0 && LumenVisualizeMode != VISUALIZE_MODE_OVERVIEW && LumenVisualizeMode != VISUALIZE_MODE_PERFORMANCE_OVERVIEW && bPostProcessingEnabled);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:1398

Scope (from outer to inner):

file
function     void AddPostProcessingPasses

Source code excerpt:

	}

	if (PassSequence.IsEnabled(EPass::VisualizeLightCulling))
	{
		ensureMsgf(View.PrimaryScreenPercentageMethod != EPrimaryScreenPercentageMethod::TemporalUpscale, TEXT("TAAU should be disabled when visualizing light culling."));

		// 0.1f comes from the values used in LightAccumulator_GetResult
		const float ComplexityScale = 1.0f / (float)(GEngine->LightComplexityColors.Num() - 1) / 0.1f;

		FVisualizeComplexityInputs PassInputs;
		PassSequence.AcceptOverrideIfLastPass(EPass::VisualizeLightCulling, PassInputs.OverrideOutput);
		PassInputs.SceneColor = OriginalSceneColor;
		PassInputs.Colors = GEngine->LightComplexityColors;
		PassInputs.ColorSamplingMethod = FVisualizeComplexityInputs::EColorSamplingMethod::Linear;
		PassInputs.ComplexityScale = ComplexityScale;
		PassInputs.bDrawLegend = true;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/TranslucentRendering.cpp:685

Scope (from outer to inner):

file
function     bool FSceneRenderer::ShouldRenderTranslucency

Source code excerpt:

{
	return  ViewFamily.EngineShowFlags.Translucency
		&& !ViewFamily.EngineShowFlags.VisualizeLightCulling
		&& !ViewFamily.UseDebugViewPS();
}

bool FSceneRenderer::ShouldRenderTranslucency(ETranslucencyPass::Type TranslucencyPass) const
{
	extern int32 GLightShaftRenderAfterDOF;