r.ForwardShading

r.ForwardShading

#Overview

name: r.ForwardShading

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

It is referenced in 25 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of r.ForwardShading is to control whether forward shading is used on desktop platforms in Unreal Engine. Forward shading is an alternative rendering technique to deferred shading, offering different trade-offs in terms of performance and visual features.

This setting variable is primarily used by the rendering system in Unreal Engine. It affects various subsystems and modules, including:

  1. The Renderer module
  2. The RenderCore module
  3. The Engine module
  4. The ShaderCompiler subsystem

The value of this variable is typically set through the console or in the engine configuration files. It can also be modified programmatically through the IConsoleManager interface.

The associated variable bForwardShading often interacts with r.ForwardShading. It’s usually used as a boolean representation of the r.ForwardShading value within the engine’s C++ code.

Developers should be aware of several important aspects when using this variable:

  1. It requires Shader Model 5 hardware.
  2. Forward shading supports MSAA and has a lower default cost but fewer supported features overall.
  3. Materials need to opt-in to more expensive features like high-quality reflections when using forward shading.
  4. Changing this setting typically requires restarting the editor.

Best practices when using this variable include:

  1. Consider the target hardware capabilities before enabling forward shading.
  2. Be aware of the limitations in terms of advanced rendering features when using forward shading.
  3. Optimize materials for forward shading if it’s enabled.
  4. Test performance and visual quality thoroughly when switching between forward and deferred shading.

Regarding the associated variable bForwardShading:

The purpose of bForwardShading is to serve as a boolean representation of the forward shading state within the engine’s C++ code. It’s often used in conditional statements to determine whether to use forward shading-specific code paths or features.

This variable is typically set based on the value of r.ForwardShading, either directly or through platform-specific settings. It’s used across various rendering-related functions and classes to adjust behavior based on the current shading mode.

Developers should be aware that bForwardShading might be set differently in different contexts (e.g., editor vs. game, different platforms), so it’s important to check its value when implementing rendering-related features that might behave differently under forward shading.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h:591

Scope (from outer to inner):

file
class        class URendererSettings : public UDeveloperSettings

Source code excerpt:


	UPROPERTY(config, EditAnywhere, Category=ForwardRenderer, meta=(
		ConsoleVariable="r.ForwardShading",
		DisplayName = "Forward Shading",
		ToolTip="Whether to use forward shading on desktop platforms, requires Shader Model 5 hardware.  Forward shading supports MSAA and has lower default cost, but fewer features supported overall.  Materials have to opt-in to more expensive features like high quality reflections.  Changing this setting requires restarting the editor.",
		ConfigRestartRequired=true))
	uint32 bForwardShading:1;

	UPROPERTY(config, EditAnywhere, Category=ForwardRenderer, meta=(

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp:678

Scope: file

Source code excerpt:

RENDERCORE_API int32 GUseForwardShading = 0;
static FAutoConsoleVariableRef CVarForwardShading(
	TEXT("r.ForwardShading"),
	GUseForwardShading,
	TEXT("Whether to use forward shading on desktop platforms - requires Shader Model 5 hardware.\n")
	TEXT("Forward shading has lower constant cost, but fewer features supported. 0:off, 1:on\n")
	TEXT("This rendering path is a work in progress with many unimplemented features, notably only a single reflection capture is applied per object and no translucency dynamic shadow receiving."),
	ECVF_RenderThreadSafe | ECVF_ReadOnly
	); 

#Loc: <Workspace>/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformBase.cpp:17

Scope (from outer to inner):

file
function     bool FTargetPlatformBase::UsesForwardShading

Source code excerpt:

bool FTargetPlatformBase::UsesForwardShading() const
{
	static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
	return CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
}

bool FTargetPlatformBase::UsesDBuffer() const
{
	static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DBuffer"));

#Loc: <Workspace>/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformSettingsBase.cpp:6

Scope (from outer to inner):

file
function     bool FTargetPlatformSettingsBase::UsesForwardShading

Source code excerpt:

bool FTargetPlatformSettingsBase::UsesForwardShading() const
{
	static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
	return CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
}

bool FTargetPlatformSettingsBase::UsesDBuffer() const
{
	static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DBuffer"));

#Loc: <Workspace>/Engine/Source/Editor/PIEPreviewDeviceProfileSelector/Private/PIEPreviewDevice.cpp:378

Scope (from outer to inner):

file
function     void FPIEPreviewDevice::ApplyRHIOverrides

Source code excerpt:

			SwitchSettings.GetBool(TEXT("/Script/SwitchRuntimeSettings.SwitchRuntimeSettings"), TEXT("bUseForwardShading"), bForwardShading);

			// apply r.ForwardShading based on Switch bUseForwardShading setting
			IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			if (CVarForwardShading)
			{
				CVarForwardShading->Set(bForwardShading ? 1 : 0);
			}
		}
		break;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/PostProcessVolume.cpp:219

Scope (from outer to inner):

file
function     bool APostProcessVolume::CanEditChange

Source code excerpt:

				PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FPostProcessSettings, ReflectionMethod))
			{
				static IConsoleVariable* ForwardShadingCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
				if (ForwardShadingCVar->GetInt() != 0)
				{
					return false;
				}
			}
		}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp:8386

