docs: add scene viewport interaction helper docs

This commit is contained in:
2026-04-04 01:24:16 +08:00
parent b7523db30d
commit c3680258e0
33 changed files with 1336 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
# BuildSceneViewportHudOverlayData
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
## 签名
```cpp
inline SceneViewportHudOverlayData BuildSceneViewportHudOverlayData(
const SceneViewportOverlayData& sceneOverlay,
bool showOrientationGizmo = true);
```
## 作用
把一份 `SceneViewportOverlayData` 封装成 HUD overlay 输入。
## 当前行为
- 直接把 `sceneOverlay` 拷入结果
-`showOrientationGizmo` 写入结果
## 关键语义
- 这是一个头文件内联 helper不做额外计算
- `SceneViewPanel` 当前用它统一组装 hover 判定和最终绘制所需的 HUD 数据
## 测试覆盖
`tests/Editor/test_scene_viewport_overlay_renderer.cpp``BuildSceneViewportHudOverlayDataTracksVisibilityIntent` 当前验证了默认可见和显式隐藏两条路径。
## 相关文档
- [SceneViewportHudOverlay](SceneViewportHudOverlay.md)
- [SceneViewportHudOverlayData](SceneViewportHudOverlayData.md)

View File

@@ -0,0 +1,37 @@
# DrawSceneViewportHudOverlay
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
## 签名
```cpp
void DrawSceneViewportHudOverlay(
ImDrawList* drawList,
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax);
```
## 作用
在 Scene View 的 `ImDrawList` 上绘制前端 HUD overlay。
## 当前实现行为
-`drawList == nullptr``overlay.HasVisibleElements() == false` 或 viewport 矩形无效时,直接返回
- 否则先裁剪到当前 viewport 区域
- 当前只会在 `showOrientationGizmo` 为真时调用 `DrawSceneViewportOrientationGizmo(...)`
## 关键语义
- 它当前不画 transform gizmo也不画 scene icon
- 这是一条纯前端 HUD 绘制链,不会把内容送进 GPU world overlay pass
## 相关文档
- [SceneViewportHudOverlay](SceneViewportHudOverlay.md)
- [SceneViewportOrientationGizmo](../SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md)

View File

@@ -0,0 +1,39 @@
# HitTestSceneViewportHudOverlay
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
## 签名
```cpp
SceneViewportHudOverlayHitResult HitTestSceneViewportHudOverlay(
const SceneViewportHudOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& mousePosition);
```
## 作用
把鼠标绝对位置解析成 HUD overlay 命中结果。
## 当前实现行为
- 当 HUD 不可见或 viewport 矩形无效时,返回空结果
- 当前只会对 orientation gizmo 做命中测试
- 命中成功时,返回:
- `kind = SceneViewportHudOverlayHitKind::OrientationAxis`
- `orientationAxis = 命中的具体轴`
## 测试覆盖
`tests/Editor/test_scene_viewport_overlay_renderer.cpp``HitTestSceneViewportHudOverlaySkipsInvalidOrHiddenOverlay` 当前验证了无效和显式隐藏时会返回空结果。
## 相关文档
- [SceneViewportHudOverlay](SceneViewportHudOverlay.md)
- [SceneViewportHudOverlayHitResult](SceneViewportHudOverlayHitResult.md)
- [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)

View File

@@ -0,0 +1,73 @@
# SceneViewportHudOverlay
**命名空间**: `XCEngine::Editor`
**类型**: `enum class + structs + free functions`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
**描述**: 定义 Scene View 前端 HUD overlay 的轻量数据结构、orientation gizmo 绘制入口以及对应的鼠标命中结果。
## 概览
`SceneViewportHudOverlay` 解决的是 Scene View 里“固定贴在 ImGui 前端的一层 HUD 交互”。
和 [SceneViewportEditorOverlayPass](../Passes/SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md) 的 GPU 世界 overlay 不同,这里处理的是:
- orientation gizmo 的可见性开关
- orientation gizmo 的 ImGui draw-list 绘制
- orientation gizmo 的鼠标命中
当前这层 HUD 不再承担 move / rotate / scale gizmo、scene icon 或 scene line 的主绘制链路;这些内容已经分别进入 editor overlay handle 命中链和 GPU overlay pass。
## 公开类型与函数
| 成员 | 说明 |
|------|------|
| `SceneViewportHudOverlayHitKind` | 当前 HUD 命中种类枚举。 |
| [SceneViewportHudOverlayHitResult](SceneViewportHudOverlayHitResult.md) | HUD 命中结果;当前主要承载 orientation axis。 |
| [SceneViewportHudOverlayData](SceneViewportHudOverlayData.md) | 一帧 HUD overlay 的输入数据。 |
| [BuildSceneViewportHudOverlayData](BuildSceneViewportHudOverlayData.md) | 从 `SceneViewportOverlayData` 组装 HUD 数据。 |
| [DrawSceneViewportHudOverlay](DrawSceneViewportHudOverlay.md) | 把 HUD 绘制到 `ImDrawList`。 |
| [HitTestSceneViewportHudOverlay](HitTestSceneViewportHudOverlay.md) | 把鼠标位置解析成 HUD 命中结果。 |
## 当前实现行为
`SceneViewportHudOverlay.cpp` 的实现:
- HUD 只在 viewport 矩形有效时工作
- 绘制时会先 `PushClipRect(viewportMin, viewportMax, true)`
- 当前唯一的可见 HUD 元素是 orientation gizmo
- 命中测试当前也只会返回 `OrientationAxis`
## 当前在 `SceneViewPanel` 中的使用方式
`SceneViewPanel` 当前会在两条链路里使用它:
- 交互判定阶段:
-`BuildSceneViewportHudOverlayData(overlay)`
- 再交给 [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md) 参与命中合并
- 最终绘制阶段:
- 调用 [DrawSceneViewportHudOverlay](DrawSceneViewportHudOverlay.md)
- 只补一层 ImGui HUD / orientation gizmo
## 与测试的对应关系
`tests/Editor/test_scene_viewport_overlay_renderer.cpp` 当前验证了:
- [BuildSceneViewportHudOverlayData](BuildSceneViewportHudOverlayData.md) 会正确追踪显示 / 隐藏意图。
- [HitTestSceneViewportHudOverlay](HitTestSceneViewportHudOverlay.md) 会在 overlay 无效或 HUD 被隐藏时直接跳过命中。
- 与 HUD 共用的 [ProjectSceneViewportWorldPoint](../SceneViewportMath/ProjectSceneViewportWorldPoint.md) 投影规则能把场景中心稳定映射到视口中心。
## 当前限制
- 当前 HUD 只有 orientation gizmo没有 transform gizmo 或 scene icon
- 命中结果只表达“点中了哪个朝向轴”,不直接执行相机对齐
- 真正的相机对齐仍由 `ViewportHostService::AlignSceneViewToOrientationAxis(...)` 在更上层调用链中完成
## 相关文档
- [SceneViewportOrientationGizmo](../SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md)
- [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)
- [SceneViewportEditorOverlayPass](../Passes/SceneViewportEditorOverlayPass/SceneViewportEditorOverlayPass.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)

