From 0a0544cbe4743e36922ae44b2c69fbd6844b11aa Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 1 Apr 2026 22:28:07 +0800 Subject: [PATCH] fix: compose camera viewport within parent render area --- engine/src/Rendering/SceneRenderer.cpp | 17 ++++--- .../unit/test_camera_scene_renderer.cpp | 48 +++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/engine/src/Rendering/SceneRenderer.cpp b/engine/src/Rendering/SceneRenderer.cpp index b2af9df8..b4e44bc8 100644 --- a/engine/src/Rendering/SceneRenderer.cpp +++ b/engine/src/Rendering/SceneRenderer.cpp @@ -56,13 +56,18 @@ Math::RectInt ResolveCameraRenderArea( const Components::CameraComponent& camera, const RenderSurface& surface) { const Math::Rect viewportRect = camera.GetViewportRect(); - const float surfaceWidth = static_cast(surface.GetWidth()); - const float surfaceHeight = static_cast(surface.GetHeight()); + const Math::RectInt parentRenderArea = surface.GetRenderArea(); + const float parentWidth = static_cast(std::max(parentRenderArea.width, 0)); + const float parentHeight = static_cast(std::max(parentRenderArea.height, 0)); - const int32_t left = static_cast(std::floor(viewportRect.x * surfaceWidth)); - const int32_t top = static_cast(std::floor(viewportRect.y * surfaceHeight)); - const int32_t right = static_cast(std::ceil((viewportRect.x + viewportRect.width) * surfaceWidth)); - const int32_t bottom = static_cast(std::ceil((viewportRect.y + viewportRect.height) * surfaceHeight)); + const int32_t left = parentRenderArea.x + + static_cast(std::floor(viewportRect.x * parentWidth)); + const int32_t top = parentRenderArea.y + + static_cast(std::floor(viewportRect.y * parentHeight)); + const int32_t right = parentRenderArea.x + + static_cast(std::ceil((viewportRect.x + viewportRect.width) * parentWidth)); + const int32_t bottom = parentRenderArea.y + + static_cast(std::ceil((viewportRect.y + viewportRect.height) * parentHeight)); return Math::RectInt(left, top, right - left, bottom - top); } diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index e64085ad..404a7fa7 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -537,6 +537,54 @@ TEST(SceneRenderer_Test, ResolvesNormalizedCameraViewportRectToPerRequestRenderA EXPECT_EQ(renderArea.height, 240); } +TEST(SceneRenderer_Test, ComposesCameraViewportRectWithinExistingSurfaceRenderArea) { + Scene scene("SceneRendererNestedViewportRectScene"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(2.0f); + camera->SetViewportRect(XCEngine::Math::Rect(0.25f, 0.1f, 0.5f, 0.4f)); + + RenderSurface surface(800, 600); + surface.SetRenderArea(XCEngine::Math::RectInt(100, 50, 400, 300)); + + SceneRenderer renderer; + const std::vector requests = + renderer.BuildRenderRequests(scene, nullptr, CreateValidContext(), surface); + + ASSERT_EQ(requests.size(), 1u); + const XCEngine::Math::RectInt renderArea = requests[0].surface.GetRenderArea(); + EXPECT_EQ(renderArea.x, 200); + EXPECT_EQ(renderArea.y, 80); + EXPECT_EQ(renderArea.width, 200); + EXPECT_EQ(renderArea.height, 120); +} + +TEST(SceneRenderer_Test, PreservesExistingSurfaceRenderAreaForFullViewportCamera) { + Scene scene("SceneRendererFullViewportNestedSurfaceScene"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(2.0f); + camera->SetViewportRect(XCEngine::Math::Rect(0.0f, 0.0f, 1.0f, 1.0f)); + + RenderSurface surface(1024, 768); + surface.SetRenderArea(XCEngine::Math::RectInt(80, 120, 320, 240)); + + SceneRenderer renderer; + const std::vector requests = + renderer.BuildRenderRequests(scene, nullptr, CreateValidContext(), surface); + + ASSERT_EQ(requests.size(), 1u); + const XCEngine::Math::RectInt renderArea = requests[0].surface.GetRenderArea(); + EXPECT_EQ(renderArea.x, 80); + EXPECT_EQ(renderArea.y, 120); + EXPECT_EQ(renderArea.width, 320); + EXPECT_EQ(renderArea.height, 240); +} + TEST(CameraRenderer_Test, UsesResolvedRenderAreaForCameraViewportDimensions) { Scene scene("CameraRendererViewportRectScene");