Files
UnrealEngine/Engine/Source/Runtime/Renderer/Private/MobileDecalRendering.cpp
2025-05-18 13:04:45 +08:00

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);
}
}