View File

@@ -0,0 +1,25 @@
# SceneViewportHudOverlayData
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
## 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `sceneOverlay` | `SceneViewportOverlayData` | orientation gizmo 绘制所需的相机/投影输入。 |
| `showOrientationGizmo` | `bool` | 当前是否允许绘制和命中 orientation gizmo。 |
## 当前语义
- [HasVisibleElements](SceneViewportHudOverlay.md) 当前等价于:
- `sceneOverlay.valid && showOrientationGizmo`
- 因此这份数据既承载“相机姿态是否有效”也承载“HUD 是否应该显示”
## 相关文档
- [SceneViewportHudOverlay](SceneViewportHudOverlay.md)
- [BuildSceneViewportHudOverlayData](BuildSceneViewportHudOverlayData.md)

View File

@@ -0,0 +1,24 @@
# SceneViewportHudOverlayHitResult
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportHudOverlay.h`
## 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `kind` | `SceneViewportHudOverlayHitKind` | 当前命中种类;默认是 `None`。 |
| `orientationAxis` | `SceneViewportOrientationAxis` | 当命中 orientation gizmo 时记录具体轴向。 |
## 当前语义
- `HasHit()` 当前只检查 `kind != None`
- 当前实现里,唯一有效的命中种类是 `OrientationAxis`
## 相关文档
- [SceneViewportHudOverlay](SceneViewportHudOverlay.md)
- [HitTestSceneViewportHudOverlay](HitTestSceneViewportHudOverlay.md)

View File

@@ -0,0 +1,41 @@
# ApplySceneViewportHoveredHandleState
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 签名
```cpp
void ApplySceneViewportHoveredHandleState(
const SceneViewportHoveredHandleState& hoveredHandleState,
bool gizmoActive,
bool showingMoveGizmo,
SceneViewportMoveGizmo& moveGizmo,
bool showingRotateGizmo,
SceneViewportRotateGizmo& rotateGizmo,
bool showingScaleGizmo,
SceneViewportScaleGizmo& scaleGizmo);
```
## 作用
把悬停状态写回当前显示中的各 gizmo。
## 当前实现行为
- 如果 `gizmoActive == true`,直接早退,不覆盖活动拖拽 gizmo 的句柄状态。
- 否则按显示开关分别调用:
- `moveGizmo.SetHoveredHandle(...)`
- `rotateGizmo.SetHoveredHandle(...)`
- `scaleGizmo.SetHoveredHandle(...)`
这保证命中解析层与 gizmo 自身 hover 表现之间只通过一份中间状态通信。
## 相关文档
- [SceneViewportHoveredHandleState](SceneViewportHoveredHandleState.md)
- [BuildSceneViewportHoveredHandleState](BuildSceneViewportHoveredHandleState.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)

View File

@@ -0,0 +1,34 @@
# BuildSceneViewportHoveredHandleState
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 签名
```cpp
SceneViewportHoveredHandleState BuildSceneViewportHoveredHandleState(
const SceneViewportInteractionResult& interaction);
```
## 作用
从统一命中结果中提取各 gizmo 需要的悬停句柄状态。
## 当前实现行为
- 先通过 `ToSceneViewportActiveGizmoKind(...)` 写入 `hoveredGizmoKind`
- 命中 `MoveGizmo` 时写入:
- `moveAxis`
- `movePlane`
- 命中 `RotateGizmo` 时写入 `rotateAxis`
- 命中 `ScaleGizmo` 时写入 `scaleHandle`
- 其余命中类型返回空状态。
## 相关文档
- [SceneViewportHoveredHandleState](SceneViewportHoveredHandleState.md)
- [ApplySceneViewportHoveredHandleState](ApplySceneViewportHoveredHandleState.md)
- [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)

View File

@@ -0,0 +1,57 @@
# BuildSceneViewportInteractionActions
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 签名
```cpp
SceneViewportInteractionActions BuildSceneViewportInteractionActions(
const SceneViewportInteractionResult& interaction,
bool hasInteractiveViewport,
bool clickedLeft,
bool canResolveViewportInteraction);
```
## 作用
把统一命中结果翻译成当前帧左键点击应该执行的动作集合。
## 当前实现行为
函数会先从 `interaction` 提取:
- `hoveredGizmoKind`
- `orientationAxis`
- `sceneIconEntityId`
随后按当前条件组合四个动作位:
- `beginTransformGizmo`
- 需要 `hasInteractiveViewport`
- 需要 `clickedLeft`
- 需要命中的是 move / rotate / scale gizmo
- `orientationGizmoClick`
- 需要 `hasInteractiveViewport`
- 需要 `clickedLeft`
- 需要 `orientationAxis != None`
- `sceneIconClick`
- 需要 `hasInteractiveViewport`
- 需要 `clickedLeft`
- 需要 `sceneIconEntityId != 0`
- `selectSceneClick`
- 需要 `hasInteractiveViewport`
- 需要 `clickedLeft`
- 需要 `canResolveViewportInteraction`
-`interaction.HasHit() == false`
因此“空白区域点选场景”的兜底动作,只有在当前允许解析 viewport 交互且确实没有命中 overlay/HUD 时才会被置位。
## 相关文档
- [SceneViewportInteractionActions](SceneViewportInteractionActions.md)
- [DispatchSceneViewportInteractionActions](DispatchSceneViewportInteractionActions.md)
- [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)

View File

@@ -0,0 +1,68 @@
# DispatchSceneViewportInteractionActions
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 签名
```cpp
void DispatchSceneViewportInteractionActions(
const SceneViewportInteractionActions& actions,
IEditorContext& context,
IViewportHostService& viewportHostService,
const ImVec2& viewportSize,
const Math::Vector2& localMousePosition);
```
## 作用
执行不属于 gizmo 拖拽生命周期本身的点击副作用朝向对齐、scene icon 直选与 object-id picking 兜底。
## 当前实现行为
### orientation gizmo 点击
`actions.orientationGizmoClick == true`,调用:
```cpp
viewportHostService.AlignSceneViewToOrientationAxis(actions.orientationAxis);
```
### scene icon 点击
`actions.sceneIconClick == true`,直接:
```cpp
context.GetSelectionManager().SetSelectedEntity(actions.sceneIconEntityId);
```
并立刻返回,不再执行 scene picking。
### 空白区域 scene picking
`actions.selectSceneClick == true`,调用:
```cpp
viewportHostService.PickSceneViewEntity(
context,
viewportSize,
ImVec2(localMousePosition.x, localMousePosition.y));
```
- 命中实体时选择该实体
- 未命中时清空选择
## 当前边界
- 该函数不处理 gizmo `TryBeginDrag(...)`;那部分仍由 `SceneViewPanel` 自己控制。
- 它也不处理 look / pan 导航状态。
- 它只分发点击后的副作用。
## 相关文档
- [BuildSceneViewportInteractionActions](BuildSceneViewportInteractionActions.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)
- [IViewportHostService](../IViewportHostService/IViewportHostService.md)

View File

@@ -0,0 +1,29 @@
# SceneViewportHoveredHandleState
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `hoveredGizmoKind` | `SceneViewportActiveGizmoKind` | 当前命中的 gizmo 大类。 |
| `moveAxis` | `SceneViewportGizmoAxis` | move gizmo 轴命中。 |
| `movePlane` | `SceneViewportGizmoPlane` | move gizmo 平面命中。 |
| `rotateAxis` | `SceneViewportRotateGizmoAxis` | rotate gizmo 轴命中。 |
| `scaleHandle` | `SceneViewportScaleGizmoHandle` | scale gizmo 句柄命中。 |
## 当前语义
- 这是面向 gizmo `SetHoveredHandle(...)` 的中间结构。
- 同一时刻只会真正关心与 `hoveredGizmoKind` 对应的那一组字段。
- 它不表达点击或选择副作用,只表达“当前鼠标悬停的是哪个 gizmo 句柄”。
## 相关文档
- [SceneViewportInteractionActions](SceneViewportInteractionActions.md)
- [BuildSceneViewportHoveredHandleState](BuildSceneViewportHoveredHandleState.md)
- [ApplySceneViewportHoveredHandleState](ApplySceneViewportHoveredHandleState.md)

View File

@@ -0,0 +1,68 @@
# SceneViewportInteractionActions
**命名空间**: `XCEngine::Editor`
**类型**: `struct + free functions`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
**描述**: 把 `SceneViewportInteractionResult` 翻译成 gizmo 悬停状态、点击语义与最终分发动作的辅助层。
## 概览
`SceneViewportInteractionActions` 是当前 Scene View 交互链路里“命中解析之后、真正执行动作之前”的收口层。
它解决三件事:
- 把统一命中结果映射成各 gizmo 可直接消费的悬停状态。
- 把“这次左键点击到底意味着什么”收口成动作结构。
- 把 orientation 对齐、scene icon 直选与 object-id picking 兜底从 `SceneViewPanel` 内联逻辑中抽出来。
当前 `SceneViewPanel` 仍然保留:
- 导航拖拽状态
- gizmo drag begin / update / end 生命周期
但具体“点击语义如何解释”已经交给这层。
## `SceneViewportInteractionActions` 字段
| 字段 | 说明 |
|------|------|
| `hoveredGizmoKind` | 命中的 transform gizmo 大类。 |
| `orientationAxis` | 命中 orientation gizmo 时的目标轴。 |
| `sceneIconEntityId` | 命中 scene icon 时的实体 id。 |
| `beginTransformGizmo` | 是否应该开始 gizmo 拖拽。 |
| `orientationGizmoClick` | 是否应该执行视角对齐。 |
| `sceneIconClick` | 是否应该直接选择 scene icon 对应实体。 |
| `selectSceneClick` | 是否应该退回 object-id picking。 |
`HasClickAction()` 当前只检查四个点击布尔位中是否至少有一个为 `true`
## 公开类型与函数
| 成员 | 说明 |
|------|------|
| [SceneViewportHoveredHandleState](SceneViewportHoveredHandleState.md) | 各 gizmo 可直接消费的悬停状态。 |
| [ToSceneViewportActiveGizmoKind](ToSceneViewportActiveGizmoKind.md) | 把统一交互种类映射到 gizmo 大类。 |
| [BuildSceneViewportHoveredHandleState](BuildSceneViewportHoveredHandleState.md) | 从统一命中结果提取悬停句柄。 |
| [ApplySceneViewportHoveredHandleState](ApplySceneViewportHoveredHandleState.md) | 把悬停状态写回各 gizmo。 |
| [BuildSceneViewportInteractionActions](BuildSceneViewportInteractionActions.md) | 把命中结果翻译成点击动作。 |
| [DispatchSceneViewportInteractionActions](DispatchSceneViewportInteractionActions.md) | 执行 orientation 对齐、scene icon 直选与 scene picking 兜底。 |
## 测试锚点
`tests/Editor/test_scene_viewport_interaction_actions.cpp` 当前覆盖了:
- move 命中到 `SceneViewportHoveredHandleState` 的映射
- orientation gizmo 点击动作生成
- 空命中到 scene picking 兜底动作的生成
- orientation 对齐动作分发
- scene icon 点击分发
- object-id picking 选择 / 清空选择分发
## 相关文档
- [SceneViewportInteractionResolver](../SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)
- [IViewportHostService](../IViewportHostService/IViewportHostService.md)

View File

@@ -0,0 +1,29 @@
# ToSceneViewportActiveGizmoKind
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportInteractionActions.h`
## 签名
```cpp
SceneViewportActiveGizmoKind ToSceneViewportActiveGizmoKind(SceneViewportInteractionKind kind);
```
## 作用
把统一的 `SceneViewportInteractionKind` 映射成 gizmo 拖拽系统使用的 `SceneViewportActiveGizmoKind`
## 当前实现行为
- `MoveGizmo` -> `SceneViewportActiveGizmoKind::Move`
- `RotateGizmo` -> `SceneViewportActiveGizmoKind::Rotate`
- `ScaleGizmo` -> `SceneViewportActiveGizmoKind::Scale`
- `OrientationGizmo` / `SceneIcon` / `None` -> `SceneViewportActiveGizmoKind::None`
## 相关文档
- [SceneViewportInteractionActions](SceneViewportInteractionActions.md)
- [BuildSceneViewportInteractionActions](BuildSceneViewportInteractionActions.md)

