ShowFlag.LightFunctions

ShowFlag.LightFunctions

#Overview

name: ShowFlag.LightFunctions

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

It is referenced in 20 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of ShowFlag.LightFunctions is to control the visibility and rendering of light functions in Unreal Engine 5. Light functions are materials that can be applied to light sources to modify their output, allowing for complex lighting effects and patterns.

This setting variable is primarily used by the rendering system, specifically in the following Unreal Engine subsystems and modules:

  1. Deferred Shading Renderer
  2. Light Function Atlas
  3. Light Function Rendering
  4. Light Rendering
  5. Lumen Scene Direct Lighting
  6. Mobile Deferred Shading
  7. Path Tracing
  8. Ray Tracing Lighting
  9. Reflection Environment Capture
  10. Translucent Lighting
  11. Variable Rate Shading
  12. Volumetric Fog Light Function

The value of this variable is typically set through the engine show flags, which can be controlled via the UI or programmatically. It is often accessed through ViewFamily.EngineShowFlags.LightFunctions.

Several other variables and systems interact with ShowFlag.LightFunctions:

  1. It is often used in conjunction with GetLightFunctionMaterial() to determine if a light function should be applied.
  2. It interacts with the Light Function Atlas system.
  3. It affects various rendering passes, including forward shading, deferred shading, and ray tracing.

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

  1. Enabling light functions can have performance implications, especially in complex scenes with many lights.
  2. Light functions are not supported in all rendering paths or on all platforms.
  3. The variable’s state can affect the appearance and behavior of lights in the scene.

Best practices for using this variable include:

  1. Only enable light functions when necessary, as they can impact performance.
  2. Use it in conjunction with proper light function materials for desired effects.
  3. Consider the target platform and rendering path when relying on light functions.
  4. Be aware of its interaction with other lighting and rendering systems.

The associated variable LightFunctions is essentially the same as ShowFlag.LightFunctions. It is used interchangeably in the code and serves the same purpose of controlling the visibility and rendering of light functions. The same considerations and best practices apply to both variables.

#References in C++ code

#Callsites

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

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

Scope: file

Source code excerpt:

SHOWFLAG_ALWAYS_ACCESSIBLE(TexturedLightProfiles,  SFG_LightingFeatures, NSLOCTEXT("UnrealEd", "TexturedLightProfilesSF", "Textured Light Profiles (IES Texture)"))
/** LightFunctions (masking light sources with a material), for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(LightFunctions, SFG_LightingFeatures, NSLOCTEXT("UnrealEd", "LightFunctionsSF", "Light Functions"))
/** Draws instanced static meshes that are not foliage or grass, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(InstancedStaticMeshes, SFG_Advanced, NSLOCTEXT("UnrealEd", "InstancedStaticMeshesSF", "Instanced Static Meshes"))
/** Draws instanced foliage, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(InstancedFoliage, SFG_Advanced, NSLOCTEXT("UnrealEd", "InstancedFoliageSF", "Foliage"))
/** Allow to see the foliage bounds used in the occlusion test */
SHOWFLAG_FIXED_IN_SHIPPING(0, HISMCOcclusionBounds, SFG_Advanced, NSLOCTEXT("UnrealEd", "HISMOcclusionBoundsSF", "HISM/Foliage Occlusion Bounds"))

#Associated Variable and Callsites

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

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

Scope: file

Source code excerpt:

/** LightProfiles, usually 1d textures to have a light (IES), for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(TexturedLightProfiles,  SFG_LightingFeatures, NSLOCTEXT("UnrealEd", "TexturedLightProfilesSF", "Textured Light Profiles (IES Texture)"))
/** LightFunctions (masking light sources with a material), for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(LightFunctions, SFG_LightingFeatures, NSLOCTEXT("UnrealEd", "LightFunctionsSF", "Light Functions"))
/** Draws instanced static meshes that are not foliage or grass, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(InstancedStaticMeshes, SFG_Advanced, NSLOCTEXT("UnrealEd", "InstancedStaticMeshesSF", "Instanced Static Meshes"))
/** Draws instanced foliage, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(InstancedFoliage, SFG_Advanced, NSLOCTEXT("UnrealEd", "InstancedFoliageSF", "Foliage"))
/** Allow to see the foliage bounds used in the occlusion test */
SHOWFLAG_FIXED_IN_SHIPPING(0, HISMCOcclusionBounds, SFG_Advanced, NSLOCTEXT("UnrealEd", "HISMOcclusionBoundsSF", "HISM/Foliage Occlusion Bounds"))

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

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::Render

