164 lines
6.8 KiB
C++
164 lines
6.8 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
MobileDecalRendering.cpp: Decals for mobile renderer
|
|
=============================================================================*/
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Stats/Stats.h"
|
|
#include "RHIDefinitions.h"
|
|
#include "RHI.h"
|
|
#include "SceneUtils.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "PostProcess/SceneRenderTargets.h"
|
|
#include "SceneRendering.h"
|
|
#include "ScenePrivate.h"
|
|
#include "SceneProxies/DeferredDecalProxy.h"
|
|
#include "DecalRenderingCommon.h"
|
|
#include "DecalRenderingShared.h"
|
|
#include "RenderCore.h"
|
|
#include "DataDrivenShaderPlatformInfo.h"
|
|
#include "CompositionLighting/PostProcessDeferredDecals.h"
|
|
#include "DBufferTextures.h"
|
|
|
|
extern void RenderDeferredDecalsMobile(FRHICommandList& RHICmdList, const FScene& Scene, const FViewInfo& View, EDecalRenderStage DecalRenderStage, EDecalRenderTargetMode RenderTargetMode);
|
|
|
|
static bool DoesPlatformSupportDecals(EShaderPlatform ShaderPlatform)
|
|
{
|
|
if (!IsMobileHDR())
|
|
{
|
|
// Vulkan uses sub-pass to fetch SceneDepth
|
|
if (IsVulkanPlatform(ShaderPlatform) ||
|
|
IsSimulatedPlatform(ShaderPlatform) ||
|
|
// Some Androids support SceneDepth fetch
|
|
(IsAndroidOpenGLESPlatform(ShaderPlatform) && GSupportsShaderDepthStencilFetch))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Metal needs DepthAux to fetch depth, and its not availle in LDR mode
|
|
return false;
|
|
}
|
|
|
|
// HDR always supports decals
|
|
return true;
|
|
}
|
|
|
|
void FMobileSceneRenderer::RenderDecals(FRHICommandList& RHICmdList, FViewInfo& View, const FInstanceCullingDrawParams* InstanceCullingDrawParams)
|
|
{
|
|
if (!DoesPlatformSupportDecals(View.GetShaderPlatform()) || !ViewFamily.EngineShowFlags.Decals || View.bIsPlanarReflection)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(RenderDecals);
|
|
SCOPE_CYCLE_COUNTER(STAT_DecalsDrawTime);
|
|
|
|
const bool bIsMobileDeferred = IsMobileDeferredShadingEnabled(View.GetShaderPlatform());
|
|
const EDecalRenderStage DecalRenderStage = bRequiresDBufferDecals ? EDecalRenderStage::Emissive : bIsMobileDeferred ? EDecalRenderStage::MobileBeforeLighting : EDecalRenderStage::Mobile;
|
|
const EDecalRenderTargetMode RenderTargetMode = bIsMobileDeferred ? EDecalRenderTargetMode::SceneColorAndGBuffer : EDecalRenderTargetMode::SceneColor;
|
|
|
|
// Deferred decals
|
|
if (Scene->Decals.Num() > 0)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, Decals);
|
|
RenderDeferredDecalsMobile(RHICmdList, *Scene, View, DecalRenderStage, RenderTargetMode);
|
|
}
|
|
|
|
EMeshPass::Type DecalMeshPassType = DecalRendering::GetMeshPassType(RenderTargetMode);
|
|
if (HasAnyDraw(View.ParallelMeshDrawCommandPasses[DecalMeshPassType]))
|
|
{
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1);
|
|
View.ParallelMeshDrawCommandPasses[DecalMeshPassType]->Draw(RHICmdList, InstanceCullingDrawParams);
|
|
}
|
|
}
|
|
|
|
void RenderDeferredDecalsMobile(FRHICommandList& RHICmdList, const FScene& Scene, const FViewInfo& View, EDecalRenderStage DecalRenderStage, EDecalRenderTargetMode RenderTargetMode)
|
|
{
|
|
FVisibleDecalList VisibleDecals;
|
|
FRelevantDecalList SortedDecals;
|
|
|
|
if (!Scene.Decals.IsEmpty())
|
|
{
|
|
VisibleDecals = DecalRendering::BuildVisibleDecalList(Scene.Decals, View);
|
|
|
|
// Build a list of decals that need to be rendered for this view
|
|
SortedDecals = DecalRendering::BuildRelevantDecalList(VisibleDecals, DecalRenderStage);
|
|
INC_DWORD_STAT_BY(STAT_Decals, SortedDecals.Num());
|
|
}
|
|
|
|
if (SortedDecals.Num() > 0)
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1);
|
|
RHICmdList.SetStreamSource(0, GetUnitCubeVertexBuffer(), 0);
|
|
|
|
for (int32 DecalIndex = 0; DecalIndex < SortedDecals.Num(); DecalIndex++)
|
|
{
|
|
const FVisibleDecal& VisibleDecal = *SortedDecals[DecalIndex];
|
|
const FMatrix ComponentToWorldMatrix = VisibleDecal.ComponentTrans.ToMatrixWithScale();
|
|
const FMatrix FrustumComponentToClip = DecalRendering::ComputeComponentToClipMatrix(View, ComponentToWorldMatrix);
|
|
|
|
const float ConservativeRadius = VisibleDecal.ConservativeRadius;
|
|
const bool bInsideDecal = ((FVector)View.ViewMatrices.GetViewOrigin() - ComponentToWorldMatrix.GetOrigin()).SizeSquared() < FMath::Square(ConservativeRadius * 1.05f + View.NearClippingDistance * 2.0f);
|
|
bool bReverseHanded = false;
|
|
{
|
|
// Account for the reversal of handedness caused by negative scale on the decal
|
|
const auto& Scale3d = VisibleDecal.ComponentTrans.GetScale3D();
|
|
bReverseHanded = Scale3d[0] * Scale3d[1] * Scale3d[2] < 0.f;
|
|
}
|
|
EDecalRasterizerState DecalRasterizerState = DecalRendering::GetDecalRasterizerState(bInsideDecal, bReverseHanded, View.bReverseCulling);
|
|
GraphicsPSOInit.RasterizerState = DecalRendering::GetDecalRasterizerState(DecalRasterizerState);
|
|
|
|
if (bInsideDecal)
|
|
{
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<
|
|
false, CF_Always,
|
|
true, CF_Equal, SO_Keep, SO_Keep, SO_Keep,
|
|
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
|
|
GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI();
|
|
}
|
|
else
|
|
{
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<
|
|
false, CF_DepthNearOrEqual,
|
|
true, CF_Equal, SO_Keep, SO_Keep, SO_Keep,
|
|
false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
|
|
GET_STENCIL_BIT_MASK(RECEIVE_DECAL, 1), 0x00>::GetRHI();
|
|
}
|
|
|
|
GraphicsPSOInit.BlendState = DecalRendering::GetDecalBlendState(VisibleDecal.BlendDesc, DecalRenderStage, RenderTargetMode);
|
|
|
|
// Set shader params
|
|
DecalRendering::SetShader(RHICmdList, GraphicsPSOInit, 0, View, VisibleDecal, DecalRenderStage, FrustumComponentToClip, &Scene);
|
|
|
|
RHICmdList.DrawIndexedPrimitive(GetUnitCubeIndexBuffer(), 0, 0, 8, 0, UE_ARRAY_COUNT(GCubeIndices) / 3, View.GetStereoPassInstanceFactor());
|
|
}
|
|
}
|
|
}
|
|
|
|
void FMobileSceneRenderer::RenderDBuffer(FRDGBuilder& GraphBuilder, FSceneTextures& SceneTextures, FDBufferTextures& DBufferTextures, FInstanceCullingManager& InstanceCullingManager)
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "RenderDBuffer");
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderDBuffer);
|
|
|
|
const EShaderPlatform Platform = GetViewFamilyInfo(Views).GetShaderPlatform();
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
|
|
{
|
|
FViewInfo& View = Views[ViewIndex];
|
|
|
|
if (!View.ShouldRenderView())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
FVisibleDecalList VisibleDecals = DecalRendering::BuildVisibleDecalList(Scene->Decals, View);
|
|
FRelevantDecalList SortedDecals = DecalRendering::BuildRelevantDecalList(VisibleDecals, EDecalRenderStage::BeforeBasePass);
|
|
FDeferredDecalPassTextures DecalPassTextures = GetDeferredDecalPassTextures(GraphBuilder, View, Scene->SubstrateSceneData, SceneTextures, &DBufferTextures, EDecalRenderStage::BeforeBasePass);
|
|
AddDeferredDecalPass(GraphBuilder, View, SortedDecals, DecalPassTextures, InstanceCullingManager, EDecalRenderStage::BeforeBasePass);
|
|
}
|
|
}
|