View File

@@ -0,0 +1,51 @@
# ResolveSceneViewportInteraction
**命名空间**: `XCEngine::Editor`
**类型**: `function overloads`
**源文件**: `editor/src/Viewport/SceneViewportInteractionResolver.h`
## 签名
```cpp
SceneViewportInteractionResult ResolveSceneViewportInteraction(
const SceneViewportOverlayHandleHitResult& overlayHandleHit,
const SceneViewportHudOverlayHitResult& hudOverlayHit);
SceneViewportInteractionResult ResolveSceneViewportInteraction(
const SceneViewportInteractionResolveRequest& request);
```
## 作用
把 Scene View 的多来源命中结果收敛成统一交互结果。
## 当前行为
### 直接合并重载
- 把 overlay handle 命中和 HUD 命中各自转成候选项
- 依次比较 `priority``distanceSq``depth``secondaryPriority`
- 返回当前最优候选对应的 [SceneViewportInteractionResult](SceneViewportInteractionResult.md)
### 请求式重载
- 如果 `overlayFrameData` 非空,先调用 `HitTestSceneViewportOverlayHandles(...)`
- 如果 `hudOverlay` 非空,先调用 `HitTestSceneViewportHudOverlay(...)`
- 再把两侧结果交给上面的直接合并重载
## 测试覆盖
`tests/Editor/test_scene_viewport_interaction_resolver.cpp` 当前覆盖了:
- 两侧都空时返回 `None`
- transform handle 会按优先级压过 HUD orientation 命中
- HUD orientation 会压过 scene icon 命中
- 请求式重载会正确委托到 overlay handle hit test
## 相关文档
- [SceneViewportInteractionResolver](SceneViewportInteractionResolver.md)
- [SceneViewportInteractionResolveRequest](SceneViewportInteractionResolveRequest.md)
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)

