diff --git a/engine/include/XCEngine/Rendering/CameraRenderRequest.h b/engine/include/XCEngine/Rendering/CameraRenderRequest.h index 0d03b871..21f8c330 100644 --- a/engine/include/XCEngine/Rendering/CameraRenderRequest.h +++ b/engine/include/XCEngine/Rendering/CameraRenderRequest.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -17,6 +18,7 @@ struct CameraRenderRequest { RenderContext context; RenderSurface surface; float cameraDepth = 0.0f; + RenderClearFlags clearFlags = RenderClearFlags::All; bool IsValid() const { return scene != nullptr && diff --git a/engine/include/XCEngine/Rendering/RenderCameraData.h b/engine/include/XCEngine/Rendering/RenderCameraData.h index a6fe7431..99b00a9f 100644 --- a/engine/include/XCEngine/Rendering/RenderCameraData.h +++ b/engine/include/XCEngine/Rendering/RenderCameraData.h @@ -9,12 +9,34 @@ namespace XCEngine { namespace Rendering { +enum class RenderClearFlags : uint8_t { + None = 0, + Color = 1 << 0, + Depth = 1 << 1, + All = (1 << 0) | (1 << 1) +}; + +constexpr RenderClearFlags operator|(RenderClearFlags lhs, RenderClearFlags rhs) { + return static_cast( + static_cast(lhs) | static_cast(rhs)); +} + +constexpr RenderClearFlags operator&(RenderClearFlags lhs, RenderClearFlags rhs) { + return static_cast( + static_cast(lhs) & static_cast(rhs)); +} + +constexpr bool HasRenderClearFlag(RenderClearFlags flags, RenderClearFlags flag) { + return static_cast(flags & flag) != 0; +} + struct RenderCameraData { Math::Matrix4x4 view = Math::Matrix4x4::Identity(); Math::Matrix4x4 projection = Math::Matrix4x4::Identity(); Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); Math::Vector3 worldPosition = Math::Vector3::Zero(); Math::Color clearColor = Math::Color::Black(); + RenderClearFlags clearFlags = RenderClearFlags::All; uint32_t viewportWidth = 0; uint32_t viewportHeight = 0; }; diff --git a/engine/src/Rendering/CameraRenderer.cpp b/engine/src/Rendering/CameraRenderer.cpp index 843cb0fb..56c24f54 100644 --- a/engine/src/Rendering/CameraRenderer.cpp +++ b/engine/src/Rendering/CameraRenderer.cpp @@ -50,6 +50,7 @@ bool CameraRenderer::Render( return false; } + sceneData.cameraData.clearFlags = request.clearFlags; return m_pipeline->Render(request.context, request.surface, sceneData); } diff --git a/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp b/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp index a90091dc..1986cd33 100644 --- a/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp +++ b/engine/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp @@ -235,12 +235,15 @@ bool BuiltinForwardPipeline::Render( ? surface.GetClearColorOverride() : sceneData.cameraData.clearColor; const float clearValues[4] = { clearColor.r, clearColor.g, clearColor.b, clearColor.a }; - for (RHI::RHIResourceView* renderTarget : renderTargets) { - if (renderTarget != nullptr) { - commandList->ClearRenderTarget(renderTarget, clearValues); + if (HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color)) { + for (RHI::RHIResourceView* renderTarget : renderTargets) { + if (renderTarget != nullptr) { + commandList->ClearRenderTarget(renderTarget, clearValues); + } } } - if (surface.GetDepthAttachment() != nullptr) { + if (surface.GetDepthAttachment() != nullptr && + HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Depth)) { commandList->ClearDepthStencil(surface.GetDepthAttachment(), 1.0f, 0); } diff --git a/engine/src/Rendering/SceneRenderer.cpp b/engine/src/Rendering/SceneRenderer.cpp index 74ddb803..032b34f9 100644 --- a/engine/src/Rendering/SceneRenderer.cpp +++ b/engine/src/Rendering/SceneRenderer.cpp @@ -47,6 +47,7 @@ std::vector SceneRenderer::BuildRenderRequests( request.context = context; request.surface = surface; request.cameraDepth = camera->GetDepth(); + request.clearFlags = RenderClearFlags::All; requests.push_back(request); return requests; } diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 84058873..c32e6f0d 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -22,7 +22,9 @@ struct MockPipelineState { uint32_t lastSurfaceHeight = 0; CameraComponent* lastCamera = nullptr; size_t lastVisibleItemCount = 0; + RenderClearFlags lastClearFlags = RenderClearFlags::All; std::vector renderedCameras; + std::vector renderedClearFlags; }; class MockPipeline final : public RenderPipeline { @@ -49,7 +51,9 @@ public: m_state->lastSurfaceHeight = surface.GetHeight(); m_state->lastCamera = sceneData.camera; m_state->lastVisibleItemCount = sceneData.visibleItems.size(); + m_state->lastClearFlags = sceneData.cameraData.clearFlags; m_state->renderedCameras.push_back(sceneData.camera); + m_state->renderedClearFlags.push_back(sceneData.cameraData.clearFlags); return true; } @@ -89,6 +93,7 @@ TEST(CameraRenderer_Test, UsesOverrideCameraAndSurfaceSizeWhenSubmittingScene) { request.context = CreateValidContext(); request.surface = RenderSurface(640, 480); request.cameraDepth = overrideCamera->GetDepth(); + request.clearFlags = RenderClearFlags::None; ASSERT_TRUE(renderer.Render(request)); EXPECT_EQ(state->renderCalls, 1); @@ -97,6 +102,7 @@ TEST(CameraRenderer_Test, UsesOverrideCameraAndSurfaceSizeWhenSubmittingScene) { EXPECT_EQ(state->lastCamera, overrideCamera); EXPECT_NE(state->lastCamera, primaryCamera); EXPECT_EQ(state->lastVisibleItemCount, 0u); + EXPECT_EQ(state->lastClearFlags, RenderClearFlags::None); } TEST(SceneRenderer_Test, BuildsSingleExplicitRequestFromSelectedCamera) { @@ -121,6 +127,7 @@ TEST(SceneRenderer_Test, BuildsSingleExplicitRequestFromSelectedCamera) { ASSERT_EQ(defaultRequests.size(), 1u); EXPECT_EQ(defaultRequests[0].camera, highCamera); EXPECT_EQ(defaultRequests[0].cameraDepth, 5.0f); + EXPECT_EQ(defaultRequests[0].clearFlags, RenderClearFlags::All); EXPECT_EQ(defaultRequests[0].surface.GetWidth(), 320u); EXPECT_EQ(defaultRequests[0].surface.GetHeight(), 180u); @@ -188,14 +195,19 @@ TEST(SceneRenderer_Test, SortsManualCameraRequestsByDepthBeforeRendering) { farRequest.context = CreateValidContext(); farRequest.surface = RenderSurface(800, 600); farRequest.cameraDepth = farCamera->GetDepth(); + farRequest.clearFlags = RenderClearFlags::None; CameraRenderRequest nearRequest = farRequest; nearRequest.camera = nearCamera; nearRequest.cameraDepth = nearCamera->GetDepth(); + nearRequest.clearFlags = RenderClearFlags::Depth; const std::vector requests = { farRequest, nearRequest }; ASSERT_TRUE(renderer.Render(requests)); ASSERT_EQ(state->renderedCameras.size(), 2u); + ASSERT_EQ(state->renderedClearFlags.size(), 2u); EXPECT_EQ(state->renderedCameras[0], nearCamera); + EXPECT_EQ(state->renderedClearFlags[0], RenderClearFlags::Depth); EXPECT_EQ(state->renderedCameras[1], farCamera); + EXPECT_EQ(state->renderedClearFlags[1], RenderClearFlags::None); }