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:
2026-10-04 01:37:49 +08:00
parent 90bf63e641
commit 4fc48c21ac
2 changed files with 19 additions and 5 deletions
+13 -4
View File
@@ -73,9 +73,12 @@ namespace
// UE 风变换行:label + 三轴色 DragFloat(轴色对齐 Gizmo:X 红 /
// Y 绿 / Z 蓝)。拖拽粗调;Ctrl+Click 进输入框键入精确值。
// 任一轴变化返回 true
// 任一轴变化返回 true。fmt = 显示格式(旋转行传 "%.1f" 对齐
// UE Details 默认 1 位小数——欧拉显示端有固有反解噪声,见
// TransformComponent::GetRotation 注释)
bool DragVec3Row(const char* label, glm::vec3& v, float speed,
float mn = -3.4e38f, float mx = 3.4e38f)
float mn = -3.4e38f, float mx = 3.4e38f,
const char* fmt = "%.2f")
{
ImGui::TextUnformatted(label);
ImGui::SameLine(72.0f); // 固定标签列宽 → 三行输入框对齐
@@ -97,7 +100,7 @@ namespace
ImGui::SetNextItemWidth(boxW);
changed |= ImGui::DragFloat(
i == 0 ? "##x" : i == 1 ? "##y" : "##z",
&v[i], speed, mn, mx, "%.2f");
&v[i], speed, mn, mx, fmt);
ImGui::PopStyleColor();
if (i < 2) ImGui::SameLine();
}
@@ -213,7 +216,13 @@ void InspectorPanel::Draw(const EditorContext& ctx, entt::entity selected)
t->SetPosition(pos);
}
glm::vec3 rot = t->GetRotation(); // 派生欧拉(度)
if (DragVec3Row("rotation", rot, 0.5f))
for (int i = 0; i < 3; ++i)
{
if (rot[i] == 0.0f) rot[i] = 0.0f; // 清 -0.0(atan2 副产物)
}
// "%.1f" = UE Details 默认显示精度(反解噪声 ~0.02° @ pitch 90°,
// 存储端 quat 精确;手输 Ctrl+Click 仍全精度写入)
if (DragVec3Row("rotation", rot, 0.5f, -3.4e38f, 3.4e38f, "%.1f"))
{
t->SetRotation(rot);
}