View File

@@ -0,0 +1,31 @@
# SceneViewportInteractionResolveRequest
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportInteractionResolver.h`
## 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `overlayFrameData` | `const SceneViewportOverlayFrameData*` | world overlay / gizmo handle 命中输入。 |
| `viewportSize` | `Math::Vector2` | 本地 viewport 尺寸。 |
| `localMousePosition` | `Math::Vector2` | viewport 本地鼠标坐标。 |
| `hudOverlay` | `const SceneViewportHudOverlayData*` | HUD overlay 命中输入。 |
| `viewportMin` | `ImVec2` | viewport 左上角绝对坐标。 |
| `viewportMax` | `ImVec2` | viewport 右下角绝对坐标。 |
| `absoluteMousePosition` | `ImVec2` | 鼠标绝对坐标。 |
## 当前语义
- 这是一份“一次交互解析请求”的输入包
- overlay handle 命中和 HUD 命中各自只消费自己需要的那部分字段
- 某一侧输入为空时,解析器会把那一侧当作“无命中来源”
## 相关文档
- [SceneViewportInteractionResolver](SceneViewportInteractionResolver.md)
- [ResolveSceneViewportInteraction](ResolveSceneViewportInteraction.md)
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)

View File

@@ -0,0 +1,72 @@
# SceneViewportInteractionResolver
**命名空间**: `XCEngine::Editor`
**类型**: `enum class + structs + free functions`
**源文件**: `editor/src/Viewport/SceneViewportInteractionResolver.h`
**描述**: 把 Scene View 的 world overlay handle 命中结果和 HUD overlay 命中结果合并成统一交互结果。
## 概览
`SceneViewportInteractionResolver` 解决的是 Scene View 输入判定里的“最后一层归并”问题。
它的输入来自两条链路:
- [SceneViewportOverlayHitTester](../SceneViewportOverlayHitTester/SceneViewportOverlayHitTester.md)
产出的 world overlay / gizmo handle 命中
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)
产出的 orientation gizmo HUD 命中
它的输出是统一的 [SceneViewportInteractionResult](SceneViewportInteractionResult.md),供 `SceneViewPanel` 决定:
- 是不是开始 move / rotate / scale gizmo 拖拽
- 是否执行 orientation gizmo 对齐
- 是否把点击解释为 scene icon 命中
## 公开类型与函数
| 成员 | 说明 |
|------|------|
| `SceneViewportInteractionKind` | 统一交互种类枚举。 |
| [SceneViewportInteractionResult](SceneViewportInteractionResult.md) | 统一交互结果。 |
| [SceneViewportInteractionResolveRequest](SceneViewportInteractionResolveRequest.md) | 请求式重载的输入包。 |
| [ResolveSceneViewportInteraction](ResolveSceneViewportInteraction.md) | 合并命中结果或从请求对象直接完成命中解析。 |
## 当前实现行为
`SceneViewportInteractionResolver.cpp` 的实现:
- 内部会把 HUD 命中和 overlay handle 命中都转成带优先级的候选项
- 决策顺序依次比较:
- `priority`
- `distanceSq`
- `depth`
- `secondaryPriority`
- HUD orientation gizmo 当前固定使用更高优先级
- 请求式重载会先分别调用:
- `HitTestSceneViewportOverlayHandles(...)`
- `HitTestSceneViewportHudOverlay(...)`
然后再复用同一套候选合并逻辑
## 与测试的对应关系
`tests/Editor/test_scene_viewport_interaction_resolver.cpp` 当前覆盖了:
- overlay 与 HUD 都为空时返回 `None`
- 高优先级 transform handle 会压过 HUD orientation 命中。
- HUD orientation 会压过 scene icon 命中。
- 请求式重载会走完整的 overlay handle hit-test 路径。
## 当前限制
- 当前只解决“命中了什么”,不执行后续动作
- 它不持有任何交互状态,也不驱动拖拽生命周期
- 具体拖拽开始/更新/结束仍由 `SceneViewPanel` 和各 gizmo 类处理
## 相关文档
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)
- [SceneViewportOverlayHitTester](../SceneViewportOverlayHitTester/SceneViewportOverlayHitTester.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)

View File

@@ -0,0 +1,30 @@
# SceneViewportInteractionResult
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportInteractionResolver.h`
## 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `kind` | `SceneViewportInteractionKind` | 当前统一交互种类。 |
| `entityId` | `uint64_t` | scene icon 命中时的对象实体 ID。 |
| `moveAxis` | `SceneViewportGizmoAxis` | move gizmo 轴命中。 |
| `movePlane` | `SceneViewportGizmoPlane` | move gizmo 平面命中。 |
| `rotateAxis` | `SceneViewportRotateGizmoAxis` | rotate gizmo 轴命中。 |
| `scaleHandle` | `SceneViewportScaleGizmoHandle` | scale gizmo 句柄命中。 |
| `orientationAxis` | `SceneViewportOrientationAxis` | orientation gizmo 轴命中。 |
## 当前语义
- `HasHit()` 当前只检查 `kind != None`
- 各字段只在各自对应的 `kind` 下有效
- 解析器不会帮调用方清理无关字段含义;调用方应按 `kind` 读取对应槽位
## 相关文档
- [SceneViewportInteractionResolver](SceneViewportInteractionResolver.md)
- [ResolveSceneViewportInteraction](ResolveSceneViewportInteraction.md)

View File

@@ -0,0 +1,39 @@
# BuildSceneViewportAxisDragPlaneNormal
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
bool BuildSceneViewportAxisDragPlaneNormal(
const SceneViewportOverlayData& overlay,
const Math::Vector3& worldAxis,
Math::Vector3& outPlaneNormal);
```
## 作用
为轴向拖拽推导一个尽量稳定、且不与活动轴平行的平面法线。
## 当前实现行为
- 若 overlay 无效或轴长度退化为零,则失败。
- 会先把活动轴归一化。
- 然后按如下顺序尝试候选法线:
- 相机 `forward`
- 相机 `up`
- 相机 `right`
- 世界 `up`
- 世界 `right`
- 世界 `forward`
- 每个候选都会先投影到“去掉活动轴分量”的平面上;第一个非零结果会被归一化并返回。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [BuildSceneViewportPlaneFromPointNormal](BuildSceneViewportPlaneFromPointNormal.md)
- [SceneViewportMoveGizmo](../SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)

View File

@@ -0,0 +1,29 @@
# BuildSceneViewportPlaneFromPointNormal
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
Math::Plane BuildSceneViewportPlaneFromPointNormal(
const Math::Vector3& point,
const Math::Vector3& normal);
```
## 作用
根据一个点和法线构造拖拽或求交所需的平面。
## 当前实现行为
- 会先把法线归一化。
- 然后使用 `Math::Plane(planeNormal, -Dot(planeNormal, point))` 构造结果。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [BuildSceneViewportAxisDragPlaneNormal](BuildSceneViewportAxisDragPlaneNormal.md)

View File

@@ -0,0 +1,31 @@
# BuildSceneViewportProjectionMatrix
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
Math::Matrix4x4 BuildSceneViewportProjectionMatrix(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight);
```
## 作用
根据垂直 FOV、视口尺寸和裁剪面构造透视投影矩阵。
## 当前实现行为
-`viewportHeight <= 0`,当前会把纵横比回退到 `1.0f`
- 其余情况下按 `viewportWidth / viewportHeight` 计算 aspect。
- 最终调用 `Math::Matrix4x4::Perspective(...)`
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [BuildSceneViewportViewProjectionMatrix](BuildSceneViewportViewProjectionMatrix.md)

View File

@@ -0,0 +1,28 @@
# BuildSceneViewportViewMatrix
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
Math::Matrix4x4 BuildSceneViewportViewMatrix(const SceneViewportOverlayData& overlay);
```
## 作用
根据当前 Scene View 相机姿态构造视图矩阵。
## 当前实现行为
- 会把 `cameraRight / cameraUp / cameraForward` 全部归一化。
- 矩阵前三行分别使用右、上、前方向和相机位置的点积偏移组装。
- 当前实现不额外检查 `overlay.valid`,默认由调用方保证输入有效。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [BuildSceneViewportViewProjectionMatrix](BuildSceneViewportViewProjectionMatrix.md)

View File