Source code excerpt:

			}

			if (ViewFamily.EngineShowFlags.LightFunctions)
			{
				// gather all the light functions that may be used (and also count how many miss shaders we will need)
				FRayTracingLightFunctionMap RayTracingLightFunctionMap;
				if (ViewFamily.EngineShowFlags.PathTracing)
				{
					RayTracingLightFunctionMap = GatherLightFunctionLightsPathTracing(Scene, ViewFamily.EngineShowFlags, ReferenceView.GetFeatureLevel());

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightFunctionAtlas.cpp:260

Scope (from outer to inner):

file
namespace    LightFunctionAtlas
function     void FLightFunctionAtlas::BeginSceneFrame

Source code excerpt:


	// Now lets check if we need to generate the atlas for this frame
	bLightFunctionAtlasEnabled = CVarLightFunctionAtlas.GetValueOnRenderThread() > 0 && ViewFamily.EngineShowFlags.LightFunctions > 0;

	// But only really enable the atlas generation if a system asks for it
	bool bVolumetricFogRequestsLF = false;
	bool bDeferredlightingRequestsLF = false;
	bool bManyLightsRequestsLF = false;
	bool bLumenRequestsLF = false;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp:260

Scope (from outer to inner):

file
function     bool FDeferredShadingSceneRenderer::RenderLightFunction

Source code excerpt:

	bool bUseHairStrands)
{
	if (ViewFamily.EngineShowFlags.LightFunctions)
	{
		return RenderLightFunctionForMaterial(GraphBuilder, SceneTextures, LightSceneInfo, ScreenShadowMaskTexture, LightSceneInfo->Proxy->GetLightFunctionMaterial(), bLightAttenuationCleared, bProjectingForForwardShading, false, bUseHairStrands);
	}
	
	return false;
}

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/LightFunctionRendering.cpp:349

Scope: file

Source code excerpt:

			PassParameters->RenderTargets[0] = FRenderTargetBinding(ScreenShadowMaskTexture, bLightAttenuationCleared ? ERenderTargetLoadAction::ELoad : ERenderTargetLoadAction::ENoAction);
			PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneTextures.Depth.Target, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite);
			PassParameters->RenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, View, FVariableRateShadingImageManager::EVRSPassType::LightFunctions);

			// If render shadow mask for hair strands, then swap depth to hair only depth
			if (bUseHairStrands)
			{
				PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(View.HairStrandsViewData.VisibilityData.HairOnlyDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthRead_StencilWrite);
			}

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

Scope (from outer to inner):

file
function     void FSceneRenderer::GatherAndSortLights

Source code excerpt:

					SortedLightInfo->SortKey.Fields.LightType = LightSceneInfoCompact.LightType;
					SortedLightInfo->SortKey.Fields.bShadowed = bDynamicShadows && CheckForProjectedShadows(LightSceneInfo);
					SortedLightInfo->SortKey.Fields.bLightFunction = ViewFamily.EngineShowFlags.LightFunctions && CheckForLightFunction(LightSceneInfo);
					SortedLightInfo->SortKey.Fields.bUsesLightingChannels = Views[ViewIndex].bUsesLightingChannels && LightSceneInfo->Proxy->GetLightingChannelMask() != GetDefaultLightingChannelMask();

					// These are not simple lights.
					SortedLightInfo->SortKey.Fields.bIsNotSimpleLight = 1;

					// Lights handled by Many Lights

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

Scope (from outer to inner):

file
class        class FLumenGatheredLight
function     FLumenGatheredLight

Source code excerpt:


		LightFunctionMaterialProxy = Proxy->GetLightFunctionMaterial();
		if (LightFunctionMaterialProxy && (!View.Family->EngineShowFlags.LightFunctions || !LightFunctionMaterialProxy->GetIncompleteMaterialWithFallback(Scene->GetFeatureLevel()).IsLightFunction()))
		{
			LightFunctionMaterialProxy = nullptr;
		}
		const bool bBatchableLightFunction = LightFunctionMaterialProxy == nullptr || (LightFunctionAtlas::IsEnabled(View, ELightFunctionAtlasSystem::Lumen) && LightSceneInfo->Proxy->HasValidLightFunctionAtlasSlot());
		
		FSceneRenderer::GetLightNameForDrawEvent(Proxy, Name);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileDeferredShadingPass.cpp:164

Scope (from outer to inner):

file
function     void SetParameters

