docs: add scene viewport transform gizmo docs

This commit is contained in:
2026-04-04 13:32:31 +08:00
parent b8de12b8e3
commit 038194b75a
48 changed files with 1859 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
# SceneViewportMoveGizmo::CancelDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
void CancelDrag(IUndoManager* undoManager = nullptr);
```
## 作用
取消一次位移拖拽事务,并清理全部活动缓存。
## 当前实现行为
- 如果传入了 `undoManager` 且当前有 pending interactive change会调用 `CancelInteractiveChange()` 回滚。
- 同样会清空全部拖拽状态。
- 额外会把 `hoveredAxis``hoveredPlane` 一并清空,避免取消后继续显示旧命中。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [EndDrag](EndDrag.md)
- [TryBeginDrag](TryBeginDrag.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportMoveGizmo::EndDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
void EndDrag(IUndoManager& undoManager);
```
## 作用
提交一次位移拖拽事务,并清理全部活动缓存。
## 当前实现行为
- 当前没有活动拖拽时直接返回。
-`undoManager` 还持有 pending interactive change会调用 `FinalizeInteractiveChange()` 提交位移结果。
- 之后清空拖拽模式、活动轴/平面、活动实体 id、拖拽平面相关缓存以及对象起始位置数组。
- 最后调用 `RefreshHandleState()` 去掉 active 标记。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [CancelDrag](CancelDrag.md)
- [UpdateDrag](UpdateDrag.md)

View File

@@ -0,0 +1,33 @@
# SceneViewportMoveGizmo::EvaluateHit
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
SceneViewportMoveGizmoHitResult EvaluateHit(const Math::Vector2& mousePosition) const;
```
## 作用
执行位移 gizmo 的命中检测,并返回当前最近命中的轴向或平面 handle。
## 当前实现行为
- draw data 不可见时直接返回空命中。
- 会先遍历三条轴向 handle用鼠标到线段的距离平方做最近点比较。
- 只有当轴向命中失败时,才会继续测试 `XY / XZ / YZ` 三个平面拖拽块。
- 平面命中通过 `PointInQuad(...)` 判断,并按四边形中心到鼠标的距离选最近平面。
- 因此当前优先级是:
- 轴向 handle
- 再到平面 handle
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SetHoveredHandle](SetHoveredHandle.md)
- [SceneViewportMoveGizmoHitResult](SceneViewportMoveGizmoHitResult.md)

View File

@@ -0,0 +1,36 @@
# SceneViewportGizmoAxis
**命名空间**: `XCEngine::Editor`
**类型**: `enum class`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 定义
```cpp
enum class SceneViewportGizmoAxis : uint8_t {
None = 0,
X,
Y,
Z
};
```
## 作用
表示当前 move gizmo 选中的单轴拖拽方向。
## 枚举值
| 值 | 说明 |
|------|------|
| `None` | 没有命中或没有激活单轴。 |
| `X` | 世界或局部 gizmo 的 X 轴。 |
| `Y` | 世界或局部 gizmo 的 Y 轴。 |
| `Z` | 世界或局部 gizmo 的 Z 轴。 |
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoHitResult](SceneViewportMoveGizmoHitResult.md)

View File

@@ -0,0 +1,36 @@
# SceneViewportGizmoPlane
**命名空间**: `XCEngine::Editor`
**类型**: `enum class`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 定义
```cpp
enum class SceneViewportGizmoPlane : uint8_t {
None = 0,
XY,
XZ,
YZ
};
```
## 作用
表示当前 move gizmo 选中的平面拖拽约束。
## 枚举值
| 值 | 说明 |
|------|------|
| `None` | 没有命中或没有激活平面 handle。 |
| `XY` | 在 `XY` 平面内移动。 |
| `XZ` | 在 `XZ` 平面内移动。 |
| `YZ` | 在 `YZ` 平面内移动。 |
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoHitResult](SceneViewportMoveGizmoHitResult.md)

View File

@@ -0,0 +1,101 @@
# SceneViewportMoveGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `class + enums + structs`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
**描述**: Scene View 位移 gizmo负责轴向/平面拖拽命中、可视化数据生成和交互式撤销集成。
## 概述
`SceneViewportMoveGizmo` 是当前 Scene View 三套 transform gizmo 中最直接的一套。它围绕一个选中 pivot 工作,并支持两类拖拽:
- 单轴拖拽: `X / Y / Z`
- 平面拖拽: `XY / XZ / YZ`
除了当前主选对象,它还会携带 `selectedObjects`,因此多选平移是当前真实支持的能力。
## 公开类型
| 成员 | 说明 |
|------|------|
| [SceneViewportGizmoAxis](SceneViewportGizmoAxis.md) | `X / Y / Z` 轴枚举。 |
| [SceneViewportGizmoPlane](SceneViewportGizmoPlane.md) | `XY / XZ / YZ` 平面枚举。 |
| [SceneViewportMoveGizmoHandleDrawData](SceneViewportMoveGizmoHandleDrawData.md) | 单个轴向 handle 的绘制状态。 |
| [SceneViewportMoveGizmoPlaneDrawData](SceneViewportMoveGizmoPlaneDrawData.md) | 单个平面 handle 的绘制状态。 |
| [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md) | 当前帧完整 gizmo 绘制数据。 |
| [SceneViewportMoveGizmoContext](SceneViewportMoveGizmoContext.md) | update / drag 所需上下文,包括 overlay、鼠标位置、pivot 和选中对象集合。 |
| [SceneViewportMoveGizmoHitResult](SceneViewportMoveGizmoHitResult.md) | 命中结果。 |
## 公开 API
### 交互主流程
- [Update](Update.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)
### 状态查询
- [State Queries](StateQueries.md)
## 当前实现行为
`SceneViewportMoveGizmo.cpp` 的实现:
- `TryBeginDrag(...)` 会先从鼠标位置构建世界射线。
- 轴向拖拽会用 [BuildSceneViewportAxisDragPlaneNormal](../SceneViewportMath/SceneViewportMath.md) 计算一个稳定拖拽平面。
- 平面拖拽直接使用所选平面的法线。
- 拖拽开始时会调用 `undoManager.BeginInteractiveChange("Move Gizmo")`
- 多选情况下,会记录每个对象的初始世界坐标,然后统一叠加同一个 `worldDelta`
- 轴向拖拽通过“射线与拖拽平面求交 -> 投影到活动轴 -> 比较标量差值”得到位移。
- 平面拖拽通过“当前命中点 - 起始命中点”再投影到活动平面得到位移。
## 设计说明
Move gizmo 的关键不是把对象“随鼠标走”,而是把 2D 鼠标输入稳定映射成 3D 约束位移。当前实现采用“拖拽平面 + 轴投影”的方式,是编辑器里很成熟的做法,因为它能兼顾:
- 轴向操作的稳定性。
- 平面操作的直观性。
- 与相机视角变化的兼容性。
## 生命周期与线程语义
- gizmo 对象由 [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md) 作为成员持有。
- [Update](Update.md) 负责刷新绘制数据与 hover 状态。
- [TryBeginDrag](TryBeginDrag.md) / [UpdateDrag](UpdateDrag.md) / [EndDrag](EndDrag.md) / [CancelDrag](CancelDrag.md) 构成一次交互式事务。
## 与测试的对应关系
`tests/Editor/test_scene_viewport_move_gizmo.cpp` 当前覆盖了:
- `X` 轴 handle 的悬停命中。
- 轴向拖拽只改动对应世界轴,并能生成 / 回滚交互式撤销。
- 轴几乎正对相机时会缩短而不是保持满长度。
- 等轴视角下平面 handle 可见且可命中。
- `XY` 平面拖拽会改动 `X / Y` 但保持 `Z` 不变。
## 当前限制
- 当前只做平移,不处理吸附、栅格对齐或轴锁定增量显示。
- 拖拽基于当前世界位置直接写回 transform没有额外的坐标系可视化历史。
## 相关文档
- [SceneViewportGizmoAxis](SceneViewportGizmoAxis.md)
- [SceneViewportGizmoPlane](SceneViewportGizmoPlane.md)
- [SceneViewportMoveGizmoContext](SceneViewportMoveGizmoContext.md)
- [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md)
- [SceneViewportMoveGizmoHitResult](SceneViewportMoveGizmoHitResult.md)
- [State Queries](StateQueries.md)
- [SceneViewportMath](../SceneViewportMath/SceneViewportMath.md)
- [SceneViewportRotateGizmo](../SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)
- [SceneViewportScaleGizmo](../SceneViewportScaleGizmo/SceneViewportScaleGizmo.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)
- [SceneView Interaction And Gizmo Model](../../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)

View File

@@ -0,0 +1,33 @@
# SceneViewportMoveGizmoContext
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 作用
封装 move gizmo 在 update、hit-test 和拖拽阶段所需的输入上下文。
## 字段说明
| 字段 | 说明 |
|------|------|
| `overlay` | 当前 Scene View 相机 overlay 数据。 |
| `viewportSize` | 视口尺寸。 |
| `mousePosition` | 视口内鼠标位置。 |
| `selectedObject` | 当前主选对象。 |
| `selectedObjects` | 当前全部选中对象,用于多选平移。 |
| `pivotWorldPosition` | gizmo pivot 的世界坐标。 |
| `axisOrientation` | gizmo 轴向所使用的旋转基。 |
## 当前使用方式
- `Update(...)` 使用它构建 draw data 和 hover 状态。
- `TryBeginDrag(...)` / `UpdateDrag(...)` 使用它从鼠标位置构建世界射线并计算拖拽位移。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md)

View File

@@ -0,0 +1,36 @@
# SceneViewportMoveGizmoDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 作用
封装当前帧 move gizmo 的完整绘制数据,供 gizmo overlay state 构建与 editor overlay frame data 复用。
## 字段说明
| 字段 | 说明 |
|------|------|
| `visible` | 整个 move gizmo 当前是否可见。 |
| `pivot` | gizmo pivot 的屏幕空间位置。 |
| `pivotRadius` | pivot 圆点半径。 |
| `handles` | 三个轴向 handle 的绘制数据。 |
| `planes` | 三个平面 handle 的绘制数据。 |
## 当前使用方式
- `SceneViewportMoveGizmo::Update(...)` 会刷新这份数据。
- `SceneViewPanel` 会经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它与当前实体 id 聚合成 overlay submission。
- [SceneViewportOverlayProviders](../SceneViewportOverlayProviders/SceneViewportOverlayProviders.md) 中的 transform-gizmo provider 会把它转成:
- `handleRecords`
- `screenTriangles`
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoHandleDrawData](SceneViewportMoveGizmoHandleDrawData.md)
- [SceneViewportMoveGizmoPlaneDrawData](SceneViewportMoveGizmoPlaneDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportMoveGizmoHandleDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 作用
描述单个轴向 move handle 在当前帧的 2D 绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `axis` | 该 handle 对应的轴。 |
| `start` | 屏幕空间起点。 |
| `end` | 屏幕空间终点。 |
| `color` | 线段与箭头主色。 |
| `visible` | 当前帧是否应该绘制。 |
| `hovered` | 鼠标是否悬停在该 handle 上。 |
| `active` | 当前是否正在拖拽该 handle。 |
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportMoveGizmoHitResult
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 作用
表示一次 move gizmo hit-test 的结果。
## 字段说明
| 字段 | 说明 |
|------|------|
| `axis` | 命中的单轴 handle未命中时为 `None`。 |
| `plane` | 命中的平面 handle未命中时为 `None`。 |
| `distanceSq` | 命中点到鼠标的平方距离,用于最近命中比较。 |
## 当前实现行为
- 内联函数 `HasHit()` 只要 `axis``plane` 任一非 `None` 就返回 `true`
- 当前设计允许调用方统一处理“单轴命中”和“平面命中”两种情况。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportGizmoAxis](SceneViewportGizmoAxis.md)
- [SceneViewportGizmoPlane](SceneViewportGizmoPlane.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportMoveGizmoPlaneDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 作用
描述单个平面 move handle 在当前帧的 2D 绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `plane` | 该 handle 对应的平面约束。 |
| `corners` | 平面四边形在屏幕空间的四个角点。 |
| `fillColor` | 平面填充色。 |
| `outlineColor` | 平面轮廓色。 |
| `visible` | 当前帧是否应该绘制。 |
| `hovered` | 鼠标是否悬停在该平面上。 |
| `active` | 当前是否正在拖拽该平面。 |
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportMoveGizmo::SetHoveredHandle
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
void SetHoveredHandle(SceneViewportGizmoAxis axis, SceneViewportGizmoPlane plane);
```
## 作用
允许外层交互系统直接写入当前 hover 结果。
## 当前实现行为
- 当前存在活动拖拽时不会覆盖内部状态。
- 若传入了有效轴,会强制清空平面 hover。
- 若轴为 `None`,则保留传入的平面 hover。
- 写入后会通过 `RefreshHandleState()` 同步显示状态。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [EvaluateHit](EvaluateHit.md)
- [Update](Update.md)

View File

@@ -0,0 +1,50 @@
# SceneViewportMoveGizmo::State Queries
**命名空间**: `XCEngine::Editor`
**类型**: `methods`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
bool IsHoveringHandle() const;
bool IsActive() const;
uint64_t GetActiveEntityId() const;
const SceneViewportMoveGizmoDrawData& GetDrawData() const;
```
## 作用
提供 move gizmo 当前 hover / active 状态、活动实体以及每帧 draw data 的只读访问。
## 当前实现行为
### `IsHoveringHandle()`
- 只要 `m_hoveredAxis != None``m_hoveredPlane != None` 就返回 `true`
- 因此它同时覆盖“轴 handle 悬停”和“平面 handle 悬停”。
### `IsActive()`
- 只要 `m_activeAxis != None``m_activePlane != None` 就返回 `true`
- 表达的是“当前是否正在执行拖拽事务”不是“gizmo 是否可见”。
### `GetActiveEntityId()`
- 直接返回 `m_activeEntityId`
- 未进入拖拽时通常为 `0`
### `GetDrawData()`
- 返回 `m_drawData` 的常量引用。
- 该数据由 [Update](Update.md) 与内部 `BuildDrawData(...)` / `RefreshHandleState()` 维护。
- 当前主调用链不会让 HUD 直接读取它;`SceneViewPanel` 会先经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它聚合进 overlay submission最终由 provider 体系转成 canonical `screenTriangles``handleRecords`
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [Update](Update.md)
- [SceneViewportMoveGizmoDrawData](SceneViewportMoveGizmoDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,54 @@
# SceneViewportMoveGizmo::TryBeginDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
bool TryBeginDrag(const SceneViewportMoveGizmoContext& context, IUndoManager& undoManager);
```
## 作用
在当前 hover 的轴或平面上启动位移拖拽,并准备 interactive undo 所需的起始数据。
## 当前实现行为
- 只会在以下条件满足时进入拖拽:
- 当前没有活动拖拽
- 当前命中了轴或平面 handle
- `selectedObject` 有效
- draw data 可见
- `undoManager` 当前没有 pending interactive change
- 会先根据 `overlay + viewportSize + mousePosition` 构建世界射线。
- 轴向拖拽路径:
- 通过 `GetAxisVector(...)` 得到当前世界轴
- 调用 `BuildSceneViewportAxisDragPlaneNormal(...)` 构造稳定拖拽平面法线
- 平面拖拽路径:
- 直接从当前命中平面得到世界法线
- 之后统一构造 `dragPlane`,并计算起始命中点 `hitPoint`
- 成功后调用 `undoManager.BeginInteractiveChange("Move Gizmo")`
- 缓存的状态包括:
- 当前拖拽模式 `Axis / Plane`
- 活动轴或活动平面
- 活动实体 id
- 活动世界轴或平面法线
- 起始 pivot、起始命中点、起始轴标量
- 所有参与拖拽对象的起始世界位置
- 如果 `selectedObjects` 为空,会退回到单对象拖拽。
## 返回值
- `true`: 已成功切换到拖拽状态。
- `false`: 几何求解、命中条件或 interactive undo 任一环节失败。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -0,0 +1,37 @@
# SceneViewportMoveGizmo::Update
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
void Update(const SceneViewportMoveGizmoContext& context);
```
## 作用
刷新当前帧位移 gizmo 的绘制数据,并维护轴向或平面 handle 的 hover 状态。
## 当前实现行为
- 会先调用 `BuildDrawData(context)` 生成轴向箭头与平面拖拽块的当前帧绘制数据。
- 当前没有活动拖拽且鼠标位于视口内时,会调用 `EvaluateHit(context.mousePosition)` 自动命中:
- 最近的轴向线段
- 或可见平面四边形
- 当前没有活动拖拽但鼠标已离开视口时,会清空 `hoveredAxis``hoveredPlane`
- 当前正在拖拽时:
- 轴向拖拽会把 hover 轴锁定到活动轴
- 平面拖拽会把 hover 平面锁定到活动平面
- 末尾通过 `RefreshHandleState()` 同步 draw data 中的 hovered / active 标记。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)

View File

@@ -0,0 +1,42 @@
# SceneViewportMoveGizmo::UpdateDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportMoveGizmo.h`
## 签名
```cpp
void UpdateDrag(const SceneViewportMoveGizmoContext& context);
```
## 作用
根据当前鼠标射线与缓存拖拽平面的交点,持续更新对象位移。
## 当前实现行为
- 只有在活动拖拽仍然有效、主选对象 id 未变化、缓存对象数组与起始位置数组长度一致时才会继续。
- 每一帧都会重新从视口状态构建世界射线,并与缓存的 `m_dragPlane` 求交。
- 轴向拖拽:
- 计算当前命中点相对起始 pivot 在活动轴上的投影标量
- 用当前标量减去 `m_dragStartAxisScalar` 得到 `deltaScalar`
- 最终位移为 `m_activeAxisDirection * deltaScalar`
- 平面拖拽:
- 计算 `hitPoint - m_dragStartHitWorldPosition`
- 再通过 `ProjectOnPlane(..., m_activePlaneNormal)` 去掉法线方向分量
- 对所有参与拖拽对象都会叠加同一个 `worldDelta`,实现多选统一平移。
## 当前实现边界
- 拖拽过程中不会重新选择对象。
- 当前没有吸附、网格对齐或数值输入。
## 相关文档
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportRotateGizmo::CancelDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
void CancelDrag(IUndoManager* undoManager = nullptr);
```
## 作用
取消一次旋转拖拽事务,并清理全部活动状态。
## 当前实现行为
- 允许传入空指针。
- 如果传入了 `undoManager` 且当前存在 pending interactive change会调用 `CancelInteractiveChange()` 回滚本次事务。
- 与 [EndDrag](EndDrag.md) 一样会清空全部活动状态。
- 额外会把 `hoveredAxis` 也清回 `None`,避免取消后继续显示旧 hover。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [EndDrag](EndDrag.md)
- [TryBeginDrag](TryBeginDrag.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportRotateGizmo::EndDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
void EndDrag(IUndoManager& undoManager);
```
## 作用
结束一次旋转拖拽事务,并提交交互式撤销结果。
## 当前实现行为
- 若当前没有活动轴,直接返回。
-`undoManager` 仍持有 pending interactive change 时,会调用 `FinalizeInteractiveChange()` 提交本次旋转。
- 随后清空活动轴、活动实体、拖拽平面、起始角、共享 pivot 标志和所有缓存对象姿态。
- 会保留当前 hover 刷新逻辑,并通过 `RefreshHandleState()` 去掉 active 标记。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [CancelDrag](CancelDrag.md)
- [UpdateDrag](UpdateDrag.md)

View File

@@ -0,0 +1,31 @@
# SceneViewportRotateGizmo::EvaluateHit
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
SceneViewportRotateGizmoHitResult EvaluateHit(const Math::Vector2& mousePosition) const;
```
## 作用
提供旋转环命中检测,并返回当前最近命中的轴。
## 当前实现行为
- 如果当前 draw data 不可见,直接返回空命中。
- 会遍历每个可见 handle 的所有离散线段。
- 对普通 `X / Y / Z` 环,只考虑 `frontFacing = true` 的可见线段。
- `View` 环不受前后向裁剪限制。
- 使用固定像素阈值比较鼠标到线段的距离平方,并返回最近命中的轴。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SetHoveredHandle](SetHoveredHandle.md)
- [SceneViewportRotateGizmoHitResult](SceneViewportRotateGizmoHitResult.md)

View File

@@ -0,0 +1,111 @@
# SceneViewportRotateGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `class + enum + structs`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
**描述**: Scene View 旋转 gizmo支持轴向环、视图环、多对象旋转、共享 pivot 旋转以及交互式撤销。
## 概述
`SceneViewportRotateGizmo` 是当前三套 transform gizmo 里几何与交互最复杂的一套。它支持四种 handle
- `X`
- `Y`
- `Z`
- `View`
同时它还能配合:
- local / global 空间模式
- `Pivot / Center` 模式
- 多选对象旋转
## 公开 API
### 交互主流程
- [Update](Update.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)
### 状态查询
- [State Queries](StateQueries.md)
### 公开类型
| 类型 | 说明 |
|------|------|
| [SceneViewportRotateGizmoAxis](SceneViewportRotateGizmoAxis.md) | 旋转 gizmo 的 handle 轴枚举。 |
| [SceneViewportRotateGizmoSegmentDrawData](SceneViewportRotateGizmoSegmentDrawData.md) | 单个环段的绘制数据。 |
| [SceneViewportRotateGizmoHandleDrawData](SceneViewportRotateGizmoHandleDrawData.md) | 单个旋转环 handle 的绘制状态。 |
| [SceneViewportRotateGizmoAngleFillDrawData](SceneViewportRotateGizmoAngleFillDrawData.md) | 当前活动旋转角填充数据。 |
| [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md) | 当前帧完整旋转 gizmo 绘制数据。 |
| [SceneViewportRotateGizmoContext](SceneViewportRotateGizmoContext.md) | update / drag 所需输入上下文。 |
| [SceneViewportRotateGizmoHitResult](SceneViewportRotateGizmoHitResult.md) | 旋转 gizmo 命中结果。 |
## 当前实现行为
`SceneViewportRotateGizmo.cpp` 的实现:
- 拖拽开始时会调用 `undoManager.BeginInteractiveChange("Rotate Gizmo")`
- 若无法稳定建立世界拖拽平面,会回退到 `screenSpaceDrag` 路径。
- `View` 环本质上走的是视图相关旋转,不参与 local-space 轴语义。
- `rotateAroundSharedPivot = true` 时,会把多对象围绕共同 pivot 一起旋转位置。
- local-space 模式下,非 `View` 轴会把旋转增量作为局部旋转乘到起始姿态上。
## 绘制与命中模型
- 每个旋转环当前离散成固定数量的线段。
- 绘制数据里会区分前向可见段和背向段。
- 活动拖拽时还会生成 `angleFill`,用于在环内显示当前旋转角区域。
## 设计说明
旋转 gizmo 往往是编辑器最容易“手感差”的控件。当前实现同时准备了世界平面拖拽和屏幕空间回退,说明它在优先保证两个目标:
- 能正确表达 3D 旋转方向。
- 在相机视角不理想时,仍然能拖得动。
这和成熟商用编辑器非常一致,因为旋转控件如果只依赖单一数学路径,通常会在某些观察角度下失去可用性。
## 生命周期与线程语义
- 对象由 [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md) 持有。
- 拖拽过程中会缓存多对象的起始位置和起始旋转。
- [EndDrag](EndDrag.md) / [CancelDrag](CancelDrag.md) 负责提交或取消交互式撤销,并清空活动状态。
## 与测试的对应关系
`tests/Editor/test_scene_viewport_rotate_gizmo.cpp` 当前覆盖了:
- `X` 轴旋转环与 `View` 环的可见性和悬停命中。
- 轴向拖拽会改变对象朝向,并生成 / 回滚交互式撤销。
- 活动拖拽期间会生成 `angleFill`,并临时重建其它环的可视几何。
- 边缘视角下会回退到 screen-space rotation。
- 带缩放父节点的子对象仍能正确旋转。
## 当前限制
- 当前没有角度吸附、数值输入或显式角度 HUD。
- 共享 pivot 旋转虽然已支持,但更复杂的多对象 local-space 组合行为仍可能继续演进。
## 相关文档
- [SceneViewportRotateGizmoAxis](SceneViewportRotateGizmoAxis.md)
- [SceneViewportRotateGizmoContext](SceneViewportRotateGizmoContext.md)
- [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md)
- [SceneViewportRotateGizmoHitResult](SceneViewportRotateGizmoHitResult.md)
- [State Queries](StateQueries.md)
- [SceneViewportMath](../SceneViewportMath/SceneViewportMath.md)
- [SceneViewportMoveGizmo](../SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
- [SceneViewportScaleGizmo](../SceneViewportScaleGizmo/SceneViewportScaleGizmo.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)
- [SceneView Interaction And Gizmo Model](../../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportRotateGizmoAngleFillDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
表示当前活动旋转角区域的填充与轮廓绘制数据。
## 字段说明
| 字段 | 说明 |
|------|------|
| `axis` | 当前填充对应的旋转轴。 |
| `pivot` | 屏幕空间 pivot。 |
| `arcPoints` | 角度填充扇形边界点。 |
| `arcPointCount` | 当前有效点数量。 |
| `fillColor` | 填充色。 |
| `outlineColor` | 轮廓色。 |
| `visible` | 当前是否需要绘制。 |
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md)

View File

@@ -0,0 +1,38 @@
# SceneViewportRotateGizmoAxis
**命名空间**: `XCEngine::Editor`
**类型**: `enum class`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 定义
```cpp
enum class SceneViewportRotateGizmoAxis : uint8_t {
None = 0,
X,
Y,
Z,
View
};
```
## 作用
表示当前旋转 gizmo 命中或激活的旋转环。
## 枚举值
| 值 | 说明 |
|------|------|
| `None` | 没有命中任何旋转环。 |
| `X` | 围绕 X 轴的旋转环。 |
| `Y` | 围绕 Y 轴的旋转环。 |
| `Z` | 围绕 Z 轴的旋转环。 |
| `View` | 面向当前视图的屏幕空间旋转环。 |
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoHitResult](SceneViewportRotateGizmoHitResult.md)

View File

@@ -0,0 +1,35 @@
# SceneViewportRotateGizmoContext
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
封装旋转 gizmo 在 update 和拖拽阶段所需的输入上下文。
## 字段说明
| 字段 | 说明 |
|------|------|
| `overlay` | 当前 Scene View 相机 overlay 数据。 |
| `viewportSize` | 视口尺寸。 |
| `mousePosition` | 当前鼠标位置。 |
| `selectedObject` | 当前主选对象。 |
| `selectedObjects` | 当前全部选中对象。 |
| `pivotWorldPosition` | 旋转 pivot 的世界坐标。 |
| `axisOrientation` | 当前 gizmo 轴向使用的旋转基。 |
| `localSpace` | 是否使用局部空间轴。 |
| `rotateAroundSharedPivot` | 多选时是否围绕共享 pivot 一起旋转位置。 |
## 当前使用方式
- `Update(...)` 用它刷新 draw data 和 hover 状态。
- `TryBeginDrag(...)` / `UpdateDrag(...)` 用它构建世界拖拽平面或屏幕空间回退路径。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md)

View File

@@ -0,0 +1,33 @@
# SceneViewportRotateGizmoDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
封装当前帧 rotate gizmo 的完整绘制数据,供 gizmo overlay state 构建与 editor overlay frame data 复用。
## 字段说明
| 字段 | 说明 |
|------|------|
| `visible` | 整个 rotate gizmo 当前是否可见。 |
| `pivot` | 屏幕空间 pivot。 |
| `handles` | `X/Y/Z/View` 四类旋转环的绘制数据。 |
| `angleFill` | 当前旋转拖拽时显示的角度填充区域。 |
## 当前使用方式
- `SceneViewportRotateGizmo::Update(...)` 会刷新这份数据。
- `SceneViewPanel` 会经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它与当前实体 id 聚合成 overlay submission。
- transform gizmo provider 再把它转成 `handleRecords``screenTriangles`
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoHandleDrawData](SceneViewportRotateGizmoHandleDrawData.md)
- [SceneViewportRotateGizmoAngleFillDrawData](SceneViewportRotateGizmoAngleFillDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportRotateGizmoHandleDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
描述单个旋转环 handle 在当前帧的绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `axis` | 当前 handle 对应的旋转轴。 |
| `segments` | 固定数量的离散环段绘制数据。 |
| `color` | 该旋转环主色。 |
| `visible` | 当前帧是否可见。 |
| `hovered` | 当前是否悬停。 |
| `active` | 当前是否处于拖拽激活态。 |
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoSegmentDrawData](SceneViewportRotateGizmoSegmentDrawData.md)
- [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportRotateGizmoHitResult
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
表示一次旋转 gizmo hit-test 的结果。
## 字段说明
| 字段 | 说明 |
|------|------|
| `axis` | 命中的旋转环。 |
| `distanceSq` | 命中点到鼠标的平方距离。 |
## 当前实现行为
- 内联 `HasHit()` 只要 `axis != SceneViewportRotateGizmoAxis::None` 就返回 `true`
- 当前命中结果统一按最近旋转环表达,不再区分单独的平面或中心 handle 类型。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoAxis](SceneViewportRotateGizmoAxis.md)

View File

@@ -0,0 +1,27 @@
# SceneViewportRotateGizmoSegmentDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 作用
描述旋转环离散后单个线段片段的绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `start` | 线段起点。 |
| `end` | 线段终点。 |
| `startAngle` | 该段起始角度。 |
| `endAngle` | 该段结束角度。 |
| `visible` | 当前线段是否可见。 |
| `frontFacing` | 该段是否位于前向可见半环。 |
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [SceneViewportRotateGizmoHandleDrawData](SceneViewportRotateGizmoHandleDrawData.md)

View File

@@ -0,0 +1,29 @@
# SceneViewportRotateGizmo::SetHoveredHandle
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
void SetHoveredHandle(SceneViewportRotateGizmoAxis axis);
```
## 作用
允许外部交互系统覆盖当前 hover 轴。
## 当前实现行为
- 仅在当前没有活动拖拽时生效。
- 直接写入 `m_hoveredAxis`,然后调用 `RefreshHandleState()` 同步显示状态。
- 这个入口通常用于外层统一命中仲裁后,把结果灌回 gizmo而不是依赖它自己内部 hit test。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [EvaluateHit](EvaluateHit.md)
- [Update](Update.md)

View File

@@ -0,0 +1,49 @@
# SceneViewportRotateGizmo::State Queries
**命名空间**: `XCEngine::Editor`
**类型**: `methods`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
bool IsHoveringHandle() const;
bool IsActive() const;
uint64_t GetActiveEntityId() const;
const SceneViewportRotateGizmoDrawData& GetDrawData() const;
```
## 作用
提供 rotate gizmo 当前 hover / active 状态、活动实体以及每帧 draw data 的只读访问。
## 当前实现行为
### `IsHoveringHandle()`
- 当前实现等价于 `m_hoveredAxis != SceneViewportRotateGizmoAxis::None`
### `IsActive()`
- 当前实现等价于 `m_activeAxis != SceneViewportRotateGizmoAxis::None`
- 表示当前是否存在进行中的旋转拖拽。
### `GetActiveEntityId()`
- 直接返回 `m_activeEntityId`
- 未激活拖拽时通常为 `0`
### `GetDrawData()`
- 返回 `m_drawData` 的常量引用。
- 该数据由 [Update](Update.md) 维护。
- 当前主调用链不会让 HUD 直接读取它;`SceneViewPanel` 会先经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它聚合进 overlay submission最终由 provider 体系转成统一的命中与绘制数据。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [Update](Update.md)
- [SceneViewportRotateGizmoDrawData](SceneViewportRotateGizmoDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,49 @@
# SceneViewportRotateGizmo::TryBeginDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
bool TryBeginDrag(const SceneViewportRotateGizmoContext& context, IUndoManager& undoManager);
```
## 作用
在当前 hover 轴上启动一次旋转拖拽,并为交互式撤销缓存初始状态。
## 当前实现行为
- 只有在以下条件同时满足时才会启动:
- 当前没有活动轴
- 当前已有 hover 轴
- `selectedObject` 有效
- draw data 可见
- `undoManager` 当前没有待提交的 interactive change
- 会根据当前 hover 轴计算世界旋转轴,并用 `pivotWorldPosition + worldAxis` 构造拖拽平面。
- 优先尝试通过 `BuildSceneViewportRay(...)` 与拖拽平面求交,得到稳定的世界空间起始方向。
- 如果世界空间路径不可用,则回退到 screen-space ring angle 方案,用最近环段角度作为起始角。
- 成功后会调用 `undoManager.BeginInteractiveChange("Rotate Gizmo")`
- 会缓存本次拖拽所需状态:
- 活动轴与活动实体 id
- 是否 local-space 旋转
- 是否 shared-pivot 旋转
- 世界旋转轴、拖拽平面、起始角
- 所有参与拖拽对象的起始世界位置与起始世界旋转
-`selectedObjects` 为空,会自动退回到仅对 `selectedObject` 单对象拖拽。
## 返回值
- `true`: 成功进入拖拽状态。
- `false`: 前置条件、命中几何或 interactive undo 任一环节失败。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -0,0 +1,38 @@
# SceneViewportRotateGizmo::Update
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
void Update(const SceneViewportRotateGizmoContext& context);
```
## 作用
刷新当前帧旋转 gizmo 的绘制数据,并根据鼠标位置维护 hover 状态。
## 当前实现行为
- 先调用内部 `BuildDrawData(context)`,重建四个旋转环和角度填充的绘制数据。
- 当前没有活动拖拽且鼠标位于视口内时,会调用 `EvaluateHit(context.mousePosition)` 自动计算当前 hover 轴。
- 当前没有活动拖拽但鼠标已离开视口时,会把 `hoveredAxis` 清回 `None`
- 当前处于拖拽中时,会强制把 hover 轴锁定为活动轴,避免拖拽过程中出现视觉跳变。
- 最后调用 `RefreshHandleState()`,把 hover / active 状态同步进 draw data。
## 当前实现边界
- `Update(...)` 只负责本帧可视化和 hover 刷新,不会启动拖拽事务。
- 该方法依赖 `SceneViewportRotateGizmoContext` 里的 overlay、viewportSize、mousePosition 与选中对象信息。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)

View File

@@ -0,0 +1,45 @@
# SceneViewportRotateGizmo::UpdateDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportRotateGizmo.h`
## 签名
```cpp
void UpdateDrag(const SceneViewportRotateGizmoContext& context);
```
## 作用
根据当前鼠标位置持续更新旋转增量,并把结果写回一个或多个选中对象。
## 当前实现行为
- 只有在活动轴有效、主选对象未变化、缓存对象数组与起始姿态数组长度一致时才继续。
- 如果拖拽以 screen-space 模式启动,会继续通过最近环段角度求当前角度。
- 如果拖拽以世界平面模式启动,会重新构建视口射线,与缓存拖拽平面求交,再把命中方向投影到活动旋转轴的法平面上。
-`NormalizeSignedAngleRadians(...)` 计算相对起始角的有符号弧度增量。
- 基于该角度增量同时构造:
- 围绕世界轴的 `worldDeltaRotation`
- 在 local-space 模式下使用的 `localDeltaRotation`
- 对每个参与拖拽对象:
- `rotateAroundSharedPivot = true` 时,先围绕共享 pivot 旋转位置
- 否则恢复到各自起始世界位置
- 再按 local-space 或 world-space 规则写回旋转
- 拖拽中会重新构造 draw data。
- 当处于 local-space 模式时,会用 `ComputeStableWorldRotation(selectedObject)` 更新可视化轴向,避免旋转过程中环轴方向失稳。
## 当前实现边界
- 旋转过程中不做角度吸附。
- 拖拽失败或几何退化时,该帧会直接保持上一帧状态。
## 相关文档
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -0,0 +1,29 @@
# SceneViewportScaleGizmo::CancelDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
void CancelDrag(IUndoManager* undoManager = nullptr);
```
## 作用
取消一次缩放拖拽,并清理当前活动 handle 的缓存状态。
## 当前实现行为
- 如果传入了 `undoManager` 且当前存在 pending interactive change会调用 `CancelInteractiveChange()` 回滚本次事务。
- 同样会清空活动状态。
- 与 [EndDrag](EndDrag.md) 相比,还会额外把 `hoveredHandle` 一并清空。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [EndDrag](EndDrag.md)
- [TryBeginDrag](TryBeginDrag.md)

View File

@@ -0,0 +1,29 @@
# SceneViewportScaleGizmo::EndDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
void EndDrag(IUndoManager& undoManager);
```
## 作用
提交一次缩放拖拽,并清理当前活动 handle 的缓存状态。
## 当前实现行为
- 当前没有活动 handle 时直接返回。
- 如果 `undoManager` 仍有 pending interactive change会调用 `FinalizeInteractiveChange()` 提交缩放结果。
- 随后清空活动 handle、活动实体 id、起始局部缩放、起始鼠标位置、屏幕方向和视觉缩放缓存。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [CancelDrag](CancelDrag.md)
- [UpdateDrag](UpdateDrag.md)

View File

@@ -0,0 +1,34 @@
# SceneViewportScaleGizmo::EvaluateHit
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
SceneViewportScaleGizmoHitResult EvaluateHit(const Math::Vector2& mousePosition) const;
```
## 作用
提供缩放 gizmo 的命中检测,并返回当前最近命中的 handle。
## 当前实现行为
- draw data 不可见时直接返回空命中。
- 会优先检测中心 uniform 方块,命中后立即返回 `Uniform`
- 之后会检测每个轴向 cap 方块,优先使用 cap 区域而不是整条线段。
- 如果 cap 都没命中,才退回到轴向线段距离测试。
- 这意味着当前缩放 gizmo 的命中优先级是:
- 中心 uniform handle
- 轴向 cap
- 轴向连线
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SetHoveredHandle](SetHoveredHandle.md)
- [SceneViewportScaleGizmoHitResult](SceneViewportScaleGizmoHitResult.md)

View File

@@ -0,0 +1,107 @@
# SceneViewportScaleGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `class + enum + structs`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
**描述**: Scene View 缩放 gizmo负责轴向缩放与 uniform 缩放,并把鼠标位移映射到局部缩放值。
## 概述
`SceneViewportScaleGizmo` 当前比 move / rotate 更克制一些。它支持的 handle 是:
- `X`
- `Y`
- `Z`
- `Uniform`
但从上下文结构可以看出,它当前只对 `selectedObject` 单对象工作,没有 move / rotate 那种多对象数组上下文。
## 当前实现行为
`SceneViewportScaleGizmo.cpp` 的实现:
- 拖拽开始时会调用 `undoManager.BeginInteractiveChange("Scale Gizmo")`
- 轴向缩放会把鼠标位移投影到活动轴在屏幕上的方向上。
- 如果现成的屏幕线段方向不可用,会退回到 [ProjectSceneViewportAxisDirectionAtPoint](../SceneViewportMath/SceneViewportMath.md) 估算方向。
- uniform 缩放使用 `mouseDelta.x - mouseDelta.y` 作为统一因子。
- 所有缩放都会经过最小值钳制,避免局部缩放降到 `0` 或负数。
## 公开类型
| 类型 | 说明 |
|------|------|
| [SceneViewportScaleGizmoHandle](SceneViewportScaleGizmoHandle.md) | 缩放 gizmo 的 handle 枚举。 |
| [SceneViewportScaleGizmoAxisHandleDrawData](SceneViewportScaleGizmoAxisHandleDrawData.md) | 单个轴向缩放 handle 的绘制状态。 |
| [SceneViewportScaleGizmoCenterHandleDrawData](SceneViewportScaleGizmoCenterHandleDrawData.md) | 中心 uniform handle 的绘制状态。 |
| [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md) | 当前帧完整缩放 gizmo 绘制数据。 |
| [SceneViewportScaleGizmoContext](SceneViewportScaleGizmoContext.md) | update / drag 阶段输入上下文。 |
| [SceneViewportScaleGizmoHitResult](SceneViewportScaleGizmoHitResult.md) | 缩放 gizmo 的命中结果。 |
## 公开 API
### 交互主流程
- [Update](Update.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)
### 状态查询
- [State Queries](StateQueries.md)
## 与 Transform 工具模式的关系
`SceneViewPanel``Transform` 组合工具模式下会把 `uniformOnly = true` 传进 context。按当前实现这意味着
- 组合工具不会暴露完整三轴缩放 handle。
- 当前更像“Move + Rotate + 中心统一缩放”的复合工具。
## 设计说明
缩放 gizmo 的交互通常比位移和旋转更容易失控,因为负缩放、极小缩放和轴向投影不稳定都会让操作体验变差。当前实现明显优先了“可控”和“安全”:
- 强制正缩放下界。
- 轴向缩放只沿屏幕可感知方向变化。
- 组合工具模式下进一步收窄成 uniform scale。
## 生命周期与线程语义
- 对象由 [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md) 持有。
- 当前只记录单个对象的起始 `localScale`,不是多对象事务。
- 主流程可参考 [Update](Update.md)、[TryBeginDrag](TryBeginDrag.md)、[UpdateDrag](UpdateDrag.md)、[EndDrag](EndDrag.md) 与 [CancelDrag](CancelDrag.md)。
## 与测试的对应关系
`tests/Editor/test_scene_viewport_scale_gizmo.cpp` 当前覆盖了:
- `X` 轴缩放 handle 的悬停命中。
- 带缩放父节点的子对象轴向缩放只改动对应局部缩放分量。
- 轴向拖拽期间 handle 长度会临时变化,结束后恢复。
- 中心 handle 会触发 uniform 缩放,并生成 / 回滚交互式撤销。
- 旋转对象的 `X` 轴 handle 会沿投影后的局部 `Right` 方向摆放。
## 当前限制
- 当前没有多对象缩放。
- 当前没有非等比多对象共享中心缩放策略。
- 没有数值输入、吸附或比例锁 UI。
## 相关文档
- [SceneViewportScaleGizmoHandle](SceneViewportScaleGizmoHandle.md)
- [SceneViewportScaleGizmoContext](SceneViewportScaleGizmoContext.md)
- [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md)
- [SceneViewportScaleGizmoHitResult](SceneViewportScaleGizmoHitResult.md)
- [State Queries](StateQueries.md)
- [SceneViewportMath](../SceneViewportMath/SceneViewportMath.md)
- [SceneViewportMoveGizmo](../SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
- [SceneViewportRotateGizmo](../SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)
- [SceneView Interaction And Gizmo Model](../../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportScaleGizmoAxisHandleDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 作用
描述单个轴向缩放 handle 在当前帧的绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `handle` | 当前轴向 handle 类型。 |
| `start` | 屏幕空间起点。 |
| `end` | 屏幕空间终点。 |
| `capCenter` | 端帽中心点。 |
| `capHalfSize` | 端帽半尺寸。 |
| `color` | 轴向颜色。 |
| `visible` | 当前帧是否可见。 |
| `hovered` | 当前是否悬停。 |
| `active` | 当前是否处于拖拽激活态。 |
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportScaleGizmoCenterHandleDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 作用
描述中心 uniform 缩放 handle 的绘制状态。
## 字段说明
| 字段 | 说明 |
|------|------|
| `center` | 中心方块的屏幕空间中心点。 |
| `halfSize` | 方块半尺寸。 |
| `fillColor` | 填充色。 |
| `outlineColor` | 轮廓色。 |
| `visible` | 当前帧是否可见。 |
| `hovered` | 当前是否悬停。 |
| `active` | 当前是否正在拖拽。 |
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md)

View File

@@ -0,0 +1,33 @@
# SceneViewportScaleGizmoContext
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 作用
封装缩放 gizmo 在 update 和拖拽阶段所需的输入上下文。
## 字段说明
| 字段 | 说明 |
|------|------|
| `overlay` | 当前 Scene View 相机 overlay 数据。 |
| `viewportSize` | 视口尺寸。 |
| `mousePosition` | 当前鼠标位置。 |
| `selectedObject` | 当前主选对象。 |
| `pivotWorldPosition` | gizmo pivot 世界坐标。 |
| `axisOrientation` | gizmo 轴向所使用的旋转基。 |
| `uniformOnly` | 是否只显示和允许中心统一缩放 handle。 |
## 当前使用方式
- `Update(...)` 会用它刷新 draw data。
- `TryBeginDrag(...)` / `UpdateDrag(...)` 会用它将鼠标位移映射到局部缩放值。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md)

View File

@@ -0,0 +1,32 @@
# SceneViewportScaleGizmoDrawData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 作用
封装当前帧 scale gizmo 的完整绘制数据,供 gizmo overlay state 构建与 editor overlay frame data 复用。
## 字段说明
| 字段 | 说明 |
|------|------|
| `visible` | 整个 scale gizmo 当前是否可见。 |
| `axisHandles` | 三个轴向缩放 handle 的绘制数据。 |
| `centerHandle` | 中心 uniform scale handle 的绘制数据。 |
## 当前使用方式
- `SceneViewportScaleGizmo::Update(...)` 会刷新这份数据。
- `SceneViewPanel` 会经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它与当前实体 id 聚合成 overlay submission。
- transform gizmo provider 再把它转成 `handleRecords``screenTriangles`
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoAxisHandleDrawData](SceneViewportScaleGizmoAxisHandleDrawData.md)
- [SceneViewportScaleGizmoCenterHandleDrawData](SceneViewportScaleGizmoCenterHandleDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,38 @@
# SceneViewportScaleGizmoHandle
**命名空间**: `XCEngine::Editor`
**类型**: `enum class`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 定义
```cpp
enum class SceneViewportScaleGizmoHandle : uint8_t {
None = 0,
X,
Y,
Z,
Uniform
};
```
## 作用
表示缩放 gizmo 当前命中或激活的 handle。
## 枚举值
| 值 | 说明 |
|------|------|
| `None` | 没有命中任何 handle。 |
| `X` | X 轴缩放。 |
| `Y` | Y 轴缩放。 |
| `Z` | Z 轴缩放。 |
| `Uniform` | 中心统一缩放 handle。 |
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoHitResult](SceneViewportScaleGizmoHitResult.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportScaleGizmoHitResult
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 作用
表示一次缩放 gizmo hit-test 的结果。
## 字段说明
| 字段 | 说明 |
|------|------|
| `handle` | 命中的缩放 handle。 |
| `distanceSq` | 命中点到鼠标的平方距离。 |
## 当前实现行为
- 内联 `HasHit()` 只要 `handle != None` 就返回 `true`
- 当前命中模型不区分轴向和平面,而是统一收敛到单个 `SceneViewportScaleGizmoHandle`
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [SceneViewportScaleGizmoHandle](SceneViewportScaleGizmoHandle.md)

View File

@@ -0,0 +1,28 @@
# SceneViewportScaleGizmo::SetHoveredHandle
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
void SetHoveredHandle(SceneViewportScaleGizmoHandle handle);
```
## 作用
允许外层输入系统直接覆盖当前 hover handle。
## 当前实现行为
- 当前存在活动 handle 时不会覆盖内部 hover 状态。
- 当前没有拖拽时,会直接写入 `m_hoveredHandle` 并刷新 draw data 状态。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [EvaluateHit](EvaluateHit.md)
- [Update](Update.md)

View File

@@ -0,0 +1,49 @@
# SceneViewportScaleGizmo::State Queries
**命名空间**: `XCEngine::Editor`
**类型**: `methods`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
bool IsHoveringHandle() const;
bool IsActive() const;
uint64_t GetActiveEntityId() const;
const SceneViewportScaleGizmoDrawData& GetDrawData() const;
```
## 作用
提供 scale gizmo 当前 hover / active 状态、活动实体以及每帧 draw data 的只读访问。
## 当前实现行为
### `IsHoveringHandle()`
- 当前实现等价于 `m_hoveredHandle != SceneViewportScaleGizmoHandle::None`
### `IsActive()`
- 当前实现等价于 `m_activeHandle != SceneViewportScaleGizmoHandle::None`
- 表示当前是否存在进行中的缩放拖拽。
### `GetActiveEntityId()`
- 直接返回 `m_activeEntityId`
- 未激活拖拽时通常为 `0`
### `GetDrawData()`
- 返回 `m_drawData` 的常量引用。
- 该数据由 [Update](Update.md) 维护。
- 当前主调用链不会让 HUD 直接读取它;`SceneViewPanel` 会先经由 [SceneViewportTransformGizmoCoordinator](../SceneViewportTransformGizmoCoordinator/SceneViewportTransformGizmoCoordinator.md) 把它聚合进 overlay submission最终由 provider 体系转成统一的命中与绘制数据。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [Update](Update.md)
- [SceneViewportScaleGizmoDrawData](SceneViewportScaleGizmoDrawData.md)
- [SceneViewportOverlayHandleBuilder](../SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)

View File

@@ -0,0 +1,48 @@
# SceneViewportScaleGizmo::TryBeginDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
bool TryBeginDrag(const SceneViewportScaleGizmoContext& context, IUndoManager& undoManager);
```
## 作用
在当前 hover 的缩放 handle 上启动一次缩放拖拽,并缓存起始局部缩放值。
## 当前实现行为
- 只有在以下条件成立时才会进入拖拽:
- 当前没有活动 handle
- 当前已有 hover handle
- `selectedObject` 有效
- draw data 可见
- `undoManager` 当前没有 pending interactive change
- 若当前 handle 不是 `Uniform`:
- 先读取对应轴向 handle 的屏幕线段方向
- 若线段方向退化为零,再调用 `ProjectSceneViewportAxisDirectionAtPoint(...)` 用世界轴投影补算
- 成功后调用 `undoManager.BeginInteractiveChange("Scale Gizmo")`
- 会缓存:
- 活动 handle 与活动实体 id
- 起始 `localScale`
- 起始鼠标位置
- 活动屏幕方向
- 当前可视化缩放因子,初始为 `Vector3::One()`
## 返回值
- `true`: 已成功进入缩放拖拽。
- `false`: 前置条件、轴向投影或 interactive undo 初始化失败。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [UpdateDrag](UpdateDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -0,0 +1,33 @@
# SceneViewportScaleGizmo::Update
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
void Update(const SceneViewportScaleGizmoContext& context);
```
## 作用
刷新当前帧缩放 gizmo 的绘制数据,并维护 hover handle。
## 当前实现行为
- 先调用 `BuildDrawData(context)` 重建三轴缩放 handle 与中心 uniform handle 的绘制数据。
- 当前没有活动拖拽且鼠标位于视口内时,会调用 `EvaluateHit(context.mousePosition)` 自动命中当前 handle。
- 当前没有活动拖拽但鼠标已离开视口时,会把 `hoveredHandle` 清回 `None`
- 当前已经处于拖拽中时,会把 hover handle 锁定为活动 handle。
- 最后通过 `RefreshHandleState()` 把 hovered / active 状态同步回 draw data。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [UpdateDrag](UpdateDrag.md)
- [EvaluateHit](EvaluateHit.md)
- [SetHoveredHandle](SetHoveredHandle.md)

View File

@@ -0,0 +1,42 @@
# SceneViewportScaleGizmo::UpdateDrag
**命名空间**: `XCEngine::Editor`
**类型**: `method`
**源文件**: `editor/src/Viewport/SceneViewportScaleGizmo.h`
## 签名
```cpp
void UpdateDrag(const SceneViewportScaleGizmoContext& context);
```
## 作用
根据鼠标位移持续更新单对象的局部缩放,并维护拖拽中的视觉反馈。
## 当前实现行为
- 只有在活动 handle 有效且主选对象 id 未变化时才会继续。
- 会先计算 `mouseDelta = currentMouse - startMouse`,再从 `m_dragStartLocalScale` 出发生成本帧新缩放值。
- `Uniform` 缩放路径:
- 使用 `mouseDelta.x - mouseDelta.y` 作为统一像素增量
- 计算统一缩放因子后同时更新 `x / y / z`
- 轴向缩放路径:
- 把鼠标位移投影到缓存的 `m_activeScreenDirection`
- 只修改当前活动轴对应的局部缩放分量
- 所有结果都会经过最小正缩放钳制,避免零缩放或负缩放。
- 写回 `selectedObject->GetTransform()->SetLocalScale(localScale)` 后,还会更新 `m_dragCurrentVisualScale`,用于拖拽中的 gizmo 可视化反馈。
## 当前实现边界
- 当前只处理单对象缩放,不会批量更新多选对象。
- 轴向缩放完全基于屏幕方向投影,不是世界平面求交模型。
## 相关文档
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo.md)
- [TryBeginDrag](TryBeginDrag.md)
- [EndDrag](EndDrag.md)
- [CancelDrag](CancelDrag.md)

View File

@@ -35,6 +35,12 @@
把 HUD 命中与 overlay handle 命中合并成统一交互结果。
- [SceneViewportInteractionActions](SceneViewportInteractionActions/SceneViewportInteractionActions.md)
把交互结果折叠成 hover / click action并分发 selection / orientation 对齐。
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
处理轴向 / 平面位移 gizmo 的绘制数据、命中与多对象拖拽事务。
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)
处理旋转环、视图环、共享 pivot 旋转和交互式撤销。
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo/SceneViewportScaleGizmo.md)
处理轴向缩放与 uniform 缩放,并把鼠标位移映射到局部缩放值。
- [SceneViewportOverlayHandleBuilder](SceneViewportOverlayHandleBuilder/SceneViewportOverlayHandleBuilder.md)
把 gizmo overlay state 转成 `screenTriangles``handleRecords`
- [SceneViewportTransformGizmoFrameBuilder](SceneViewportTransformGizmoFrameBuilder/SceneViewportTransformGizmoFrameBuilder.md)
@@ -64,4 +70,7 @@
- [ViewportObjectIdPicker](ViewportObjectIdPicker/ViewportObjectIdPicker.md)
- [SceneViewportHudOverlay](SceneViewportHudOverlay/SceneViewportHudOverlay.md)
- [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md)
- [SceneViewportMoveGizmo](SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
- [SceneViewportRotateGizmo](SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)
- [SceneViewportScaleGizmo](SceneViewportScaleGizmo/SceneViewportScaleGizmo.md)
- [SceneView Interaction And Gizmo Model](../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)