fix(editor): euler display precision at gimbal lock (90 -> 89.98)
Typing 90 degrees on the pitch axis showed 89.98. The stored quat is
exact (matrices differ by 0.0) -- the noise is display-side: quat's
sin(90) components square to 0.99999994 in float, and asin() diverges
at |sin|->1, amplifying 6e-8 into 0.02 degrees. Yaw/roll use atan2 and
were always exact, matching the user's report being X-axis only.
Two fixes, both aligned with how UE gets away with it (internally UE
is quat + equally pathological, its Details panel just shows one
decimal):
- GetRotation gimbal-lock threshold 1.0 -> 1-1e-6: pitch near +-90
now takes the composite-angle atan2 branch (ratio-stable) instead
of asin, so typing 90.0 reads back exactly 90.0. Probed: X=90 and
X=-90 now round-trip to 0 error; generic poses stay ~1e-6 deg.
- Rotation row shows one decimal ("%.1f", UE Details default), masking
the residual asin noise for angles near (not at) the pole; Ctrl+Click
input stays full precision. Negative zero from atan2 cleaned up.
Remaining asin noise for e.g. 89.9 (~9e-4 deg) is below the 1-decimal
display and unreachable in practice.
This commit is contained in:
@@ -65,7 +65,12 @@ namespace Engine::ECS {
|
||||
{
|
||||
const glm::mat3 R = glm::mat3_cast(m_Rotation);
|
||||
const f32 sp = std::clamp(-R[2][1], -1.0f, 1.0f); // = sin(pitch)
|
||||
if (std::abs(sp) < 1.0f) {
|
||||
// 万向锁分支阈值 1e-6:asin 在 |sin|→1 处导数发散(sin90 的
|
||||
// float 表示差 6e-8 → asin 放大成 0.02° 显示噪声,用户实测
|
||||
// 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(
|
||||
std::asin(sp),
|
||||
std::atan2(R[2][0], R[2][2]),
|
||||
|
||||
Reference in New Issue
Block a user