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

@@ -13,11 +13,29 @@ class Scene;
namespace Rendering {
struct ObjectIdRenderRequest {
RenderSurface surface;
bool IsRequested() const {
return !surface.GetColorAttachments().empty();
}
bool IsValid() const {
const std::vector<RHI::RHIResourceView*>& colorAttachments = surface.GetColorAttachments();
return !colorAttachments.empty() &&
colorAttachments[0] != nullptr &&
surface.GetDepthAttachment() != nullptr &&
surface.GetRenderAreaWidth() > 0 &&
surface.GetRenderAreaHeight() > 0;
}
};
struct CameraRenderRequest {
const Components::Scene* scene = nullptr;
Components::CameraComponent* camera = nullptr;
RenderContext context;
RenderSurface surface;
ObjectIdRenderRequest objectId;
float cameraDepth = 0.0f;
uint8_t cameraStackOrder = 0;
RenderClearFlags clearFlags = RenderClearFlags::All;

View File

@@ -1,6 +1,7 @@
#pragma once
#include <XCEngine/Rendering/CameraRenderRequest.h>
#include <XCEngine/Rendering/ObjectIdPass.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include <memory>
@@ -21,12 +22,17 @@ public:
CameraRenderer();
explicit CameraRenderer(std::unique_ptr<RenderPipeline> pipeline);
explicit CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
CameraRenderer(
std::unique_ptr<RenderPipeline> pipeline,
std::unique_ptr<ObjectIdPass> objectIdPass);
~CameraRenderer();
void SetPipeline(std::unique_ptr<RenderPipeline> pipeline);
void SetPipelineAsset(std::shared_ptr<const RenderPipelineAsset> pipelineAsset);
void SetObjectIdPass(std::unique_ptr<ObjectIdPass> objectIdPass);
RenderPipeline* GetPipeline() const { return m_pipeline.get(); }
const RenderPipelineAsset* GetPipelineAsset() const { return m_pipelineAsset.get(); }
ObjectIdPass* GetObjectIdPass() const { return m_objectIdPass.get(); }
bool Render(const CameraRenderRequest& request);
@@ -36,6 +42,7 @@ private:
RenderSceneExtractor m_sceneExtractor;
std::shared_ptr<const RenderPipelineAsset> m_pipelineAsset;
std::unique_ptr<RenderPipeline> m_pipeline;
std::unique_ptr<ObjectIdPass> m_objectIdPass;
};
} // namespace Rendering

View File

@@ -0,0 +1,32 @@
#pragma once
#include <XCEngine/Core/Math/Vector4.h>
#include <cstdint>
namespace XCEngine {
namespace Rendering {
inline uint32_t EncodeObjectIdToUInt32(uint64_t objectId) {
return static_cast<uint32_t>(objectId & 0xFFFFFFFFull);
}
inline Math::Vector4 EncodeObjectIdToColor(uint64_t objectId) {
const uint32_t encodedId = EncodeObjectIdToUInt32(objectId);
constexpr float kInv255 = 1.0f / 255.0f;
return Math::Vector4(
static_cast<float>((encodedId >> 0) & 0xFFu) * kInv255,
static_cast<float>((encodedId >> 8) & 0xFFu) * kInv255,
static_cast<float>((encodedId >> 16) & 0xFFu) * kInv255,
static_cast<float>((encodedId >> 24) & 0xFFu) * kInv255);
}
inline uint32_t DecodeObjectIdFromColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return static_cast<uint32_t>(r) |
(static_cast<uint32_t>(g) << 8u) |
(static_cast<uint32_t>(b) << 16u) |
(static_cast<uint32_t>(a) << 24u);
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,24 @@
#pragma once
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSceneExtractor.h>
#include <XCEngine/Rendering/RenderSurface.h>
namespace XCEngine {
namespace Rendering {
class ObjectIdPass {
public:
virtual ~ObjectIdPass() = default;
virtual bool Render(
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) = 0;
virtual void Shutdown() {
}
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,58 @@
#pragma once
#include <XCEngine/Rendering/ObjectIdPass.h>
#include <XCEngine/Rendering/ObjectIdEncoding.h>
#include <XCEngine/Rendering/RenderResourceCache.h>
#include <unordered_map>
namespace XCEngine {
namespace Rendering {
namespace Passes {
class BuiltinObjectIdPass final : public ObjectIdPass {
public:
~BuiltinObjectIdPass() override;
bool Render(
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData) override;
void Shutdown() override;
private:
struct PerObjectConstants {
Math::Matrix4x4 projection = Math::Matrix4x4::Identity();
Math::Matrix4x4 view = Math::Matrix4x4::Identity();
Math::Matrix4x4 model = Math::Matrix4x4::Identity();
Math::Vector4 objectIdColor = Math::Vector4::Zero();
};
struct OwnedDescriptorSet {
RHI::RHIDescriptorPool* pool = nullptr;
RHI::RHIDescriptorSet* set = nullptr;
};
bool EnsureInitialized(const RenderContext& context);
bool CreateResources(const RenderContext& context);
void DestroyResources();
RHI::RHIDescriptorSet* GetOrCreatePerObjectSet(uint64_t objectId);
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
bool DrawVisibleItem(
const RenderContext& context,
const RenderSceneData& sceneData,
const VisibleRenderItem& visibleItem);
RHI::RHIDevice* m_device = nullptr;
RHI::RHIType m_backendType = RHI::RHIType::D3D12;
RHI::RHIPipelineLayout* m_pipelineLayout = nullptr;
RHI::RHIPipelineState* m_pipelineState = nullptr;
RenderResourceCache m_resourceCache;
std::unordered_map<uint64_t, OwnedDescriptorSet> m_perObjectSets;
};
} // namespace Passes
} // namespace Rendering
} // namespace XCEngine