From be2013f3c4c549da585d9f536aa0b9df8689600c Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sun, 5 Apr 2026 23:00:33 +0800 Subject: [PATCH] Split builtin forward scene into opaque and transparent passes --- .../Pipelines/BuiltinForwardPipeline.h | 9 ++ .../Pipelines/BuiltinForwardPipeline.cpp | 119 ++++++++++++++---- .../unit/test_builtin_forward_pipeline.cpp | 8 ++ 3 files changed, 111 insertions(+), 25 deletions(-) diff --git a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h index 2bd03c6c..8007a7d1 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h +++ b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h @@ -38,6 +38,7 @@ class RenderSurface; namespace Pipelines { namespace Detail { class BuiltinForwardOpaquePass; +class BuiltinForwardTransparentPass; } // namespace Detail class BuiltinForwardPipeline : public RenderPipeline { @@ -56,6 +57,7 @@ public: private: friend class Detail::BuiltinForwardOpaquePass; + friend class Detail::BuiltinForwardTransparentPass; struct OwnedDescriptorSet { RHI::RHIDescriptorPool* pool = nullptr; @@ -233,7 +235,14 @@ private: RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem); static LightingConstants BuildLightingConstants(const RenderLightingData& lightingData); static AdditionalLightConstants BuildAdditionalLightConstants(const RenderAdditionalLightData& lightData); + bool BeginForwardScenePass(const RenderPassContext& context); + void EndForwardScenePass(const RenderPassContext& context); bool ExecuteForwardOpaquePass(const RenderPassContext& context); + bool ExecuteForwardTransparentPass(const RenderPassContext& context); + bool DrawVisibleItems( + const RenderContext& context, + const RenderSceneData& sceneData, + bool drawTransparentItems); bool DrawVisibleItem( const RenderContext& context, const RenderSceneData& sceneData, diff --git a/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp b/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp index 4f07aad2..cd2143d8 100644 --- a/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp +++ b/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp @@ -40,6 +40,32 @@ private: BuiltinForwardPipeline& m_pipeline; }; +class BuiltinForwardTransparentPass final : public RenderPass { +public: + explicit BuiltinForwardTransparentPass(BuiltinForwardPipeline& pipeline) + : m_pipeline(pipeline) { + } + + const char* GetName() const override { + return "BuiltinForwardTransparentPass"; + } + + bool Initialize(const RenderContext& context) override { + return m_pipeline.EnsureInitialized(context); + } + + void Shutdown() override { + m_pipeline.DestroyPipelineResources(); + } + + bool Execute(const RenderPassContext& context) override { + return m_pipeline.ExecuteForwardTransparentPass(context); + } + +private: + BuiltinForwardPipeline& m_pipeline; +}; + } // namespace Detail namespace { @@ -53,6 +79,7 @@ bool IsDepthFormat(RHI::Format format) { BuiltinForwardPipeline::BuiltinForwardPipeline() { m_passSequence.AddPass(std::make_unique(*this)); + m_passSequence.AddPass(std::make_unique(*this)); } BuiltinForwardPipeline::~BuiltinForwardPipeline() { @@ -118,7 +145,7 @@ bool BuiltinForwardPipeline::Render( return m_passSequence.Execute(passContext); } -bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& passContext) { +bool BuiltinForwardPipeline::BeginForwardScenePass(const RenderPassContext& passContext) { const RenderContext& context = passContext.renderContext; const RenderSurface& surface = passContext.surface; const RenderSceneData& sceneData = passContext.sceneData; @@ -128,11 +155,9 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p return false; } - std::vector renderTargets = colorAttachments; RHI::RHICommandList* commandList = context.commandList; - if (surface.IsAutoTransitionEnabled()) { - for (RHI::RHIResourceView* renderTarget : renderTargets) { + for (RHI::RHIResourceView* renderTarget : colorAttachments) { if (renderTarget != nullptr) { commandList->TransitionBarrier( renderTarget, @@ -142,6 +167,7 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p } } + std::vector renderTargets = colorAttachments; commandList->SetRenderTargets( static_cast(renderTargets.size()), renderTargets.data(), @@ -187,17 +213,80 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p } commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList); + return true; +} + +void BuiltinForwardPipeline::EndForwardScenePass(const RenderPassContext& passContext) { + const RenderContext& context = passContext.renderContext; + const RenderSurface& surface = passContext.surface; + const std::vector& colorAttachments = surface.GetColorAttachments(); + RHI::RHICommandList* commandList = context.commandList; + + if (!surface.IsAutoTransitionEnabled()) { + return; + } + + commandList->EndRenderPass(); + for (RHI::RHIResourceView* renderTarget : colorAttachments) { + if (renderTarget != nullptr) { + commandList->TransitionBarrier( + renderTarget, + RHI::ResourceStates::RenderTarget, + surface.GetColorStateAfter()); + } + } +} + +bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& passContext) { + const RenderContext& context = passContext.renderContext; + const RenderSceneData& sceneData = passContext.sceneData; + + if (!BeginForwardScenePass(passContext)) { + return false; + } if (sceneData.lighting.HasMainDirectionalShadow() && IsDepthFormat(sceneData.lighting.mainDirectionalShadow.shadowMap->GetFormat())) { - commandList->TransitionBarrier( + context.commandList->TransitionBarrier( sceneData.lighting.mainDirectionalShadow.shadowMap, RHI::ResourceStates::DepthWrite, RHI::ResourceStates::PixelShaderResource); } + return DrawVisibleItems(context, sceneData, false); +} + +bool BuiltinForwardPipeline::ExecuteForwardTransparentPass(const RenderPassContext& passContext) { + const RenderContext& context = passContext.renderContext; + const RenderSceneData& sceneData = passContext.sceneData; + + const bool drawResult = DrawVisibleItems(context, sceneData, true); + + if (sceneData.lighting.HasMainDirectionalShadow() && + IsDepthFormat(sceneData.lighting.mainDirectionalShadow.shadowMap->GetFormat())) { + context.commandList->TransitionBarrier( + sceneData.lighting.mainDirectionalShadow.shadowMap, + RHI::ResourceStates::PixelShaderResource, + RHI::ResourceStates::DepthWrite); + } + + EndForwardScenePass(passContext); + + return drawResult; +} + +bool BuiltinForwardPipeline::DrawVisibleItems( + const RenderContext& context, + const RenderSceneData& sceneData, + bool drawTransparentItems) { + RHI::RHICommandList* commandList = context.commandList; RHI::RHIPipelineState* currentPipelineState = nullptr; for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) { + const bool isTransparentItem = IsTransparentRenderQueue(visibleItem.renderQueue); + if (isTransparentItem != drawTransparentItems) { + continue; + } + const Resources::Material* material = ResolveMaterial(visibleItem); BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit; if (!TryResolveSurfacePassType(material, pass)) { @@ -216,26 +305,6 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p DrawVisibleItem(context, sceneData, visibleItem); } - if (sceneData.lighting.HasMainDirectionalShadow() && - IsDepthFormat(sceneData.lighting.mainDirectionalShadow.shadowMap->GetFormat())) { - commandList->TransitionBarrier( - sceneData.lighting.mainDirectionalShadow.shadowMap, - RHI::ResourceStates::PixelShaderResource, - RHI::ResourceStates::DepthWrite); - } - - if (surface.IsAutoTransitionEnabled()) { - commandList->EndRenderPass(); - for (RHI::RHIResourceView* renderTarget : renderTargets) { - if (renderTarget != nullptr) { - commandList->TransitionBarrier( - renderTarget, - RHI::ResourceStates::RenderTarget, - surface.GetColorStateAfter()); - } - } - } - return true; } diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index 8361a861..ab19fb76 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -45,6 +45,14 @@ TEST(BuiltinForwardPipeline_Test, UsesFloat3PositionInputLayoutForStaticMeshVert EXPECT_EQ(texcoord.alignedByteOffset, static_cast(offsetof(StaticMeshVertex, uv0))); } +TEST(BuiltinForwardPipeline_Test, SplitsSceneItemsIntoOpaqueAndTransparentQueueRanges) { + EXPECT_FALSE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::Background))); + EXPECT_FALSE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::Geometry))); + EXPECT_FALSE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::AlphaTest))); + EXPECT_TRUE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::Transparent))); + EXPECT_TRUE(IsTransparentRenderQueue(static_cast(MaterialRenderQueue::Overlay))); +} + TEST(BuiltinForwardPipeline_Test, BuiltinForwardShaderDeclaresExplicitForwardResourceContract) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath());