editor: scale gizmo fully self-drawn (screen-space, view-independent)

ImGuizmo scale hover/drag relies on ray-plane intersection with the
axis as plane normal; in front views (axis ⟂ camera-to-object) the
intersection numerator is identically zero, so handles can't be
grabbed and values jump randomly; axes parallel to the view have zero
screen displacement. Submodule is read-only and AxisMask can only hide
degenerate axes, not replace them.

Replace the library scale path entirely with a screen-space gizmo:
- three axis rods (line + end square) + center uniform-scale square,
  constant screen size in any view
- axis drag: mouse delta projected onto the axis' screen direction
- axis pointing at camera: radial mapping (drag away = grow)
- center square: uniform scale (library MT_SCALE_XYZ semantics)
- Ctrl snapping quantizes the result; scale clamped >= 0.01
- pick suppressed while hovering/dragging the self-drawn handles
This commit is contained in:
2026-10-03 12:23:00 +08:00
parent 21b33d7d7f
commit c9d4eed043
2 changed files with 337 additions and 75 deletions
+15 -1
View File
@@ -35,7 +35,21 @@ struct GizmoState {
int op = 7; // ImGuizmo::TRANSLATE(TRANSLATE_X|Y|Z)
bool localSpace = true; // 操纵空间:true=模型轴(旋转/缩放语义),
// T 键切 world
bool dragging = false; // 拖拽中(IsUsing)→ 鼠标归 Gizmo 不给游戏侧
bool dragging = false; // 拖拽中(IsUsing 或自绘缩放拖拽)→ 鼠标归
// Gizmo 不给游戏侧(Editor::BlockingMouse)
// ---- 自绘缩放 gizmo(op==SCALE 整体不走 ImGuizmo)----
// 库内缩放的 hover/拖拽依赖"法线=轴"平面求交:正对视角(轴⊥
// 相机连线)时求交分子恒 0 → 杆抓不到、数值随机猛变;轴∥视线
// 时又无屏幕位移。submodule 禁改,AxisMask 只能"藏"不能"补"
// → 调用层整体自绘三轴杆 + 中心等比方块(纯屏幕空间数学,任意
// 视角良构),实现见 ViewportPanel.cpp ScaleGizmoSelf
bool scaleDragActive = false; // 自绘缩放拖拽中
int scaleDragAxis = -1; // 拖拽目标:0/1/2 轴;-2 = 中心等比
bool scaleHover = false; // 本帧悬停/拖拽自绘手柄 → 抑制 pick
float scaleStartMouse[2] = {0.0f, 0.0f}; // 拖拽起始鼠标(屏幕系)
float scaleStartDist = 0.0f; // 起始鼠标到杆心距离(径向映射用)
float scaleStartScale[3] = {1.0f, 1.0f, 1.0f}; // 拖拽起始 scale
};
class ViewportPanel {