Source code excerpt:

		FMaterialShader::SetParameters(BatchedParameters, Proxy, Material, View);

		// LightFunctions can use primitive data, set identity so we do not crash on a missing binding
		auto& PrimitivePS = GetUniformBufferParameter<FPrimitiveUniformShaderParameters>();
		SetUniformBufferParameter(BatchedParameters, PrimitivePS, GIdentityPrimitiveUniformBuffer);
	}
};

IMPLEMENT_MATERIAL_SHADER_TYPE(, FMobileDirectionalLightFunctionPS, TEXT("/Engine/Private/MobileDeferredShading.usf"), TEXT("MobileDirectionalLightPS"), SF_Pixel);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileDeferredShadingPass.cpp:247

Scope (from outer to inner):

file
class        class FMobileRadialLightFunctionPS : public FMaterialShader
function     void SetParameters

Source code excerpt:

		FMaterialShader::SetParameters(BatchedParameters, Proxy, Material, View);
		
		// LightFunctions can use primitive data, set identity so we do not crash on a missing binding
		auto& PrimitivePS = GetUniformBufferParameter<FPrimitiveUniformShaderParameters>();
		SetUniformBufferParameter(BatchedParameters, PrimitivePS, GIdentityPrimitiveUniformBuffer);
	}
};

IMPLEMENT_MATERIAL_SHADER_TYPE(,FMobileRadialLightFunctionPS, TEXT("/Engine/Private/MobileDeferredShading.usf"), TEXT("MobileRadialLightPS"), SF_Pixel);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileDeferredShadingPass.cpp:488

Scope (from outer to inner):

file
function     static void RenderDirectionalLight

Source code excerpt:

	
	const FMaterialRenderProxy* LightFunctionMaterialProxy = nullptr;
	if (View.Family->EngineShowFlags.LightFunctions)
	{
		LightFunctionMaterialProxy = DirectionalLight.Proxy->GetLightFunctionMaterial();
	}

	FMobileDirectionalLightFunctionPS::FParameters PassParameters;
	PassParameters.MobileDirectionalLight = Scene.UniformBuffers.MobileDirectionalLightUniformBuffers[LightingChannel + 1];

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileDeferredShadingPass.cpp:765

Scope (from outer to inner):

file
function     static void RenderLocalLight

Source code excerpt:

		
	const FMaterialRenderProxy* LightFunctionMaterialProxy = nullptr;
	if (View.Family->EngineShowFlags.LightFunctions)
	{
		LightFunctionMaterialProxy = LightSceneInfo.Proxy->GetLightFunctionMaterial();
	}

	FMobileRadialLightFunctionPS::FParameters PassParameters;
	const bool bShouldCastShadow = LightSceneInfo.SetupMobileMovableLocalLightShadowParameters(View, VisibleLightInfos, PassParameters.MobileMovableLocalLightShadow);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PathTracing.cpp:1363

Scope (from outer to inner):

file
function     FRayTracingLightFunctionMap GatherLightFunctionLightsPathTracing

Source code excerpt:

