ADD: object movement system

This commit is contained in:
2025-11-24 17:54:39 +09:00
parent 7ec4b16502
commit 3c3137258d
5 changed files with 144 additions and 9 deletions

View File

@@ -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

View File

@@ -14,6 +14,7 @@
#include "render/vk_renderpass_tonemap.h"
#include "render/vk_renderpass_background.h"
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtc/matrix_transform.hpp>
#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<float>(extent.width) / static_cast<float>(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

View File

@@ -344,6 +344,28 @@ void SceneManager::addMeshInstance(const std::string &name, std::shared_ptr<Mesh
dynamicMeshInstances[name] = std::move(inst);
}
bool SceneManager::getMeshInstanceTransform(const std::string &name, glm::mat4 &outTransform)
{
auto it = dynamicMeshInstances.find(name);
if (it == dynamicMeshInstances.end())
{
return false;
}
outTransform = it->second.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);

View File

@@ -95,6 +95,8 @@ public:
void addMeshInstance(const std::string &name, std::shared_ptr<MeshAsset> mesh,
const glm::mat4 &transform = glm::mat4(1.f),
std::optional<BoundsType> 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<LoadedGLTF> 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();

View File

@@ -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):