diff --git a/App/editor/ViewportPanel.cpp b/App/editor/ViewportPanel.cpp index 78a29a1..e754fce 100644 --- a/App/editor/ViewportPanel.cpp +++ b/App/editor/ViewportPanel.cpp @@ -23,6 +23,7 @@ #include #include +#include // GTX 扩展(实验性)需显式开启:matrix_decompose(矩阵→SRT 分解)、 // quaternion(eulerAngles 四元数→欧拉角) @@ -147,17 +148,41 @@ std::optional ViewportPanel::Draw(const EditorContext &ctx, gizmo.dragging = ImGuizmo::IsUsing(); // 拖拽生效:分解 world 矩阵写回 SRT(Set* 标脏 → - // UpdateTransforms 重算 → 渲染下帧生效)。 - // eulerAngles 与 Compose 的 YXZ 旋转序在复合旋转下 - // 可能微差——每帧从 World 重读不累积;表现不对再换 - // ImGuizmo::DecomposeMatrixToComponents(TODO) + // UpdateTransforms 重算 → 渲染下帧生效) if (ImGuizmo::IsUsing()) { glm::vec3 scale, transl, skew; glm::quat rot; glm::vec4 persp; if (glm::decompose(m, scale, rot, transl, skew, persp)) { - const glm::vec3 euler = - degrees(eulerAngles(rot)); + // 旋转写回:glm::eulerAngles 的序约定(XYZ 系) + // 与 Compose 的 YXZ 不一致,复合旋转下往返失真 + // (拖拽乱跳、缩放串轴)。改为按引擎 YXZ 序 + //(R = Ry·Rx·Rz)从旋转矩阵直接提取欧拉角, + // 保证 decompose 出的 R 与 Compose 重组的 R + // 严格相等,拖拽零漂移 + const glm::mat3 R = glm::mat3_cast(rot); + const f32 sp = -R[2][1]; // = sin(pitch) + glm::vec3 euler; + if (std::abs(sp) < 1.0f) { + // 常规区(float32 下覆盖全部非奇异姿态): + // 由 R = Ry·Rx·Rz 展开反解,cx 在 atan2 + // 分子分母中约掉,pitch→±90° 依然精确 + euler = glm::vec3( + glm::degrees(std::asin(sp)), + glm::degrees(std::atan2(R[2][0], R[2][2])), + glm::degrees(std::atan2(R[0][1], R[1][1]))); + } else { + // float 真奇异(|pitch|=90°):yaw/roll 只 + // 剩组合角,约定 roll=0(UE 同策略)归入 + // yaw;±90° 两支组合角符号不同 + const f32 pitch = sp > 0 ? 90.0f : -90.0f; + const f32 yaw = sp > 0 + ? glm::degrees(std::atan2( + -R[0][2], R[1][2])) + : glm::degrees(std::atan2( + -R[0][2], -R[1][2])); + euler = glm::vec3(pitch, yaw, 0.0f); + } tr->SetPosition(transl) .SetRotation(euler) .SetScale(scale);