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:
@@ -70,19 +70,28 @@ namespace Engine::ECS {
|
|||||||
// 90 → 89.98)。贴锁区改走组合角 atan2(分子分母同源缩放,
|
// 90 → 89.98)。贴锁区改走组合角 atan2(分子分母同源缩放,
|
||||||
// 比值稳定)→ 手输 90.0 显示 90.0。落入该窄区(±0.00057°)
|
// 比值稳定)→ 手输 90.0 显示 90.0。落入该窄区(±0.00057°)
|
||||||
// 的真实 yaw/roll 被归并为组合角,UI 输入不可达,可接受
|
// 的真实 yaw/roll 被归并为组合角,UI 输入不可达,可接受
|
||||||
if (std::abs(sp) < 1.0f - 1e-6f) {
|
glm::vec3 euler = std::abs(sp) < 1.0f - 1e-6f
|
||||||
return glm::degrees(glm::vec3(
|
? glm::degrees(glm::vec3(
|
||||||
std::asin(sp),
|
std::asin(sp),
|
||||||
std::atan2(R[2][0], R[2][2]),
|
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 同策略)
|
return euler;
|
||||||
// 归入 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 写入(标脏,脏实体由 UpdateTransforms 重算)----
|
// ---- 写入(标脏,脏实体由 UpdateTransforms 重算)----
|
||||||
|
|||||||
@@ -52,6 +52,14 @@ namespace Engine {
|
|||||||
if (mouseDX != 0 || mouseDY != 0)
|
if (mouseDX != 0 || mouseDY != 0)
|
||||||
{
|
{
|
||||||
glm::vec3 rot = transform.GetRotation();
|
glm::vec3 rot = transform.GetRotation();
|
||||||
|
// GetRotation 是 0-360 显示域(UE Details 约定);pitch 的
|
||||||
|
// clamp 需要连续域,wrap 回 [-180,180)(yaw 同步处理,
|
||||||
|
// 跨 ±180 继续累减不打折返)
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
rot[i] = std::fmod(rot[i], 360.0f);
|
||||||
|
if (rot[i] >= 180.0f) rot[i] -= 360.0f;
|
||||||
|
if (rot[i] < -180.0f) rot[i] += 360.0f;
|
||||||
|
}
|
||||||
// 右手系绕 Y 正角度 = 向左转,鼠标右移(DX>0)应看向右
|
// 右手系绕 Y 正角度 = 向左转,鼠标右移(DX>0)应看向右
|
||||||
// → yaw 取负。pitch 正角度 = 抬头,鼠标下移(DY>0)低头
|
// → yaw 取负。pitch 正角度 = 抬头,鼠标下移(DY>0)低头
|
||||||
// → rot.x 直接用负号,两者符号已核对一致
|
// → rot.x 直接用负号,两者符号已核对一致
|
||||||
|
|||||||
Reference in New Issue
Block a user