From 710d63ad9897b9b008c8f7353f854a08516252d6 Mon Sep 17 00:00:00 2001 From: antopilo Date: Mon, 14 Apr 2025 21:11:26 -0400 Subject: [PATCH] Added mouse picking --- .../SceneEditor/Widgets/ViewportWidget.cpp | 30 +++++++++++++- Nuake/Source/Nuake/Rendering/Vulkan/Cmd.cpp | 26 ++++++++++++ Nuake/Source/Nuake/Rendering/Vulkan/Cmd.h | 3 ++ .../Vulkan/Pipeline/RenderPipeline.cpp | 37 ----------------- .../Rendering/Vulkan/SceneRenderPipeline.cpp | 41 ++++++++++++++++--- .../Rendering/Vulkan/SceneRenderPipeline.h | 16 +++++++- .../Nuake/Rendering/Vulkan/SceneViewport.cpp | 2 - 7 files changed, 108 insertions(+), 47 deletions(-) diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp index c7b1015a..c0909d10 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/ViewportWidget.cpp @@ -9,6 +9,8 @@ #include "Nuake/Rendering/Vulkan/SceneViewport.h" #include "Nuake/Rendering/Vulkan/DebugCmd.h" +#include "Nuake/Rendering/Vulkan/SceneRenderPipeline.h" + #include #include #include @@ -85,7 +87,9 @@ void ViewportWidget::Draw() ImGui::Image(textureDesc, regionAvail, { 0, 1 }, { 1, 0 }); ImGui::PopStyleVar(); - const Vector2& mousePos = Input::GetMousePosition(); + float title_bar_height = ImGui::GetFontSize() + ImGui::GetStyle().FramePadding.y * 2; + Vector2 mousePos = Input::GetMousePosition(); + mousePos.y -= title_bar_height; const ImVec2& windowPos = ImGui::GetWindowPos(); const auto windowPosNuake = Vector2(windowPos.x, windowPos.y); @@ -93,6 +97,8 @@ void ViewportWidget::Draw() const bool isInsideWidth = mousePos.x > windowPos.x && mousePos.x < windowPos.x + windowSize.x; const bool isInsideHeight = mousePos.y > windowPos.y && mousePos.y < windowPos.y + windowSize.y; this->isHoveringViewport = isInsideWidth && isInsideHeight; + auto pixelPos = (mousePos - windowPosNuake) * Engine::GetProject()->Settings.ResolutionScale; + // TODO(antopilo) drag n drop ImGuizmo::SetDrawlist(); @@ -187,6 +193,28 @@ void ViewportWidget::Draw() } } + if (!Engine::IsPlayMode() && !ImGuizmo::IsUsing() && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && ImGui::GetIO().WantCaptureMouse && isHoveringViewport) + { + auto& sceneRenderer = VkRenderer::Get().SceneRenderers[sceneViewport->GetID()]; + sceneRenderer->sceneRenderPipeline->MousePick(pixelPos, [&](uint32_t picked) + { + Logger::Log("Mouse Picked: " + std::to_string(picked)); + + constexpr uint32_t INVALID_PICK_ID = 4187593120; + if (picked != INVALID_PICK_ID) + { + Nuake::Entity entity = Nuake::Entity((entt::entity)picked, editorContext.GetScene().get()); + if (entity.IsValid()) + { + editorContext.SetSelection(entity); + } + } + else + { + editorContext.SetSelection(EditorSelection()); + } + }); + } } else { diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.cpp index f42fbdf5..e3d146b7 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.cpp @@ -1,4 +1,5 @@ #include "Cmd.h" +#include "VulkanAllocatedBuffer.h" using namespace Nuake; @@ -153,6 +154,31 @@ void Cmd::CopyImageToImage(Ref src, Ref dst) const vkCmdBlitImage2(CmdBuffer, &blitInfo); } +void Cmd::CopyImageToBuffer(Ref src, Ref dst, const Vector2& offset, const Vector3& extent) const +{ + VkBufferImageCopy copyRegion{}; + copyRegion.bufferOffset = 0; + copyRegion.bufferRowLength = 0; // tightly packed + copyRegion.bufferImageHeight = 0; + + copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.imageSubresource.mipLevel = 0; + copyRegion.imageSubresource.baseArrayLayer = 0; + copyRegion.imageSubresource.layerCount = 1; + + copyRegion.imageOffset = { (int)offset.x, (int)offset.y, 0 }; // pixel offset (e.g. { mouseX, mouseY, 0 }) + copyRegion.imageExtent = { (uint32_t)extent.x, (uint32_t)extent.y, 1 }; // pixel size (e.g. { 1, 1, 1 } for one pixel) + + vkCmdCopyImageToBuffer( + CmdBuffer, + src->GetImage(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst->GetBuffer(), + 1, + ©Region + ); +} + void Cmd::SetLineRasterizationMode(VkLineRasterizationMode mode) const { vkCmdSetLineRasterizationModeEXT(CmdBuffer, mode); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.h b/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.h index c388a0e7..52978533 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/Cmd.h @@ -6,6 +6,8 @@ namespace Nuake { + class AllocatedBuffer; + class Cmd { private: @@ -32,6 +34,7 @@ namespace Nuake void DrawIndexed(uint32_t count) const; void PushConstants(VkPipelineLayout pipeline, size_t size, void* data ) const; void CopyBuffer(VkBuffer src, VkBuffer dst, size_t size) const; + void CopyImageToBuffer(Ref src, Ref dst, const Vector2& offset, const Vector3& extent = {1, 1, 1}) const; void TransitionImageLayout(Ref img, VkImageLayout layout) const; void CopyImageToImage(Ref src, Ref dst) const; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp index 335e01b1..28e54973 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/Pipeline/RenderPipeline.cpp @@ -327,43 +327,6 @@ bool RenderPipeline::Build() for (auto& pass : RenderPasses) { pass.Build(); - - //for (auto& input : pass.GetInputs()) - //{ - // bool alreadyFoundAttachment = false; - // if (attachments.find(input) == attachments.end()) - // { - // if (pass.GetDepthAttachment().Image && pass.GetDepthAttachment().Name == input) - // { - // pass.SetInput(input, pass.GetDepthAttachment()); - // alreadyFoundAttachment = true; - // } - // else - // { - // Logger::Log("Failed to build RenderPipeline. input " + input + " not found in previous passes.", "vulkan", CRITICAL); - // return false; - // } - // } - // - // if (!alreadyFoundAttachment) - // { - // pass.SetInput(input, attachments[input]); - // } - //} - - //for (auto& attachment : pass.GetAttachments()) - //{ - // attachments[attachment.Name] = attachment; - //} - // - //if (pass.GetDepthAttachment().Image) - //{ - // attachments[pass.GetDepthAttachment().Name] = pass.GetDepthAttachment(); - //} - } - - for (auto& pass : RenderPasses) - { } Built = true; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp index d481e9e1..bebad4c9 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -196,7 +196,7 @@ SceneRenderPipeline::SceneRenderPipeline() TonemappedOutput = CreateRef(ImageFormat::RGBA8, defaultSize); TonemappedOutput->SetDebugName("TonemappedOutput"); - GBufferEntityID = CreateRef(ImageFormat::RGBA16F, defaultSize); + GBufferEntityID = CreateRef(ImageFormat::RGBA32F, defaultSize); GBufferEntityID->SetDebugName("GBufferEntityID"); OutlineOutput = CreateRef(ImageFormat::RGBA8, defaultSize); @@ -268,11 +268,41 @@ void SceneRenderPipeline::Render(PassRenderContext& ctx) { GizmoOutput, GBufferEntityID, GBufferDepth }, // Reusing depth from gBuffer { GizmoCombineOutput }, { OutlineOutput }, - { LineCombineOutput }, { LineOutput, GBufferDepth }, + { LineCombineOutput }, }; GBufferPipeline.Execute(ctx, pipelineInputs); + + // Mouse Picking requests + if (!mousePickingRequests.empty()) + { + for (auto& request : mousePickingRequests) + { + size_t bufferSize = sizeof(Vector4); + Ref stagingBuffer = CreateRef(bufferSize, BufferUsage::TRANSFER_DST, MemoryUsage::GPU_TO_CPU); + + assert(request.mousePosition.x < GBufferEntityID->GetSize().x && request.mousePosition.y < GBufferEntityID->GetSize().y && "Mouse coord out of bounds"); + request.mousePosition.y = GBufferEntityID->GetSize().y - request.mousePosition.y; + + VkRenderer::Get().ImmediateSubmit([&](VkCommandBuffer cmd) + { + Cmd command(cmd); + command.TransitionImageLayout(GBufferEntityID, VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + command.CopyImageToBuffer(GBufferEntityID, stagingBuffer, request.mousePosition); + command.TransitionImageLayout(GBufferEntityID, VkImageLayout::VK_IMAGE_LAYOUT_GENERAL); + }); + + void* mappedData; + vmaMapMemory(VulkanAllocator::Get().GetAllocator(), stagingBuffer->GetAllocation(), &mappedData); + Vector4 entityID = *reinterpret_cast(mappedData); + vmaUnmapMemory(VulkanAllocator::Get().GetAllocator(), stagingBuffer->GetAllocation()); + + request.callback(static_cast(entityID.r)); + } + + mousePickingRequests.clear(); + } } void SceneRenderPipeline::RecreatePipeline() @@ -709,10 +739,11 @@ void SceneRenderPipeline::RecreatePipeline() GBufferPipeline.Build(); } -int SceneRenderPipeline::MousePick(const Vector2& coord) +void SceneRenderPipeline::MousePick(const Vector2& coord, MousePickingCb mousePickingCb) { - GBufferEntityID->GetImage(); - return 0; + assert(coord.x > 0 && coord.y > 0 && "Mouse coords out of bounds"); + + mousePickingRequests.push_back({ coord, std::move(mousePickingCb) }); } Ref SceneRenderPipeline::ResizeImage(PassRenderContext& ctx, Ref image, const Vector2& size) diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h index d2a1f052..c0b5f194 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.h @@ -9,6 +9,8 @@ #include "Nuake/Core/MulticastDelegate.h" #include "Constant/LineConstant.h" +#include + namespace Nuake { struct GBufferConstant @@ -118,6 +120,14 @@ namespace Nuake class DebugCmd; class DebugLineCmd; + using MousePickingCb = std::function; + + struct MousePickingRequest + { + Vector2 mousePosition; + MousePickingCb callback; + }; + // This class handles all the rendering of the scene class SceneRenderPipeline { @@ -127,6 +137,8 @@ namespace Nuake static std::vector ssaoKernelSamples; static Ref ssaoNoiseTexture; + std::vector mousePickingRequests; + // Attachments GBuffer Ref GBufferAlbedo; Ref GBufferDepth; @@ -184,14 +196,14 @@ namespace Nuake void SetCamera(UUID camera); void Render(PassRenderContext& ctx); - Ref GetOutput() { return OutlineOutput; } + Ref GetOutput() { return LineCombineOutput; } MulticastDelegate& OnDebugDraw() { return DebugDrawDelegate; } MulticastDelegate& OnLineDraw() { return DebugLineDrawDelegate; } void RecreatePipeline(); - int MousePick(const Vector2& coord); + void MousePick(const Vector2& coord, MousePickingCb mousePickingCb); private: Ref ResizeImage(PassRenderContext& ctx, Ref image, const Vector2& size); }; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.cpp index 5cc16390..f7e87d1b 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneViewport.cpp @@ -18,8 +18,6 @@ Viewport::Viewport(UUID inViewId, const Vector2& inViewportSize) : int Viewport::MousePick(const Vector2& mouseCoord) { - auto& sceneRenderer = VkRenderer::Get().SceneRenderers[id]; - int result = sceneRenderer->sceneRenderPipeline->MousePick(mouseCoord); return 0;