FRayTracingLightFunctionMap GatherLightFunctionLightsPathTracing(FScene* Scene, const FEngineShowFlags EngineShowFlags, ERHIFeatureLevel::Type InFeatureLevel)
{
	checkf(EngineShowFlags.LightFunctions, TEXT("This function should not be called if light functions are disabled"));
	FRayTracingLightFunctionMap RayTracingLightFunctionMap;
	for (const FLightSceneInfoCompact& Light : Scene->Lights)
	{
		FLightSceneInfo* LightSceneInfo = Light.LightSceneInfo;
		auto MaterialProxy = LightSceneInfo->Proxy->GetLightFunctionMaterial();
		if (MaterialProxy)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PathTracing.cpp:2491

Scope: file

Source code excerpt:

	Config.LightShowFlags |= View.Family->EngineShowFlags.PointLights           ? 1 << 4 : 0;
	Config.LightShowFlags |= View.Family->EngineShowFlags.TexturedLightProfiles ? 1 << 5 : 0;
	Config.LightShowFlags |= View.Family->EngineShowFlags.LightFunctions        ? 1 << 6 : 0;
	Config.LightShowFlags |= CVarPathTracingLightFunctionColor.GetValueOnRenderThread() ? 1 << 7 : 0;
	// the following flags all mess with diffuse/spec overrides and therefore change the image
	Config.LightShowFlags |= View.Family->EngineShowFlags.Diffuse                    ? 1 << 8 : 0;
	Config.LightShowFlags |= View.Family->EngineShowFlags.Specular                   ? 1 << 9 : 0;
	Config.LightShowFlags |= View.Family->EngineShowFlags.OverrideDiffuseAndSpecular ? 1 << 10 : 0;
	Config.LightShowFlags |= View.Family->EngineShowFlags.LightingOnlyOverride       ? 1 << 11 : 0;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/RayTracing/RayTracingLighting.cpp:518

Scope (from outer to inner):

file
function     FRayTracingLightFunctionMap GatherLightFunctionLights

Source code excerpt:

FRayTracingLightFunctionMap GatherLightFunctionLights(FScene* Scene, const FEngineShowFlags EngineShowFlags, ERHIFeatureLevel::Type InFeatureLevel)
{
	checkf(EngineShowFlags.LightFunctions, TEXT("This function should not be called if light functions are disabled"));

	// gives control over lighting functions in raytraced effects, independently of the show flag (for performance testing / debug)
	if (CVarRayTracingLightFunction.GetValueOnRenderThread() == 0)
	{
		return {};
	}

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp:1294

Scope (from outer to inner):

file
function     void CaptureSceneIntoScratchCubemap

Source code excerpt:

		// Conditionally exclude particles and light functions as they are usually dynamic, and can't be captured well
		ViewFamily.EngineShowFlags.Particles = 0;
		ViewFamily.EngineShowFlags.LightFunctions = abs(GReflectionCaptureEnableLightFunctions) ? 1 : 0;
		ViewFamily.EngineShowFlags.SetCompositeEditorPrimitives(false);
		// These are highly dynamic and can't be captured effectively
		ViewFamily.EngineShowFlags.LightShafts = 0;
		// Don't apply sky lighting diffuse when capturing the sky light source, or we would have feedback
		ViewFamily.EngineShowFlags.SkyLighting = !bCapturingForSkyLight;
		// Skip lighting for emissive only

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/TranslucentLighting.cpp:1044

Scope (from outer to inner):

file
function     void FTranslucentLightInjectionCollector::AddLightForInjection

Source code excerpt:

		const ERHIFeatureLevel::Type FeatureLevel = View.FeatureLevel;

		const bool bApplyLightFunction = (View.Family->EngineShowFlags.LightFunctions &&
			LightSceneInfo.Proxy->GetLightFunctionMaterial() && 
			LightSceneInfo.Proxy->GetLightFunctionMaterial()->GetIncompleteMaterialWithFallback(FeatureLevel).IsLightFunction());

		const FMaterialRenderProxy* MaterialProxy = bApplyLightFunction ? 
			LightSceneInfo.Proxy->GetLightFunctionMaterial() : 
			UMaterial::GetDefaultMaterial(MD_LightFunction)->GetRenderProxy();

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/VariableRateShading/VariableRateShadingImageManager.cpp:774

Scope (from outer to inner):

file
class        class FDebugVariableRateShadingCS : public FGlobalShader

Source code excerpt:

			CVarByPassType[EVRSPassType::SSR] = &CVarVRS_SSR;
			CVarByPassType[EVRSPassType::ReflectionEnvironmentAndSky] = &CVarVRSReflectionEnvironmentSky;
			CVarByPassType[EVRSPassType::LightFunctions] = &CVarVRSLightFunctions;
			CVarByPassType[EVRSPassType::Decals] = &CVarVRSDecals;
		}
	} StaticData;

	uint32 ImageTypeAsInt = StaticData.CVarByPassType[PassType]->GetValueOnRenderThread();
	if (ImageTypeAsInt >= 0 && ImageTypeAsInt <= EVRSImageType::Conservative)

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/VolumetricFogLightFunction.cpp:145

Scope: file

Source code excerpt:

				bOutUseDirectionalLightShadowing = LightSceneInfo->Proxy->CastsVolumetricShadow();

				if (CheckForLightFunction(LightSceneInfo) && ViewFamily.EngineShowFlags.LightFunctions)
				{
					OutDirectionalLightSceneInfo = LightSceneInfo;
					break;	// we only deal with the directional light function so we directly stop now
				}
			}
		}

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Public/VariableRateShadingImageManager.h:32

Scope (from outer to inner):

file
class        class FVariableRateShadingImageManager : public FRenderResource

Source code excerpt:

		SSR,
		ReflectionEnvironmentAndSky,
		LightFunctions,
		Decals,
		Num
	};

	/**
	 * Image type to request from generator. Only the CAS generator currently distinguishes between Full and Conservative