feat: add UE5 LED display client — backend API, C++ source, stereo framework
Backend: - Add /api/v1/ue/* endpoints (compute-points, cables, landing-points, satellites, status) returning flat JSON optimised for UE5 C++ parsing UE5 client (ue_client/): - PlanetDataManager: HTTP fetch + local mock JSON loader, spawns ComputePointActors - ComputePointActor / InteractiveObjectBase: hover/select state, material switching - GlobeInteractionComponent: drag-to-rotate via CesiumGeoreference origin shift, inertia, zoom - StereoRenderingManager: runtime SbS/TbB stereo toggle, IPD control (format TBD) - MotionCaptureInterface: protocol-agnostic gesture/rotate/zoom delegate interface (impl TBD) - PlanetPlayerController: unified mouse + motion-capture input routing - PlanetGameMode, Build.cs, Config, mock data Docs: - ue5_mvp_fused_plan.md updated to v3.0 for LED display context - ue_client_setup_guide.md: step-by-step editor setup guide - ue_todo.md: pending items blocked on vendor answers (stereo format + mocap protocol) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
319
docs/ue_client_setup_guide.md
Normal file
319
docs/ue_client_setup_guide.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# UE5 客户端手动操作指南
|
||||
|
||||
> 本指南对应 `ue_client/` 目录下已生成的所有代码和配置。
|
||||
> 代码已写好,你只需要做编辑器里的点击操作。
|
||||
> 遇到红色错误先看文末"常见问题"章节。
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
| 软件 | 版本 | 下载地址 |
|
||||
|------|------|---------|
|
||||
| Unreal Engine | **5.3** | Epic Games Launcher → Library → 5.3 |
|
||||
| Cesium for Unreal | 最新 | 直接在下一步从 Marketplace 安装 |
|
||||
| Visual Studio | 2022 Community | visualstudio.microsoft.com(安装 C++ 游戏开发工作负载) |
|
||||
|
||||
> **注意**:Cesium for Unreal 必须先安装,否则代码会编译失败。
|
||||
|
||||
---
|
||||
|
||||
## 第一阶段(Phase A):本地演示版(不需要后端)
|
||||
|
||||
### 步骤 1:安装 Cesium for Unreal
|
||||
|
||||
1. 打开 **Epic Games Launcher**
|
||||
2. 顶部切换到 **Unreal Engine** 选项卡
|
||||
3. 左侧点击 **Marketplace** → 搜索 `Cesium for Unreal`
|
||||
4. 点击 **免费获取**(Free),然后点击 **安装到引擎** → 选择 5.3
|
||||
5. 等待安装完成
|
||||
|
||||
---
|
||||
|
||||
### 步骤 2:打开项目
|
||||
|
||||
1. 打开 **Epic Games Launcher** → **Unreal Engine** → **Library**
|
||||
2. 找到 5.3,点击右侧 **Launch** 旁边的下拉箭头 → **Browse**
|
||||
3. 导航到 `planet/ue_client/`,选择 `PlanetClient.uproject`,点击打开
|
||||
4. UE 会提示"缺少模块,需要重新编译" → 点击 **Yes**
|
||||
5. 等待编译完成(首次约 5-10 分钟)
|
||||
|
||||
> 如果编译报错:见文末"常见问题 → 编译错误"
|
||||
|
||||
---
|
||||
|
||||
### 步骤 3:创建新关卡
|
||||
|
||||
1. 菜单栏 → **File** → **New Level**
|
||||
2. 选择 **Empty Level**(空关卡)
|
||||
3. 保存:**File** → **Save Current Level As**
|
||||
路径:`Content/Maps/`,名称:`EarthMap`
|
||||
4. 点击 **Save**
|
||||
|
||||
---
|
||||
|
||||
### 步骤 4:添加 Cesium 地球
|
||||
|
||||
1. 顶部菜单栏 → **Cesium**(如果没有此菜单,说明插件未激活:Edit → Plugins → 搜索 Cesium → 勾选 Enable → 重启)
|
||||
2. 在 Cesium 面板里点击 **Add Blank 3D Tiles Tileset** — 这会自动在场景里添加:
|
||||
- `CesiumGeoreference` Actor
|
||||
- `Cesium3DTileset` Actor(地球瓦片)
|
||||
3. 再点击 **Add Cesium ion Bing Maps Aerial** 添加卫星影像底图(需要免费 Cesium ion 账号)
|
||||
|
||||
> 如果没有 Cesium ion 账号:Cesium 菜单 → Connect to Cesium ion → 注册免费账号
|
||||
|
||||
---
|
||||
|
||||
### 步骤 5:添加相机 Pawn
|
||||
|
||||
1. 菜单栏 → **Cesium** → 找到 **Dynamic Pawn**(名称可能是 `CesiumFlyToComponent` 相关的 Blueprint)
|
||||
**或者**:Content Browser → 顶部搜索框输入 `DynamicPawn` → 找到插件内容里的 `DynamicPawn` → 拖入场景
|
||||
2. 在 **Outliner** 面板里点击刚拖入的 `DynamicPawn`
|
||||
3. 在 **Details** 面板里,找到 **Auto Possess Player** → 改为 **Player 0**
|
||||
|
||||
> 这样游戏启动时摄像机会自动使用这个可飞行的地球相机。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 6:配置 GameMode
|
||||
|
||||
1. 菜单栏 → **Window** → **World Settings**(如果没有,也可以在 Details Panel 里找)
|
||||
2. 在 **World Settings** 面板里找到 **Game Mode Override**
|
||||
3. 点击下拉框 → 搜索 `PlanetGameMode` → 选择它
|
||||
4. 找到 **Default Pawn Class** → 改为上一步拖入的 `DynamicPawn`
|
||||
|
||||
---
|
||||
|
||||
### 步骤 7:创建 ComputePoint Blueprint
|
||||
|
||||
这步把我写的 C++ 类包装成可以在编辑器里配置材质的 Blueprint。
|
||||
|
||||
1. **Content Browser** → 空白处右键 → **Blueprint Class**
|
||||
2. 搜索父类:输入 `ComputePointActor` → 找到 `AComputePointActor` → 点击 **Select**
|
||||
3. 命名为 `BP_ComputePointActor`,保存到 `Content/Blueprints/`
|
||||
|
||||
**配置 BP_ComputePointActor 的网格和材质:**
|
||||
|
||||
4. 双击打开 `BP_ComputePointActor`
|
||||
5. 在左侧 **Components** 面板里点击 `SphereMesh`
|
||||
6. 在右侧 **Details** 面板里找到 **Static Mesh** → 点击下拉 → 搜索 `Sphere` → 选择 **Engine/BasicShapes/Sphere**
|
||||
7. 找到 **Material** → 点击下拉 → 搜索 `M_Basic_Wall` 或者创建新材质(见下方)
|
||||
|
||||
**创建三种状态的材质(颜色点即可):**
|
||||
|
||||
8. Content Browser → 右键 → **Material** → 命名 `M_PointNormal`
|
||||
- 双击打开 → 右键空白区域 → 搜索 `Constant3Vector` → 连接到 `Base Color`
|
||||
- 颜色设为橙色:`(1.0, 0.4, 0.0)`
|
||||
- 保存
|
||||
|
||||
9. 同样方式创建 `M_PointHovered`(颜色白色 `1,1,1`)和 `M_PointSelected`(颜色青色 `0,1,1`)
|
||||
|
||||
**回到 BP_ComputePointActor:**
|
||||
|
||||
10. 在 **Details** 面板里:
|
||||
- **Normal Material** → 选 `M_PointNormal`
|
||||
- **Hovered Material** → 选 `M_PointHovered`
|
||||
- **Selected Material** → 选 `M_PointSelected`
|
||||
- **Point Scale** → `80000`(根据实际效果调整)
|
||||
11. 点击左上角 **Compile** → **Save**
|
||||
|
||||
---
|
||||
|
||||
### 步骤 8:放置 DataManager 并配置
|
||||
|
||||
1. **Content Browser** → 右键 → **Blueprint Class** → 父类搜索 `PlanetDataManager` → 选择 `APlanetDataManager`
|
||||
2. 命名为 `BP_PlanetDataManager`,保存到 `Content/Blueprints/`
|
||||
3. 将 `BP_PlanetDataManager` **拖入场景**(Outliner 里会出现它)
|
||||
4. 在 Outliner 里点击它 → 在 **Details** 面板里配置:
|
||||
- **Use Local Mock Data** → ✅ **勾选**(Phase A 不需要后端)
|
||||
- **Mock Data Path** → 留空(代码会自动找 `Content/Data/mock_compute_points.json`)
|
||||
- **Compute Point Class** → 选择 `BP_ComputePointActor`
|
||||
- **Point Altitude Meters** → `50000`(海拔 50km,可调)
|
||||
|
||||
---
|
||||
|
||||
### 步骤 9:测试 Phase A
|
||||
|
||||
1. 点击顶部工具栏绿色 **Play** 按钮(或 Alt+P)
|
||||
2. 地球应该加载卫星影像
|
||||
3. 应该看到 10 个橙色球体分布在地球上(对应 mock JSON 里的 TOP500 超算)
|
||||
4. 鼠标移到球体上 → 变白色(Hover)
|
||||
5. 点击球体 → 变青色(Selected)
|
||||
|
||||
**验证通过标准:**
|
||||
- [x] 地球可见
|
||||
- [x] 橙色球体出现在正确位置(美国、日本、荷兰、芬兰等)
|
||||
- [x] 悬停变色
|
||||
- [x] 点击变色
|
||||
|
||||
---
|
||||
|
||||
## 第二阶段(Phase B):连接真实后端
|
||||
|
||||
### 步骤 10:确认后端新接口可用
|
||||
|
||||
后端代码已添加新路由,先验证它已经运行:
|
||||
|
||||
```bash
|
||||
# 在 WSL 或终端里
|
||||
curl http://localhost:8000/api/v1/ue/status
|
||||
```
|
||||
|
||||
应该返回类似:
|
||||
```json
|
||||
{"ok": true, "server_time": "...", "compute_points_count": 500, ...}
|
||||
```
|
||||
|
||||
如果 curl 失败:
|
||||
- 检查 `planet.sh` 是否在运行(`./planet.sh start`)
|
||||
- 检查 WSL2 → Windows 的网络:在 UE 里使用 `172.x.x.x`(WSL 网关地址)而不是 `localhost`
|
||||
|
||||
---
|
||||
|
||||
### 步骤 11:获取 WSL2 → Windows 的正确 IP
|
||||
|
||||
在 WSL 终端里运行:
|
||||
|
||||
```bash
|
||||
cat /etc/resolv.conf | grep nameserver | awk '{print $2}'
|
||||
```
|
||||
|
||||
记下这个 IP(例如 `172.22.32.1`)。
|
||||
|
||||
---
|
||||
|
||||
### 步骤 12:切换 DataManager 到实时模式
|
||||
|
||||
1. 在 Outliner 里点击 `BP_PlanetDataManager`
|
||||
2. Details 面板里:
|
||||
- **Use Local Mock Data** → **取消勾选**
|
||||
- **Backend Base URL** → 填入 `http://172.22.32.1:8000`(你的实际 WSL IP)
|
||||
3. 重新 Play → DataManager 会通过 HTTP 拉取真实数据
|
||||
|
||||
---
|
||||
|
||||
### 步骤 13:绑定点击事件显示信息卡(可选,需要 UMG)
|
||||
|
||||
这步是可选的,需要创建一个 Widget Blueprint 来显示选中点的信息。
|
||||
|
||||
1. Content Browser → 右键 → **User Interface** → **Widget Blueprint**
|
||||
2. 命名为 `WBP_PointInfo`
|
||||
|
||||
**设计 Widget 布局:**
|
||||
|
||||
3. 双击打开 `WBP_PointInfo`
|
||||
4. 从左侧 **Palette** 拖入以下控件到画布:
|
||||
- `Canvas Panel`(容器,设置为全屏)
|
||||
- `Border`(右下角定位,用作信息卡背景,宽 300,高 200)
|
||||
- `Text Block` × 4(名称、排名、算力、国家)
|
||||
|
||||
**绑定事件(Blueprint 里操作):**
|
||||
|
||||
5. 打开 `BP_PlanetDataManager` 的 Event Graph
|
||||
6. 找到 **BeginPlay** 节点
|
||||
7. 拖出线 → 搜索 **Bind Event to On Point Selected**(这是我在 PlayerController 里定义的委托)
|
||||
|
||||
> 具体蓝图连线:从 PlayerController 获取 OnPointSelected → Bind → 在回调里 Create Widget WBP_PointInfo → Add to Viewport → Set 各个文本
|
||||
|
||||
---
|
||||
|
||||
## 文件结构总览
|
||||
|
||||
```
|
||||
ue_client/
|
||||
PlanetClient.uproject ← UE 项目入口
|
||||
Config/
|
||||
DefaultGame.ini ← GameMode 配置
|
||||
DefaultEngine.ini ← 渲染/引擎设置
|
||||
DefaultInput.ini ← 键鼠输入绑定
|
||||
Content/
|
||||
Data/
|
||||
mock_compute_points.json ← Phase A 本地测试数据(10个超算)
|
||||
Maps/
|
||||
EarthMap.umap ← 你在步骤3创建的关卡
|
||||
Blueprints/
|
||||
BP_ComputePointActor ← 步骤7创建
|
||||
BP_PlanetDataManager ← 步骤8创建
|
||||
Source/
|
||||
PlanetClient/
|
||||
PlanetClient.Build.cs ← 模块依赖(HTTP、JSON、Cesium)
|
||||
PlanetClient.h/.cpp ← 模块入口
|
||||
PlanetDataTypes.h ← 数据结构定义(FComputePoint 等)
|
||||
PlanetDataManager.h/.cpp ← HTTP 拉取 + 生成 Actor
|
||||
ComputePointActor.h/.cpp ← 单个超算点的可视化 Actor
|
||||
PlanetPlayerController.h/.cpp ← 鼠标点击、悬停、相机控制
|
||||
PlanetGameMode.h/.cpp ← GameMode 入口
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 后端新接口一览
|
||||
|
||||
后端已新增以下接口(无需认证,直接访问):
|
||||
|
||||
| 接口 | 说明 |
|
||||
|------|------|
|
||||
| `GET /api/v1/ue/status` | 健康检查 + 各数据源数量 |
|
||||
| `GET /api/v1/ue/compute-points` | TOP500 超算数据(平铺 JSON) |
|
||||
| `GET /api/v1/ue/landing-points` | 海缆登陆点(平铺 JSON) |
|
||||
| `GET /api/v1/ue/cables` | 海缆路由几何(segments 数组) |
|
||||
| `GET /api/v1/ue/satellites` | 卫星 TLE 数据 |
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 编译报错 "Cannot open include file: CesiumGeoreference.h"
|
||||
**A:** Cesium for Unreal 没有正确安装,或者没有在 `.uproject` 里启用。检查:
|
||||
1. Epic Launcher → 插件是否安装到 5.3
|
||||
2. `PlanetClient.uproject` 里 `Plugins` 数组是否有 `CesiumForUnreal: true`
|
||||
3. UE 编辑器 → Edit → Plugins → 搜索 Cesium → 确认已勾选 Enabled
|
||||
|
||||
### Q: Play 之后没有看到橙色球体
|
||||
**A:** 按以下顺序排查:
|
||||
1. Output Log(Window → Output Log)里搜索 `PlanetDataManager` — 查看是否有报错
|
||||
2. 检查 `BP_PlanetDataManager` 的 Details → **Compute Point Class** 是否已设置为 `BP_ComputePointActor`
|
||||
3. 检查 **Mock Data Path** 是否正确(留空则自动用 `Content/Data/mock_compute_points.json`)
|
||||
4. 检查 **Use Local Mock Data** 是否已勾选
|
||||
|
||||
### Q: 地球是灰色的没有卫星影像
|
||||
**A:** 需要 Cesium ion 账号:
|
||||
1. Cesium 菜单 → Connect to Cesium ion
|
||||
2. 注册免费账号并授权
|
||||
3. 重新添加 **Cesium ion Bing Maps Aerial** tileset
|
||||
|
||||
### Q: WSL2 里的后端 UE 无法访问(Phase B)
|
||||
**A:** WSL2 和 Windows 是不同网络命名空间。方法:
|
||||
1. 在 WSL 里运行 `ip route show default | awk '{print $3}'` — 这是 Windows 主机的 IP
|
||||
2. 后端绑定到 `0.0.0.0:8000`(检查 `uvicorn` 启动参数,应已如此配置)
|
||||
3. 在 UE 的 DataManager 里填写这个 IP 而不是 `localhost`
|
||||
|
||||
### Q: TransformLongitudeLatitudeHeightPositionToUnreal 不存在
|
||||
**A:** Cesium for Unreal API 在不同版本有变化。如果编译报此错,将 `PlanetDataManager.cpp` 里的调用改为:
|
||||
```cpp
|
||||
// Cesium for Unreal v1.x 的旧 API:
|
||||
FVector WorldPos = Georeference->TransformLongitudeLatitudeHeightToUnreal(
|
||||
Pt.Longitude, Pt.Latitude, PointAltitudeMeters);
|
||||
|
||||
// 或者通过 GeoTransforms:
|
||||
#include "CesiumGlobeAnchorComponent.h"
|
||||
// ... 见 Cesium 文档
|
||||
```
|
||||
|
||||
### Q: 点击球体没有反应
|
||||
**A:**
|
||||
1. 确认 `SphereMesh` 上 **Collision Presets** 不是 `NoCollision`
|
||||
- 打开 `BP_ComputePointActor` → 点击 `SphereMesh` → Details → Collision → 改为 `BlockAllDynamic`
|
||||
2. 确认 PlayerController 的 `bEnableClickEvents = true`(代码里已设置)
|
||||
3. Output Log 里搜索是否有输入相关报错
|
||||
|
||||
---
|
||||
|
||||
## 下一步(一期完成后)
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| 海缆路径渲染 | `/api/v1/ue/cables` 已就绪,需要在 UE 里用 Spline 绘制 |
|
||||
| 信息卡 UMG | 创建 Widget Blueprint 并在 PlayerController OnPointSelected 里显示 |
|
||||
| WebSocket 实时更新 | 后端已有 WebSocket,UE 端需要使用 WebSockets 插件 |
|
||||
| 卫星轨迹 | TLE 数据已就绪,需要在 UE 里做轨道传播计算 |
|
||||
62
docs/ue_todo.md
Normal file
62
docs/ue_todo.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# UE5 客户端 — 待供应商回复的 TODO
|
||||
|
||||
> 以下两个问题答复后,对应代码可在一天内完成。
|
||||
> 其余所有代码均已写好,不依赖这两个答案。
|
||||
|
||||
---
|
||||
|
||||
## TODO-1:视频处理器输入格式
|
||||
|
||||
**等待信息**:LED 屏配套视频处理器(如诺瓦星云)接受什么 3D 信号格式?
|
||||
|
||||
| 可能答案 | 对应操作 |
|
||||
|---------|---------|
|
||||
| Side-by-Side(左右并排) | `StereoRenderingManager.cpp` 里 `EnableStereo` 的 `SideBySide` 分支已写好,直接启用 |
|
||||
| Top-Bottom(上下叠加) | 同上,切换到 `TopBottom` 分支 |
|
||||
| 行交错(行偏振直驱) | 需要新写一个 PostProcess Material,把左右眼奇偶行合并输出 |
|
||||
| 私有协议 | 需要供应商提供 UE5 插件或信号格式文档 |
|
||||
|
||||
**代码位置**:
|
||||
```
|
||||
ue_client/Source/PlanetClient/StereoRenderingManager.h — 第 8-18 行 TODO 注释
|
||||
ue_client/Source/PlanetClient/StereoRenderingManager.cpp — EnableStereo() 函数
|
||||
```
|
||||
|
||||
**需要同时确认**:
|
||||
- 视频处理器品牌和型号
|
||||
- 屏幕物理分辨率(用于配置 UE5 输出分辨率)
|
||||
- 3D 启用时是否需要特殊信号时序(如 3D Frame Packing)
|
||||
|
||||
---
|
||||
|
||||
## TODO-2:动捕中间件协议
|
||||
|
||||
**等待信息**:光学姿态识别系统用什么协议输出数据给 UE5?
|
||||
|
||||
| 可能答案 | 对应操作 |
|
||||
|---------|---------|
|
||||
| **Live Link**(首选) | 在 UE5 编辑器里添加 Live Link Source,零代码接入,约 2 小时完成 |
|
||||
| **OSC over UDP** | 新建 `MotionCaptureReceiverOSC.h/.cpp`,实现 UDP 监听和 OSC 解析,约 1 天 |
|
||||
| 私有 SDK(提供 .dll) | 需要 SDK 文档,封装成 UE5 插件,约 2-3 天 |
|
||||
| 私有 SDK(提供 UE5 插件) | 直接安装插件,对接事件接口,约 0.5 天 |
|
||||
|
||||
**代码位置(已预留接口,填协议实现即可)**:
|
||||
```
|
||||
ue_client/Source/PlanetClient/MotionCaptureInterface.h — UMotionCaptureReceiver 基类
|
||||
ue_client/Source/PlanetClient/PlanetPlayerController.cpp — BindMotionCaptureEvents() 函数(TODO 注释处取消注释)
|
||||
ue_client/Source/PlanetClient/PlanetClient.Build.cs — TODO 注释的 LiveLink/Sockets 依赖
|
||||
```
|
||||
|
||||
**需要同时确认**:
|
||||
- 手势集合(供应商能识别哪些具体手势,用于填写 `EMotionGesture` 枚举)
|
||||
- 数据刷新频率(帧率)
|
||||
- 是否支持持续输出旋转增量,还是只能输出离散手势事件
|
||||
|
||||
---
|
||||
|
||||
## 答复到位后的操作清单
|
||||
|
||||
拿到答案后告诉我,我来:
|
||||
|
||||
1. **视频处理器格式** → 配置 `StereoRenderingManager`,把 `bAutoEnableOnPlay` 改为 `true`,写进 setup guide
|
||||
2. **动捕协议** → 实现对应的 `UMotionCaptureReceiver` 子类,更新 `Build.cs` 依赖,在 `PlayerController::BeginPlay` 里取消注释绑定代码
|
||||
Reference in New Issue
Block a user