From a1308502764b23910e5680590588adf64950eb3c Mon Sep 17 00:00:00 2001 From: atdunbg Date: Sat, 3 Oct 2026 12:03:07 +0800 Subject: [PATCH] =?UTF-8?q?feat(editor):=20Gizmo=20=E9=80=80=E5=8C=96?= =?UTF-8?q?=E8=BD=B4=E8=87=AA=E5=8A=A8=E9=9A=90=E8=97=8F=EF=BC=88=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=B1=82=20SetAxisMask=EF=BC=8CUE=20=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 正对视角 + 物体竖直偏移时,单轴拖拽灵敏度 sinθ(轴与相机连线夹角)→0: 拖拽投影系数趋 0("数值不变"),激活平面与鼠标射线共面(IntersectRayPlane denom→0 返回 -1 被当交点距离)。按灵敏度 <0.25(θ<14.5°)将病态轴 SetAxisMask 隐藏(库公开 API,按轴关绘制+激活,保留含该轴的平面手柄 与中心块兜底),相机移动后自动恢复——可激活性决定可见性,零库改动。 --- App/editor/ViewportPanel.cpp | 37 +++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/App/editor/ViewportPanel.cpp b/App/editor/ViewportPanel.cpp index 7a899c4..dfb5587 100644 --- a/App/editor/ViewportPanel.cpp +++ b/App/editor/ViewportPanel.cpp @@ -40,6 +40,12 @@ namespace constexpr float kSnapRotateDeg = 15.0f; // 度 constexpr float kSnapScale = 0.1f; // 缩放步进 + // 单轴拖拽灵敏度下限:sinθ(轴与"相机→物体"连线夹角)。低于该值 + // 时拖拽投影系数 <0.25 且激活平面与鼠标射线近共面——视觉上 + // "看得见、抓了没反应"。≈14.5°,略宽于库默认可见角(≈11.5°), + // 只藏真正病态的轴,不动可用轴 + constexpr float kAxisMinSin = 0.25f; + // Vulkan proj → ImGuizmo 期望的 OpenGL 形式(Y-up、Z∈[-1,1]): // Y 行翻回(抵消 Vulkan clip Y 向下翻转);z 行 = 2*z - w 即 // 深度 [0,1] → [-1,1]。glm 列主序 m[col][row],逐列改 row1/row2 @@ -146,9 +152,7 @@ std::optional ViewportPanel::Draw(const EditorContext &ctx, const ImVec2 mn = ImGui::GetItemRectMin(); ImGuizmo::SetRect(mn.x, mn.y, size.x, size.y); - // 不调 SetPlaneLimit/SetAxisLimit——全默认参数,与 - // Horizon 同款(官方库出货行为:轴仅在几乎正对视线 - // 时隐藏,任何自行抬高阈值都会过早藏轴) + // 不调 SetPlaneLimit/SetAxisLimit——可见度保持库默认 glm::mat4 m = tr->World(); // 操作空间:local(模型轴,旋转/缩放随物体朝向直观)/ @@ -157,6 +161,33 @@ std::optional ViewportPanel::Draw(const EditorContext &ctx, const ImGuizmo::MODE mode = gizmo.localSpace ? ImGuizmo::LOCAL : ImGuizmo::WORLD; + // 退化轴隐藏(UE 语义:可激活性决定可见性)。库的单轴 + // 激活平面包含"轴 + 相机连线",鼠标射线∥连线时求交 + // denom→0 返回 -1 被当交点距离(L2347-2349),拖拽 + // delta 在轴上的投影系数 = sinθ 也同时趋 0——表现为 + // "杆看得见、抓了没反应/数值不变"。按灵敏度把病态轴 + // SetAxisMask 隐藏(库内按轴关绘制+激活,单轴 mask + // 时保留含该轴的平面手柄兜底);相机一移动自动恢复 + const glm::vec3 camPos(glm::inverse(view)[3]); + glm::vec3 camToObj = glm::vec3(m[3]) - camPos; + const float camDist = glm::length(camToObj); + const glm::mat3 rotM(m); + bool maskAxis[3] = {false, false, false}; + if (camDist > 1e-4f) { + camToObj /= camDist; + for (int i = 0; i < 3; ++i) { + const glm::vec3 axis = gizmo.localSpace + ? glm::normalize(rotM[i]) + : glm::vec3(float(i == 0), float(i == 1), + float(i == 2)); + maskAxis[i] = + glm::length(glm::cross(camToObj, axis)) + < kAxisMinSin; + } + } + ImGuizmo::SetAxisMask(maskAxis[0], maskAxis[1], + maskAxis[2]); + // Ctrl 按住 → 吸附(UE Grid Snap 语义)。库的约定 //(docs/documentation.md):平移 = 世界单位 float[3] // 逐轴;旋转 = snap[0] 按度(库内自行 DEG2RAD,传弧度