feat: add camera viewport rect render areas

This commit is contained in:
2026-04-01 13:01:11 +08:00
parent 0fe02fd1b4
commit f80fb9860e
9 changed files with 219 additions and 12 deletions

View File

@@ -23,6 +23,12 @@ struct MockPipelineState {
bool renderResult = true;
uint32_t lastSurfaceWidth = 0;
uint32_t lastSurfaceHeight = 0;
int32_t lastRenderAreaX = 0;
int32_t lastRenderAreaY = 0;
int32_t lastRenderAreaWidth = 0;
int32_t lastRenderAreaHeight = 0;
uint32_t lastCameraViewportWidth = 0;
uint32_t lastCameraViewportHeight = 0;
CameraComponent* lastCamera = nullptr;
size_t lastVisibleItemCount = 0;
RenderClearFlags lastClearFlags = RenderClearFlags::All;
@@ -59,7 +65,14 @@ public:
++m_state->renderCalls;
m_state->lastSurfaceWidth = surface.GetWidth();
m_state->lastSurfaceHeight = surface.GetHeight();
const XCEngine::Math::RectInt renderArea = surface.GetRenderArea();
m_state->lastRenderAreaX = renderArea.x;
m_state->lastRenderAreaY = renderArea.y;
m_state->lastRenderAreaWidth = renderArea.width;
m_state->lastRenderAreaHeight = renderArea.height;
m_state->lastCamera = sceneData.camera;
m_state->lastCameraViewportWidth = sceneData.cameraData.viewportWidth;
m_state->lastCameraViewportHeight = sceneData.cameraData.viewportHeight;
m_state->lastVisibleItemCount = sceneData.visibleItems.size();
m_state->lastClearFlags = sceneData.cameraData.clearFlags;
m_state->renderedCameras.push_back(sceneData.camera);
@@ -163,6 +176,12 @@ TEST(CameraRenderer_Test, UsesOverrideCameraAndSurfaceSizeWhenSubmittingScene) {
EXPECT_EQ(state->renderCalls, 1);
EXPECT_EQ(state->lastSurfaceWidth, 640u);
EXPECT_EQ(state->lastSurfaceHeight, 480u);
EXPECT_EQ(state->lastRenderAreaX, 0);
EXPECT_EQ(state->lastRenderAreaY, 0);
EXPECT_EQ(state->lastRenderAreaWidth, 640);
EXPECT_EQ(state->lastRenderAreaHeight, 480);
EXPECT_EQ(state->lastCameraViewportWidth, 640u);
EXPECT_EQ(state->lastCameraViewportHeight, 480u);
EXPECT_EQ(state->lastCamera, overrideCamera);
EXPECT_NE(state->lastCamera, primaryCamera);
EXPECT_EQ(state->lastVisibleItemCount, 0u);
@@ -330,6 +349,54 @@ TEST(SceneRenderer_Test, HonorsExplicitOverrideCameraClearMode) {
EXPECT_EQ(requests[0].clearFlags, RenderClearFlags::Depth);
}
TEST(SceneRenderer_Test, ResolvesNormalizedCameraViewportRectToPerRequestRenderArea) {
Scene scene("SceneRendererViewportRectScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
camera->SetViewportRect(XCEngine::Math::Rect(0.25f, 0.1f, 0.5f, 0.4f));
SceneRenderer renderer;
const std::vector<CameraRenderRequest> requests =
renderer.BuildRenderRequests(scene, nullptr, CreateValidContext(), RenderSurface(800, 600));
ASSERT_EQ(requests.size(), 1u);
const XCEngine::Math::RectInt renderArea = requests[0].surface.GetRenderArea();
EXPECT_EQ(renderArea.x, 200);
EXPECT_EQ(renderArea.y, 60);
EXPECT_EQ(renderArea.width, 400);
EXPECT_EQ(renderArea.height, 240);
}
TEST(CameraRenderer_Test, UsesResolvedRenderAreaForCameraViewportDimensions) {
Scene scene("CameraRendererViewportRectScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetViewportRect(XCEngine::Math::Rect(0.125f, 0.25f, 0.5f, 0.5f));
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(std::make_unique<MockPipeline>(state));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(640, 480);
request.surface.SetRenderArea(XCEngine::Math::RectInt(80, 120, 320, 240));
ASSERT_TRUE(renderer.Render(request));
EXPECT_EQ(state->lastRenderAreaX, 80);
EXPECT_EQ(state->lastRenderAreaY, 120);
EXPECT_EQ(state->lastRenderAreaWidth, 320);
EXPECT_EQ(state->lastRenderAreaHeight, 240);
EXPECT_EQ(state->lastCameraViewportWidth, 320u);
EXPECT_EQ(state->lastCameraViewportHeight, 240u);
}
TEST(SceneRenderer_Test, ForwardsPipelineLifetimeAndRenderCallsToCameraRenderer) {
Scene scene("SceneRendererScene");