diff --git a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs index e4239bf4..31e9be52 100644 --- a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs +++ b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs @@ -89,4 +89,69 @@ namespace ProjectScripts }; } } + + public sealed class ProjectCustomOpaquePass + : ScriptableRenderPass + { + public ProjectCustomOpaquePass() + { + renderPassEvent = + RenderPassEvent.RenderOpaques; + } + + protected override bool RecordRenderGraph( + ScriptableRenderContext context, + RenderingData renderingData) + { + return context != null && + renderingData != null && + renderingData.isMainSceneStage && + RecordOpaqueScenePhase(context); + } + } + + public sealed class ProjectCustomRenderer + : ScriptableRenderer + { + private readonly ProjectCustomOpaquePass m_opaquePass = + new ProjectCustomOpaquePass(); + + protected override void AddRenderPasses( + RenderingData renderingData) + { + if (renderingData == null || + !renderingData.isMainSceneStage) + { + return; + } + + EnqueuePass(m_opaquePass); + } + } + + public sealed class ProjectCustomRendererData + : ScriptableRendererData + { + protected override ScriptableRenderer CreateRenderer() + { + return new ProjectCustomRenderer(); + } + + protected override string GetPipelineRendererAssetKey() + { + return "BuiltinForward"; + } + } + + public sealed class ProjectCustomRendererPipelineAsset + : RendererBackedRenderPipelineAsset + { + public ProjectCustomRendererPipelineAsset() + { + rendererDataList = new ScriptableRendererData[] + { + new ProjectCustomRendererData() + }; + } + } } diff --git a/tests/scripting/test_project_script_assembly.cpp b/tests/scripting/test_project_script_assembly.cpp index f78eff9a..94d82b58 100644 --- a/tests/scripting/test_project_script_assembly.cpp +++ b/tests/scripting/test_project_script_assembly.cpp @@ -165,6 +165,15 @@ TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetRenderPipelineAssetClasse "ProjectScripts", "ProjectUniversalFeaturePipelineAsset"}), classes.end()); + EXPECT_NE( + std::find( + classes.begin(), + classes.end(), + ScriptClassDescriptor{ + "GameScripts", + "ProjectScripts", + "ProjectCustomRendererPipelineAsset"}), + classes.end()); } TEST_F( @@ -259,4 +268,96 @@ TEST_F( recorder->Shutdown(); } +TEST_F( + ProjectScriptAssemblyTest, + CreatesProjectCustomRendererPipelineAssetThroughManagedBridge) { + const auto bridge = + XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge(); + ASSERT_NE(bridge, nullptr); + + const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = { + "GameScripts", + "ProjectScripts", + "ProjectCustomRendererPipelineAsset" + }; + + std::shared_ptr + assetRuntime = bridge->CreateAssetRuntime(descriptor); + ASSERT_NE(assetRuntime, nullptr); + EXPECT_NE(assetRuntime->GetPipelineRendererAsset(), nullptr); + + std::unique_ptr recorder = + assetRuntime->CreateStageRecorder(); + ASSERT_NE(recorder, nullptr); + + const XCEngine::Rendering::RenderContext renderContext = {}; + ASSERT_TRUE(recorder->Initialize(renderContext)); + EXPECT_TRUE( + recorder->SupportsStageRenderGraph( + XCEngine::Rendering::CameraFrameStage::MainScene)); + EXPECT_FALSE( + recorder->SupportsStageRenderGraph( + XCEngine::Rendering::CameraFrameStage::PostProcess)); + + XCEngine::Rendering::RenderGraph graph; + XCEngine::Rendering::RenderGraphBuilder graphBuilder(graph); + XCEngine::Rendering::RenderGraphTextureDesc colorDesc = {}; + colorDesc.width = 64u; + colorDesc.height = 64u; + colorDesc.format = + static_cast( + XCEngine::RHI::Format::R8G8B8A8_UNorm); + XCEngine::Rendering::RenderGraphTextureDesc depthDesc = colorDesc; + depthDesc.format = + static_cast( + XCEngine::RHI::Format::D32_Float); + const XCEngine::Rendering::RenderGraphTextureHandle colorTarget = + graphBuilder.CreateTransientTexture( + "ProjectCustomMainSceneColor", + colorDesc); + const XCEngine::Rendering::RenderGraphTextureHandle depthTarget = + graphBuilder.CreateTransientTexture( + "ProjectCustomMainSceneDepth", + depthDesc); + + const XCEngine::Rendering::RenderSceneData sceneData = {}; + const XCEngine::Rendering::RenderSurface surface(64u, 64u); + bool executionSucceeded = true; + XCEngine::Rendering::RenderGraphBlackboard blackboard = {}; + const XCEngine::Rendering::RenderPipelineStageRenderGraphContext graphContext = { + graphBuilder, + "ProjectCustomMainScene", + XCEngine::Rendering::CameraFrameStage::MainScene, + renderContext, + sceneData, + surface, + nullptr, + nullptr, + XCEngine::RHI::ResourceStates::Common, + {}, + { colorTarget }, + depthTarget, + {}, + &executionSucceeded, + &blackboard + }; + + EXPECT_TRUE(recorder->RecordStageRenderGraph(graphContext)); + + XCEngine::Rendering::CompiledRenderGraph compiledGraph = {}; + XCEngine::Containers::String errorMessage; + ASSERT_TRUE( + XCEngine::Rendering::RenderGraphCompiler::Compile( + graph, + compiledGraph, + &errorMessage)) + << errorMessage.CStr(); + ASSERT_EQ(compiledGraph.GetPassCount(), 1u); + EXPECT_STREQ( + compiledGraph.GetPassName(0).CStr(), + "ProjectCustomMainScene.Opaque"); + + recorder->Shutdown(); +} + } // namespace