feat(editor): rotation display in UE's 0-360 convention

User pointed out the real gap: UE Details shows rotation in [0,360)
(-90 reads 270); our readback exposed [-180,180] with negative zeros.
GetRotation now wraps each axis to [0,360) via fmod -- strictly
equivalent math (each axis has 360-degree period), so matrix-rebuild
consumers like Camera::EulerRotMat are unaffected. The one consumer
needing a continuous domain is the free-look pitch clamp [-89,89] in
Camera::Update, which wraps back to [-180,180) before applying deltas.
This commit is contained in:
2026-10-04 01:46:05 +08:00
parent 4fc48c21ac
commit 4498bc7535
2 changed files with 27 additions and 10 deletions
+19 -10
View File
@@ -70,19 +70,28 @@ namespace Engine::ECS {
// 90 → 89.98)。贴锁区改走组合角 atan2(分子分母同源缩放,
// 比值稳定)→ 手输 90.0 显示 90.0。落入该窄区(±0.00057°)
// 的真实 yaw/roll 被归并为组合角,UI 输入不可达,可接受
if (std::abs(sp) < 1.0f - 1e-6f) {
return glm::degrees(glm::vec3(
glm::vec3 euler = std::abs(sp) < 1.0f - 1e-6f
? glm::degrees(glm::vec3(
std::asin(sp),
std::atan2(R[2][0], R[2][2]),
std::atan2(R[0][1], R[1][1])));
std::atan2(R[0][1], R[1][1])))
: (sp > 0.0f
? glm::vec3(90.0f,
glm::degrees(std::atan2(-R[0][2], R[1][2])),
0.0f)
: glm::vec3(-90.0f,
glm::degrees(std::atan2(-R[0][2], -R[1][2])),
0.0f));
// 显示约定 = UE Details 的 0-360(-90 → 270)。逐轴 fmod wrap
// 与 [-180,180] 数学严格等价(每轴旋转周期 360°),矩阵重建类
// 消费端(Camera::EulerRotMat 等)不受影响;需要连续域做
// clamp/lerp 的调用方自行 wrap 回 [-180,180](如自由视角)
for (int i = 0; i < 3; ++i) {
euler[i] = std::fmod(euler[i], 360.0f);
if (euler[i] < 0.0f) euler[i] += 360.0f;
if (euler[i] >= 360.0f) euler[i] = 0.0f; // 浮点边界
}
// ±90° 万向锁:yaw/roll 只剩组合角,约定 roll=0(UE 同策略)
// 归入 yaw;两支组合角符号不同
return sp > 0.0f
? glm::vec3(90.0f,
glm::degrees(std::atan2(-R[0][2], R[1][2])), 0.0f)
: glm::vec3(-90.0f,
glm::degrees(std::atan2(-R[0][2], -R[1][2])), 0.0f);
return euler;
}
// ---- 写入(标脏,脏实体由 UpdateTransforms 重算)----