Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/BasePassRendering.cpp
Sebastien Hillaire ff9a2e30f6 Strata - PDO now relies on in shader depth test to avoid UAV write or material data when the depth buffer does not match.
(we cannot rely on LateZ to cull UAV writes)

#rb luke.thatcher
#preflight 628797c78828ea88c85302dc
#fyi charles.derousiers

[CL 20301945 by Sebastien Hillaire in ue5-main branch]
2022-05-20 16:08:18 -04:00

2111 lines
87 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BasePassRendering.h"
#include "DeferredShadingRenderer.h"
#include "DistortionRendering.h"
#include "DynamicPrimitiveDrawing.h"
#include "ScenePrivate.h"
#include "MeshPassProcessor.inl"
#include "EditorPrimitivesRendering.h"
#include "TranslucentRendering.h"
#include "SingleLayerWaterRendering.h"
#include "Rendering/SkyAtmosphereCommonData.h"
#include "SceneTextureParameters.h"
#include "CompositionLighting/CompositionLighting.h"
#include "CompositionLighting/PostProcessAmbientOcclusion.h"
#include "SceneViewExtension.h"
#include "VariableRateShadingImageManager.h"
#include "OneColorShader.h"
#include "ClearQuad.h"
#include "ProfilingDebugging/CpuProfilerTrace.h"
#include "DebugProbeRendering.h"
#include "AnisotropyRendering.h"
#include "Nanite/NaniteVisualize.h"
// Changing this causes a full shader recompile
static TAutoConsoleVariable<int32> CVarSelectiveBasePassOutputs(
TEXT("r.SelectiveBasePassOutputs"),
0,
TEXT("Enables shaders to only export to relevant rendertargets.\n") \
TEXT(" 0: Export in all rendertargets.\n") \
TEXT(" 1: Export only into relevant rendertarget.\n"),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
// Changing this causes a full shader recompile
static TAutoConsoleVariable<int32> CVarGlobalClipPlane(
TEXT("r.AllowGlobalClipPlane"),
0,
TEXT("Enables mesh shaders to support a global clip plane, needed for planar reflections, which adds about 15% BasePass GPU cost on PS4."),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
// Changing this causes a full shader recompile
static TAutoConsoleVariable<int32> CVarVertexFoggingForOpaque(
TEXT("r.VertexFoggingForOpaque"),
1,
TEXT("Causes opaque materials to use per-vertex fogging, which costs less and integrates properly with MSAA. Only supported with forward shading."),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarRHICmdFlushRenderThreadTasksBasePass(
TEXT("r.RHICmdFlushRenderThreadTasksBasePass"),
0,
TEXT("Wait for completion of parallel render thread tasks at the end of the base pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksBasePass is > 0 we will flush."));
static TAutoConsoleVariable<int32> CVarSupportStationarySkylight(
TEXT("r.SupportStationarySkylight"),
1,
TEXT("Enables Stationary and Dynamic Skylight shader permutations."),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarSupportLowQualityLightmaps(
TEXT("r.SupportLowQualityLightmaps"),
1,
TEXT("Support low quality lightmap shader permutations"),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarSupportAllShaderPermutations(
TEXT("r.SupportAllShaderPermutations"),
0,
TEXT("Local user config override to force all shader permutation features on."),
ECVF_ReadOnly | ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarParallelBasePass(
TEXT("r.ParallelBasePass"),
1,
TEXT("Toggles parallel base pass rendering. Parallel rendering must be enabled for this to have an effect."),
ECVF_RenderThreadSafe);
static TAutoConsoleVariable<int32> CVarClearGBufferDBeforeBasePass(
TEXT("r.ClearGBufferDBeforeBasePass"),
1,
TEXT("Whether to clear GBuffer D before basepass"),
ECVF_RenderThreadSafe);
// Scene color alpha is used during scene captures and planar reflections. 1 indicates background should be shown, 0 indicates foreground is fully present.
static const float kSceneColorClearAlpha = 1.0f;
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSharedBasePassUniformParameters, "BasePass");
IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FOpaqueBasePassUniformParameters, "OpaqueBasePass", SceneTextures);
IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FTranslucentBasePassUniformParameters, "TranslucentBasePass", SceneTextures);
// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
#define IMPLEMENT_BASEPASS_VERTEXSHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \
typedef TBasePassVS< LightMapPolicyType > TBasePassVS##LightMapPolicyName ; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassVS##LightMapPolicyName,TEXT("/Engine/Private/BasePassVertexShader.usf"),TEXT("Main"),SF_Vertex);
#define IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,bEnableSkyLight,SkyLightName) \
typedef TBasePassPS<LightMapPolicyType, bEnableSkyLight> TBasePassPS##LightMapPolicyName##SkyLightName; \
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassPS##LightMapPolicyName##SkyLightName,TEXT("/Engine/Private/BasePassPixelShader.usf"),TEXT("MainPS"),SF_Pixel);
// Implement a pixel shader type for skylights and one without, and one vertex shader that will be shared between them
#define IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \
IMPLEMENT_BASEPASS_VERTEXSHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \
IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,true,Skylight) \
IMPLEMENT_BASEPASS_PIXELSHADER_TYPE(LightMapPolicyType,LightMapPolicyName,false,);
// Implement shader types per lightmap policy
// If renaming or refactoring these, remember to update FMaterialResource::GetRepresentativeInstructionCounts and FPreviewMaterial::ShouldCache().
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedTranslucencyPolicy, FSelfShadowedTranslucencyPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedCachedPointIndirectLightingPolicy, FSelfShadowedCachedPointIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( FSelfShadowedVolumetricLightmapPolicy, FSelfShadowedVolumetricLightmapPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_NO_LIGHTMAP>, FNoLightMapPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING>, FPrecomputedVolumetricLightmapLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_CACHED_VOLUME_INDIRECT_LIGHTING>, FCachedVolumeIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_CACHED_POINT_INDIRECT_LIGHTING>, FCachedPointIndirectLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_NO_LIGHTMAP>, FSimpleNoLightmapLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING>, FSimpleLightmapOnlyLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING>, FSimpleDirectionalLightLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING>, FSimpleStationaryLightPrecomputedShadowsLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING>, FSimpleStationaryLightSingleSampleShadowsLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING>, FSimpleStationaryLightVolumetricLightmapShadowsLightingPolicy );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_LQ_LIGHTMAP>, TLightMapPolicyLQ );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_HQ_LIGHTMAP>, TLightMapPolicyHQ );
IMPLEMENT_BASEPASS_LIGHTMAPPED_SHADER_TYPE( TUniformLightMapPolicy<LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP>, TDistanceFieldShadowsAndLightMapPolicyHQ );
IMPLEMENT_MATERIAL_SHADER_TYPE(, F128BitRTBasePassPS, TEXT("/Engine/Private/BasePassPixelShader.usf"), TEXT("MainPS"), SF_Pixel);
DEFINE_GPU_DRAWCALL_STAT(Basepass);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer ClearGBufferAtMaxZ"), STAT_FDeferredShadingSceneRenderer_ClearGBufferAtMaxZ, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer ViewExtensionPostRenderBasePass"), STAT_FDeferredShadingSceneRenderer_ViewExtensionPostRenderBasePass, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("BasePass"), STAT_CLM_BasePass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterBasePass"), STAT_CLM_AfterBasePass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AnisotropyPass"), STAT_CLM_AnisotropyPass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterAnisotropyPass"), STAT_CLM_AfterAnisotropyPass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("BasePass"), STAT_CLP_BasePass, STATGROUP_ParallelCommandListMarkers);
static bool IsBasePassWaitForTasksEnabled()
{
return CVarRHICmdFlushRenderThreadTasksBasePass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0;
}
void SetTranslucentRenderState(FMeshPassProcessorRenderState& DrawRenderState, const FMaterial& Material, const EShaderPlatform Platform, ETranslucencyPass::Type InTranslucencyPassType)
{
if (Material.IsStrataMaterial())
{
if (Material.IsDualBlendingEnabled(Platform))
{
if (InTranslucencyPassType == ETranslucencyPass::TPT_StandardTranslucency || InTranslucencyPassType == ETranslucencyPass::TPT_AllTranslucency)
{
// If we are in the transparancy pass (before DoF) we do standard dual blending, and the alpha gets ignored
// Blend by putting add in target 0 and multiply by background in target 1.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_One, BF_Source1Alpha>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterDOF)
{
// In the separate pass (after DoF), we want let alpha pass through, and then multiply our color modulation in the after DoF Modulation pass.
// Alpha is BF_Zero for source and BF_One for dest, which leaves alpha unchanged
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
// In the separate pass (after DoF) modulate, we want to only darken the target by our multiplication term, and ignore the addition term.
// For regular dual blending, our function is:
// FrameBuffer = MRT0 + MRT1 * FrameBuffer;
// So we can just remove the MRT0 component and it will modulate as expected.
// Alpha we will leave unchanged.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
// We don't actually currently support color modulation in the post-motion blur pass at the moment, so just do the same as post-DOF for now
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
}
else
{
if (Material.GetStrataBlendMode() == SBM_ColoredTransmittanceOnly)
{
// Modulate with the existing scene color, preserve destination alpha.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGB, BO_Add, BF_DestColor, BF_Zero>::GetRHI());
}
else if (Material.GetStrataBlendMode() == SBM_AlphaHoldout)
{
// Blend by holding out the matte shape of the source alpha
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI());
}
else
{
// We always use premultipled alpha for translucent rendering.
// If a material was requesting dual source blending, the shader will use static platofm knowledge to convert colored transmittance to a grey scale transmittance.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI());
}
}
}
else if (Material.GetShadingModels().HasShadingModel(MSM_ThinTranslucent))
{
// Special case for dual blending, which is not exposed as a parameter in the material editor
if (Material.IsDualBlendingEnabled(Platform))
{
if (InTranslucencyPassType == ETranslucencyPass::TPT_StandardTranslucency || InTranslucencyPassType == ETranslucencyPass::TPT_AllTranslucency)
{
// If we are in the transparancy pass (before DoF) we do standard dual blending, and the alpha gets ignored
// Blend by putting add in target 0 and multiply by background in target 1.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_One, BF_Source1Alpha>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterDOF)
{
// In the separate pass (after DoF), we want let alpha pass through, and then multiply our color modulation in the after DoF Modulation pass.
// Alpha is BF_Zero for source and BF_One for dest, which leaves alpha unchanged
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterDOFModulate)
{
// In the separate pass (after DoF) modulate, we want to only darken the target by our multiplication term, and ignore the addition term.
// For regular dual blending, our function is:
// FrameBuffer = MRT0 + MRT1 * FrameBuffer;
// So we can just remove the MRT0 component and it will modulate as expected.
// Alpha we will leave unchanged.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
else if (InTranslucencyPassType == ETranslucencyPass::TPT_TranslucencyAfterMotionBlur)
{
// We don't actually currently support color modulation in the post-motion blur pass at the moment, so just do the same as post-DOF for now
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Source1Color, BO_Add, BF_Zero, BF_One>::GetRHI());
}
}
else
{
// If unsupported, we still use premultipled alpha but the shader will use the variation converting color transmittance to a grey scale transmittance.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI());
}
}
else
{
switch (Material.GetBlendMode())
{
default:
case BLEND_Opaque:
// Opaque materials are rendered together in the base pass, where the blend state is set at a higher level
break;
case BLEND_Masked:
// Masked materials are rendered together in the base pass, where the blend state is set at a higher level
break;
case BLEND_Translucent:
// Note: alpha channel used by separate translucency, storing how much of the background should be added when doing the final composite
// The Alpha channel is also used by non-separate translucency when rendering to scene captures, which store the final opacity
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI());
break;
case BLEND_Additive:
// Add to the existing scene color
// Note: alpha channel used by separate translucency, storing how much of the background should be added when doing the final composite
// The Alpha channel is also used by non-separate translucency when rendering to scene captures, which store the final opacity
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI());
break;
case BLEND_Modulate:
// Modulate with the existing scene color, preserve destination alpha.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGB, BO_Add, BF_DestColor, BF_Zero>::GetRHI());
break;
case BLEND_AlphaComposite:
// Blend with existing scene color. New color is already pre-multiplied by alpha.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI());
break;
case BLEND_AlphaHoldout:
// Blend by holding out the matte shape of the source alpha
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI());
break;
};
}
const bool bDisableDepthTest = Material.ShouldDisableDepthTest();
const bool bEnableResponsiveAA = Material.ShouldEnableResponsiveAA();
const bool bIsPostMotionBlur = Material.IsTranslucencyAfterMotionBlurEnabled();
if (bEnableResponsiveAA && !bIsPostMotionBlur)
{
if (bDisableDepthTest)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<
false, CF_Always,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK
>::GetRHI());
DrawRenderState.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK);
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<
false, CF_DepthNearOrEqual,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
STENCIL_TEMPORAL_RESPONSIVE_AA_MASK, STENCIL_TEMPORAL_RESPONSIVE_AA_MASK
>::GetRHI());
DrawRenderState.SetStencilRef(STENCIL_TEMPORAL_RESPONSIVE_AA_MASK);
}
}
else if (bDisableDepthTest)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
}
}
FMeshDrawCommandSortKey CalculateTranslucentMeshStaticSortKey(const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, uint16 MeshIdInPrimitive)
{
uint16 SortKeyPriority = 0;
float DistanceOffset = 0.0f;
if (PrimitiveSceneProxy)
{
const FPrimitiveSceneInfo* PrimitiveSceneInfo = PrimitiveSceneProxy->GetPrimitiveSceneInfo();
SortKeyPriority = (uint16)((int32)PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority() - (int32)SHRT_MIN);
DistanceOffset = PrimitiveSceneInfo->Proxy->GetTranslucencySortDistanceOffset();
}
FMeshDrawCommandSortKey SortKey;
SortKey.Translucent.MeshIdInPrimitive = MeshIdInPrimitive;
SortKey.Translucent.Priority = SortKeyPriority;
SortKey.Translucent.Distance = *(uint32*)(&DistanceOffset); // View specific, so will be filled later inside VisibleMeshCommands.
return SortKey;
}
FMeshDrawCommandSortKey CalculateBasePassMeshStaticSortKey(EDepthDrawingMode EarlyZPassMode, EBlendMode BlendMode, const FMeshMaterialShader* VertexShader, const FMeshMaterialShader* PixelShader)
{
FMeshDrawCommandSortKey SortKey;
SortKey.BasePass.VertexShaderHash = (VertexShader ? VertexShader->GetSortKey() : 0) & 0xFFFF;
SortKey.BasePass.PixelShaderHash = PixelShader ? PixelShader->GetSortKey() : 0;
if (EarlyZPassMode != DDM_None)
{
SortKey.BasePass.Masked = BlendMode == EBlendMode::BLEND_Masked ? 0 : 1;
}
else
{
SortKey.BasePass.Masked = BlendMode == EBlendMode::BLEND_Masked ? 1 : 0;
}
return SortKey;
}
void SetDepthStencilStateForBasePass(
const FSceneView* ViewIfDynamicMeshCommand,
FMeshPassProcessorRenderState& DrawRenderState,
ERHIFeatureLevel::Type FeatureLevel,
const FMeshBatch& Mesh,
int32 StaticMeshId,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
const FMaterial& MaterialResource,
bool bEnableReceiveDecalOutput)
{
const bool bMaskedInEarlyPass = (MaterialResource.IsMasked() || Mesh.bDitheredLODTransition) && MaskedInEarlyPass(GShaderPlatformForFeatureLevel[FeatureLevel]);
if (bEnableReceiveDecalOutput)
{
// Set stencil value for this draw call
// This is effectively extending the GBuffer using the stencil bits
const uint8 StencilValue = GET_STENCIL_BIT_MASK(RECEIVE_DECAL, PrimitiveSceneProxy ? !!PrimitiveSceneProxy->ReceivesDecals() : 0x00)
| GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, PrimitiveSceneProxy ? PrimitiveSceneProxy->HasDistanceFieldRepresentation() : 0x00)
| STENCIL_LIGHTING_CHANNELS_MASK(PrimitiveSceneProxy ? PrimitiveSceneProxy->GetLightingChannelStencilValue() : 0x00);
if (bMaskedInEarlyPass)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<
false, CF_Equal,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0xFF, GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1) | GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, 1) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
>::GetRHI());
DrawRenderState.SetStencilRef(StencilValue);
}
else if (DrawRenderState.GetDepthStencilAccess() & FExclusiveDepthStencil::DepthWrite)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<
true, CF_GreaterEqual,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0xFF, GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1) | GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, 1) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
>::GetRHI());
DrawRenderState.SetStencilRef(StencilValue);
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<
false, CF_GreaterEqual,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0xFF, GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1) | GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, 1) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
>::GetRHI());
DrawRenderState.SetStencilRef(StencilValue);
}
}
else if (bMaskedInEarlyPass)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Equal>::GetRHI());
}
if (ViewIfDynamicMeshCommand && StaticMeshId >= 0 && Mesh.bDitheredLODTransition)
{
checkSlow(ViewIfDynamicMeshCommand->bIsViewInfo);
const FViewInfo* ViewInfo = static_cast<const FViewInfo*>(ViewIfDynamicMeshCommand);
if (ViewInfo->bAllowStencilDither)
{
if (ViewInfo->StaticMeshFadeOutDitheredLODMap[StaticMeshId] || ViewInfo->StaticMeshFadeInDitheredLODMap[StaticMeshId])
{
const uint32 RestoreStencilRef = DrawRenderState.GetStencilRef();
DrawRenderState.SetDepthStencilState(
TStaticDepthStencilState<
false, CF_Equal,
true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
0xFF, GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1) | GET_STENCIL_BIT_MASK(DISTANCE_FIELD_REPRESENTATION, 1) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
>::GetRHI());
DrawRenderState.SetStencilRef(RestoreStencilRef);
}
}
}
}
void SetupBasePassState(FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const bool bShaderComplexity, FMeshPassProcessorRenderState& DrawRenderState)
{
DrawRenderState.SetDepthStencilAccess(BasePassDepthStencilAccess);
if (bShaderComplexity)
{
// Additive blending when shader complexity viewmode is enabled.
DrawRenderState.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI());
// Disable depth writes as we have a full depth prepass.
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
}
else
{
// Opaque blending for all G buffer targets, depth tests and writes.
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.BasePassOutputsVelocityDebug"));
if (CVar && CVar->GetValueOnRenderThread() == 2)
{
DrawRenderState.SetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA, CW_NONE>::GetRHI());
}
else
{
DrawRenderState.SetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA>::GetRHI());
}
if (DrawRenderState.GetDepthStencilAccess() & FExclusiveDepthStencil::DepthWrite)
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI());
}
else
{
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
}
}
}
/**
* Get shader templates allowing to redirect between compatible shaders.
*/
template <ELightMapPolicyType Policy>
bool GetUniformBasePassShaders(
const FMaterial& Material,
FVertexFactoryType* VertexFactoryType,
ERHIFeatureLevel::Type FeatureLevel,
bool bEnableSkyLight,
bool bUse128bitRT,
TShaderRef<TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>>* VertexShader,
TShaderRef<TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>>* PixelShader
)
{
FMaterialShaderTypes ShaderTypes;
if(VertexShader)
{
ShaderTypes.AddShaderType<TBasePassVS<TUniformLightMapPolicy<Policy>>>();
}
if(PixelShader)
{
if (bEnableSkyLight)
{
ShaderTypes.AddShaderType<TBasePassPS<TUniformLightMapPolicy<Policy>, true>>();
}
else
{
if (bUse128bitRT && (Policy == LMP_NO_LIGHTMAP))
{
ShaderTypes.AddShaderType<F128BitRTBasePassPS>();
}
else
{
ShaderTypes.AddShaderType<TBasePassPS<TUniformLightMapPolicy<Policy>, false>>();
}
}
}
FMaterialShaders Shaders;
if (!Material.TryGetShaders(ShaderTypes, VertexFactoryType, Shaders))
{
return false;
}
Shaders.TryGetVertexShader(VertexShader);
Shaders.TryGetPixelShader(PixelShader);
return true;
}
template <>
bool GetBasePassShaders<FUniformLightMapPolicy>(
const FMaterial& Material,
FVertexFactoryType* VertexFactoryType,
FUniformLightMapPolicy LightMapPolicy,
ERHIFeatureLevel::Type FeatureLevel,
bool bEnableSkyLight,
bool bUse128bitRT,
TShaderRef<TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>>* VertexShader,
TShaderRef<TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>>* PixelShader
)
{
switch (LightMapPolicy.GetIndirectPolicy())
{
case LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING:
return GetUniformBasePassShaders<LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_CACHED_VOLUME_INDIRECT_LIGHTING:
return GetUniformBasePassShaders<LMP_CACHED_VOLUME_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_CACHED_POINT_INDIRECT_LIGHTING:
return GetUniformBasePassShaders<LMP_CACHED_POINT_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING:
return GetUniformBasePassShaders<LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_NO_LIGHTMAP:
return GetUniformBasePassShaders<LMP_SIMPLE_NO_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING:
return GetUniformBasePassShaders<LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING:
return GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING:
return GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING:
return GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_LQ_LIGHTMAP:
return GetUniformBasePassShaders<LMP_LQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_HQ_LIGHTMAP:
return GetUniformBasePassShaders<LMP_HQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP:
return GetUniformBasePassShaders<LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
case LMP_NO_LIGHTMAP:
return GetUniformBasePassShaders<LMP_NO_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableSkyLight, bUse128bitRT, VertexShader, PixelShader);
default:
check(false);
return false;
}
}
void SetupSharedBasePassParameters(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
bool bLumenGIEnabled,
FSharedBasePassUniformParameters& SharedParameters)
{
SharedParameters.Forward = *View.ForwardLightingResources.ForwardLightData;
SetupFogUniformParameters(GraphBuilder, View, SharedParameters.Fog);
if (View.IsInstancedStereoPass())
{
const FViewInfo& InstancedView = *View.GetInstancedView();
SharedParameters.ForwardISR = *InstancedView.ForwardLightingResources.ForwardLightData;
SetupFogUniformParameters(GraphBuilder, (FViewInfo&)InstancedView, SharedParameters.FogISR);
}
else
{
SharedParameters.ForwardISR = *View.ForwardLightingResources.ForwardLightData;
SharedParameters.FogISR = SharedParameters.Fog;
}
const FScene* Scene = View.Family->Scene ? View.Family->Scene->GetRenderScene() : nullptr;
const FPlanarReflectionSceneProxy* ReflectionSceneProxy = Scene ? Scene->GetForwardPassGlobalPlanarReflection() : nullptr;
SetupReflectionUniformParameters(View, SharedParameters.Reflection);
SetupPlanarReflectionUniformParameters(View, ReflectionSceneProxy, SharedParameters.PlanarReflection);
// Skip base pass skylight if Lumen GI is enabled, as Lumen handles the skylight.
// Ideally we would choose a different shader permutation to skip skylight, but Lumen GI is only known per-view
SharedParameters.UseBasePassSkylight = bLumenGIEnabled ? 0 : 1;
}
TRDGUniformBufferRef<FOpaqueBasePassUniformParameters> CreateOpaqueBasePassUniformBuffer(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const int32 ViewIndex,
const FForwardBasePassTextures& ForwardBasePassTextures,
const FDBufferTextures& DBufferTextures,
const FSceneWithoutWaterTextures* SceneWithoutWaterTextures,
bool bLumenGIEnabled)
{
FOpaqueBasePassUniformParameters& BasePassParameters = *GraphBuilder.AllocParameters<FOpaqueBasePassUniformParameters>();
SetupSharedBasePassParameters(GraphBuilder, View, bLumenGIEnabled, BasePassParameters.Shared);
const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
// Forward shading
{
BasePassParameters.UseForwardScreenSpaceShadowMask = 0;
BasePassParameters.ForwardScreenSpaceShadowMaskTexture = SystemTextures.White;
BasePassParameters.IndirectOcclusionTexture = SystemTextures.White;
BasePassParameters.ResolvedSceneDepthTexture = SystemTextures.White;
if (ForwardBasePassTextures.ScreenSpaceShadowMask)
{
BasePassParameters.UseForwardScreenSpaceShadowMask = 1;
BasePassParameters.ForwardScreenSpaceShadowMaskTexture = ForwardBasePassTextures.ScreenSpaceShadowMask;
}
if (HasBeenProduced(ForwardBasePassTextures.ScreenSpaceAO))
{
BasePassParameters.IndirectOcclusionTexture = ForwardBasePassTextures.ScreenSpaceAO;
}
if (ForwardBasePassTextures.SceneDepthIfResolved)
{
BasePassParameters.ResolvedSceneDepthTexture = ForwardBasePassTextures.SceneDepthIfResolved;
}
BasePassParameters.Is24BitUnormDepthStencil = ForwardBasePassTextures.bIs24BitUnormDepthStencil ? 1 : 0;
}
// DBuffer Decals
BasePassParameters.DBuffer = GetDBufferParameters(GraphBuilder, DBufferTextures, View.GetShaderPlatform());
// Single Layer Water
BasePassParameters.SceneWithoutSingleLayerWaterMinMaxUV = FVector4f(0.0f, 0.0f, 1.0f, 1.0f);
BasePassParameters.SceneColorWithoutSingleLayerWaterTexture = SystemTextures.Black;
BasePassParameters.SceneDepthWithoutSingleLayerWaterTexture = SystemTextures.Black;
BasePassParameters.SceneColorWithoutSingleLayerWaterSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
BasePassParameters.SceneDepthWithoutSingleLayerWaterSampler = TStaticSamplerState<SF_Point>::GetRHI();
if (SceneWithoutWaterTextures)
{
BasePassParameters.SceneWithoutSingleLayerWaterMinMaxUV = SceneWithoutWaterTextures->Views[ViewIndex].MinMaxUV;
BasePassParameters.SceneColorWithoutSingleLayerWaterTexture = SceneWithoutWaterTextures->ColorTexture;
BasePassParameters.SceneDepthWithoutSingleLayerWaterTexture = SceneWithoutWaterTextures->DepthTexture;
}
BasePassParameters.PreIntegratedGFTexture = GSystemTextures.PreintegratedGF->GetRHI();
BasePassParameters.PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
SetupDistortionParams(BasePassParameters.DistortionParams, View);
// Strata
Strata::BindStrataBasePassUniformParameters(GraphBuilder, View, BasePassParameters.Strata);
// Misc
BasePassParameters.EyeAdaptationTexture = GetEyeAdaptationTexture(GraphBuilder, View);
return GraphBuilder.CreateUniformBuffer(&BasePassParameters);
}
static void ClearGBufferAtMaxZ(
FRDGBuilder& GraphBuilder,
TArrayView<const FViewInfo> Views,
const FRenderTargetBindingSlots& BasePassRenderTargets,
FLinearColor ClearColor0)
{
check(Views.Num() > 0);
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_ClearGBufferAtMaxZ);
RDG_EVENT_SCOPE(GraphBuilder, "ClearGBufferAtMaxZ");
const uint32 ActiveTargetCount = BasePassRenderTargets.GetActiveCount();
FGlobalShaderMap* ShaderMap = Views[0].ShaderMap;
TShaderMapRef<TOneColorVS<true> > VertexShader(ShaderMap);
TOneColorPixelShaderMRT::FPermutationDomain PermutationVector;
PermutationVector.Set<TOneColorPixelShaderMRT::TOneColorPixelShaderNumOutputs>(ActiveTargetCount);
TShaderMapRef<TOneColorPixelShaderMRT>PixelShader(ShaderMap, PermutationVector);
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets = BasePassRenderTargets;
// Clear each viewport by drawing background color at MaxZ depth
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
GraphBuilder.AddPass(
{},
PassParameters,
ERDGPassFlags::Raster,
[&View, VertexShader, PixelShader, ActiveTargetCount, ClearColor0](FRHICommandList& RHICmdList)
{
const FLinearColor ClearColors[MaxSimultaneousRenderTargets] =
{
ClearColor0,
FLinearColor(0.5f,0.5f,0.5f,0),
FLinearColor(0,0,0,1),
FLinearColor(0,0,0,0),
FLinearColor(0,1,1,1),
FLinearColor(1,1,1,1),
FLinearColor::Transparent,
FLinearColor::Transparent
};
FGraphicsPipelineStateInitializer GraphicsPSOInit;
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
// Opaque rendering, depth test but no depth writes
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
GraphicsPSOInit.BlendState = TStaticBlendStateWriteMask<>::GetRHI();
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI();
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GetVertexDeclarationFVector4();
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
GraphicsPSOInit.PrimitiveType = PT_TriangleStrip;
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
VertexShader->SetDepthParameter(RHICmdList, float(ERHIZBuffer::FarPlane));
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1);
PixelShader->SetColors(RHICmdList, PixelShader, ClearColors, ActiveTargetCount);
RHICmdList.SetStreamSource(0, GClearVertexBuffer.VertexBufferRHI, 0);
RHICmdList.DrawPrimitive(0, 2, 1);
});
}
}
BEGIN_SHADER_PARAMETER_STRUCT(FPostBasePassViewExtensionParameters, )
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
void FDeferredShadingSceneRenderer::RenderBasePass(
FRDGBuilder& GraphBuilder,
FSceneTextures& SceneTextures,
const FDBufferTextures& DBufferTextures,
FExclusiveDepthStencil::Type BasePassDepthStencilAccess,
FRDGTextureRef ForwardShadowMaskTexture,
FInstanceCullingManager& InstanceCullingManager,
bool bNaniteEnabled,
const TArrayView<Nanite::FRasterResults>& NaniteRasterResults)
{
TRACE_CPUPROFILER_EVENT_SCOPE(FDeferredShadingSceneRenderer::RenderBasePass);
const bool bEnableParallelBasePasses = GRHICommandList.UseParallelAlgorithms() && CVarParallelBasePass.GetValueOnRenderThread();
static const auto ClearMethodCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ClearSceneMethod"));
bool bRequiresRHIClear = true;
bool bRequiresFarZQuadClear = false;
if (ClearMethodCVar)
{
int32 ClearMethod = ClearMethodCVar->GetValueOnRenderThread();
if (ClearMethod == 0 && !ActiveViewFamily->EngineShowFlags.Game)
{
// Do not clear the scene only if the view family is in game mode.
ClearMethod = 1;
}
switch (ClearMethod)
{
case 0: // No clear
bRequiresRHIClear = false;
bRequiresFarZQuadClear = false;
break;
case 1: // RHICmdList.Clear
bRequiresRHIClear = true;
bRequiresFarZQuadClear = false;
break;
case 2: // Clear using far-z quad
bRequiresFarZQuadClear = true;
bRequiresRHIClear = false;
break;
}
}
// Always perform a full buffer clear for wireframe, shader complexity view mode, and stationary light overlap viewmode.
if (ActiveViewFamily->EngineShowFlags.Wireframe || ActiveViewFamily->EngineShowFlags.ShaderComplexity || ActiveViewFamily->EngineShowFlags.StationaryLightOverlap)
{
bRequiresRHIClear = true;
bRequiresFarZQuadClear = false;
}
const bool bIsWireframeRenderpass = ActiveViewFamily->EngineShowFlags.Wireframe && FSceneRenderer::ShouldCompositeEditorPrimitives(Views[0]);
const bool bDebugViewMode = ActiveViewFamily->UseDebugViewPS();
const bool bRenderLightmapDensity = ActiveViewFamily->EngineShowFlags.LightMapDensity && AllowDebugViewmodes();
const bool bRenderSkyAtmosphereEditorNotifications = ShouldRenderSkyAtmosphereEditorNotifications();
const bool bDoParallelBasePass = bEnableParallelBasePasses && !bDebugViewMode && !bRenderLightmapDensity; // DebugView and LightmapDensity are non-parallel substitutions inside BasePass
const bool bNeedsBeginRender = AllowDebugViewmodes() &&
(ActiveViewFamily->EngineShowFlags.RequiredTextureResolution ||
ActiveViewFamily->EngineShowFlags.VirtualTexturePendingMips ||
ActiveViewFamily->EngineShowFlags.MaterialTextureScaleAccuracy ||
ActiveViewFamily->EngineShowFlags.MeshUVDensityAccuracy ||
ActiveViewFamily->EngineShowFlags.PrimitiveDistanceAccuracy ||
ActiveViewFamily->EngineShowFlags.ShaderComplexity ||
ActiveViewFamily->EngineShowFlags.LODColoration ||
ActiveViewFamily->EngineShowFlags.HLODColoration);
const bool bForwardShadingEnabled = IsForwardShadingEnabled(SceneTextures.Config.ShaderPlatform);
const FExclusiveDepthStencil ExclusiveDepthStencil(BasePassDepthStencilAccess);
TStaticArray<FTextureRenderTargetBinding, MaxSimultaneousRenderTargets> BasePassTextures;
uint32 BasePassTextureCount = SceneTextures.GetGBufferRenderTargets(BasePassTextures);
Strata::AppendStrataMRTs(*this, BasePassTextureCount, BasePassTextures);
TArrayView<FTextureRenderTargetBinding> BasePassTexturesView = MakeArrayView(BasePassTextures.GetData(), BasePassTextureCount);
FRDGTextureRef BasePassDepthTexture = SceneTextures.Depth.Target;
FLinearColor SceneColorClearValue;
if (bRequiresRHIClear)
{
if (ActiveViewFamily->EngineShowFlags.ShaderComplexity && SceneTextures.QuadOverdraw)
{
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(SceneTextures.QuadOverdraw), FUintVector4(0, 0, 0, 0));
}
if (ActiveViewFamily->EngineShowFlags.ShaderComplexity || ActiveViewFamily->EngineShowFlags.StationaryLightOverlap)
{
SceneColorClearValue = FLinearColor(0, 0, 0, kSceneColorClearAlpha);
}
else
{
SceneColorClearValue = FLinearColor(Views[0].BackgroundColor.R, Views[0].BackgroundColor.G, Views[0].BackgroundColor.B, kSceneColorClearAlpha);
}
ERenderTargetLoadAction ColorLoadAction = ERenderTargetLoadAction::ELoad;
if (SceneTextures.Color.Target->Desc.ClearValue.GetClearColor() == SceneColorClearValue)
{
ColorLoadAction = ERenderTargetLoadAction::EClear;
}
else
{
ColorLoadAction = ERenderTargetLoadAction::ENoAction;
}
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets = GetRenderTargetBindings(ColorLoadAction, BasePassTexturesView);
if (!CVarClearGBufferDBeforeBasePass.GetValueOnRenderThread() && SceneTextures.Config.GBufferD.Index > 0 && SceneTextures.Config.GBufferD.Index < (int32)BasePassTextureCount)
{
PassParameters->RenderTargets[SceneTextures.Config.GBufferD.Index].SetLoadAction(ERenderTargetLoadAction::ENoAction);
}
GraphBuilder.AddPass(RDG_EVENT_NAME("GBufferClear"), PassParameters, ERDGPassFlags::Raster,
[PassParameters, ColorLoadAction, SceneColorClearValue](FRHICommandList& RHICmdList)
{
// If no fast-clear action was used, we need to do an MRT shader clear.
if (ColorLoadAction == ERenderTargetLoadAction::ENoAction)
{
const FRenderTargetBindingSlots& RenderTargets = PassParameters->RenderTargets;
FLinearColor ClearColors[MaxSimultaneousRenderTargets];
FRHITexture* Textures[MaxSimultaneousRenderTargets];
int32 TextureIndex = 0;
RenderTargets.Enumerate([&](const FRenderTargetBinding& RenderTarget)
{
FRHITexture* TextureRHI = RenderTarget.GetTexture()->GetRHI();
ClearColors[TextureIndex] = TextureIndex == 0 ? SceneColorClearValue : TextureRHI->GetClearColor();
Textures[TextureIndex] = TextureRHI;
++TextureIndex;
});
// Clear color only; depth-stencil is fast cleared.
DrawClearQuadMRT(RHICmdList, true, TextureIndex, ClearColors, false, 0, false, 0);
}
});
if (bRenderSkyAtmosphereEditorNotifications)
{
// We only render this warning text when bRequiresRHIClear==true to make sure the scene color buffer is allocated at this stage.
// When false, the option specifies that all pixels must be written to by a sky dome anyway.
RenderSkyAtmosphereEditorNotifications(GraphBuilder, SceneTextures.Color.Target);
}
}
#if WITH_EDITOR
if (ActiveViewFamily->EngineShowFlags.Wireframe)
{
checkf(ExclusiveDepthStencil.IsDepthWrite(), TEXT("Wireframe base pass requires depth-write, but it is set to read-only."));
BasePassTextureCount = 1;
BasePassTextures[0] = SceneTextures.EditorPrimitiveColor;
BasePassTexturesView = MakeArrayView(BasePassTextures.GetData(), BasePassTextureCount);
BasePassDepthTexture = SceneTextures.EditorPrimitiveDepth;
auto* PassParameters = GraphBuilder.AllocParameters<FRenderTargetParameters>();
PassParameters->RenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::EClear, BasePassTexturesView);
PassParameters->RenderTargets.DepthStencil = FDepthStencilBinding(BasePassDepthTexture, ERenderTargetLoadAction::EClear, ERenderTargetLoadAction::EClear, ExclusiveDepthStencil);
GraphBuilder.AddPass(RDG_EVENT_NAME("WireframeClear"), PassParameters, ERDGPassFlags::Raster, [](FRHICommandList&) {});
}
#endif
// Render targets bindings should remain constant at this point.
FRenderTargetBindingSlots BasePassRenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::ELoad, BasePassTexturesView);
BasePassRenderTargets.DepthStencil = FDepthStencilBinding(BasePassDepthTexture, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, ExclusiveDepthStencil);
BasePassRenderTargets.ShadingRateTexture = GVRSImageManager.GetVariableRateShadingImage(GraphBuilder, *ActiveViewFamily, nullptr, EVRSType::None);
FForwardBasePassTextures ForwardBasePassTextures{};
if (bForwardShadingEnabled)
{
ForwardBasePassTextures.SceneDepthIfResolved = SceneTextures.Depth.IsSeparate() ? SceneTextures.Depth.Resolve : nullptr;
ForwardBasePassTextures.ScreenSpaceAO = SceneTextures.ScreenSpaceAO;
ForwardBasePassTextures.ScreenSpaceShadowMask = ForwardShadowMaskTexture;
}
else if (!ExclusiveDepthStencil.IsDepthWrite())
{
// If depth write is not enabled, we can bound the depth texture as read only
ForwardBasePassTextures.SceneDepthIfResolved = SceneTextures.Depth.Resolve;
}
ForwardBasePassTextures.bIs24BitUnormDepthStencil = ForwardBasePassTextures.SceneDepthIfResolved ? GPixelFormats[ForwardBasePassTextures.SceneDepthIfResolved->Desc.Format].bIs24BitUnormDepthStencil : 1;
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_BasePass));
RenderBasePassInternal(GraphBuilder, SceneTextures, BasePassRenderTargets, BasePassDepthStencilAccess, ForwardBasePassTextures, DBufferTextures, bDoParallelBasePass, bRenderLightmapDensity, InstanceCullingManager, bNaniteEnabled, NaniteRasterResults);
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_AfterBasePass));
if (ActiveViewFamily->ViewExtensions.Num() > 0)
{
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_ViewExtensionPostRenderBasePass);
RDG_EVENT_SCOPE(GraphBuilder, "BasePass_ViewExtensions");
auto* PassParameters = GraphBuilder.AllocParameters<FPostBasePassViewExtensionParameters>();
PassParameters->RenderTargets = BasePassRenderTargets;
PassParameters->SceneTextures = CreateSceneTextureUniformBuffer(GraphBuilder, &GetActiveSceneTextures(), FeatureLevel, ESceneTextureSetupMode::None);
GraphBuilder.AddPass(
{},
PassParameters,
ERDGPassFlags::Raster,
[this](FRHICommandListImmediate& RHICmdList)
{
for (auto& ViewExtension : ActiveViewFamily->ViewExtensions)
{
for (FViewInfo& View : Views)
{
SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
ViewExtension->PostRenderBasePass_RenderThread(RHICmdList, View);
}
}
});
}
if (bRequiresFarZQuadClear)
{
ClearGBufferAtMaxZ(GraphBuilder, Views, BasePassRenderTargets, SceneColorClearValue);
}
if (ShouldRenderAnisotropyPass(Views))
{
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_AnisotropyPass));
RenderAnisotropyPass(GraphBuilder, SceneTextures, bEnableParallelBasePasses);
GraphBuilder.SetCommandListStat(GET_STATID(STAT_CLM_AfterAnisotropyPass));
}
#if !(UE_BUILD_SHIPPING)
if (!bForwardShadingEnabled)
{
StampDeferredDebugProbeMaterialPS(GraphBuilder, Views, BasePassRenderTargets, SceneTextures);
}
#endif
}
BEGIN_SHADER_PARAMETER_STRUCT(FOpaqueBasePassParameters, )
SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View)
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCapture)
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FOpaqueBasePassUniformParameters, BasePass)
SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
static void RenderEditorPrimitivesForDPG(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
FOpaqueBasePassParameters* PassParameters,
const FMeshPassProcessorRenderState& DrawRenderState,
ESceneDepthPriorityGroup DepthPriorityGroup,
FInstanceCullingManager& InstanceCullingManager)
{
const FScene* Scene = View.Family->Scene->GetRenderScene();
GraphBuilder.AddPass(
RDG_EVENT_NAME("%s", *UEnum::GetValueAsString(DepthPriorityGroup)),
PassParameters,
ERDGPassFlags::Raster,
[&View, DrawRenderState, DepthPriorityGroup](FRHICommandListImmediate& RHICmdList)
{
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, DepthPriorityGroup);
if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
{
const bool bNeedToSwitchVerticalAxis = RHINeedsToSwitchVerticalAxis(View.GetShaderPlatform());
DrawDynamicMeshPass(View, RHICmdList,
[&View, &DrawRenderState](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FEditorPrimitivesBasePassMeshProcessor PassMeshProcessor(
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
false,
DynamicMeshPassContext);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
const FBatchedElements& BatchedViewElements = DepthPriorityGroup == SDPG_World ? View.BatchedViewElements : View.TopBatchedViewElements;
DrawDynamicMeshPass(View, RHICmdList,
[&View, &DrawRenderState](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)
{
FEditorPrimitivesBasePassMeshProcessor PassMeshProcessor(
View.Family->Scene->GetRenderScene(),
View.GetFeatureLevel(),
&View,
DrawRenderState,
false,
DynamicMeshPassContext);
const uint64 DefaultBatchElementMask = ~0ull;
for (int32 MeshIndex = 0; MeshIndex < View.TopViewMeshElements.Num(); MeshIndex++)
{
const FMeshBatch& MeshBatch = View.TopViewMeshElements[MeshIndex];
PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);
}
});
// Draw the view's batched simple elements(lines, sprites, etc).
View.TopBatchedViewElements.Draw(RHICmdList, DrawRenderState, View.GetFeatureLevel(), bNeedToSwitchVerticalAxis, View, false);
}
});
}
static bool HasEditorPrimitivesForDPG(const FViewInfo& View, ESceneDepthPriorityGroup DepthPriorityGroup)
{
bool bHasPrimitives = View.SimpleElementCollector.HasPrimitives(DepthPriorityGroup);
if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
{
const TIndirectArray<FMeshBatch>& ViewMeshElementList = (DepthPriorityGroup == SDPG_Foreground ? View.TopViewMeshElements : View.ViewMeshElements);
bHasPrimitives |= ViewMeshElementList.Num() > 0;
const FBatchedElements& BatchedViewElements = DepthPriorityGroup == SDPG_World ? View.BatchedViewElements : View.TopBatchedViewElements;
bHasPrimitives |= BatchedViewElements.HasPrimsToDraw();
}
return bHasPrimitives;
}
static void RenderEditorPrimitives(
FRDGBuilder& GraphBuilder,
FOpaqueBasePassParameters* PassParameters,
const FViewInfo& View,
const FMeshPassProcessorRenderState& DrawRenderState,
FInstanceCullingManager& InstanceCullingManager)
{
RDG_EVENT_SCOPE(GraphBuilder, "EditorPrimitives");
RenderEditorPrimitivesForDPG(GraphBuilder, View, PassParameters, DrawRenderState, SDPG_World, InstanceCullingManager);
if (HasEditorPrimitivesForDPG(View, SDPG_Foreground))
{
// Write foreground primitives into depth buffer without testing
{
auto* DepthWritePassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
*DepthWritePassParameters = *PassParameters;
// Change to depth writable
DepthWritePassParameters->RenderTargets.DepthStencil.SetDepthStencilAccess(FExclusiveDepthStencil::DepthWrite_StencilWrite);
FMeshPassProcessorRenderState NoDepthTestDrawRenderState(DrawRenderState);
NoDepthTestDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_Always>::GetRHI());
NoDepthTestDrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthWrite_StencilWrite);
RenderEditorPrimitivesForDPG(GraphBuilder, View, DepthWritePassParameters, NoDepthTestDrawRenderState, SDPG_Foreground, InstanceCullingManager);
}
// Render foreground primitives with depth testing
RenderEditorPrimitivesForDPG(GraphBuilder, View, PassParameters, DrawRenderState, SDPG_Foreground, InstanceCullingManager);
}
}
void FDeferredShadingSceneRenderer::RenderBasePassInternal(
FRDGBuilder& GraphBuilder,
const FSceneTextures& SceneTextures,
const FRenderTargetBindingSlots& BasePassRenderTargets,
FExclusiveDepthStencil::Type BasePassDepthStencilAccess,
const FForwardBasePassTextures& ForwardBasePassTextures,
const FDBufferTextures& DBufferTextures,
bool bParallelBasePass,
bool bRenderLightmapDensity,
FInstanceCullingManager& InstanceCullingManager,
bool bNaniteEnabled,
const TArrayView<Nanite::FRasterResults>& NaniteRasterResults)
{
RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderBasePass);
SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderBasePass, FColor::Emerald);
#if WITH_DEBUG_VIEW_MODES
Nanite::EDebugViewMode NaniteDebugViewMode = Nanite::EDebugViewMode::None;
if (ActiveViewFamily->EngineShowFlags.Wireframe)
{
NaniteDebugViewMode = Nanite::EDebugViewMode::Wireframe;
}
else if (bRenderLightmapDensity)
{
NaniteDebugViewMode = Nanite::EDebugViewMode::LightmapDensity;
}
else if (ActiveViewFamily->UseDebugViewPS())
{
switch (ActiveViewFamily->GetDebugViewShaderMode())
{
case DVSM_ShaderComplexity: // Default shader complexity viewmode
case DVSM_ShaderComplexityContainedQuadOverhead: // Show shader complexity with quad overdraw scaling the PS instruction count.
case DVSM_ShaderComplexityBleedingQuadOverhead: // Show shader complexity with quad overdraw bleeding the PS instruction count over the quad.
case DVSM_QuadComplexity: // Show quad overdraw only.
NaniteDebugViewMode = Nanite::EDebugViewMode::ShaderComplexity;
break;
default:
break;
}
}
#endif
FRDGTextureRef NaniteColorTarget = SceneTextures.Color.Target;
FRDGTextureRef NaniteDepthTarget = SceneTextures.Depth.Target;
#if WITH_EDITOR && WITH_DEBUG_VIEW_MODES
if (NaniteDebugViewMode == Nanite::EDebugViewMode::Wireframe)
{
NaniteColorTarget = SceneTextures.EditorPrimitiveColor;
NaniteDepthTarget = SceneTextures.EditorPrimitiveDepth;
}
#endif
auto RenderNaniteDepthPass = [&](FViewInfo& View, int32 ViewIndex)
{
// Emit Nanite depth if there was not an earlier depth pre-pass
if (!ShouldRenderPrePass())
{
Nanite::FRasterResults& RasterResults = NaniteRasterResults[ViewIndex];
// Emit velocity with depth if not writing it in base pass.
FRDGTexture* VelocityBuffer = !IsUsingBasePassVelocity(ShaderPlatform) ? SceneTextures.Velocity : nullptr;
const bool bEmitStencilMask = NANITE_MATERIAL_STENCIL != 0;
Nanite::EmitDepthTargets(
GraphBuilder,
*Scene,
View,
RasterResults.PageConstants,
RasterResults.VisibleClustersSWHW,
RasterResults.ViewsBuffer,
SceneTextures.Depth.Target,
RasterResults.VisBuffer64,
VelocityBuffer,
RasterResults.MaterialDepth,
RasterResults.MaterialResolve,
ShouldRenderPrePass(),
bEmitStencilMask
);
}
};
auto RenderNaniteBasePass = [&](FViewInfo& View, int32 ViewIndex)
{
Nanite::FRasterResults& RasterResults = NaniteRasterResults[ViewIndex];
#if WITH_DEBUG_VIEW_MODES
if (NaniteDebugViewMode != Nanite::EDebugViewMode::None)
{
Nanite::RenderDebugViewMode(
GraphBuilder,
NaniteDebugViewMode,
*Scene,
View,
*ActiveViewFamily,
RasterResults,
NaniteColorTarget,
NaniteDepthTarget,
SceneTextures.QuadOverdraw
);
}
else
#endif
{
Nanite::DrawBasePass(
GraphBuilder,
View.NaniteMaterialPassCommands,
*this,
SceneTextures,
DBufferTextures,
*Scene,
View,
RasterResults
);
}
};
if (bRenderLightmapDensity || ActiveViewFamily->UseDebugViewPS())
{
if (bRenderLightmapDensity)
{
// Override the base pass with the lightmap density pass if the viewmode is enabled.
RenderLightMapDensities(GraphBuilder, Views, BasePassRenderTargets);
}
else if (ActiveViewFamily->UseDebugViewPS())
{
// Override the base pass with one of the debug view shader mode (see EDebugViewShaderMode) if required.
RenderDebugViewMode(GraphBuilder, Views, SceneTextures.QuadOverdraw, BasePassRenderTargets);
}
// Debug view support for Nanite
if (bNaniteEnabled)
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
RenderNaniteDepthPass(View, ViewIndex);
RenderNaniteBasePass(View, ViewIndex);
}
}
}
else
{
SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime);
RDG_EVENT_SCOPE(GraphBuilder, "BasePass");
RDG_GPU_STAT_SCOPE(GraphBuilder, Basepass);
const bool bNeedsPrePass = ShouldRenderPrePass();
if (bParallelBasePass)
{
RDG_WAIT_FOR_TASKS_CONDITIONAL(GraphBuilder, IsBasePassWaitForTasksEnabled());
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
View.BeginRenderView();
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
FMeshPassProcessorRenderState DrawRenderState;
SetupBasePassState(BasePassDepthStencilAccess, ActiveViewFamily->EngineShowFlags.ShaderComplexity, DrawRenderState);
FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, nullptr, bLumenGIEnabled);
PassParameters->RenderTargets = BasePassRenderTargets;
const bool bShouldRenderView = View.ShouldRenderView();
if (bShouldRenderView)
{
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
GraphBuilder.AddPass(
RDG_EVENT_NAME("BasePassParallel"),
PassParameters,
ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
[this, &View, PassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
{
FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), *this, View, FParallelCommandListBindings(PassParameters));
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &PassParameters->InstanceCullingDrawParams);
});
}
if (bNaniteEnabled)
{
RenderNaniteDepthPass(View, ViewIndex);
RenderNaniteBasePass(View, ViewIndex);
}
RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager);
if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere)
{
FOpaqueBasePassParameters* SkyPassPassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
SkyPassPassParameters->BasePass = PassParameters->BasePass;
SkyPassPassParameters->RenderTargets = BasePassRenderTargets;
SkyPassPassParameters->View = View.GetShaderParameters();
SkyPassPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassPassParameters->InstanceCullingDrawParams);
GraphBuilder.AddPass(
RDG_EVENT_NAME("SkyPassParallel"),
SkyPassPassParameters,
ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
[this, &View, SkyPassPassParameters](const FRDGPass* InPass, FRHICommandListImmediate& RHICmdList)
{
FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), *this, View, FParallelCommandListBindings(SkyPassPassParameters));
View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(&ParallelCommandListSet, RHICmdList, &SkyPassPassParameters->InstanceCullingDrawParams);
});
}
}
}
else
{
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
RDG_GPU_MASK_SCOPE(GraphBuilder, View.GPUMask);
RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
View.BeginRenderView();
const bool bLumenGIEnabled = GetViewPipelineState(View).DiffuseIndirectMethod == EDiffuseIndirectMethod::Lumen;
FMeshPassProcessorRenderState DrawRenderState;
SetupBasePassState(BasePassDepthStencilAccess, ActiveViewFamily->EngineShowFlags.ShaderComplexity, DrawRenderState);
FOpaqueBasePassParameters* PassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
PassParameters->View = View.GetShaderParameters();
PassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
PassParameters->BasePass = CreateOpaqueBasePassUniformBuffer(GraphBuilder, View, ViewIndex, ForwardBasePassTextures, DBufferTextures, nullptr, bLumenGIEnabled);
PassParameters->RenderTargets = BasePassRenderTargets;
const bool bShouldRenderView = View.ShouldRenderView();
if (bShouldRenderView)
{
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams);
GraphBuilder.AddPass(
RDG_EVENT_NAME("BasePass"),
PassParameters,
ERDGPassFlags::Raster,
[this, &View, PassParameters](FRHICommandList& RHICmdList)
{
SetStereoViewport(RHICmdList, View, 1.0f);
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(nullptr, RHICmdList, &PassParameters->InstanceCullingDrawParams);
}
);
}
if (bNaniteEnabled)
{
RenderNaniteDepthPass(View, ViewIndex);
RenderNaniteBasePass(View, ViewIndex);
}
RenderEditorPrimitives(GraphBuilder, PassParameters, View, DrawRenderState, InstanceCullingManager);
if (bShouldRenderView && View.Family->EngineShowFlags.Atmosphere)
{
FOpaqueBasePassParameters* SkyPassParameters = GraphBuilder.AllocParameters<FOpaqueBasePassParameters>();
SkyPassParameters->BasePass = PassParameters->BasePass;
SkyPassParameters->RenderTargets = BasePassRenderTargets;
SkyPassParameters->View = View.GetShaderParameters();
SkyPassParameters->ReflectionCapture = View.ReflectionCaptureUniformBuffer;
View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].BuildRenderingCommands(GraphBuilder, Scene->GPUScene, SkyPassParameters->InstanceCullingDrawParams);
GraphBuilder.AddPass(
RDG_EVENT_NAME("SkyPass"),
SkyPassParameters,
ERDGPassFlags::Raster,
[this, &View, SkyPassParameters](FRHICommandList& RHICmdList)
{
SetStereoViewport(RHICmdList, View, 1.0f);
View.ParallelMeshDrawCommandPasses[EMeshPass::SkyPass].DispatchDraw(nullptr, RHICmdList, &SkyPassParameters->InstanceCullingDrawParams);
}
);
}
}
}
}
}
template<typename LightMapPolicyType>
bool FBasePassMeshProcessor::Process(
const FMeshBatch& RESTRICT MeshBatch,
uint64 BatchElementMask,
int32 StaticMeshId,
const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,
const FMaterialRenderProxy& RESTRICT MaterialRenderProxy,
const FMaterial& RESTRICT MaterialResource,
EBlendMode BlendMode,
FMaterialShadingModelField ShadingModels,
const LightMapPolicyType& RESTRICT LightMapPolicy,
const typename LightMapPolicyType::ElementDataType& RESTRICT LightMapElementData,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode)
{
const FVertexFactory* VertexFactory = MeshBatch.VertexFactory;
const bool bRenderSkylight = Scene && Scene->ShouldRenderSkylightInBasePass(BlendMode) && ShadingModels.IsLit();
TMeshProcessorShaders<
TBasePassVertexShaderPolicyParamType<LightMapPolicyType>,
TBasePassPixelShaderPolicyParamType<LightMapPolicyType>> BasePassShaders;
if (!GetBasePassShaders<LightMapPolicyType>(
MaterialResource,
VertexFactory->GetType(),
LightMapPolicy,
FeatureLevel,
bRenderSkylight,
Get128BitRequirement(),
&BasePassShaders.VertexShader,
&BasePassShaders.PixelShader
))
{
return false;
}
FMeshPassProcessorRenderState DrawRenderState(PassDrawRenderState);
SetDepthStencilStateForBasePass(
ViewIfDynamicMeshCommand,
DrawRenderState,
FeatureLevel,
MeshBatch,
StaticMeshId,
PrimitiveSceneProxy,
MaterialResource,
bEnableReceiveDecalOutput);
if (bTranslucentBasePass)
{
SetTranslucentRenderState(DrawRenderState, MaterialResource, GShaderPlatformForFeatureLevel[FeatureLevel], TranslucencyPassType);
}
TBasePassShaderElementData<LightMapPolicyType> ShaderElementData(LightMapElementData);
ShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, true);
FMeshDrawCommandSortKey SortKey = FMeshDrawCommandSortKey::Default;
if (bTranslucentBasePass)
{
SortKey = CalculateTranslucentMeshStaticSortKey(PrimitiveSceneProxy, MeshBatch.MeshIdInPrimitive);
}
else
{
SortKey = CalculateBasePassMeshStaticSortKey(EarlyZPassMode, BlendMode, BasePassShaders.VertexShader.GetShader(), BasePassShaders.PixelShader.GetShader());
}
BuildMeshDrawCommands(
MeshBatch,
BatchElementMask,
PrimitiveSceneProxy,
MaterialRenderProxy,
MaterialResource,
DrawRenderState,
BasePassShaders,
MeshFillMode,
MeshCullMode,
SortKey,
EMeshPassFeatures::Default,
ShaderElementData);
return true;
}
bool FBasePassMeshProcessor::AddMeshBatchForSimpleForwardShading(
const FMeshBatch& RESTRICT MeshBatch,
uint64 BatchElementMask,
int32 StaticMeshId,
const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,
const FMaterialRenderProxy& MaterialRenderProxy,
const FMaterial& Material,
const FLightMapInteraction& LightMapInteraction,
bool bIsLitMaterial,
bool bAllowStaticLighting,
bool bUseVolumetricLightmap,
bool bAllowIndirectLightingCache,
ERasterizerFillMode MeshFillMode,
ERasterizerCullMode MeshCullMode)
{
const EBlendMode BlendMode = Material.GetBlendMode();
const FMaterialShadingModelField ShadingModels = Material.GetShadingModels();
bool bResult = false;
if (bAllowStaticLighting && LightMapInteraction.GetType() == LMIT_Texture)
{
const FShadowMapInteraction ShadowMapInteraction = (MeshBatch.LCI && bIsLitMaterial)
? MeshBatch.LCI->GetShadowMapInteraction(FeatureLevel)
: FShadowMapInteraction();
if (ShadowMapInteraction.GetType() == SMIT_Texture)
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
}
else if (bIsLitMaterial
&& bAllowStaticLighting
&& bUseVolumetricLightmap
&& PrimitiveSceneProxy)
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else if (bIsLitMaterial
&& IsIndirectLightingCacheAllowed(FeatureLevel)
&& bAllowIndirectLightingCache
&& PrimitiveSceneProxy)
{
const FIndirectLightingCacheAllocation* IndirectLightingCacheAllocation = PrimitiveSceneProxy->GetPrimitiveSceneInfo()->IndirectLightingCacheAllocation;
const bool bPrimitiveIsMovable = PrimitiveSceneProxy->IsMovable();
const bool bPrimitiveUsesILC = PrimitiveSceneProxy->GetIndirectLightingCacheQuality() != ILCQ_Off;
// Use the indirect lighting cache shaders if the object has a cache allocation
// This happens for objects with unbuilt lighting
if (bPrimitiveUsesILC &&
((IndirectLightingCacheAllocation && IndirectLightingCacheAllocation->IsValid())
// Use the indirect lighting cache shaders if the object is movable, it may not have a cache allocation yet because that is done in InitViews
// And movable objects are sometimes rendered in the static draw lists
|| bPrimitiveIsMovable))
{
// Use a lightmap policy that supports reading indirect lighting from a single SH sample
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_NO_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
}
else if (bIsLitMaterial)
{
// Always choosing shaders to support dynamic directional even if one is not present
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_SIMPLE_NO_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
return bResult;
}
void FBasePassMeshProcessor::AddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId)
{
if (MeshBatch.bUseForMaterial)
{
// Determine the mesh's material and blend mode.
const FMaterialRenderProxy* MaterialRenderProxy = MeshBatch.MaterialRenderProxy;
while (MaterialRenderProxy)
{
const FMaterial* Material = MaterialRenderProxy->GetMaterialNoFallback(FeatureLevel);
if (Material && Material->GetRenderingThreadShaderMap())
{
if (TryAddMeshBatch(MeshBatch, BatchElementMask, PrimitiveSceneProxy, StaticMeshId, *MaterialRenderProxy, *Material))
{
break;
}
}
MaterialRenderProxy = MaterialRenderProxy->GetFallback(FeatureLevel);
}
}
}
bool AllowStaticLighting()
{
static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
return (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnRenderThread() != 0);
}
bool FBasePassMeshProcessor::TryAddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId, const FMaterialRenderProxy& MaterialRenderProxy, const FMaterial& Material)
{
// Determine the mesh's material and blend mode.
const EBlendMode BlendMode = Material.GetBlendMode();
const EStrataBlendMode StrataBlendMode = Material.GetStrataBlendMode();
const FMaterialShadingModelField ShadingModels = Material.GetShadingModels();
const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode);
const FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(MeshBatch);
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(MeshBatch, Material, OverrideSettings);
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(MeshBatch, Material, OverrideSettings);
bool bShouldDraw = false;
if (bTranslucentBasePass)
{
if (bIsTranslucent && !Material.IsDeferredDecal())
{
switch (TranslucencyPassType)
{
case ETranslucencyPass::TPT_StandardTranslucency:
bShouldDraw = !Material.IsTranslucencyAfterDOFEnabled() && !Material.IsTranslucencyAfterMotionBlurEnabled();
break;
case ETranslucencyPass::TPT_TranslucencyAfterDOF:
bShouldDraw = Material.IsTranslucencyAfterDOFEnabled() && StrataBlendMode != SBM_ColoredTransmittanceOnly;
break;
// only dual blended or modulate surfaces need background modulation
case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate:
bShouldDraw = Material.IsTranslucencyAfterDOFEnabled() && (Material.IsDualBlendingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel)) ||
BlendMode == BLEND_Modulate || StrataBlendMode == SBM_ColoredTransmittanceOnly);
break;
case ETranslucencyPass::TPT_TranslucencyAfterMotionBlur:
bShouldDraw = Material.IsTranslucencyAfterMotionBlurEnabled();
break;
case ETranslucencyPass::TPT_AllTranslucency:
bShouldDraw = true;
break;
}
}
}
else
{
bShouldDraw = !bIsTranslucent;
}
// Only draw opaque materials.
bool bResult = true;
if (bShouldDraw
&& (!PrimitiveSceneProxy || PrimitiveSceneProxy->ShouldRenderInMainPass())
&& ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain())
&& ShouldIncludeMaterialInDefaultOpaquePass(Material))
{
// Check for a cached light-map.
const bool bIsLitMaterial = ShadingModels.IsLit();
const bool bAllowStaticLighting = AllowStaticLighting();
const FLightMapInteraction LightMapInteraction = (bAllowStaticLighting && MeshBatch.LCI && bIsLitMaterial)
? MeshBatch.LCI->GetLightMapInteraction(FeatureLevel)
: FLightMapInteraction();
// force LQ lightmaps based on system settings
const bool bPlatformAllowsHighQualityLightMaps = AllowHighQualityLightmaps(FeatureLevel);
const bool bAllowHighQualityLightMaps = bPlatformAllowsHighQualityLightMaps && LightMapInteraction.AllowsHighQualityLightmaps();
const bool bAllowIndirectLightingCache = Scene && Scene->PrecomputedLightVolumes.Num() > 0;
const bool bUseVolumetricLightmap = Scene && Scene->VolumetricLightmapSceneData.HasData();
FMeshMaterialShaderElementData MeshMaterialShaderElementData;
MeshMaterialShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, true);
if (IsSimpleForwardShadingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel)))
{
// Only compiling simple lighting shaders for HQ lightmaps to save on permutations
check(bPlatformAllowsHighQualityLightMaps);
bResult = AddMeshBatchForSimpleForwardShading(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
LightMapInteraction,
bIsLitMaterial,
bAllowStaticLighting,
bUseVolumetricLightmap,
bAllowIndirectLightingCache,
MeshFillMode,
MeshCullMode);
}
// Render volumetric translucent self-shadowing only for >= SM4 and fallback to non-shadowed for lesser shader models
else if (bIsLitMaterial
&& bIsTranslucent
&& PrimitiveSceneProxy
&& PrimitiveSceneProxy->CastsVolumetricTranslucentShadow())
{
checkSlow(ViewIfDynamicMeshCommand && ViewIfDynamicMeshCommand->bIsViewInfo);
const FViewInfo* ViewInfo = (FViewInfo*)ViewIfDynamicMeshCommand;
const int32 PrimitiveIndex = PrimitiveSceneProxy->GetPrimitiveSceneInfo()->GetIndex();
const FUniformBufferRHIRef* UniformBufferPtr = ViewInfo->TranslucentSelfShadowUniformBufferMap.Find(PrimitiveIndex);
FSelfShadowLightCacheElementData ElementData;
ElementData.LCI = MeshBatch.LCI;
ElementData.SelfShadowTranslucencyUniformBuffer = UniformBufferPtr ? (*UniformBufferPtr).GetReference() : GEmptyTranslucentSelfShadowUniformBuffer.GetUniformBufferRHI();
if (bIsLitMaterial
&& bAllowStaticLighting
&& bUseVolumetricLightmap
&& PrimitiveSceneProxy)
{
bResult = Process< FSelfShadowedVolumetricLightmapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FSelfShadowedVolumetricLightmapPolicy(),
ElementData,
MeshFillMode,
MeshCullMode);
}
else if (IsIndirectLightingCacheAllowed(FeatureLevel)
&& bAllowIndirectLightingCache
&& PrimitiveSceneProxy)
{
// Apply cached point indirect lighting as well as self shadowing if needed
bResult = Process< FSelfShadowedCachedPointIndirectLightingPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FSelfShadowedCachedPointIndirectLightingPolicy(),
ElementData,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FSelfShadowedTranslucencyPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FSelfShadowedTranslucencyPolicy(),
ElementData.SelfShadowTranslucencyUniformBuffer,
MeshFillMode,
MeshCullMode);
}
}
else
{
static const auto CVarSupportLowQualityLightmap = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportLowQualityLightmaps"));
const bool bAllowLowQualityLightMaps = (!CVarSupportLowQualityLightmap) || (CVarSupportLowQualityLightmap->GetValueOnAnyThread() != 0);
switch (LightMapInteraction.GetType())
{
case LMIT_Texture:
if (bAllowHighQualityLightMaps)
{
const FShadowMapInteraction ShadowMapInteraction = (bAllowStaticLighting && MeshBatch.LCI && bIsLitMaterial)
? MeshBatch.LCI->GetShadowMapInteraction(FeatureLevel)
: FShadowMapInteraction();
if (ShadowMapInteraction.GetType() == SMIT_Texture)
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_HQ_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
}
else if (bAllowLowQualityLightMaps)
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_LQ_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
break;
default:
if (bIsLitMaterial
&& bAllowStaticLighting
&& bUseVolumetricLightmap
&& PrimitiveSceneProxy
&& (PrimitiveSceneProxy->IsMovable()
|| PrimitiveSceneProxy->NeedsUnbuiltPreviewLighting()
|| PrimitiveSceneProxy->GetLightmapType() == ELightmapType::ForceVolumetric))
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else if (bIsLitMaterial
&& IsIndirectLightingCacheAllowed(FeatureLevel)
&& Scene
&& Scene->PrecomputedLightVolumes.Num() > 0
&& PrimitiveSceneProxy)
{
const FIndirectLightingCacheAllocation* IndirectLightingCacheAllocation = PrimitiveSceneProxy->GetPrimitiveSceneInfo()->IndirectLightingCacheAllocation;
const bool bPrimitiveIsMovable = PrimitiveSceneProxy->IsMovable();
const bool bPrimitiveUsesILC = PrimitiveSceneProxy->GetIndirectLightingCacheQuality() != ILCQ_Off;
// Use the indirect lighting cache shaders if the object has a cache allocation
// This happens for objects with unbuilt lighting
if (bPrimitiveUsesILC &&
((IndirectLightingCacheAllocation && IndirectLightingCacheAllocation->IsValid())
// Use the indirect lighting cache shaders if the object is movable, it may not have a cache allocation yet because that is done in InitViews
// And movable objects are sometimes rendered in the static draw lists
|| bPrimitiveIsMovable))
{
if (CanIndirectLightingCacheUseVolumeTexture(FeatureLevel)
// Translucency forces point sample for pixel performance
&& !bIsTranslucent
&& ((IndirectLightingCacheAllocation && !IndirectLightingCacheAllocation->bPointSample)
|| (bPrimitiveIsMovable && PrimitiveSceneProxy->GetIndirectLightingCacheQuality() == ILCQ_Volume)))
{
// Use a lightmap policy that supports reading indirect lighting from a volume texture for dynamic objects
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_CACHED_VOLUME_INDIRECT_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
else
{
// Use a lightmap policy that supports reading indirect lighting from a single SH sample
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_CACHED_POINT_INDIRECT_LIGHTING),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
}
else
{
bResult = Process< FUniformLightMapPolicy >(
MeshBatch,
BatchElementMask,
StaticMeshId,
PrimitiveSceneProxy,
MaterialRenderProxy,
Material,
BlendMode,
ShadingModels,
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
MeshBatch.LCI,
MeshFillMode,
MeshCullMode);
}
break;
};
}
}
return bResult;
}
FBasePassMeshProcessor::FBasePassMeshProcessor(
const FScene* Scene,
ERHIFeatureLevel::Type InFeatureLevel,
const FSceneView* InViewIfDynamicMeshCommand,
const FMeshPassProcessorRenderState& InDrawRenderState,
FMeshPassDrawListContext* InDrawListContext,
EFlags Flags,
ETranslucencyPass::Type InTranslucencyPassType)
: FMeshPassProcessor(Scene, InFeatureLevel, InViewIfDynamicMeshCommand, InDrawListContext)
, PassDrawRenderState(InDrawRenderState)
, TranslucencyPassType(InTranslucencyPassType)
, bTranslucentBasePass(InTranslucencyPassType != ETranslucencyPass::TPT_MAX)
, bEnableReceiveDecalOutput((Flags & EFlags::CanUseDepthStencil) == EFlags::CanUseDepthStencil)
, EarlyZPassMode(Scene ? Scene->EarlyZPassMode : DDM_None)
, bRequiresExplicit128bitRT((Flags & EFlags::bRequires128bitRT) == EFlags::bRequires128bitRT)
{
}
FMeshPassProcessor* CreateBasePassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
SetupBasePassState(Scene->DefaultBasePassDepthStencilAccess, false, PassDrawRenderState);
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags);
}
FMeshPassProcessor* CreateTranslucencyStandardPassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_StandardTranslucency);
}
FMeshPassProcessor* CreateTranslucencyAfterDOFProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_TranslucencyAfterDOF);
}
FMeshPassProcessor* CreateTranslucencyAfterDOFModulateProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_TranslucencyAfterDOFModulate);
}
FMeshPassProcessor* CreateTranslucencyAfterMotionBlurProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
PassDrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthNop_StencilNop);
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::None;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_TranslucencyAfterMotionBlur);
}
FMeshPassProcessor* CreateTranslucencyAllPassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
{
FMeshPassProcessorRenderState PassDrawRenderState;
PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
const FBasePassMeshProcessor::EFlags Flags = FBasePassMeshProcessor::EFlags::CanUseDepthStencil;
return new(FMemStack::Get()) FBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_AllTranslucency);
}
FRegisterPassProcessorCreateFunction RegisterBasePass(&CreateBasePassProcessor, EShadingPath::Deferred, EMeshPass::BasePass, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
FRegisterPassProcessorCreateFunction RegisterTranslucencyStandardPass(&CreateTranslucencyStandardPassProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyStandard, EMeshPassFlags::MainView);
FRegisterPassProcessorCreateFunction RegisterTranslucencyAfterDOFPass(&CreateTranslucencyAfterDOFProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterDOF, EMeshPassFlags::MainView);
FRegisterPassProcessorCreateFunction RegisterTranslucencyAfterDOFModulatePass(&CreateTranslucencyAfterDOFModulateProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterDOFModulate, EMeshPassFlags::MainView);
FRegisterPassProcessorCreateFunction RegisterTranslucencyAfterMotionBlurPass(&CreateTranslucencyAfterMotionBlurProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterMotionBlur, EMeshPassFlags::MainView);
FRegisterPassProcessorCreateFunction RegisterTranslucencyAllPass(&CreateTranslucencyAllPassProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAll, EMeshPassFlags::MainView);