@@ -0,0 +1,32 @@
# BuildSceneViewportViewProjectionMatrix
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
Math::Matrix4x4 BuildSceneViewportViewProjectionMatrix(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight);
```
## 作用
组合视图矩阵与投影矩阵,得到用于世界点投影的 view-projection 矩阵。
## 当前实现行为
- 当前实现直接返回:
- `Projection * View`
- 它是 [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md) 和 [ProjectSceneViewportAxisDirectionAtPoint](ProjectSceneViewportAxisDirectionAtPoint.md) 的基础。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [BuildSceneViewportViewMatrix](BuildSceneViewportViewMatrix.md)
- [BuildSceneViewportProjectionMatrix](BuildSceneViewportProjectionMatrix.md)

View File

@@ -0,0 +1,33 @@
# DistanceToSegmentSquared
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
float DistanceToSegmentSquared(
const Math::Vector2& point,
const Math::Vector2& segmentStart,
const Math::Vector2& segmentEnd,
float* outSegmentT = nullptr);
```
## 作用
计算一个二维点到线段的平方距离。
## 当前实现行为
- 若线段长度退化到零,会直接退回“点到起点”的平方距离。
- 否则会计算线段参数 `t`,并在 `[0, 1]` 内钳制。
- 若传入了 `outSegmentT`,会回写最近点在线段上的参数位置。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [SceneViewportMoveGizmo](../SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
- [SceneViewportRotateGizmo](../SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)

View File

@@ -0,0 +1,32 @@
# ProjectSceneViewportAxisDirection
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
bool ProjectSceneViewportAxisDirection(
const SceneViewportOverlayData& overlay,
const Math::Vector3& worldAxis,
Math::Vector2& outScreenDirection);
```
## 作用
估计一个世界轴在当前视口屏幕上的二维方向。
## 当前实现行为
-`overlay.valid == false`,直接失败。
- 会先把 `worldAxis` 归一化并变换到当前视图空间。
- 最终使用 `(viewAxis.x, -viewAxis.y)` 作为屏幕方向。
- 若结果退化到零长度,则返回 `false`
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [ProjectSceneViewportAxisDirectionAtPoint](ProjectSceneViewportAxisDirectionAtPoint.md)

View File

@@ -0,0 +1,35 @@
# ProjectSceneViewportAxisDirectionAtPoint
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
bool ProjectSceneViewportAxisDirectionAtPoint(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight,
const Math::Vector3& worldPoint,
const Math::Vector3& worldAxis,
Math::Vector2& outScreenDirection,
float sampleDistance = 1.0f);
```
## 作用
以具体世界采样点为基准,估计一个轴在屏幕上的方向。
## 当前实现行为
- 会先校验 overlay、视口尺寸、轴长度和 `sampleDistance`
- 主路径是投影 `worldPoint``worldPoint + axis * sampleDistance` 两个点,然后取它们的屏幕差向量。
- 若任一点投影失败或结果退化到零长度,则回退到 [ProjectSceneViewportAxisDirection](ProjectSceneViewportAxisDirection.md)。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [ProjectSceneViewportAxisDirection](ProjectSceneViewportAxisDirection.md)

View File

@@ -0,0 +1,34 @@
# ProjectSceneViewportWorldPoint
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
SceneViewportProjectedPoint ProjectSceneViewportWorldPoint(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight,
const Math::Vector3& worldPoint);
```
## 作用
把世界空间点投影到 Scene View 屏幕坐标。
## 当前实现行为
-`overlay` 无效或视口宽高太小,会直接返回默认结果。
- 会先计算 clip-space 点;`clipPoint.w <= epsilon` 时直接判定不可见。
- 否则把点除以 `w` 转成 NDC再换算到屏幕坐标。
- `visible` 只有在 `x/y/z` 全部位于标准裁剪范围时才为真。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [SceneViewportProjectedPoint](SceneViewportProjectedPoint.md)
- [ProjectSceneViewportWorldPointClamped](ProjectSceneViewportWorldPointClamped.md)

View File

@@ -0,0 +1,35 @@
# ProjectSceneViewportWorldPointClamped
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 签名
```cpp
bool ProjectSceneViewportWorldPointClamped(
const SceneViewportOverlayData& overlay,
float viewportWidth,
float viewportHeight,
const Math::Vector3& worldPoint,
float edgePadding,
SceneViewportProjectedPoint& outProjectedPoint);
```
## 作用
投影世界点,并把屏幕坐标钳制到给定边缘内。
## 当前实现行为
- 会先调用 [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md)。
- 若 overlay 无效、视口尺寸无效或深度小于 `0`,则失败。
- 否则按 `edgePadding``screenPosition` 钳制在视口矩形内部。
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md)
- [SceneViewportProjectedPoint](SceneViewportProjectedPoint.md)

View File

@@ -0,0 +1,84 @@
# SceneViewportMath
**命名空间**: `XCEngine::Editor`
**类型**: `header-helper`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
**描述**: 为 Scene View overlay、gizmo 和 picking 提供统一的投影、屏幕方向、拖拽平面和距离计算 helper。
## 概述
`SceneViewportMath.h``Viewport` 模块里最基础的“几何工具层”。它把很多本来容易散落在 gizmo / picker / overlay builder 里的数学过程集中到一个地方,例如:
- 构建 view / projection / view-projection 矩阵。
- 世界点投影到视口屏幕坐标。
- 世界轴投影到屏幕方向。
- 线段距离计算。
- 基于相机方向为轴向拖拽自动求稳定拖拽平面。
这类 helper 的价值很像商业引擎编辑器里的 `HandleUtility` 一类基础设施。
## 主要能力
| 函数 | 说明 |
|------|------|
| [SceneViewportProjectedPoint](SceneViewportProjectedPoint.md) | 世界点投影后的屏幕坐标、深度和可见性结果。 |
| [BuildSceneViewportViewMatrix](BuildSceneViewportViewMatrix.md) | 由 `cameraRight / Up / Forward / Position` 组装视图矩阵。 |
| [BuildSceneViewportProjectionMatrix](BuildSceneViewportProjectionMatrix.md) | 基于垂直 FOV 和视口宽高创建透视投影。 |
| [BuildSceneViewportViewProjectionMatrix](BuildSceneViewportViewProjectionMatrix.md) | 组合视图矩阵与投影矩阵。 |
| [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md) | 把世界点投影为屏幕坐标和 `ndcDepth`。 |
| [ProjectSceneViewportAxisDirection](ProjectSceneViewportAxisDirection.md) | 计算世界轴在屏幕上的朝向。 |
| [ProjectSceneViewportAxisDirectionAtPoint](ProjectSceneViewportAxisDirectionAtPoint.md) | 以具体采样点为基准估计屏幕轴方向。 |
| [ProjectSceneViewportWorldPointClamped](ProjectSceneViewportWorldPointClamped.md) | 投影后做边缘钳制。 |
| [DistanceToSegmentSquared](DistanceToSegmentSquared.md) | 供 gizmo hit-test 使用的二维距离 helper。 |
| [BuildSceneViewportPlaneFromPointNormal](BuildSceneViewportPlaneFromPointNormal.md) | 由点和法线构建拖拽平面。 |
| [BuildSceneViewportAxisDragPlaneNormal](BuildSceneViewportAxisDragPlaneNormal.md) | 为轴向拖拽推导合适的平面法线。 |
## 当前实现行为
- 这些 helper 全部是 `inline` 函数,没有独立 `.cpp`
- [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md) 在 `clipPoint.w <= epsilon` 时会直接判定不可见。
- [ProjectSceneViewportAxisDirectionAtPoint](ProjectSceneViewportAxisDirectionAtPoint.md) 会优先做两点投影采样,失败时回退到纯方向投影。
- [BuildSceneViewportAxisDragPlaneNormal](BuildSceneViewportAxisDragPlaneNormal.md) 会按相机 forward / up / right 以及世界基轴顺序寻找一个不与拖拽轴平行的候选法线。
## 设计说明
把这些数学过程集中起来有两个收益:
- Scene View gizmo 的 hit-test、拖拽和绘制可以共享完全一致的投影逻辑。
- 当视口投影规则调整时,不需要分别修改 move / rotate / scale 三套代码。
这类“统一几何约定层”是编辑器工具质量很重要的一部分。没有它,交互往往会出现看起来能点到、实际拖起来方向不对,或者不同 gizmo 手感不一致的问题。
## 与测试的对应关系
`tests/Editor/test_scene_viewport_overlay_renderer.cpp` 当前验证了:
- [BuildSceneViewportViewMatrix](BuildSceneViewportViewMatrix.md) 与编辑器相机 transform 约定一致。
- [BuildSceneViewportProjectionMatrix](BuildSceneViewportProjectionMatrix.md) 和 [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md) 的投影结果符合 Scene View 预期。
- [BuildSceneViewportAxisDragPlaneNormal](BuildSceneViewportAxisDragPlaneNormal.md) 会在相机 forward 与拖拽轴对齐时回退到其它稳定法线候选。
## 当前限制
- 当前投影 helper 假设的是标准透视视口语义,不是更一般化的任意裁剪空间工具库。
- 没有对极端数值稳定性做更重的保护,例如非常接近 near plane 的大规模场景。
## 相关文档
- [SceneViewportProjectedPoint](SceneViewportProjectedPoint.md)
- [BuildSceneViewportViewMatrix](BuildSceneViewportViewMatrix.md)
- [BuildSceneViewportProjectionMatrix](BuildSceneViewportProjectionMatrix.md)
- [BuildSceneViewportViewProjectionMatrix](BuildSceneViewportViewProjectionMatrix.md)
- [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md)
- [ProjectSceneViewportAxisDirection](ProjectSceneViewportAxisDirection.md)
- [ProjectSceneViewportAxisDirectionAtPoint](ProjectSceneViewportAxisDirectionAtPoint.md)
- [ProjectSceneViewportWorldPointClamped](ProjectSceneViewportWorldPointClamped.md)
- [DistanceToSegmentSquared](DistanceToSegmentSquared.md)
- [BuildSceneViewportPlaneFromPointNormal](BuildSceneViewportPlaneFromPointNormal.md)
- [BuildSceneViewportAxisDragPlaneNormal](BuildSceneViewportAxisDragPlaneNormal.md)
- [SceneViewportMoveGizmo](../SceneViewportMoveGizmo/SceneViewportMoveGizmo.md)
- [SceneViewportRotateGizmo](../SceneViewportRotateGizmo/SceneViewportRotateGizmo.md)
- [SceneViewportScaleGizmo](../SceneViewportScaleGizmo/SceneViewportScaleGizmo.md)
- [SceneViewportPicker](../SceneViewportPicker/SceneViewportPicker.md)

View File

@@ -0,0 +1,35 @@
# SceneViewportProjectedPoint
**命名空间**: `XCEngine::Editor`
**类型**: `struct`
**源文件**: `editor/src/Viewport/SceneViewportMath.h`
## 定义
```cpp
struct SceneViewportProjectedPoint {
Math::Vector2 screenPosition = Math::Vector2::Zero();
float ndcDepth = 0.0f;
bool visible = false;
};
```
## 作用
表示一个世界点投影到 Scene View 后的屏幕坐标、深度和可见性。
## 字段说明
| 字段 | 说明 |
|------|------|
| `screenPosition` | 投影后的屏幕坐标。 |
| `ndcDepth` | 投影后的 NDC 深度。 |
| `visible` | 是否位于可见裁剪范围内。 |
## 相关文档
- [SceneViewportMath](SceneViewportMath.md)
- [ProjectSceneViewportWorldPoint](ProjectSceneViewportWorldPoint.md)
- [ProjectSceneViewportWorldPointClamped](ProjectSceneViewportWorldPointClamped.md)

View File

@@ -0,0 +1,38 @@
# DrawSceneViewportOrientationGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportOrientationGizmo.h`
## 签名
```cpp
void DrawSceneViewportOrientationGizmo(
ImDrawList* drawList,
const SceneViewportOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax);
```
## 作用
在 Scene View 右上角绘制朝向 gizmo包括中心立方体和六个方向轴帽。
## 当前实现行为
- `drawList == nullptr``overlay.valid == false` 时直接返回。
- 会先根据 `viewportMin / viewportMax` 计算控件中心点。
- 然后调用 `BuildSortedAxisHandles(overlay)` 生成六个方向 handle 的投影与排序数据。
- 绘制顺序分为三段:
- 先画 `sortDepth > 0` 的前景轴帽
- 再画中心 cube
- 最后画 `sortDepth <= 0` 的背面轴帽
- 这种顺序让前向轴帽保持可见,同时仍然保留中心立方体对背向轴的遮挡关系。
## 相关文档
- [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo.md)
- [HitTestSceneViewportOrientationGizmo](HitTestSceneViewportOrientationGizmo.md)
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)

View File

@@ -0,0 +1,43 @@
# HitTestSceneViewportOrientationGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `function`
**源文件**: `editor/src/Viewport/SceneViewportOrientationGizmo.h`
## 签名
```cpp
SceneViewportOrientationAxis HitTestSceneViewportOrientationGizmo(
const SceneViewportOverlayData& overlay,
const ImVec2& viewportMin,
const ImVec2& viewportMax,
const ImVec2& mousePosition);
```
## 作用
检测鼠标当前命中了哪个朝向 gizmo handle并返回对应的语义朝向轴。
## 当前实现行为
- `overlay.valid == false` 时直接返回 `SceneViewportOrientationAxis::None`
- 会基于当前视口矩形重新计算控件中心。
- 再构造一份 `AxisHandleVisual` 数组,并按 `sortDepth` 从小到大排序。
- 随后依次调用 `HitTestAxisHandle(...)` 做命中测试,命中即返回:
- `PositiveX / NegativeX`
- `PositiveY / NegativeY`
- `PositiveZ / NegativeZ`
- 全部失败时返回 `SceneViewportOrientationAxis::None`
## 设计含义
- 该函数只负责把 2D 点击解析成朝向语义。
- 真正的相机对齐动作仍然由视口宿主服务执行。
## 相关文档
- [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo.md)
- [DrawSceneViewportOrientationGizmo](DrawSceneViewportOrientationGizmo.md)
- [ViewportHostService](../ViewportHostService/ViewportHostService.md)

