r.ForwardShading
r.ForwardShading
#Overview
name: r.ForwardShading
This variable is created as a Console Variable (cvar).
- type:
Var
- help:
Whether to use forward shading on desktop platforms - requires Shader Model 5 hardware.\nForward shading has lower constant cost, but fewer features supported. 0:off, 1:on\nThis 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.
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:
- The Renderer module
- The RenderCore module
- The Engine module
- 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:
- It requires Shader Model 5 hardware.
- Forward shading supports MSAA and has a lower default cost but fewer supported features overall.
- Materials need to opt-in to more expensive features like high-quality reflections when using forward shading.
- Changing this setting typically requires restarting the editor.
Best practices when using this variable include:
- Consider the target hardware capabilities before enabling forward shading.
- Be aware of the limitations in terms of advanced rendering features when using forward shading.
- Optimize materials for forward shading if it’s enabled.
- 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)
{