You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
[FYI] Chris.Bunner, Krzysztof.Narkowicz, Marcus.Wassmer, Yuriy.Odonnell, Matt.Kuhlenschmidt #rb Krzysztof.Narkowicz #ROBOMERGE-OWNER: ryan.vance #ROBOMERGE-AUTHOR: kevin.ortegren #ROBOMERGE-SOURCE: CL 6308573 via CL 6309266 via CL 6315508 #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 6348696 by joe conley in Dev-VR branch]
1566 lines
64 KiB
C++
1566 lines
64 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
BasePassRendering.cpp: Base pass rendering implementation.
|
|
=============================================================================*/
|
|
|
|
#include "BasePassRendering.h"
|
|
#include "DeferredShadingRenderer.h"
|
|
#include "DynamicPrimitiveDrawing.h"
|
|
#include "ScenePrivate.h"
|
|
#include "MeshPassProcessor.inl"
|
|
#include "EditorPrimitivesRendering.h"
|
|
#include "TranslucentRendering.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> CVarRHICmdBasePassDeferredContexts(
|
|
TEXT("r.RHICmdBasePassDeferredContexts"),
|
|
1,
|
|
TEXT("True to use deferred contexts to parallelize base pass command list execution."));
|
|
|
|
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> CVarSupportAtmosphericFog(
|
|
TEXT("r.SupportAtmosphericFog"),
|
|
1,
|
|
TEXT("Enables AtmosphericFog 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);
|
|
|
|
/** Whether to replace lightmap textures with solid colors to visualize the mip-levels. */
|
|
bool GVisualizeMipLevels = false;
|
|
|
|
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FSharedBasePassUniformParameters, "BasePass");
|
|
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FOpaqueBasePassUniformParameters, "OpaqueBasePass");
|
|
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FTranslucentBasePassUniformParameters, "TranslucentBasePass");
|
|
|
|
// Typedef is necessary because the C preprocessor thinks the comma in the template parameter list is a comma in the macro parameter list.
|
|
// BasePass Vertex Shader needs to include hull and domain shaders for tessellation, these only compile for D3D11
|
|
#define IMPLEMENT_BASEPASS_VERTEXSHADER_TYPE(LightMapPolicyType,LightMapPolicyName) \
|
|
typedef TBasePassVS< LightMapPolicyType, false > TBasePassVS##LightMapPolicyName ; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassVS##LightMapPolicyName,TEXT("/Engine/Private/BasePassVertexShader.usf"),TEXT("Main"),SF_Vertex); \
|
|
typedef TBasePassHS< LightMapPolicyType, false > TBasePassHS##LightMapPolicyName; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassHS##LightMapPolicyName,TEXT("/Engine/Private/BasePassTessellationShaders.usf"),TEXT("MainHull"),SF_Hull); \
|
|
typedef TBasePassDS< LightMapPolicyType > TBasePassDS##LightMapPolicyName; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassDS##LightMapPolicyName,TEXT("/Engine/Private/BasePassTessellationShaders.usf"),TEXT("MainDomain"),SF_Domain);
|
|
|
|
#define IMPLEMENT_BASEPASS_VERTEXSHADER_ONLY_TYPE(LightMapPolicyType,LightMapPolicyName,AtmosphericFogShaderName) \
|
|
typedef TBasePassVS<LightMapPolicyType,true> TBasePassVS##LightMapPolicyName##AtmosphericFogShaderName; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassVS##LightMapPolicyName##AtmosphericFogShaderName,TEXT("/Engine/Private/BasePassVertexShader.usf"),TEXT("Main"),SF_Vertex) \
|
|
typedef TBasePassHS< LightMapPolicyType, true> TBasePassHS##LightMapPolicyName##AtmosphericFogShaderName; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TBasePassHS##LightMapPolicyName##AtmosphericFogShaderName,TEXT("/Engine/Private/BasePassTessellationShaders.usf"),TEXT("MainHull"),SF_Hull);
|
|
|
|
#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_VERTEXSHADER_ONLY_TYPE(LightMapPolicyType,LightMapPolicyName,AtmosphericFog) \
|
|
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 );
|
|
|
|
DECLARE_GPU_STAT(Basepass);
|
|
|
|
void SetBasePassDitheredLODTransitionState(const FSceneView* SceneView, const FMeshBatch& RESTRICT Mesh, int32 StaticMeshId, FMeshPassProcessorRenderState& DrawRenderState)
|
|
{
|
|
if (SceneView && StaticMeshId >= 0 && Mesh.bDitheredLODTransition)
|
|
{
|
|
checkSlow(SceneView->bIsViewInfo);
|
|
const FViewInfo* ViewInfo = (FViewInfo*)SceneView;
|
|
|
|
if (ViewInfo->bAllowStencilDither)
|
|
{
|
|
if (ViewInfo->StaticMeshFadeOutDitheredLODMap[StaticMeshId])
|
|
{
|
|
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) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
|
|
>::GetRHI());
|
|
}
|
|
else if (ViewInfo->StaticMeshFadeInDitheredLODMap[StaticMeshId])
|
|
{
|
|
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) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
|
|
>::GetRHI());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetTranslucentRenderState(FMeshPassProcessorRenderState& DrawRenderState, const FMaterial& Material)
|
|
{
|
|
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;
|
|
};
|
|
|
|
const bool bDisableDepthTest = Material.ShouldDisableDepthTest();
|
|
const bool bEnableResponsiveAA = Material.ShouldEnableResponsiveAA();
|
|
|
|
if (bEnableResponsiveAA)
|
|
{
|
|
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;
|
|
|
|
if (PrimitiveSceneProxy)
|
|
{
|
|
const FPrimitiveSceneInfo* PrimitiveSceneInfo = PrimitiveSceneProxy->GetPrimitiveSceneInfo();
|
|
SortKeyPriority = (uint16)((int32)PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority() - (int32)SHRT_MIN);
|
|
}
|
|
|
|
FMeshDrawCommandSortKey SortKey;
|
|
SortKey.Translucent.MeshIdInPrimitive = MeshIdInPrimitive;
|
|
SortKey.Translucent.Priority = SortKeyPriority;
|
|
SortKey.Translucent.Distance = 0; // 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 = PointerHash(VertexShader) & 0xFFFF;
|
|
SortKey.BasePass.PixelShaderHash = PointerHash(PixelShader);
|
|
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(FMeshPassProcessorRenderState& DrawRenderState, ERHIFeatureLevel::Type FeatureLevel, const FMeshBatch& Mesh, const FPrimitiveSceneProxy* PrimitiveSceneProxy, bool bEnableReceiveDecalOutput, bool bUseDebugViewPS, FDepthStencilStateRHIParamRef LodFadeOverrideDepthStencilState)
|
|
{
|
|
static IConsoleVariable* EarlyZPassOnlyMaterialMaskingCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.EarlyZPassOnlyMaterialMasking"));
|
|
bool bMaskInEarlyPass = (EarlyZPassOnlyMaterialMaskingCVar && Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->IsMasked() && EarlyZPassOnlyMaterialMaskingCVar->GetInt());
|
|
|
|
if (bEnableReceiveDecalOutput && !bUseDebugViewPS)
|
|
{
|
|
// 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)
|
|
| STENCIL_LIGHTING_CHANNELS_MASK(PrimitiveSceneProxy ? PrimitiveSceneProxy->GetLightingChannelStencilValue() : 0x00);
|
|
|
|
if (LodFadeOverrideDepthStencilState != nullptr)
|
|
{
|
|
//@TODO: Handle bMaskInEarlyPass in this case (used when a LODTransition is specified)
|
|
DrawRenderState.SetDepthStencilState(LodFadeOverrideDepthStencilState);
|
|
DrawRenderState.SetStencilRef(StencilValue);
|
|
}
|
|
else if (bMaskInEarlyPass)
|
|
{
|
|
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) | 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) | 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) | STENCIL_LIGHTING_CHANNELS_MASK(0x7)
|
|
>::GetRHI());
|
|
DrawRenderState.SetStencilRef(StencilValue);
|
|
}
|
|
}
|
|
else if (bMaskInEarlyPass)
|
|
{
|
|
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<false, CF_Equal>::GetRHI());
|
|
}
|
|
}
|
|
|
|
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>
|
|
void GetUniformBasePassShaders(
|
|
const FMaterial& Material,
|
|
FVertexFactoryType* VertexFactoryType,
|
|
ERHIFeatureLevel::Type FeatureLevel,
|
|
bool bEnableAtmosphericFog,
|
|
bool bEnableSkyLight,
|
|
FBaseHS*& HullShader,
|
|
FBaseDS*& DomainShader,
|
|
TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>*& VertexShader,
|
|
TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>*& PixelShader
|
|
)
|
|
{
|
|
const EMaterialTessellationMode MaterialTessellationMode = Material.GetTessellationMode();
|
|
|
|
const bool bNeedsHSDS = RHISupportsTessellation(GShaderPlatformForFeatureLevel[FeatureLevel])
|
|
&& VertexFactoryType->SupportsTessellationShaders()
|
|
&& MaterialTessellationMode != MTM_NoTessellation;
|
|
|
|
if (bNeedsHSDS)
|
|
{
|
|
DomainShader = Material.GetShader<TBasePassDS<TUniformLightMapPolicy<Policy> > >(VertexFactoryType);
|
|
|
|
// Metal requires matching permutations, but no other platform should worry about this complication.
|
|
if (bEnableAtmosphericFog && DomainShader && IsMetalPlatform(EShaderPlatform(DomainShader->GetTarget().Platform)))
|
|
{
|
|
HullShader = Material.GetShader<TBasePassHS<TUniformLightMapPolicy<Policy>, true > >(VertexFactoryType);
|
|
}
|
|
else
|
|
{
|
|
HullShader = Material.GetShader<TBasePassHS<TUniformLightMapPolicy<Policy>, false > >(VertexFactoryType);
|
|
}
|
|
}
|
|
|
|
if (bEnableAtmosphericFog)
|
|
{
|
|
VertexShader = (TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TBasePassVS<TUniformLightMapPolicy<Policy>, true> >(VertexFactoryType);
|
|
}
|
|
else
|
|
{
|
|
VertexShader = (TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TBasePassVS<TUniformLightMapPolicy<Policy>, false> >(VertexFactoryType);
|
|
}
|
|
if (bEnableSkyLight)
|
|
{
|
|
PixelShader = (TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TBasePassPS<TUniformLightMapPolicy<Policy>, true> >(VertexFactoryType);
|
|
}
|
|
else
|
|
{
|
|
PixelShader = (TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TBasePassPS<TUniformLightMapPolicy<Policy>, false> >(VertexFactoryType);
|
|
}
|
|
}
|
|
|
|
template <>
|
|
void GetBasePassShaders<FUniformLightMapPolicy>(
|
|
const FMaterial& Material,
|
|
FVertexFactoryType* VertexFactoryType,
|
|
FUniformLightMapPolicy LightMapPolicy,
|
|
ERHIFeatureLevel::Type FeatureLevel,
|
|
bool bEnableAtmosphericFog,
|
|
bool bEnableSkyLight,
|
|
FBaseHS*& HullShader,
|
|
FBaseDS*& DomainShader,
|
|
TBasePassVertexShaderPolicyParamType<FUniformLightMapPolicy>*& VertexShader,
|
|
TBasePassPixelShaderPolicyParamType<FUniformLightMapPolicy>*& PixelShader
|
|
)
|
|
{
|
|
switch (LightMapPolicy.GetIndirectPolicy())
|
|
{
|
|
case LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_CACHED_VOLUME_INDIRECT_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_CACHED_VOLUME_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_CACHED_POINT_INDIRECT_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_CACHED_POINT_INDIRECT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_NO_LIGHTMAP:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_NO_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_LIGHTMAP_ONLY_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING:
|
|
GetUniformBasePassShaders<LMP_SIMPLE_STATIONARY_VOLUMETRICLIGHTMAP_SHADOW_LIGHTING>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_LQ_LIGHTMAP:
|
|
GetUniformBasePassShaders<LMP_LQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_HQ_LIGHTMAP:
|
|
GetUniformBasePassShaders<LMP_HQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
case LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP:
|
|
GetUniformBasePassShaders<LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
default:
|
|
check(false);
|
|
case LMP_NO_LIGHTMAP:
|
|
GetUniformBasePassShaders<LMP_NO_LIGHTMAP>(Material, VertexFactoryType, FeatureLevel, bEnableAtmosphericFog, bEnableSkyLight, HullShader, DomainShader, VertexShader, PixelShader);
|
|
break;
|
|
}
|
|
}
|
|
|
|
FTextureRHIRef& GetEyeAdaptation(const FViewInfo& View)
|
|
{
|
|
if (View.HasValidEyeAdaptation())
|
|
{
|
|
IPooledRenderTarget* EyeAdaptationRT = View.GetEyeAdaptation();
|
|
if (EyeAdaptationRT)
|
|
{
|
|
return EyeAdaptationRT->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
}
|
|
|
|
return GWhiteTexture->TextureRHI;
|
|
}
|
|
|
|
void SetupSharedBasePassParameters(
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FViewInfo& View,
|
|
FSceneRenderTargets& SceneRenderTargets,
|
|
FSharedBasePassUniformParameters& SharedParameters)
|
|
{
|
|
SharedParameters.Forward = View.ForwardLightingResources->ForwardLightData;
|
|
|
|
if (View.bIsInstancedStereoEnabled && View.StereoPass == EStereoscopicPass::eSSP_LEFT_EYE)
|
|
{
|
|
const FSceneView& RightEye = *View.Family->Views[1];
|
|
SharedParameters.ForwardISR = RightEye.ForwardLightingResources->ForwardLightData;
|
|
}
|
|
else
|
|
{
|
|
SharedParameters.ForwardISR = View.ForwardLightingResources->ForwardLightData;
|
|
}
|
|
|
|
const FScene* Scene = View.Family->Scene ? View.Family->Scene->GetRenderScene() : nullptr;
|
|
const FPlanarReflectionSceneProxy* ReflectionSceneProxy = Scene ? Scene->GetForwardPassGlobalPlanarReflection() : nullptr;
|
|
|
|
SetupReflectionUniformParameters(View, SharedParameters.Reflection);
|
|
SetupFogUniformParameters(View, SharedParameters.Fog);
|
|
SetupPlanarReflectionUniformParameters(View, ReflectionSceneProxy, SharedParameters.PlanarReflection);
|
|
|
|
const IPooledRenderTarget* PooledRT = GetSubsufaceProfileTexture_RT(RHICmdList);
|
|
|
|
if (!PooledRT)
|
|
{
|
|
// no subsurface profile was used yet
|
|
PooledRT = GSystemTextures.BlackDummy;
|
|
}
|
|
|
|
const FSceneRenderTargetItem& Item = PooledRT->GetRenderTargetItem();
|
|
SharedParameters.SSProfilesTexture = Item.ShaderResourceTexture;
|
|
}
|
|
|
|
void CreateOpaqueBasePassUniformBuffer(
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FViewInfo& View,
|
|
IPooledRenderTarget* ForwardScreenSpaceShadowMask,
|
|
TUniformBufferRef<FOpaqueBasePassUniformParameters>& BasePassUniformBuffer)
|
|
{
|
|
FSceneRenderTargets& SceneRenderTargets = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
FOpaqueBasePassUniformParameters BasePassParameters;
|
|
SetupSharedBasePassParameters(RHICmdList, View, SceneRenderTargets, BasePassParameters.Shared);
|
|
|
|
// Forward shading
|
|
{
|
|
if (ForwardScreenSpaceShadowMask)
|
|
{
|
|
BasePassParameters.UseForwardScreenSpaceShadowMask = 1;
|
|
BasePassParameters.ForwardScreenSpaceShadowMaskTexture = ForwardScreenSpaceShadowMask->GetRenderTargetItem().ShaderResourceTexture;
|
|
}
|
|
else
|
|
{
|
|
BasePassParameters.UseForwardScreenSpaceShadowMask = 0;
|
|
BasePassParameters.ForwardScreenSpaceShadowMaskTexture = GSystemTextures.WhiteDummy.GetReference()->GetRenderTargetItem().ShaderResourceTexture;
|
|
}
|
|
|
|
IPooledRenderTarget* IndirectOcclusion = SceneRenderTargets.ScreenSpaceAO;
|
|
|
|
if (!SceneRenderTargets.bScreenSpaceAOIsValid)
|
|
{
|
|
IndirectOcclusion = GSystemTextures.WhiteDummy;
|
|
}
|
|
|
|
BasePassParameters.IndirectOcclusionTexture = IndirectOcclusion->GetRenderTargetItem().ShaderResourceTexture;
|
|
|
|
FTextureRHIParamRef ResolvedSceneDepthTextureValue = GSystemTextures.WhiteDummy->GetRenderTargetItem().ShaderResourceTexture;
|
|
|
|
if (SceneRenderTargets.GetMSAACount() > 1)
|
|
{
|
|
ResolvedSceneDepthTextureValue = SceneRenderTargets.SceneDepthZ->GetRenderTargetItem().ShaderResourceTexture;
|
|
}
|
|
|
|
BasePassParameters.ResolvedSceneDepthTexture = ResolvedSceneDepthTextureValue;
|
|
}
|
|
|
|
// DBuffer Decals
|
|
{
|
|
const bool bIsDBufferEnabled = IsUsingDBuffers(View.GetShaderPlatform());
|
|
IPooledRenderTarget* DBufferA = bIsDBufferEnabled && SceneRenderTargets.DBufferA ? SceneRenderTargets.DBufferA : GSystemTextures.BlackAlphaOneDummy;
|
|
IPooledRenderTarget* DBufferB = bIsDBufferEnabled && SceneRenderTargets.DBufferB ? SceneRenderTargets.DBufferB : GSystemTextures.DefaultNormal8Bit;
|
|
IPooledRenderTarget* DBufferC = bIsDBufferEnabled && SceneRenderTargets.DBufferC ? SceneRenderTargets.DBufferC : GSystemTextures.BlackAlphaOneDummy;
|
|
|
|
BasePassParameters.DBufferATexture = DBufferA->GetRenderTargetItem().ShaderResourceTexture;
|
|
BasePassParameters.DBufferBTexture = DBufferB->GetRenderTargetItem().ShaderResourceTexture;
|
|
BasePassParameters.DBufferCTexture = DBufferC->GetRenderTargetItem().ShaderResourceTexture;
|
|
BasePassParameters.DBufferATextureSampler = TStaticSamplerState<>::GetRHI();
|
|
BasePassParameters.DBufferBTextureSampler = TStaticSamplerState<>::GetRHI();
|
|
BasePassParameters.DBufferCTextureSampler = TStaticSamplerState<>::GetRHI();
|
|
|
|
if ((GSupportsRenderTargetWriteMask || IsUsingPerPixelDBufferMask(View.GetShaderPlatform())) && SceneRenderTargets.DBufferMask)
|
|
{
|
|
BasePassParameters.DBufferRenderMask = SceneRenderTargets.DBufferMask->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
else
|
|
{
|
|
BasePassParameters.DBufferRenderMask = GSystemTextures.WhiteDummy->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
}
|
|
|
|
// Misc
|
|
BasePassParameters.EyeAdaptation = GetEyeAdaptation(View);
|
|
|
|
FScene* Scene = View.Family->Scene ? View.Family->Scene->GetRenderScene() : nullptr;
|
|
|
|
if (Scene)
|
|
{
|
|
Scene->UniformBuffers.OpaqueBasePassUniformBuffer.UpdateUniformBufferImmediate(BasePassParameters);
|
|
BasePassUniformBuffer = Scene->UniformBuffers.OpaqueBasePassUniformBuffer;
|
|
}
|
|
else
|
|
{
|
|
BasePassUniformBuffer = TUniformBufferRef<FOpaqueBasePassUniformParameters>::CreateUniformBufferImmediate(BasePassParameters, UniformBuffer_SingleFrame);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders the scene's base pass. This assumes there is a current renderpass active.
|
|
* @return true if anything was rendered
|
|
*/
|
|
bool FDeferredShadingSceneRenderer::RenderBasePass(FRHICommandListImmediate& RHICmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, IPooledRenderTarget* ForwardScreenSpaceShadowMask, bool bParallelBasePass, bool bRenderLightmapDensity)
|
|
{
|
|
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(RenderBasePass);
|
|
SCOPED_NAMED_EVENT(FDeferredShadingSceneRenderer_RenderBasePass, FColor::Emerald);
|
|
|
|
bool bDirty = false;
|
|
|
|
RHICmdList.AutomaticCacheFlushAfterComputeShader(false);
|
|
|
|
if (bRenderLightmapDensity)
|
|
{
|
|
// Override the base pass with the lightmap density pass if the viewmode is enabled.
|
|
bDirty = RenderLightMapDensities(RHICmdList);
|
|
}
|
|
else if (ViewFamily.UseDebugViewPS())
|
|
{
|
|
// Override the base pass with one of the debug view shader mode (see EDebugViewShaderMode) if required.
|
|
bDirty = RenderDebugViewMode(RHICmdList);
|
|
}
|
|
else
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, BasePass);
|
|
SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime);
|
|
SCOPED_GPU_STAT(RHICmdList, Basepass);
|
|
|
|
if (bParallelBasePass)
|
|
{
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
|
|
FScopedCommandListWaitForTasks Flusher(CVarRHICmdFlushRenderThreadTasksBasePass.GetValueOnRenderThread() > 0 || CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0, RHICmdList);
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
|
|
FViewInfo& View = Views[ViewIndex];
|
|
SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
|
|
|
|
TUniformBufferRef<FOpaqueBasePassUniformParameters> BasePassUniformBuffer;
|
|
CreateOpaqueBasePassUniformBuffer(RHICmdList, View, ForwardScreenSpaceShadowMask, BasePassUniformBuffer);
|
|
|
|
FMeshPassProcessorRenderState DrawRenderState(View, BasePassUniformBuffer);
|
|
|
|
SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);
|
|
|
|
if (View.ShouldRenderView())
|
|
{
|
|
Scene->UniformBuffers.UpdateViewUniformBuffer(View);
|
|
|
|
RenderBasePassViewParallel(View, RHICmdList, BasePassDepthStencilAccess, DrawRenderState);
|
|
}
|
|
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
|
|
FSceneRenderTargets::Get(RHICmdList).BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, BasePassDepthStencilAccess, this->ViewFamily.EngineShowFlags.ShaderComplexity);
|
|
RenderEditorPrimitives(RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState, bDirty);
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
bDirty = true; // assume dirty since we are not going to wait
|
|
}
|
|
else
|
|
{
|
|
// Must have an open renderpass before getting here in single threaded mode.
|
|
check(RHICmdList.IsInsideRenderPass());
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
|
|
FViewInfo& View = Views[ViewIndex];
|
|
SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
|
|
|
|
TUniformBufferRef<FOpaqueBasePassUniformParameters> BasePassUniformBuffer;
|
|
CreateOpaqueBasePassUniformBuffer(RHICmdList, View, ForwardScreenSpaceShadowMask, BasePassUniformBuffer);
|
|
|
|
FMeshPassProcessorRenderState DrawRenderState(View, BasePassUniformBuffer);
|
|
|
|
SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);
|
|
|
|
if (View.ShouldRenderView())
|
|
{
|
|
Scene->UniformBuffers.UpdateViewUniformBuffer(View);
|
|
|
|
bDirty |= RenderBasePassView(RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState);
|
|
}
|
|
|
|
RenderEditorPrimitives(RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState, bDirty);
|
|
}
|
|
}
|
|
}
|
|
|
|
RHICmdList.AutomaticCacheFlushAfterComputeShader(true);
|
|
RHICmdList.FlushComputeShaderCache();
|
|
|
|
return bDirty;
|
|
}
|
|
|
|
static void SetupBasePassView(FRHICommandList& RHICmdList, const FViewInfo& View, const FSceneRenderer* SceneRenderer, const bool bIsEditorPrimitivePass = false)
|
|
{
|
|
if (!View.IsInstancedStereoPass() || bIsEditorPrimitivePass)
|
|
{
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
if (View.bIsMultiViewEnabled)
|
|
{
|
|
const uint32 LeftMinX = SceneRenderer->Views[0].ViewRect.Min.X;
|
|
const uint32 LeftMaxX = SceneRenderer->Views[0].ViewRect.Max.X;
|
|
const uint32 RightMinX = SceneRenderer->Views[1].ViewRect.Min.X;
|
|
const uint32 RightMaxX = SceneRenderer->Views[1].ViewRect.Max.X;
|
|
|
|
const uint32 LeftMaxY = SceneRenderer->Views[0].ViewRect.Max.Y;
|
|
const uint32 RightMaxY = SceneRenderer->Views[1].ViewRect.Max.Y;
|
|
|
|
RHICmdList.SetStereoViewport(LeftMinX, RightMinX, 0, 0, 0.0f, LeftMaxX, RightMaxX, LeftMaxY, RightMaxY, 1.0f);
|
|
}
|
|
else
|
|
{
|
|
RHICmdList.SetViewport(0, 0, 0, SceneRenderer->InstancedStereoWidth, View.ViewRect.Max.Y, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("Basepass"), STAT_CLP_Basepass, STATGROUP_ParallelCommandListMarkers);
|
|
|
|
class FBasePassParallelCommandListSet : public FParallelCommandListSet
|
|
{
|
|
public:
|
|
FExclusiveDepthStencil::Type BasePassDepthStencilAccess;
|
|
|
|
FBasePassParallelCommandListSet(
|
|
const FViewInfo& InView,
|
|
FRHICommandListImmediate& InParentCmdList,
|
|
bool bInParallelExecute,
|
|
bool bInCreateSceneContext,
|
|
const FSceneRenderer* InSceneRenderer,
|
|
FExclusiveDepthStencil::Type InBasePassDepthStencilAccess,
|
|
const FMeshPassProcessorRenderState& InDrawRenderState)
|
|
: FParallelCommandListSet(GET_STATID(STAT_CLP_Basepass), InView, InSceneRenderer, InParentCmdList, bInParallelExecute, bInCreateSceneContext, InDrawRenderState)
|
|
, BasePassDepthStencilAccess(InBasePassDepthStencilAccess)
|
|
{
|
|
}
|
|
|
|
virtual ~FBasePassParallelCommandListSet()
|
|
{
|
|
Dispatch();
|
|
}
|
|
|
|
virtual void SetStateOnCommandList(FRHICommandList& CmdList) override
|
|
{
|
|
FParallelCommandListSet::SetStateOnCommandList(CmdList);
|
|
FSceneRenderTargets::Get(CmdList).BeginRenderingGBuffer(CmdList, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, BasePassDepthStencilAccess, SceneRenderer->ViewFamily.EngineShowFlags.ShaderComplexity, false, FLinearColor(0, 0, 0, 1), SceneRenderer->ViewFamily.EngineShowFlags.Wireframe);
|
|
SetupBasePassView(CmdList, View, SceneRenderer);
|
|
}
|
|
};
|
|
|
|
void FDeferredShadingSceneRenderer::RenderBasePassViewParallel(FViewInfo& View, FRHICommandListImmediate& ParentCmdList, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FMeshPassProcessorRenderState& InDrawRenderState)
|
|
{
|
|
check(ParentCmdList.IsOutsideRenderPass());
|
|
|
|
FBasePassParallelCommandListSet ParallelSet(View, ParentCmdList,
|
|
CVarRHICmdBasePassDeferredContexts.GetValueOnRenderThread() > 0,
|
|
CVarRHICmdFlushRenderThreadTasksBasePass.GetValueOnRenderThread() == 0 && CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() == 0,
|
|
this,
|
|
BasePassDepthStencilAccess,
|
|
InDrawRenderState);
|
|
|
|
// enqueue RHIThread command that blocks on prereq, lock / unlock vertex buffer upload
|
|
|
|
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(&ParallelSet, ParentCmdList);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::RenderEditorPrimitives(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FMeshPassProcessorRenderState& InDrawRenderState, bool& bOutDirty)
|
|
{
|
|
FMeshPassProcessorRenderState DrawRenderState(InDrawRenderState);
|
|
SetupBasePassState(BasePassDepthStencilAccess, ViewFamily.EngineShowFlags.ShaderComplexity, DrawRenderState);
|
|
SetupBasePassView(RHICmdList, View, this, true);
|
|
|
|
RenderEditorPrimitivesForDPG(RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState, SDPG_World, bOutDirty);
|
|
|
|
if (HasEditorPrimitivesForDPG(View, SDPG_Foreground))
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
|
|
// Write foreground primitives into depth buffer without testing
|
|
{
|
|
// Change to depth writable
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
SceneContext.BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite, false);
|
|
|
|
// need to setup view again after reconfiguring render targets
|
|
SetupBasePassView(RHICmdList, View, this, true);
|
|
|
|
FMeshPassProcessorRenderState NoDepthTestDrawRenderState(DrawRenderState);
|
|
NoDepthTestDrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_Always>::GetRHI());
|
|
NoDepthTestDrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthWrite_StencilWrite);
|
|
RenderEditorPrimitivesForDPG(RHICmdList, View, BasePassDepthStencilAccess, NoDepthTestDrawRenderState, SDPG_Foreground, bOutDirty);
|
|
|
|
RHICmdList.EndRenderPass();
|
|
|
|
// Restore default base pass depth access
|
|
SceneContext.BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::ELoad, ERenderTargetLoadAction::ELoad, BasePassDepthStencilAccess, false);
|
|
SetupBasePassView(RHICmdList, View, this, true);
|
|
}
|
|
|
|
// Render foreground primitives with depth testing
|
|
RenderEditorPrimitivesForDPG(RHICmdList, View, BasePassDepthStencilAccess, DrawRenderState, SDPG_Foreground, bOutDirty);
|
|
}
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::RenderEditorPrimitivesForDPG(FRHICommandList& RHICmdList, const FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FMeshPassProcessorRenderState& DrawRenderState, ESceneDepthPriorityGroup DepthPriorityGroup, bool& bOutDirty)
|
|
{
|
|
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, DrawRenderState, View, EBlendModeFilter::OpaqueAndMasked, DepthPriorityGroup);
|
|
|
|
bool bDirty = false;
|
|
if (!View.Family->EngineShowFlags.CompositeEditorPrimitives)
|
|
{
|
|
const bool bNeedToSwitchVerticalAxis = RHINeedsToSwitchVerticalAxis(ShaderPlatform);
|
|
|
|
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).
|
|
bDirty |= View.TopBatchedViewElements.Draw(RHICmdList, DrawRenderState, FeatureLevel, bNeedToSwitchVerticalAxis, View, false) || bDirty;
|
|
}
|
|
|
|
if (bDirty)
|
|
{
|
|
bOutDirty = true;
|
|
}
|
|
}
|
|
|
|
bool FDeferredShadingSceneRenderer::RenderBasePassView(FRHICommandListImmediate& RHICmdList, FViewInfo& View, FExclusiveDepthStencil::Type BasePassDepthStencilAccess, const FMeshPassProcessorRenderState& InDrawRenderState)
|
|
{
|
|
bool bDirty = false;
|
|
FMeshPassProcessorRenderState DrawRenderState(InDrawRenderState);
|
|
SetupBasePassView(RHICmdList, View, this);
|
|
|
|
View.ParallelMeshDrawCommandPasses[EMeshPass::BasePass].DispatchDraw(nullptr, RHICmdList);
|
|
|
|
return bDirty;
|
|
}
|
|
|
|
template<typename LightMapPolicyType>
|
|
void 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();
|
|
const bool bRenderAtmosphericFog = IsTranslucentBlendMode(BlendMode) && (Scene && Scene->HasAtmosphericFog() && Scene->ReadOnlyCVARCache.bEnableAtmosphericFog);
|
|
|
|
TMeshProcessorShaders<
|
|
TBasePassVertexShaderPolicyParamType<LightMapPolicyType>,
|
|
FBaseHS,
|
|
FBaseDS,
|
|
TBasePassPixelShaderPolicyParamType<LightMapPolicyType>> BasePassShaders;
|
|
|
|
GetBasePassShaders<LightMapPolicyType>(
|
|
MaterialResource,
|
|
VertexFactory->GetType(),
|
|
LightMapPolicy,
|
|
FeatureLevel,
|
|
bRenderAtmosphericFog,
|
|
bRenderSkylight,
|
|
BasePassShaders.HullShader,
|
|
BasePassShaders.DomainShader,
|
|
BasePassShaders.VertexShader,
|
|
BasePassShaders.PixelShader
|
|
);
|
|
|
|
|
|
FMeshPassProcessorRenderState DrawRenderState(PassDrawRenderState);
|
|
|
|
SetDepthStencilStateForBasePass(DrawRenderState, FeatureLevel, MeshBatch, PrimitiveSceneProxy, bEnableReceiveDecalOutput, false, nullptr);
|
|
|
|
if (bTranslucentBasePass)
|
|
{
|
|
SetTranslucentRenderState(DrawRenderState, MaterialResource);
|
|
}
|
|
|
|
SetBasePassDitheredLODTransitionState(ViewIfDynamicMeshCommand, MeshBatch, StaticMeshId, DrawRenderState);
|
|
|
|
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, BasePassShaders.PixelShader);
|
|
}
|
|
|
|
BuildMeshDrawCommands(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
MaterialResource,
|
|
DrawRenderState,
|
|
BasePassShaders,
|
|
MeshFillMode,
|
|
MeshCullMode,
|
|
SortKey,
|
|
EMeshPassFeatures::Default,
|
|
ShaderElementData);
|
|
}
|
|
|
|
void 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();
|
|
|
|
if (bAllowStaticLighting && LightMapInteraction.GetType() == LMIT_Texture)
|
|
{
|
|
const FShadowMapInteraction ShadowMapInteraction = (MeshBatch.LCI && bIsLitMaterial)
|
|
? MeshBatch.LCI->GetShadowMapInteraction()
|
|
: FShadowMapInteraction();
|
|
|
|
if (ShadowMapInteraction.GetType() == SMIT_Texture)
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_SIMPLE_STATIONARY_PRECOMPUTED_SHADOW_LIGHTING),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
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
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_SIMPLE_STATIONARY_SINGLESAMPLE_SHADOW_LIGHTING),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
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
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_SIMPLE_DIRECTIONAL_LIGHT_LIGHTING),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_SIMPLE_NO_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
}
|
|
|
|
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* FallbackMaterialRenderProxyPtr = nullptr;
|
|
const FMaterial& Material = MeshBatch.MaterialRenderProxy->GetMaterialWithFallback(FeatureLevel, FallbackMaterialRenderProxyPtr);
|
|
|
|
const FMaterialRenderProxy& MaterialRenderProxy = FallbackMaterialRenderProxyPtr ? *FallbackMaterialRenderProxyPtr : *MeshBatch.MaterialRenderProxy;
|
|
|
|
const EBlendMode BlendMode = Material.GetBlendMode();
|
|
const FMaterialShadingModelField ShadingModels = Material.GetShadingModels();
|
|
const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode);
|
|
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(MeshBatch, Material);
|
|
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(MeshBatch, Material);
|
|
|
|
|
|
bool bShouldDraw = false;
|
|
|
|
if (bTranslucentBasePass)
|
|
{
|
|
if (bIsTranslucent && !Material.IsDeferredDecal())
|
|
{
|
|
switch (TranslucencyPassType)
|
|
{
|
|
case ETranslucencyPass::TPT_StandardTranslucency:
|
|
bShouldDraw = !Material.IsTranslucencyAfterDOFEnabled();
|
|
break;
|
|
|
|
case ETranslucencyPass::TPT_TranslucencyAfterDOF:
|
|
bShouldDraw = Material.IsTranslucencyAfterDOFEnabled();
|
|
break;
|
|
|
|
case ETranslucencyPass::TPT_AllTranslucency:
|
|
bShouldDraw = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bShouldDraw = !bIsTranslucent;
|
|
}
|
|
|
|
|
|
// Only draw opaque materials.
|
|
if (bShouldDraw
|
|
&& (!PrimitiveSceneProxy || PrimitiveSceneProxy->ShouldRenderInMainPass())
|
|
&& ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain()))
|
|
{
|
|
// Check for a cached light-map.
|
|
const bool bIsLitMaterial = ShadingModels.IsLit();
|
|
static const auto AllowStaticLightingVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"));
|
|
const bool bAllowStaticLighting = (!AllowStaticLightingVar || AllowStaticLightingVar->GetValueOnRenderThread() != 0);
|
|
|
|
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);
|
|
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)
|
|
{
|
|
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
|
|
Process< FSelfShadowedCachedPointIndirectLightingPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FSelfShadowedCachedPointIndirectLightingPolicy(),
|
|
ElementData,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
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()
|
|
: FShadowMapInteraction();
|
|
|
|
if (ShadowMapInteraction.GetType() == SMIT_Texture)
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_HQ_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
}
|
|
else if (bAllowLowQualityLightMaps)
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_LQ_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
else
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
break;
|
|
default:
|
|
if (bIsLitMaterial
|
|
&& bAllowStaticLighting
|
|
&& Scene
|
|
&& Scene->VolumetricLightmapSceneData.HasData()
|
|
&& PrimitiveSceneProxy
|
|
&& (PrimitiveSceneProxy->IsMovable()
|
|
|| PrimitiveSceneProxy->NeedsUnbuiltPreviewLighting()
|
|
|| PrimitiveSceneProxy->GetLightmapType() == ELightmapType::ForceVolumetric))
|
|
{
|
|
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
|
|
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
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_CACHED_POINT_INDIRECT_LIGHTING),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Process< FUniformLightMapPolicy >(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
StaticMeshId,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
Material,
|
|
BlendMode,
|
|
ShadingModels,
|
|
FUniformLightMapPolicy(LMP_NO_LIGHTMAP),
|
|
MeshBatch.LCI,
|
|
MeshFillMode,
|
|
MeshCullMode);
|
|
}
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
}
|
|
|
|
FMeshPassProcessor* CreateBasePassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
|
|
{
|
|
FMeshPassProcessorRenderState PassDrawRenderState(Scene->UniformBuffers.ViewUniformBuffer, Scene->UniformBuffers.OpaqueBasePassUniformBuffer);
|
|
PassDrawRenderState.SetInstancedViewUniformBuffer(Scene->UniformBuffers.InstancedViewUniformBuffer);
|
|
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(Scene->UniformBuffers.ViewUniformBuffer, Scene->UniformBuffers.TranslucentBasePassUniformBuffer);
|
|
PassDrawRenderState.SetInstancedViewUniformBuffer(Scene->UniformBuffers.InstancedViewUniformBuffer);
|
|
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(Scene->UniformBuffers.ViewUniformBuffer, Scene->UniformBuffers.TranslucentBasePassUniformBuffer);
|
|
PassDrawRenderState.SetInstancedViewUniformBuffer(Scene->UniformBuffers.InstancedViewUniformBuffer);
|
|
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* CreateTranslucencyAllPassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
|
|
{
|
|
FMeshPassProcessorRenderState PassDrawRenderState(Scene->UniformBuffers.ViewUniformBuffer, Scene->UniformBuffers.TranslucentBasePassUniformBuffer);
|
|
PassDrawRenderState.SetInstancedViewUniformBuffer(Scene->UniformBuffers.InstancedViewUniformBuffer);
|
|
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::CachedMeshCommands | EMeshPassFlags::MainView);
|
|
FRegisterPassProcessorCreateFunction RegisterTranslucencyAfterDOFPass(&CreateTranslucencyAfterDOFProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAfterDOF, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView);
|
|
FRegisterPassProcessorCreateFunction RegisterTranslucencyAllPass(&CreateTranslucencyAllPassProcessor, EShadingPath::Deferred, EMeshPass::TranslucencyAll, EMeshPassFlags::CachedMeshCommands | EMeshPassFlags::MainView); |