Scope (from outer to inner):

file
function     void GlobalBeginCompileShader

Source code excerpt:

		else
		{
			static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
		}
		SET_SHADER_DEFINE(Input.Environment, FORWARD_SHADING, bForwardShading);
	}

	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderGenerationUtil.cpp:356

Scope (from outer to inner):

file
function     static FShaderGlobalDefines FetchShaderGlobalDefines

Source code excerpt:

		else
		{
			static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
		}
		Ret.FORWARD_SHADING = bForwardShading;
	}
#else
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading"));
		Ret.FORWARD_SHADING = CVar ? (CVar->GetValueOnAnyThread() != 0) : 0;
	}
#endif

	{
		static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VertexFoggingForOpaque"));

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/Shader.cpp:1890

Scope (from outer to inner):

file
function     void ShaderMapAppendKeyString

Source code excerpt:

		{
			// shader platform doesn't match a specific target platform, use cvar setting for forward shading
			static IConsoleVariable* CVarForwardShadingLocal = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShadingLocal ? (CVarForwardShadingLocal->GetInt() != 0) : false;
		}

		if (bForwardShading)
		{
			KeyString += TEXT("_FS");

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Source/Editor/PIEPreviewDeviceProfileSelector/Private/PIEPreviewDevice.cpp:375

Scope (from outer to inner):

file
function     void FPIEPreviewDevice::ApplyRHIOverrides

Source code excerpt:

			FConfigFile SwitchSettings;
			FConfigCacheIni::LoadLocalIniFile(SwitchSettings, TEXT("Engine"), true, TEXT("Switch"));
			bool bForwardShading = false;
			SwitchSettings.GetBool(TEXT("/Script/SwitchRuntimeSettings.SwitchRuntimeSettings"), TEXT("bUseForwardShading"), bForwardShading);

			// apply r.ForwardShading based on Switch bUseForwardShading setting
			IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			if (CVarForwardShading)
			{
				CVarForwardShading->Set(bForwardShading ? 1 : 0);
			}
		}
		break;

		default:
		break;

#Loc: <Workspace>/Engine/Source/Editor/PIEPreviewDeviceProfileSelector/Private/PIEPreviewDevice.cpp:481

Scope (from outer to inner):

file
function     FString FPIEPreviewDevice::GetProfile

Source code excerpt:

			bool bSupportDesktopRenderer = false;
			SwitchSettings.GetBool(TEXT("/Script/SwitchRuntimeSettings.SwitchRuntimeSettings"), TEXT("bSupportDesktopRenderer"), bSupportDesktopRenderer);
			bool bForwardShading = false;
			SwitchSettings.GetBool(TEXT("/Script/SwitchRuntimeSettings.SwitchRuntimeSettings"), TEXT("bUseForwardShading"), bForwardShading);
	
			// taken from FSwitchApplication::UpdateActiveDeviceProfile()
			Profile = DeviceSpecs->SwitchProperties.Docked ?
				((!bSupportDesktopRenderer || bForwardShading) ? TEXT("Switch_Console_Forward") : TEXT("Switch_Console_Deferred")) :
				((!bSupportDesktopRenderer || bForwardShading) ? TEXT("Switch_Handheld_Forward") : TEXT("Switch_Handheld_Deferred"));
		
			break;
		}
	}

	return Profile;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Engine/RendererSettings.h:595

