refactor: extract viewport object id picker

This commit is contained in:
2026-04-01 20:24:17 +08:00
parent 6cd4cd9be9
commit 1af958a272
4 changed files with 236 additions and 37 deletions

View File

@@ -6,6 +6,7 @@
#include "IViewportHostService.h"
#include "SceneViewportPicker.h"
#include "SceneViewportCameraController.h"
#include "ViewportObjectIdPicker.h"
#include "ViewportHostSurfaceUtils.h"
#include "UI/ImGuiBackendBridge.h"
@@ -15,7 +16,6 @@
#include <XCEngine/RHI/RHIEnums.h>
#include <XCEngine/RHI/RHIResourceView.h>
#include <XCEngine/RHI/RHITexture.h>
#include <XCEngine/Rendering/ObjectIdEncoding.h>
#include <XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h>
#include <XCEngine/Rendering/Passes/BuiltinSceneViewPostPassPlan.h>
#include <XCEngine/Rendering/Passes/BuiltinObjectIdOutlinePass.h>
@@ -876,46 +876,34 @@ private:
const ImVec2& viewportSize,
const ImVec2& viewportMousePosition,
uint64_t& outEntityId) {
outEntityId = 0;
if (m_device == nullptr ||
m_sceneViewLastRenderContext.commandQueue == nullptr ||
entry.objectIdTexture == nullptr ||
!entry.hasValidObjectIdFrame ||
viewportSize.x <= 1.0f ||
viewportSize.y <= 1.0f ||
viewportMousePosition.x < 0.0f ||
viewportMousePosition.y < 0.0f ||
viewportMousePosition.x > viewportSize.x ||
viewportMousePosition.y > viewportSize.y) {
if (m_device == nullptr) {
outEntityId = 0;
return false;
}
auto* commandQueue =
m_sceneViewLastRenderContext.commandQueue;
if (commandQueue == nullptr) {
return false;
}
ViewportObjectIdPickContext pickContext = {};
pickContext.commandQueue = m_sceneViewLastRenderContext.commandQueue;
pickContext.texture = entry.objectIdTexture;
pickContext.textureState = entry.objectIdState;
pickContext.textureWidth = entry.width;
pickContext.textureHeight = entry.height;
pickContext.hasValidFrame = entry.hasValidObjectIdFrame;
pickContext.viewportSize = viewportSize;
pickContext.viewportMousePosition = viewportMousePosition;
const uint32_t pixelX = ClampViewportPixelCoordinate(viewportMousePosition.x, entry.width);
const uint32_t pixelY = ClampViewportPixelCoordinate(viewportMousePosition.y, entry.height);
std::array<uint8_t, 4> rgba = {};
if (!m_device->ReadTexturePixelRGBA8(
commandQueue,
entry.objectIdTexture,
entry.objectIdState,
pixelX,
pixelY,
rgba)) {
return false;
}
outEntityId = static_cast<uint64_t>(Rendering::DecodeObjectIdFromColor(
rgba[0],
rgba[1],
rgba[2],
rgba[3]));
return true;
return TryPickViewportObjectIdEntity(
pickContext,
[this](const ViewportObjectIdReadbackRequest& request, std::array<uint8_t, 4>& outRgba) {
return m_device != nullptr &&
m_device->ReadTexturePixelRGBA8(
request.commandQueue,
request.texture,
request.textureState,
request.pixelX,
request.pixelY,
outRgba);
},
outEntityId);
}
void DestroyViewportResources(ViewportEntry& entry) {

View File

@@ -0,0 +1,95 @@
#pragma once
#include "ViewportHostSurfaceUtils.h"
#include <XCEngine/RHI/RHICommandQueue.h>
#include <XCEngine/RHI/RHIEnums.h>
#include <XCEngine/RHI/RHITexture.h>
#include <XCEngine/Rendering/ObjectIdEncoding.h>
#include <array>
#include <cstdint>
namespace XCEngine {
namespace Editor {
struct ViewportObjectIdPickContext {
RHI::RHICommandQueue* commandQueue = nullptr;
RHI::RHITexture* texture = nullptr;
RHI::ResourceStates textureState = RHI::ResourceStates::Common;
uint32_t textureWidth = 0;
uint32_t textureHeight = 0;
bool hasValidFrame = false;
ImVec2 viewportSize = ImVec2(0.0f, 0.0f);
ImVec2 viewportMousePosition = ImVec2(0.0f, 0.0f);
};
struct ViewportObjectIdReadbackRequest {
RHI::RHICommandQueue* commandQueue = nullptr;
RHI::RHITexture* texture = nullptr;
RHI::ResourceStates textureState = RHI::ResourceStates::Common;
uint32_t pixelX = 0;
uint32_t pixelY = 0;
};
inline bool CanPickViewportObjectId(const ViewportObjectIdPickContext& context) {
return context.commandQueue != nullptr &&
context.texture != nullptr &&
context.textureWidth > 0 &&
context.textureHeight > 0 &&
context.hasValidFrame &&
context.viewportSize.x > 1.0f &&
context.viewportSize.y > 1.0f &&
context.viewportMousePosition.x >= 0.0f &&
context.viewportMousePosition.y >= 0.0f &&
context.viewportMousePosition.x <= context.viewportSize.x &&
context.viewportMousePosition.y <= context.viewportSize.y;
}
inline bool BuildViewportObjectIdReadbackRequest(
const ViewportObjectIdPickContext& context,
ViewportObjectIdReadbackRequest& outRequest) {
outRequest = {};
if (!CanPickViewportObjectId(context)) {
return false;
}
outRequest.commandQueue = context.commandQueue;
outRequest.texture = context.texture;
outRequest.textureState = context.textureState;
outRequest.pixelX = ClampViewportPixelCoordinate(
context.viewportMousePosition.x,
context.textureWidth);
outRequest.pixelY = ClampViewportPixelCoordinate(
context.viewportMousePosition.y,
context.textureHeight);
return true;
}
template <typename ReadPixelFn>
bool TryPickViewportObjectIdEntity(
const ViewportObjectIdPickContext& context,
ReadPixelFn&& readPixel,
uint64_t& outEntityId) {
outEntityId = 0;
ViewportObjectIdReadbackRequest request = {};
if (!BuildViewportObjectIdReadbackRequest(context, request)) {
return false;
}
std::array<uint8_t, 4> rgba = {};
if (!readPixel(request, rgba)) {
return false;
}
outEntityId = static_cast<uint64_t>(Rendering::DecodeObjectIdFromColor(
rgba[0],
rgba[1],
rgba[2],
rgba[3]));
return true;
}
} // namespace Editor
} // namespace XCEngine