From 3c3137258d39910291dbedea6033e182da4ef019 Mon Sep 17 00:00:00 2001 From: hydrogendeuteride Date: Mon, 24 Nov 2025 17:54:39 +0900 Subject: [PATCH] ADD: object movement system --- Readme.md | 4 +- src/core/vk_engine_ui.cpp | 111 +++++++++++++++++++++++++++++++++++--- src/scene/vk_scene.cpp | 33 ++++++++++++ src/scene/vk_scene.h | 3 ++ texture_compression.py | 2 +- 5 files changed, 144 insertions(+), 9 deletions(-) diff --git a/Readme.md b/Readme.md index 6e476e8..3949635 100644 --- a/Readme.md +++ b/Readme.md @@ -6,10 +6,10 @@ Work-In-Progress Vulkan render engine Current structure: - Flexible render graph system with multiple render passes, Hot reloading - Deferred rendering -- PBR (IBL is WIP), cascaded shadows, normal mapping (MikkTSpace tangents optional) +- PBR, cascaded shadows, normal mapping (MikkTSpace tangents optional) - GLTF loading and rendering, primitive creation and rendering. - Supports texture compression(BCn, non glTF standard), LRU reload -- IBL +- Object clicking, generation. Work-In-Progress - [ ] TAA diff --git a/src/core/vk_engine_ui.cpp b/src/core/vk_engine_ui.cpp index a53e3ea..c326f7d 100644 --- a/src/core/vk_engine_ui.cpp +++ b/src/core/vk_engine_ui.cpp @@ -14,6 +14,7 @@ #include "render/vk_renderpass_tonemap.h" #include "render/vk_renderpass_background.h" #include +#include #include "render/rg_graph.h" #include "core/vk_pipeline_manager.h" #include "core/texture_cache.h" @@ -755,7 +756,23 @@ namespace } SceneManager *sceneMgr = eng->_sceneManager.get(); - const GPUSceneData &sceneData = sceneMgr->getSceneData(); + + // Choose a pick to edit: prefer last pick, then hover. + VulkanEngine::PickInfo *pick = nullptr; + if (eng->_lastPick.valid) + { + pick = &eng->_lastPick; + } + else if (eng->_hoverPick.valid) + { + pick = &eng->_hoverPick; + } + + if (!pick || pick->ownerName.empty()) + { + ImGui::TextUnformatted("No selection for gizmo (pick or hover an instance)."); + return; + } static ImGuizmo::OPERATION op = ImGuizmo::TRANSLATE; static ImGuizmo::MODE mode = ImGuizmo::LOCAL; @@ -778,24 +795,106 @@ namespace { None, MeshInstance, - GLTFInstance, - Node + GLTFInstance }; GizmoTarget target = GizmoTarget::None; + if (pick->ownerType == RenderObject::OwnerType::MeshInstance) + { + if (sceneMgr->getMeshInstanceTransform(pick->ownerName, targetTransform)) + { + target = GizmoTarget::MeshInstance; + ImGui::Text("Editing mesh instance: %s", pick->ownerName.c_str()); + } + } + else if (pick->ownerType == RenderObject::OwnerType::GLTFInstance) + { + if (sceneMgr->getGLTFInstanceTransform(pick->ownerName, targetTransform)) + { + target = GizmoTarget::GLTFInstance; + ImGui::Text("Editing glTF instance: %s", pick->ownerName.c_str()); + } + } + + if (target == GizmoTarget::None) + { + ImGui::TextUnformatted("Gizmo only supports dynamic mesh/glTF instances."); + return; + } + ImGuiIO &io = ImGui::GetIO(); ImGuizmo::SetOrthographic(false); ImGuizmo::SetDrawlist(); ImGuizmo::SetRect(0.0f, 0.0f, io.DisplaySize.x, io.DisplaySize.y); - glm::mat4 view = sceneData.view; - glm::mat4 proj = sceneData.proj; + // Build a distance-based perspective projection for ImGuizmo instead of + // using the engine's reversed-Z Vulkan projection. + Camera &cam = sceneMgr->getMainCamera(); + float fovRad = glm::radians(cam.fovDegrees); + VkExtent2D extent = eng->_swapchainManager + ? eng->_swapchainManager->swapchainExtent() + : VkExtent2D{1, 1}; + float aspect = extent.height > 0 + ? static_cast(extent.width) / static_cast(extent.height) + : 1.0f; - proj[1][1] *= -1.0f; + // Distance from camera to object; clamp to avoid degenerate planes. + glm::vec3 camPos = cam.position; + glm::vec3 objPos = pick->worldPos; + float dist = glm::length(objPos - camPos); + if (!std::isfinite(dist) || dist <= 0.0f) + { + dist = 1.0f; + } + // Near/far based on distance: keep ratio reasonable for precision. + float nearPlane = glm::max(0.05f, dist * 0.05f); + float farPlane = glm::max(nearPlane * 50.0f, dist * 2.0f); + + glm::mat4 view = cam.getViewMatrix(); + glm::mat4 proj = glm::perspective(fovRad, aspect, nearPlane, farPlane); + + glm::mat4 before = targetTransform; + + ImDrawList* dl = ImGui::GetForegroundDrawList(); + ImGuizmo::SetDrawlist(dl); + + ImGuizmo::SetRect(0.0f, 0.0f, io.DisplaySize.x, io.DisplaySize.y); ImGuizmo::Manipulate(&view[0][0], &proj[0][0], op, mode, &targetTransform[0][0]); + + bool changed = false; + for (int c = 0; c < 4 && !changed; ++c) + { + for (int r = 0; r < 4; ++r) + { + if (before[c][r] != targetTransform[c][r]) + { + changed = true; + break; + } + } + } + + if (changed) + { + switch (target) + { + case GizmoTarget::MeshInstance: + sceneMgr->setMeshInstanceTransform(pick->ownerName, targetTransform); + break; + case GizmoTarget::GLTFInstance: + sceneMgr->setGLTFInstanceTransform(pick->ownerName, targetTransform); + break; + default: + break; + } + + // Keep pick debug info roughly in sync. + pick->worldTransform = targetTransform; + pick->worldPos = glm::vec3(targetTransform[3]); + } } } // namespace diff --git a/src/scene/vk_scene.cpp b/src/scene/vk_scene.cpp index 494172d..ae385fc 100644 --- a/src/scene/vk_scene.cpp +++ b/src/scene/vk_scene.cpp @@ -344,6 +344,28 @@ void SceneManager::addMeshInstance(const std::string &name, std::shared_ptrsecond.transform; + return true; +} + +bool SceneManager::setMeshInstanceTransform(const std::string &name, const glm::mat4 &transform) +{ + auto it = dynamicMeshInstances.find(name); + if (it == dynamicMeshInstances.end()) + { + return false; + } + it->second.transform = transform; + return true; +} + bool SceneManager::removeMeshInstance(const std::string &name) { return dynamicMeshInstances.erase(name) > 0; @@ -391,6 +413,17 @@ bool SceneManager::removeGLTFInstance(const std::string &name) return true; } +bool SceneManager::getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform) +{ + auto it = dynamicGLTFInstances.find(name); + if (it == dynamicGLTFInstances.end()) + { + return false; + } + outTransform = it->second.transform; + return true; +} + bool SceneManager::setGLTFInstanceTransform(const std::string &name, const glm::mat4 &transform) { auto it = dynamicGLTFInstances.find(name); diff --git a/src/scene/vk_scene.h b/src/scene/vk_scene.h index 573e9e5..dfb2a09 100644 --- a/src/scene/vk_scene.h +++ b/src/scene/vk_scene.h @@ -95,6 +95,8 @@ public: void addMeshInstance(const std::string &name, std::shared_ptr mesh, const glm::mat4 &transform = glm::mat4(1.f), std::optional boundsType = {}); + bool getMeshInstanceTransform(const std::string &name, glm::mat4 &outTransform); + bool setMeshInstanceTransform(const std::string &name, const glm::mat4 &transform); bool removeMeshInstance(const std::string &name); void clearMeshInstances(); @@ -108,6 +110,7 @@ public: void addGLTFInstance(const std::string &name, std::shared_ptr scene, const glm::mat4 &transform = glm::mat4(1.f)); bool removeGLTFInstance(const std::string &name); + bool getGLTFInstanceTransform(const std::string &name, glm::mat4 &outTransform); bool setGLTFInstanceTransform(const std::string &name, const glm::mat4 &transform); void clearGLTFInstances(); diff --git a/texture_compression.py b/texture_compression.py index ef8dedd..e5c0505 100644 --- a/texture_compression.py +++ b/texture_compression.py @@ -59,7 +59,7 @@ def parse_gltf_roles(gltf_path: Path): def mark(uri, role): if not uri: return - # normal > albedo > mr 우선 + prio = {"normal": 3, "albedo": 2, "mr": 1} old = roles.get(uri) if old is None or prio[role] > prio.get(old, 0):