201 lines
11 KiB
Markdown
201 lines
11 KiB
Markdown
# opendance-windows
|
||
|
||
OpenDance Studio **阶段二**:Windows 客户端(Godot 4)。
|
||
|
||
接收 Android 辅助 App 通过 WebSocket 推送的 33 点骨骼关键点,驱动 VRM 角色,
|
||
并与 Web 管理服务端下发的参考动作做实时 DTW 评分。
|
||
|
||
> 本客户端只接收关键点坐标,**不接收、不存储任何视频画面**。
|
||
|
||
## 状态
|
||
|
||
**阶段二已完成**:T-WIN-001 -> T-WIN-011 全部落地。
|
||
|
||
| 验收项 | 结果 |
|
||
|--|--|
|
||
| 脚本编译 | OK 全部通过(无 SCRIPT ERROR) |
|
||
| 无头测试 | OK **580 项全部通过**(8 个测试套件) |
|
||
| 应用启动 | OK 180 帧无运行时错误 |
|
||
| Windows 导出 | OK 生成 `OpenDance.exe`(104 MB,PE 头校验通过)+ `OpenDance.pck` |
|
||
| 真实 VRM 验证 | OK 154 骨骼 VRoid 模型,humanoid 覆盖率 **100%** |
|
||
| 骨骼重定向 | OK 关键点方向与骨骼实际指向点积 **1.0000** |
|
||
| 跨实现交叉校验 | OK 关节角与 Web 服务端 TypeScript 实现**逐帧一致** |
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 验证(编译 -> 测试 -> 启动)
|
||
GODOT_BIN=/path/to/godot bash build/verify.sh
|
||
|
||
# 导出 Windows 可执行文件
|
||
GODOT_BIN=/path/to/godot bash build/export-windows.sh release
|
||
|
||
# 打包发布产物
|
||
bash build/package-release.sh 0.1.0
|
||
```
|
||
|
||
详细使用说明见 [`README.txt`](README.txt),工程约束见 [`DSH.md`](DSH.md)。
|
||
|
||
## 初次部署(从零跑起来)
|
||
|
||
本节面向**第一次拿到本仓库**的人:从安装引擎到跑通「Web 服务端 + 本端 + Android」
|
||
三端链路。地址与端口一律使用占位符或产品默认值。
|
||
|
||
### 1. 前置条件
|
||
|
||
| 项 | 要求 |
|
||
|--|--|
|
||
| 操作系统 | 运行客户端:Windows 10/11(x86_64)。开发与导出:Windows 或 Linux 均可 |
|
||
| Godot | **4.7.x**(`project.godot` 声明特性 `4.7`,本仓库按 4.7.2 验证)。使用**标准版**(GDScript),**不需要 .NET / C# 版** |
|
||
| 显卡与图形界面 | 渲染后端为 **GL Compatibility**,运行需支持 OpenGL 3.3 的显卡与驱动。仅无头测试与导出可无 GPU、可无图形界面 |
|
||
| 导出模板 | **仅打包导出时需要**:必须安装与编辑器**完全同版本**的 export templates(`.tpz`) |
|
||
| 磁盘与网络 | Godot 编辑器 + 导出模板约数百 MB;导出产物 `OpenDance.exe` 约 104 MB、`OpenDance.pck` 约 107 KB。本端需能访问 Web 服务端 API(默认 TCP 3000),并与 Android 设备处于同一局域网、放行本端 **TCP 8765 入站** |
|
||
|
||
### 2. 获取代码
|
||
|
||
```bash
|
||
git clone https://<Gitea 地址>/<owner>/opendance-windows
|
||
cd opendance-windows
|
||
```
|
||
|
||
### 3. 首次运行(编辑器内)
|
||
|
||
1. 启动 Godot 4.7.x,在项目管理器选择「导入」,指向本仓库的 `project.godot`。
|
||
2. **首次导入会执行资源导入**(生成 `.godot/`),耗时从数十秒到数分钟不等;请等待完成,不要在导入中途关闭编辑器。
|
||
3. 主场景已在 `project.godot` 中配置为 `res://scenes/main.tscn`,直接按 **F5**(或「运行项目」)即可。
|
||
4. 界面全部由 GDScript 代码构建,不需要在编辑器里编辑场景,这是刻意设计(见 `DSH.md` 6)。
|
||
5. 首次运行会在用户数据目录生成配置与日志:
|
||
|
||
```
|
||
%APPDATA%\Godot\app_userdata\OpenDance Studio\opendance.cfg
|
||
%APPDATA%\Godot\app_userdata\OpenDance Studio\logs\godot.log
|
||
```
|
||
|
||
### 4. 配置服务端地址
|
||
|
||
- 位置:主界面顶部「**服务端地址**」输入框,填好后点「**保存并测试**」。
|
||
- 配置字段名(`opendance.cfg`):`api_base_url`。
|
||
- **端口区分**:客户端只访问 Web 服务端的 **API 端口(默认 3000)**;管理端页面在**管理端口(默认 3001)**,客户端不使用该端口。
|
||
- 示例占位符:
|
||
|
||
```
|
||
http://<服务器地址>:3000
|
||
http://192.0.2.10:3000
|
||
```
|
||
|
||
保存后点「**刷新目录**」;顶部应显示「服务端正常 | DB ...」,左侧列出已发布的曲目 / 动作 / 模型。
|
||
|
||
### 5. 与另外两端的联通
|
||
|
||
| 对端 | 方向 | 本端配置 | 说明 |
|
||
|--|--|--|--|
|
||
| Android 辅助 App | Android -> 本端(WebSocket) | `listen_host`(默认 `0.0.0.0`)、`listen_port`(默认 **8765**)、`ws_subprotocol`(默认 `opendance.pose.v1`) | 本端是 WebSocket **服务端**;Android 端填写本端主界面显示的「接收地址」,形如 `ws://<本机局域网地址>:8765/pose` |
|
||
| Web 服务端 | 本端 -> Web(HTTP) | `api_base_url`(默认 `http://127.0.0.1:3000`) | 需先在服务端**发布**曲目 / 动作 / 模型,动作还须**完成关键点预处理**,否则目录为空或动作不可选 |
|
||
|
||
- **Android 侧无本端可配置项**:接收地址由 Android App 自己填写;本端只监听固定端口 8765(可在 `opendance.cfg` 改 `listen_port` 后点「重新连接接收服务」生效)。
|
||
- 已知限制:Godot 的 `WebSocketPeer` 不暴露握手请求路径,本端**接受任意 path**,只校验子协议 `opendance.pose.v1`(见「已知限制」1)。
|
||
- 接收状态可用主界面「**查看接收状态**」查看:连接数、累计帧、丢帧、畸形帧。
|
||
|
||
### 6. 打包导出
|
||
|
||
```bash
|
||
# Linux 上直接导出 Windows 可执行文件(推荐)
|
||
GODOT_BIN=/path/to/godot bash build/export-windows.sh release
|
||
|
||
# Windows 上兜底导出
|
||
powershell -ExecutionPolicy Bypass -File build\export-windows.ps1
|
||
|
||
# 打成可分发的 zip(可选)
|
||
bash build/package-release.sh 0.1.0
|
||
```
|
||
|
||
| 产物 | 位置 | 说明 |
|
||
|--|--|--|
|
||
| `OpenDance.exe` | `build/windows/` | 主程序,约 104 MB;脚本校验前 2 字节为 `MZ`(合法 PE) |
|
||
| `OpenDance.pck` | `build/windows/` | 资源包,约 107 KB;**必须与 exe 同目录** |
|
||
| `OpenDance.console.exe` | `build/windows/` | 控制台包装器,可能生成,非必需 |
|
||
| `opendance-windows-v0.1.0.zip` | `dist-release/` | 发布包:exe + pck + `THIRD_PARTY.md` + `README.txt` + `contracts/` |
|
||
|
||
导出前必须安装与编辑器同版本的 export templates,否则脚本会报「未找到导出模板」。
|
||
|
||
### 7. 自检清单
|
||
|
||
| 检查 | 命令 | 预期输出 |
|
||
|--|--|--|
|
||
| 一键验证(编译 + 测试 + 启动) | `GODOT_BIN=/path/to/godot bash build/verify.sh` | 末行「验证全部通过」,退出码 0 |
|
||
| 无头单元 / 集成测试 | `$GODOT --headless --path . --script res://tests/run_tests.gd` | `== 结果:580 通过 / 0 失败 ==` 与 `全部通过`(仓库基线 580 项 / 8 个套件;缺 VRM 素材或服务端不可达时相关用例显式跳过,数字会减少) |
|
||
| 启动冒烟(180 帧) | `$GODOT --headless --path . --quit-after 180` | 无 `SCRIPT ERROR` / `ERROR:`,进程退出码 0 |
|
||
| 日志检查 | 打开 `%APPDATA%\Godot\app_userdata\OpenDance Studio\logs\godot.log` | 无 `SCRIPT ERROR`、无 `ERROR:` |
|
||
| 导出产物校验 | `bash build/export-windows.sh release` | 输出「PE 头校验通过」,且 `build/windows/OpenDance.exe` 前 2 字节为 `4d5a` |
|
||
| 服务端联通 | 主界面「服务端地址」->「保存并测试」 | 顶部显示「服务端正常 | DB ...」 |
|
||
|
||
### 8. 常见问题
|
||
|
||
| 现象 | 原因 | 处理 |
|
||
|--|--|--|
|
||
| 游戏界面提示「模型加载失败:缺少骨骼」或「骨骼绑定失败,模型可能不受支持」 | 模型没有 `Skeleton3D`,或骨骼命名不在 humanoid 映射表内;驱动至少需要 hips / spine / neck / head + 四肢共 16 根核心骨骼 | 换用标准 VRM(VRoid Studio 导出);看「人形覆盖率」,低于 60% 会提示「骨骼覆盖偏低,动作可能不完整」;必要时在 `src/model/humanoid_map.gd` 增加命名映射 |
|
||
| 顶部「服务端不可达」或「目录拉取失败」 | Web 服务端未启动、地址或端口写错(误填管理端口 3001)、或网络不通 | 确认 `api_base_url` 为 `http://<服务器地址>:3000`;浏览器访问 `http://<服务器地址>:3000/health` 应返回 200;再点「保存并测试」 |
|
||
| 导出失败:「未找到导出模板」 | 未安装 export templates,或版本 / 路径与编辑器不一致 | 编辑器「编辑器 -> 管理导出模板 -> 下载并安装」;Linux 放 `~/.local/share/godot/export_templates/<版本>.stable/`,Windows 放 `%APPDATA%\Godot\export_templates\<版本>.stable\` |
|
||
| 提示「接收服务启动失败(端口 8765 可能被占用)」 | TCP 8765 被占用或未放行 | 改 `opendance.cfg` 的 `listen_port` 后点「重新连接接收服务」,并同步修改 Android 端填写的接收地址 |
|
||
| 手机已连接但分数一直是 0 | Android 端未开始推流,或帧内关键点置信度都低于 0.5 | 「查看接收状态」确认累计帧在增长、畸形帧为 0;确认 Android 端子协议为 `opendance.pose.v1` |
|
||
|
||
## 技术栈
|
||
|
||
| 组件 | 选型 |
|
||
|--|--|
|
||
| 引擎 | Godot 4.7.x(MIT) |
|
||
| VRM 加载 | Godot 内置 GLTFDocument |
|
||
| 通信 | WebSocketPeer(服务端)+ HTTPRequest |
|
||
| 评分 | DTW + 关节角度差异(纯 GDScript) |
|
||
|
||
## 架构
|
||
|
||
```
|
||
Android 辅助 App ──239 字节关键点帧──▶ 本端 WebSocket 服务端:8765
|
||
│
|
||
Web 服务端 ──GET /api/catalog/export────────┤
|
||
──GET /api/motions/:id/keypoints ┘
|
||
▼
|
||
VRM 驱动 + DTW 评分
|
||
```
|
||
|
||
```
|
||
src/
|
||
├── autoload/ AppConfig / CatalogStore / PoseReceiver / ScoreService
|
||
├── net/ 239 字节编解码、WebSocket 服务、REST 客户端、NDJSON 解析
|
||
├── model/ VRM 加载、humanoid 骨骼名映射
|
||
├── anim/ 关键点 -> 骨骼重定向
|
||
├── score/ 特征提取、DTW、评分规则
|
||
└── ui/ 主界面 / 游戏界面 / 结算 / 关于 / 来源展示
|
||
```
|
||
|
||
界面**全部用 GDScript 代码构建**(不手写 `.tscn`),因此可被无头导入与单元测试覆盖。
|
||
|
||
## 依赖的契约(opendance-web v0.1.0 冻结)
|
||
|
||
- [`contracts/websocket-keypoints.md`](contracts/websocket-keypoints.md) - 239 字节关键点帧与文本控制消息(本端为**接收方**)
|
||
- [`contracts/skeleton-topology.md`](contracts/skeleton-topology.md) - MediaPipe 33 点拓扑、父节点表、9 个关节角特征
|
||
- [`contracts/rest-api.yaml`](contracts/rest-api.yaml) - 目录与关键点序列 API
|
||
- [`contracts/data-models.md`](contracts/data-models.md) - 资源字段与 VRM 优先规则
|
||
- [`contracts/model-formats.md`](contracts/model-formats.md) - 模型与动作格式、关键点序列结构
|
||
|
||
`contracts/` 是**只读快照**。任何跨端契约变更必须先回到
|
||
[`opendance-web`](https://<Gitea 地址>/<owner>/opendance-web) 修改并提升版本,
|
||
再在本仓库创建适配任务。
|
||
|
||
## 已知限制
|
||
|
||
1. Godot 的 `WebSocketPeer` 不暴露握手请求路径,因此**无法校验 path 是否为 `/pose`**,
|
||
实现接受任意 path,仅校验子协议 `opendance.pose.v1`。
|
||
2. 文档原选型 `godot-vrm` GDExtension 不发布预编译产物,改用 Godot 内置 glTF 导入器
|
||
+ 自实现骨骼名映射;理由见 `DSH.md` 6。
|
||
3. `build/export-windows.ps1` 未在真实 Windows 上执行过(本环境无 Windows)。
|
||
两条路径共用同名导出预设与相同的 PE 头校验逻辑。
|
||
4. 真实 VRM 样例仅放在 `_scratch/`(已 gitignore),版权原因不入库;
|
||
测试在找不到模型时显式跳过而非伪装通过。
|
||
|
||
## 第三方开源声明
|
||
|
||
见 [`THIRD_PARTY.md`](THIRD_PARTY.md),或客户端「关于」页面。
|
||
未使用 SMPL 模型及其衍生拓扑,统一采用 MediaPipe 33 点拓扑。
|