Scope (from outer to inner):

file
class        class URendererSettings : public UDeveloperSettings

Source code excerpt:

		ToolTip="Whether to use forward shading on desktop platforms, requires Shader Model 5 hardware.  Forward shading supports MSAA and has lower default cost, but fewer features supported overall.  Materials have to opt-in to more expensive features like high quality reflections.  Changing this setting requires restarting the editor.",
		ConfigRestartRequired=true))
	uint32 bForwardShading:1;

	UPROPERTY(config, EditAnywhere, Category=ForwardRenderer, meta=(
		ConsoleVariable="r.VertexFoggingForOpaque",
		ToolTip="Causes opaque materials to use per-vertex fogging, which costs slightly less.  Only supported with forward shading. Changing this setting requires restarting the editor.",
		ConfigRestartRequired=true))
	uint32 bVertexFoggingForOpaque:1;

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/RendererSettings.cpp:368

Scope (from outer to inner):

file
function     bool URendererSettings::CanEditChange

Source code excerpt:

		|| InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(URendererSettings, ShadowMapMethod))
	{
		return !bForwardShading;
	}

	if ((InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(URendererSettings, bMobileSupportDeferredOnOpenGL)))
	{
		return MobileShadingPath.GetValue() > 0;
	}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp:8378

Scope (from outer to inner):

file
function     void GlobalBeginCompileShader

