From 51736253e3c632a262dfc43a4396876cbcf4b5b8 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 1 Apr 2026 01:33:46 +0800 Subject: [PATCH] feat: add explicit camera clear modes --- .../XCEngine/Components/CameraComponent.h | 11 ++++++++++ engine/src/Components/CameraComponent.cpp | 3 +++ engine/src/Rendering/SceneRenderer.cpp | 16 +++++++++++++- .../test_camera_light_component.cpp | 16 ++++++++++++++ .../unit/test_camera_scene_renderer.cpp | 21 ++++++++++++++++++- 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/engine/include/XCEngine/Components/CameraComponent.h b/engine/include/XCEngine/Components/CameraComponent.h index a29839a0..4d58ff23 100644 --- a/engine/include/XCEngine/Components/CameraComponent.h +++ b/engine/include/XCEngine/Components/CameraComponent.h @@ -11,6 +11,13 @@ enum class CameraProjectionType { Orthographic }; +enum class CameraClearMode { + Auto = 0, + ColorAndDepth, + DepthOnly, + None +}; + class CameraComponent : public Component { public: std::string GetName() const override { return "Camera"; } @@ -36,6 +43,9 @@ public: bool IsPrimary() const { return m_primary; } void SetPrimary(bool value) { m_primary = value; } + CameraClearMode GetClearMode() const { return m_clearMode; } + void SetClearMode(CameraClearMode value) { m_clearMode = value; } + const Math::Color& GetClearColor() const { return m_clearColor; } void SetClearColor(const Math::Color& value) { m_clearColor = value; } @@ -50,6 +60,7 @@ private: float m_farClipPlane = 1000.0f; float m_depth = 0.0f; bool m_primary = true; + CameraClearMode m_clearMode = CameraClearMode::Auto; Math::Color m_clearColor = Math::Color(0.192f, 0.302f, 0.475f, 1.0f); }; diff --git a/engine/src/Components/CameraComponent.cpp b/engine/src/Components/CameraComponent.cpp index 614f7465..eab10883 100644 --- a/engine/src/Components/CameraComponent.cpp +++ b/engine/src/Components/CameraComponent.cpp @@ -33,6 +33,7 @@ void CameraComponent::Serialize(std::ostream& os) const { os << "far=" << m_farClipPlane << ";"; os << "depth=" << m_depth << ";"; os << "primary=" << (m_primary ? 1 : 0) << ";"; + os << "clearMode=" << static_cast(m_clearMode) << ";"; os << "clearColor=" << m_clearColor.r << "," << m_clearColor.g << "," << m_clearColor.b << "," << m_clearColor.a << ";"; } @@ -65,6 +66,8 @@ void CameraComponent::Deserialize(std::istream& is) { m_depth = std::stof(value); } else if (key == "primary") { m_primary = (std::stoi(value) != 0); + } else if (key == "clearMode") { + m_clearMode = static_cast(std::stoi(value)); } else if (key == "clearColor") { std::replace(value.begin(), value.end(), ',', ' '); std::istringstream ss(value); diff --git a/engine/src/Rendering/SceneRenderer.cpp b/engine/src/Rendering/SceneRenderer.cpp index 97f7fd9f..c0aa403a 100644 --- a/engine/src/Rendering/SceneRenderer.cpp +++ b/engine/src/Rendering/SceneRenderer.cpp @@ -26,6 +26,20 @@ bool IsUsableCamera(const Components::CameraComponent* camera) { camera->GetGameObject()->IsActiveInHierarchy(); } +RenderClearFlags ResolveClearFlags(const Components::CameraComponent& camera, size_t cameraIndex) { + switch (camera.GetClearMode()) { + case Components::CameraClearMode::ColorAndDepth: + return RenderClearFlags::All; + case Components::CameraClearMode::DepthOnly: + return RenderClearFlags::Depth; + case Components::CameraClearMode::None: + return RenderClearFlags::None; + case Components::CameraClearMode::Auto: + default: + return cameraIndex == 0 ? RenderClearFlags::All : RenderClearFlags::Depth; + } +} + } // namespace SceneRenderer::SceneRenderer() = default; @@ -88,7 +102,7 @@ std::vector SceneRenderer::BuildRenderRequests( request.context = context; request.surface = surface; request.cameraDepth = camera->GetDepth(); - request.clearFlags = cameraIndex == 0 ? RenderClearFlags::All : RenderClearFlags::Depth; + request.clearFlags = ResolveClearFlags(*camera, cameraIndex); requests.push_back(request); } diff --git a/tests/Components/test_camera_light_component.cpp b/tests/Components/test_camera_light_component.cpp index 33f1d56f..79798eab 100644 --- a/tests/Components/test_camera_light_component.cpp +++ b/tests/Components/test_camera_light_component.cpp @@ -3,6 +3,8 @@ #include #include +#include + using namespace XCEngine::Components; namespace { @@ -16,6 +18,7 @@ TEST(CameraComponent_Test, DefaultValues) { EXPECT_FLOAT_EQ(camera.GetNearClipPlane(), 0.1f); EXPECT_FLOAT_EQ(camera.GetFarClipPlane(), 1000.0f); EXPECT_TRUE(camera.IsPrimary()); + EXPECT_EQ(camera.GetClearMode(), CameraClearMode::Auto); } TEST(CameraComponent_Test, SetterClamping) { @@ -32,6 +35,19 @@ TEST(CameraComponent_Test, SetterClamping) { EXPECT_GT(camera.GetFarClipPlane(), camera.GetNearClipPlane()); } +TEST(CameraComponent_Test, SerializeRoundTripPreservesClearMode) { + CameraComponent source; + source.SetClearMode(CameraClearMode::DepthOnly); + + std::stringstream stream; + source.Serialize(stream); + + CameraComponent target; + target.Deserialize(stream); + + EXPECT_EQ(target.GetClearMode(), CameraClearMode::DepthOnly); +} + TEST(LightComponent_Test, DefaultValues) { LightComponent light; diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 5c6b21a6..29d5198f 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -287,6 +287,7 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid auto* highCamera = highCameraObject->AddComponent(); highCamera->SetPrimary(true); highCamera->SetDepth(5.0f); + highCamera->SetClearMode(CameraClearMode::None); SceneRenderer renderer; const RenderContext context = CreateValidContext(); @@ -302,7 +303,7 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid EXPECT_EQ(defaultRequests[0].surface.GetHeight(), 180u); EXPECT_EQ(defaultRequests[1].camera, highCamera); EXPECT_EQ(defaultRequests[1].cameraDepth, 5.0f); - EXPECT_EQ(defaultRequests[1].clearFlags, RenderClearFlags::Depth); + EXPECT_EQ(defaultRequests[1].clearFlags, RenderClearFlags::None); const std::vector overrideRequests = renderer.BuildRenderRequests(scene, lowCamera, context, surface); @@ -311,6 +312,24 @@ TEST(SceneRenderer_Test, BuildsSortedRequestsForAllUsableCamerasAndHonorsOverrid EXPECT_EQ(overrideRequests[0].clearFlags, RenderClearFlags::All); } +TEST(SceneRenderer_Test, HonorsExplicitOverrideCameraClearMode) { + Scene scene("SceneRendererOverrideClearModeScene"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(2.0f); + camera->SetClearMode(CameraClearMode::DepthOnly); + + SceneRenderer renderer; + const std::vector requests = + renderer.BuildRenderRequests(scene, camera, CreateValidContext(), RenderSurface(640, 360)); + + ASSERT_EQ(requests.size(), 1u); + EXPECT_EQ(requests[0].camera, camera); + EXPECT_EQ(requests[0].clearFlags, RenderClearFlags::Depth); +} + TEST(SceneRenderer_Test, ForwardsPipelineLifetimeAndRenderCallsToCameraRenderer) { Scene scene("SceneRendererScene");