View File

@@ -0,0 +1,55 @@
# SceneViewportOrientationGizmo
**命名空间**: `XCEngine::Editor`
**类型**: `free functions`
**源文件**: `editor/src/Viewport/SceneViewportOrientationGizmo.h`
**描述**: 绘制 Scene View 右上角朝向 gizmo并把鼠标点击解析为 `SceneViewportOrientationAxis`
## 概述
`SceneViewportOrientationGizmo` 是 Scene View 里典型的“编辑器导航控件”。它不是变换 gizmo也不直接修改相机只负责两件事
- 在右上角绘制一个朝向立方体和轴向帽。
- 根据鼠标点击命中返回目标朝向轴。
真正的相机对齐动作仍然由 [IViewportHostService](../IViewportHostService/IViewportHostService.md) / [ViewportHostService](../ViewportHostService/ViewportHostService.md) 执行。
## 公开函数
| 函数 | 说明 |
|------|------|
| [DrawSceneViewportOrientationGizmo](DrawSceneViewportOrientationGizmo.md) | 绘制右上角朝向 gizmo。 |
| [HitTestSceneViewportOrientationGizmo](HitTestSceneViewportOrientationGizmo.md) | 把鼠标位置解析为 `SceneViewportOrientationAxis`。 |
## 当前实现行为
`SceneViewportOrientationGizmo.cpp` 的实现:
- [DrawSceneViewportOrientationGizmo](DrawSceneViewportOrientationGizmo.md) 会把世界 `X / Y / Z` 轴转换到当前 Scene View 相机空间,并以自定义 cube + 轴向 cap 的方式绘制,而不是直接贴图。
- [HitTestSceneViewportOrientationGizmo](HitTestSceneViewportOrientationGizmo.md) 会对轴向 handle 做独立命中测试,并返回 `PositiveX / NegativeX / ...` 这样的语义轴。
## 设计说明
这层分离很合理:
- UI helper 只关心“点中了哪个方向”。
- 宿主服务再决定“如何让相机朝那个方向看过去”。
这样绘制与状态应用不会耦合在一个类里,后续如果要替换为更复杂的 orientation widget也不需要重写视口宿主服务。
## 当前限制
- 当前返回的是轴语义,不包含自由旋转或拖拽环导航。
- 控件交互是点击式,不是完整的 3D trackball。
## 相关文档
- [DrawSceneViewportOrientationGizmo](DrawSceneViewportOrientationGizmo.md)
- [HitTestSceneViewportOrientationGizmo](HitTestSceneViewportOrientationGizmo.md)
- [IViewportHostService](../IViewportHostService/IViewportHostService.md)
- [ViewportHostService](../ViewportHostService/ViewportHostService.md)
- [SceneViewportHudOverlay](../SceneViewportHudOverlay/SceneViewportHudOverlay.md)
- [SceneViewPanel](../../panels/SceneViewPanel/SceneViewPanel.md)

View File

@@ -21,12 +21,16 @@
当前宿主实现,持有 editor camera、render target 与 Scene View overlay 缓存。
- [SceneViewportCameraController](SceneViewportCameraController/SceneViewportCameraController.md)
维护 Scene View 相机的焦点、距离、朝向和飞行速度,并把结果写回隐藏相机变换。
- [SceneViewportMath](SceneViewportMath/SceneViewportMath.md)
提供投影、屏幕方向、拖拽平面和距离计算等几何 helper供 gizmo / overlay / picker 共用。
- [SceneViewportPicker](SceneViewportPicker/SceneViewportPicker.md)
提供 CPU 射线选取 helper当前更多用于辅助 gizmo 命中和保留的几何拾取路径。
- [ViewportObjectIdPicker](ViewportObjectIdPicker/ViewportObjectIdPicker.md)
封装 Scene View object-id 读回请求构建、像素坐标映射与颜色解码,是当前主点击选取链路的底层 helper。
- [SceneViewportHudOverlay](SceneViewportHudOverlay/SceneViewportHudOverlay.md)
负责前端 HUD / orientation gizmo 的构造、绘制和命中。
- [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md)
提供右上角朝向 gizmo 的绘制和点击命中,供 HUD overlay 复用。
- [SceneViewportInteractionResolver](SceneViewportInteractionResolver/SceneViewportInteractionResolver.md)
把 HUD 命中与 overlay handle 命中合并成统一交互结果。
- [SceneViewportInteractionActions](SceneViewportInteractionActions/SceneViewportInteractionActions.md)
@@ -55,6 +59,9 @@
- [Editor](../Editor.md)
- [SceneViewPanel](../panels/SceneViewPanel/SceneViewPanel.md)
- [SceneViewportCameraController](SceneViewportCameraController/SceneViewportCameraController.md)
- [SceneViewportMath](SceneViewportMath/SceneViewportMath.md)
- [SceneViewportPicker](SceneViewportPicker/SceneViewportPicker.md)
- [ViewportObjectIdPicker](ViewportObjectIdPicker/ViewportObjectIdPicker.md)
- [SceneViewportHudOverlay](SceneViewportHudOverlay/SceneViewportHudOverlay.md)
- [SceneViewportOrientationGizmo](SceneViewportOrientationGizmo/SceneViewportOrientationGizmo.md)
- [SceneView Interaction And Gizmo Model](../../../_guides/Editor/SceneView-Interaction-And-Gizmo-Model.md)