feat: add gpu object id scene picking

This commit is contained in:
2026-04-01 16:44:11 +08:00
parent 6e2711f9e8
commit 6927b4b380
10 changed files with 1030 additions and 3 deletions

View File

@@ -2,6 +2,7 @@
#include <XCEngine/Components/CameraComponent.h>
#include <XCEngine/Rendering/CameraRenderer.h>
#include <XCEngine/Rendering/ObjectIdPass.h>
#include <XCEngine/Rendering/RenderPipelineAsset.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/SceneRenderer.h>
@@ -100,6 +101,32 @@ private:
std::shared_ptr<MockPipelineAssetState> m_state;
};
class MockObjectIdPass final : public ObjectIdPass {
public:
MockObjectIdPass(
std::shared_ptr<MockPipelineState> state,
bool renderResult = true)
: m_state(std::move(state))
, m_renderResult(renderResult) {
}
bool Render(
const RenderContext&,
const RenderSurface&,
const RenderSceneData&) override {
m_state->eventLog.push_back("objectId");
return m_renderResult;
}
void Shutdown() override {
m_state->eventLog.push_back("shutdown:objectId");
}
private:
std::shared_ptr<MockPipelineState> m_state;
bool m_renderResult = true;
};
class TrackingPass final : public RenderPass {
public:
TrackingPass(
@@ -227,6 +254,51 @@ TEST(CameraRenderer_Test, ExecutesInjectedPreAndPostPassSequencesAroundPipelineR
"shutdown:pre" }));
}
TEST(CameraRenderer_Test, ExecutesObjectIdPassBetweenPipelineAndPostPassesWhenRequested) {
Scene scene("CameraRendererObjectIdPassScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(3.0f);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::make_unique<MockObjectIdPass>(state));
RenderPassSequence prePasses;
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
RenderPassSequence postPasses;
postPasses.AddPass(std::make_unique<TrackingPass>(state, "post"));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(320, 180);
request.cameraDepth = camera->GetDepth();
request.preScenePasses = &prePasses;
request.postScenePasses = &postPasses;
request.objectId.surface = RenderSurface(320, 180);
request.objectId.surface.SetColorAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1));
request.objectId.surface.SetDepthAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(2));
ASSERT_TRUE(renderer.Render(request));
EXPECT_EQ(
state->eventLog,
(std::vector<std::string>{
"init:pre",
"pre",
"pipeline",
"objectId",
"init:post",
"post",
"shutdown:post",
"shutdown:pre" }));
}
TEST(CameraRenderer_Test, ShutsDownInitializedPassesWhenPipelineRenderFails) {
Scene scene("CameraRendererFailureScene");
@@ -256,6 +328,43 @@ TEST(CameraRenderer_Test, ShutsDownInitializedPassesWhenPipelineRenderFails) {
(std::vector<std::string>{ "init:pre", "pre", "pipeline", "shutdown:pre" }));
}
TEST(CameraRenderer_Test, StopsRenderingWhenObjectIdPassFails) {
Scene scene("CameraRendererObjectIdFailureScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(2.0f);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::make_unique<MockObjectIdPass>(state, false));
RenderPassSequence prePasses;
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
RenderPassSequence postPasses;
postPasses.AddPass(std::make_unique<TrackingPass>(state, "post"));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(320, 180);
request.cameraDepth = camera->GetDepth();
request.preScenePasses = &prePasses;
request.postScenePasses = &postPasses;
request.objectId.surface = RenderSurface(320, 180);
request.objectId.surface.SetColorAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1));
request.objectId.surface.SetDepthAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(2));
EXPECT_FALSE(renderer.Render(request));
EXPECT_EQ(
state->eventLog,
(std::vector<std::string>{ "init:pre", "pre", "pipeline", "objectId", "shutdown:pre" }));
}
TEST(CameraRenderer_Test, ShutsDownSequencesWhenPostPassInitializationFails) {
Scene scene("CameraRendererPostPassInitFailureScene");