// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= MobileTranslucentRendering.cpp: translucent rendering implementation. =============================================================================*/ #include "CoreMinimal.h" #include "HAL/IConsoleManager.h" #include "RHI.h" #include "HitProxies.h" #include "Shader.h" #include "StaticBoundShaderState.h" #include "SceneUtils.h" #include "RHIStaticStates.h" #include "PostProcess/SceneRenderTargets.h" #include "GlobalShader.h" #include "SceneRenderTargetParameters.h" #include "SceneRendering.h" #include "LightMapRendering.h" #include "MaterialShaderType.h" #include "MeshMaterialShaderType.h" #include "MeshMaterialShader.h" #include "BasePassRendering.h" #include "DynamicPrimitiveDrawing.h" #include "TranslucentRendering.h" #include "MobileBasePassRendering.h" #include "ScenePrivate.h" #include "ScreenRendering.h" #include "PostProcess/SceneFilterRendering.h" #include "PipelineStateCache.h" #include "MeshPassProcessor.inl" #include "ClearQuad.h" void FMobileSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList, const FViewInfo& View) { const bool bShouldRenderTranslucency = ShouldRenderTranslucency(StandardTranslucencyPass) && ViewFamily.EngineShowFlags.Translucency && !ViewFamily.UseDebugViewPS(); if (bShouldRenderTranslucency) { CSV_SCOPED_TIMING_STAT_EXCLUSIVE(RenderTranslucency); SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); SCOPED_DRAW_EVENT(RHICmdList, Translucency); SCOPED_GPU_STAT(RHICmdList, Translucency); RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); View.ParallelMeshDrawCommandPasses[StandardTranslucencyMeshPass].DispatchDraw(nullptr, RHICmdList, &MeshPassInstanceCullingDrawParams[StandardTranslucencyMeshPass]); } } BEGIN_SHADER_PARAMETER_STRUCT(FMobileBasePassParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FMobileBasePassUniformParameters, MobileBasePass) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() void FMobileSceneRenderer::RenderInverseOpacity(FRDGBuilder& GraphBuilder, const FViewInfo& View) { View.BeginRenderView(); UpdateDirectionalLightUniformBuffers(GraphBuilder, View); const FSceneTextures& SceneTextures = FSceneTextures::Get(GraphBuilder); EMobileSceneTextureSetupMode SetupMode = EMobileSceneTextureSetupMode::CustomDepth; auto* InverseOpacityParameters = GraphBuilder.AllocParameters(); InverseOpacityParameters->View = View.GetShaderParameters(); InverseOpacityParameters->MobileBasePass = CreateMobileBasePassUniformBuffer(GraphBuilder, View, EMobileBasePass::Translucent, SetupMode); InverseOpacityParameters->RenderTargets[0] = FRenderTargetBinding(SceneTextures.Color.Target, SceneTextures.Color.Resolve, ERenderTargetLoadAction::EClear); InverseOpacityParameters->RenderTargets.DepthStencil = FDepthStencilBinding(SceneTextures.Depth.Target, ERenderTargetLoadAction::EClear, FExclusiveDepthStencil::DepthWrite_StencilWrite); // Opacity could fetch depth as we use exactly the same shaders as in base pass InverseOpacityParameters->RenderTargets.SubpassHint = ESubpassHint::DepthReadSubpass; GraphBuilder.AddPass(RDG_EVENT_NAME("InverseOpacityPass"), InverseOpacityParameters, ERDGPassFlags::Raster, [this, &View](FRHICommandListImmediate& RHICmdList) { // Mobile multi-view is not side by side stereo const FViewInfo& TranslucentViewport = (View.bIsMobileMultiViewEnabled) ? Views[0] : View; RHICmdList.SetViewport(TranslucentViewport.ViewRect.Min.X, TranslucentViewport.ViewRect.Min.Y, 0.0f, TranslucentViewport.ViewRect.Max.X, TranslucentViewport.ViewRect.Max.Y, 1.0f); // Default clear value for a SceneColor is (0,0,0,0), after this pass will blend inverse opacity into final render target with an 1-SrcAlpha op // to make this blending work untouched pixels must have alpha = 1 DrawClearQuad(RHICmdList, FLinearColor(0, 0, 0, 1)); // GPUCULL_TODO: View.ParallelMeshDrawCommandPasses[EMeshPass::MobileInverseOpacity].BuildRenderingCommands(GraphBuilder, Scene->GPUScene); RHICmdList.NextSubpass(); if (ShouldRenderTranslucency(ETranslucencyPass::TPT_AllTranslucency) && View.ShouldRenderView()) { View.ParallelMeshDrawCommandPasses[EMeshPass::MobileInverseOpacity].DispatchDraw(nullptr, RHICmdList); } }); } // This pass is registered only when we render to scene capture, see UpdateSceneCaptureContentMobile_RenderThread() FMeshPassProcessor* CreateMobileInverseOpacityPassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext) { FMeshPassProcessorRenderState PassDrawRenderState; PassDrawRenderState.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); PassDrawRenderState.SetBlendState(TStaticBlendState::GetRHI()); PassDrawRenderState.SetDepthStencilAccess(FExclusiveDepthStencil::DepthRead_StencilRead); const FMobileBasePassMeshProcessor::EFlags Flags = FMobileBasePassMeshProcessor::EFlags::CanUseDepthStencil | FMobileBasePassMeshProcessor::EFlags::ForcePassDrawRenderState; return new(FMemStack::Get()) FMobileBasePassMeshProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, PassDrawRenderState, InDrawListContext, Flags, ETranslucencyPass::TPT_AllTranslucency); }