Source code excerpt:

	}

	bool bForwardShading = false;
	{
		if (TargetPlatform)
		{
			bForwardShading = TargetPlatform->UsesForwardShading();
		}
		else
		{
			static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
		}
		SET_SHADER_DEFINE(Input.Environment, FORWARD_SHADING, bForwardShading);
	}

	{
		if (VelocityEncodeDepth((EShaderPlatform)Target.Platform))
		{
			SET_SHADER_DEFINE(Input.Environment, VELOCITY_ENCODE_DEPTH, 1);

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderCompiler.cpp:8417

Scope (from outer to inner):

file
function     void GlobalBeginCompileShader

Source code excerpt:

		static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VertexFoggingForOpaque"));
		bool bVertexFoggingForOpaque = false;
		if (bForwardShading)
		{
			bVertexFoggingForOpaque = CVar ? (CVar->GetInt() != 0) : 0;
			if (TargetPlatform)
			{
				const int32 PlatformHeightFogMode = TargetPlatform->GetHeightFogModeForOpaque();
				if (PlatformHeightFogMode == 1)

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderGenerationUtil.cpp:347

Scope (from outer to inner):

file
function     static FShaderGlobalDefines FetchShaderGlobalDefines

Source code excerpt:

#if WITH_EDITOR
	{
		bool bForwardShading = false;

		ITargetPlatform* TargetPlatformPtr = GetTargetPlatformManager()->FindTargetPlatformWithSupport(TEXT("ShaderFormat"), LegacyShaderPlatformToShaderFormat((EShaderPlatform)TargetPlatform));
		if (TargetPlatformPtr)
		{
			bForwardShading = TargetPlatformPtr->UsesForwardShading();
		}
		else
		{
			static IConsoleVariable* CVarForwardShading = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShading ? (CVarForwardShading->GetInt() != 0) : false;
		}
		Ret.FORWARD_SHADING = bForwardShading;
	}
#else
	{
		static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading"));
		Ret.FORWARD_SHADING = CVar ? (CVar->GetValueOnAnyThread() != 0) : 0;
	}

#Loc: <Workspace>/Engine/Source/Runtime/RenderCore/Private/Shader.cpp:1881

Scope (from outer to inner):

file
function     void ShaderMapAppendKeyString

Source code excerpt:


	{
		bool bForwardShading = false;
		if (TargetPlatform)
		{
			// if there is a specific target platform that matches our shader platform, use that to drive forward shading
			bForwardShading = TargetPlatform->UsesForwardShading();
		}
		else
		{
			// shader platform doesn't match a specific target platform, use cvar setting for forward shading
			static IConsoleVariable* CVarForwardShadingLocal = IConsoleManager::Get().FindConsoleVariable(TEXT("r.ForwardShading"));
			bForwardShading = CVarForwardShadingLocal ? (CVarForwardShadingLocal->GetInt() != 0) : false;
		}

		if (bForwardShading)
		{
			KeyString += TEXT("_FS");
		}
	}

	{

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

Scope (from outer to inner):

file
function     void FCompositionLighting::TryInit

Source code excerpt:

	}

	const bool bForwardShading = IsForwardShadingEnabled(SceneTextures.Config.ShaderPlatform);

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
	{
		const FViewInfo& View = Views[ViewIndex];

		FAOConfig& ViewConfig = ViewAOConfigs[ViewIndex];

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

Scope (from outer to inner):

file
function     void FCompositionLighting::TryInit

Source code excerpt:

		ViewConfig.Levels = FSSAOHelper::ComputeAmbientOcclusionPassCount(View);

		if (!bForwardShading)
		{
			ViewConfig.GTAOType = FSSAOHelper::GetGTAOPassType(View, ViewConfig.Levels);
		}

		if (ViewConfig.GTAOType == EGTAOType::EOff && ViewConfig.Levels > 0)
		{
			ViewConfig.bSSAOAsync = FSSAOHelper::IsAmbientOcclusionAsyncCompute(View, ViewConfig.Levels);

			ViewConfig.SSAOLocation = View.HZB != nullptr && (ViewConfig.bSSAOAsync || bForwardShading)
				? ESSAOLocation::BeforeBasePass
				: ESSAOLocation::AfterBasePass;
		}
	}

	bInitialized = true;

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

Scope (from outer to inner):

file
function     void FDeferredShadingSceneRenderer::RenderLights

Source code excerpt:

						if (bUseHairDeepShadow)
						{
							RenderHairStrandsShadowMask(GraphBuilder, Views, &LightSceneInfo, VisibleLightInfos, false /*bForwardShading*/, ScreenShadowMaskTexture);
						}
					}
					else // (OcclusionType == FOcclusionType::Shadowmap)
					{					
						const auto ClearShadowMask = [&](FRDGTextureRef InScreenShadowMaskTexture)
						{

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h:380

Scope (from outer to inner):

file
class        class TMobileBasePassPS : public TMobileBasePassPSBaseType<LightMapPolicyType>
function     static bool ShouldCompilePermutation

Source code excerpt:

		const bool bMaterialUsesForwardShading = bIsLit && bIsTranslucent;
		// Translucent materials always support clustered shading on mobile deferred
		const bool bForwardShading = !bDeferredShadingEnabled || bMaterialUsesForwardShading;

		EMobileLocalLightSetting SupportedLocalLightsType = EMobileLocalLightSetting::LOCAL_LIGHTS_DISABLED;
		if (bForwardShading && bIsLit)
		{
			SupportedLocalLightsType = GetMobileForwardLocalLightSetting(Parameters.Platform);
		}
		// Deferred shading does not need SkyLight and LocalLight permutations
		// TODO: skip skylight permutations for deferred	
		bool bEnableLocalLights = LocalLightSetting != EMobileLocalLightSetting::LOCAL_LIGHTS_DISABLED;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileBasePassRendering.h:410

Scope (from outer to inner):

file
class        class TMobileBasePassPS : public TMobileBasePassPSBaseType<LightMapPolicyType>
function     static void ModifyCompilationEnvironment

Source code excerpt:

		const bool bMaterialUsesForwardShading = bIsLit && bTranslucentMaterial;
		// Translucent materials always support clustered shading on mobile deferred
		const bool bForwardShading = !bDeferredShadingEnabled || bMaterialUsesForwardShading;
		// Only stationary skylights contribute into basepass with deferred shading materials. Has to do this test as on some project configurations we dont have a separate permutation for no-skylight
		const bool bEnableSkylightInBasePass = bEnableSkyLight && (bForwardShading || FReadOnlyCVARCache::EnableStationarySkylight());

		TMobileBasePassPSBaseType<LightMapPolicyType>::ModifyCompilationEnvironment(Parameters, OutEnvironment);
		OutEnvironment.SetDefine(TEXT("ENABLE_SKY_LIGHT"), bEnableSkylightInBasePass);
		OutEnvironment.SetDefine(TEXT("ENABLE_AMBIENT_OCCLUSION"), IsMobileAmbientOcclusionEnabled(Parameters.Platform) ? 1u : 0u);
		
		FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/SkyAtmosphereRendering.cpp:1775

Scope (from outer to inner):

file
function     void FSceneRenderer::RenderSkyAtmosphereInternal

Source code excerpt:

	check(SkyRC.MSAASampleCount <= 8);
	// We only support MSAA in forward, not in deferred.
	const bool bForwardShading = IsForwardShadingEnabled(Scene->GetShaderPlatform());
	check(bForwardShading || (!bForwardShading && SkyRC.MSAASampleCount == 1));

	// Render the sky, and optionally the atmosphere aerial perspective, on the scene luminance buffer
	{
		FLightSceneProxy* AtmosphereLight0Proxy = Scene->AtmosphereLights[0] ? Scene->AtmosphereLights[0]->Proxy : nullptr;
		FLightSceneProxy* AtmosphereLight1Proxy = Scene->AtmosphereLights[1] ? Scene->AtmosphereLights[1]->Proxy : nullptr;
		const float CloudShadowOnAtmosphereStrength0 = AtmosphereLight0Proxy ? AtmosphereLight0Proxy->GetCloudShadowOnAtmosphereStrength() : 0.0f;

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/VolumetricRenderTarget.cpp:795

Scope (from outer to inner):

file
function     void ComposeVolumetricRenderTargetOverScene

Source code excerpt:

		check(SceneDepthTexture->Desc.NumSamples <= 8);
		// We only support MSAA in forward, not in deferred.
		const bool bForwardShading = IsForwardShadingEnabled(ViewInfo.GetShaderPlatform());
		check(bForwardShading || (!bForwardShading && SceneDepthTexture->Desc.NumSamples==1));

		FComposeVolumetricRTOverScenePS::FPermutationDomain PermutationVector;
		PermutationVector.Set<FComposeVolumetricRTOverScenePS::FUpsamplingMode>(UpsamplingMode);
		PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderUnderWaterBuffer>(0);
		PermutationVector.Set<FComposeVolumetricRTOverScenePS::FRenderCameraComposeWithWater>((bComposeWithWater && ViewInfo.IsUnderwater()) ? 1 : 0);
		PermutationVector.Set<FComposeVolumetricRTOverScenePS::FMSAASampleCount>(SceneDepthTexture->Desc.NumSamples);

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/VolumetricRenderTarget.cpp:815

Scope (from outer to inner):

file
function     void ComposeVolumetricRenderTargetOverScene

Source code excerpt:

		PassParameters->FullResolutionToVolumetricBufferResolutionScale = GetCompositionFullResolutionToVolumetricBufferResolutionScale(VRTMode);
		PassParameters->SceneTextures = SceneTextures.UniformBuffer;
		PassParameters->ForwardShadingEnable = bForwardShading ? 1 : 0;
		GetTextureSafeUvCoordBound(PassParameters->VolumetricTexture, PassParameters->VolumetricTextureValidCoordRect, PassParameters->VolumetricTextureValidUvRect);

		PassParameters->WaterLinearDepthTexture = WaterPassData.DepthTexture;
		PassParameters->WaterLinearDepthSampler = TStaticSamplerState<SF_Point>::GetRHI();
		if (bComposeWithWater)
		{