依据 Gitea v1.27.3 modules/charset/escape_stream.go 的判定规则 (analyzeDetectResults:仅当左右相邻字符都不是非 ASCII 时才标记, 且 _common 表恒定生效),把说明文档中会被标记的全角标点 (,:;?!() 等)改为半角,并保证成对括号宽度一致。 中文语境中的全角标点(左右均为中文)保持原样,不动代码与契约语义。
138 lines
6.0 KiB
Markdown
138 lines
6.0 KiB
Markdown
# DSH.md -- opendance-windows(OpenDance Studio 项目二:Windows 客户端)
|
|
|
|
## 0. 本文件的作用
|
|
|
|
本文件是 **opendance-windows 仓库内**的 DSH 执行约束。顶层说明书见
|
|
《DSH 开发文档:OpenDance Studio》,二者冲突时以顶层文档为准。
|
|
|
|
## 1. 项目定位
|
|
|
|
Windows 客户端是核心体验载体:接收 Android 辅助 App 推送的 33 点骨骼关键点,
|
|
驱动 VRM 角色,并与 Web 服务端下发的参考动作做实时 DTW 评分。
|
|
|
|
```
|
|
Android 辅助 App ──239 字节关键点帧──▶ 本端(WebSocket 服务端:8765)
|
|
│
|
|
Web 服务端 ──GET /api/catalog/export──────┤
|
|
──GET /api/motions/:id/keypoints┘
|
|
▼
|
|
VRM 驱动 + DTW 评分
|
|
```
|
|
|
|
**本端是 WebSocket 的「服务端」,Android 主动连入**(契约 websocket-keypoints.md 1)。
|
|
|
|
## 2. 技术栈
|
|
|
|
| 组件 | 选型 | 说明 |
|
|
|--|--|--|
|
|
| 引擎 | Godot 4.7.2(MIT) | 可在 Linux 上导出 Windows exe |
|
|
| VRM 加载 | **Godot 内置 GLTFDocument** | 见 6 的选型变更说明 |
|
|
| 多格式导入 | Godot 内置 glTF 导入器 | FBX 由管理端转 BVH 后下发 |
|
|
| 通信 | WebSocketPeer + HTTPRequest | 无第三方依赖 |
|
|
| 评分 | DTW + 关节角度差异 | 纯 GDScript 实现 |
|
|
| 渲染 | GL Compatibility | 兼容性最好,便于无 GPU 导出 |
|
|
|
|
## 3. 单次会话加载范围
|
|
|
|
允许加载:
|
|
|
|
1. 本文件 `DSH.md`
|
|
2. `project.yaml`
|
|
3. 当前 `tasks/xxx.md`
|
|
4. 该任务文件中 `load` 列出的文件
|
|
5. `contracts/` 中被明确引用的**锚点片段**
|
|
|
|
禁止加载:
|
|
|
|
- `opendance-web` / `opendance-android` 的任何源码
|
|
- 非当前任务的 `tasks/*.md`
|
|
- 完整 `contracts/` 目录(只引用锚点)
|
|
- `.godot/` 导入缓存、`build/windows/` 导出产物、`_scratch/` 下的模型素材
|
|
|
|
## 4. 上下文预算
|
|
|
|
| 项 | 建议值 |
|
|
|--|--|
|
|
| 单任务文件数 | <= 6 |
|
|
| 单任务代码行数 | <= 1500 |
|
|
| 单任务 Token | <= 12K |
|
|
| 契约引用 | 只引用锚点,不加载全文 |
|
|
|
|
## 5. 目录结构
|
|
|
|
```
|
|
opendance-windows/
|
|
├── project.godot # Godot 工程(autoload、渲染、窗口配置)
|
|
├── export_presets.cfg # ★ 必须位于项目根目录(Godot 硬性要求)
|
|
├── project.yaml / DSH.md
|
|
├── tasks/ # 001~011 单任务说明书
|
|
├── contracts/ # 只读契约快照(来源 opendance-web v0.1.0)
|
|
├── scenes/main.tscn # 仅一个挂载 main.gd 的根节点
|
|
├── src/
|
|
│ ├── autoload/ # AppConfig / CatalogStore / PoseReceiver / ScoreService
|
|
│ ├── net/ # 239 字节编解码、WebSocket 服务、REST 客户端、NDJSON 解析
|
|
│ ├── model/ # VRM 加载、humanoid 骨骼名映射
|
|
│ ├── anim/ # 关键点 -> 骨骼重定向
|
|
│ ├── score/ # 特征提取、DTW、评分规则
|
|
│ └── ui/ # 主界面 / 游戏界面 / 结算 / 关于 / 来源展示
|
|
├── tests/ # 无头测试框架 + 用例
|
|
└── build/ # 导出脚本(sh / ps1)
|
|
```
|
|
|
|
## 6. 界面构建方式与选型变更(重要)
|
|
|
|
**界面全部用 GDScript 代码构建,不手写 `.tscn`。**
|
|
`.tscn` 是带 uid 与节点路径的手写格式,在没有编辑器的情况下极易出错且难以验证;
|
|
用代码构建可随脚本一起被无头导入和单元测试覆盖。`scenes/main.tscn` 因此只保留一个根节点。
|
|
|
|
**VRM 加载改用 Godot 内置 glTF 导入器**(文档 5.1 原选型为 godot-vrm GDExtension):
|
|
|
|
- `V-Sekai/godot-vrm` **不发布任何预编译产物**(无 GitHub Release,仅源码,
|
|
需用 godot-cpp 本地编译原生库),这会同时破坏「Linux 上导出 Windows exe」的验收路径。
|
|
- VRM 本身就是 glTF 2.0 二进制容器:实测内置导入器可完整解析 154 骨骼的 VRoid 模型,
|
|
且 `GLTFState.json` 可直接读取 `extensions.VRMC_vrm` / `extensions.VRM` 判定版本。
|
|
- humanoid 骨骼按名字映射(`src/model/humanoid_map.gd`),覆盖 VRoid / VRM 0.x / Mixamo 三种命名。
|
|
|
|
若日后接入 godot-vrm,只需替换 `VrmLoader.load_from_file`,对外接口不变。
|
|
|
|
## 7. 硬性约束
|
|
|
|
1. **绝不让视频帧离开设备**:本端只接收 33 个关键点的坐标,不接收也不存储图像。
|
|
2. **契约先行**:改交互先改 `opendance-web` 的 `contracts/`,再回本仓库同步快照。
|
|
3. **不假设骨骼轴向约定**:重定向基于「静止朝向 -> 目标朝向」的最小旋转,
|
|
`pose = parent_global_basis⁻¹ x desired` 这一合成公式由真实 VRM 实测标定,
|
|
有回归测试守护,不得凭记忆改写。
|
|
4. **上传/下载的模型不入库**:真实 VRM 样例仅放在 `_scratch/`(已 gitignore),
|
|
版权原因不得提交。
|
|
5. **不使用 SMPL 拓扑**,统一 MediaPipe 33 点。
|
|
6. 关于页面与 `THIRD_PARTY.md` 必须与 `contracts/open-source-credits.md` 一致。
|
|
|
|
## 8. 验证(每任务执行)
|
|
|
|
```bash
|
|
GODOT=/path/to/godot # Godot 4.7.x
|
|
|
|
# 1. 全部脚本编译通过(无输出即通过)
|
|
$GODOT --headless --path. --import 2>&1 | grep -E "SCRIPT ERROR|Parse Error"
|
|
|
|
# 2. 无头单元测试 + 真实 API 集成(API 不可达时相关用例显式跳过)
|
|
$GODOT --headless --path. --script res://tests/run_tests.gd
|
|
|
|
# 3. 应用可启动(autoload + UI 构建无报错)
|
|
$GODOT --headless --path. --quit-after 180
|
|
|
|
# 4. Windows 导出(需先安装 export templates)
|
|
bash build/export-windows.sh release
|
|
```
|
|
|
|
## 9. 上下文超标时的拆分策略
|
|
|
|
| 超标原因 | 拆分方式 |
|
|
|--|--|
|
|
| 单任务涉及多个界面 | 按界面拆(主/游戏/结算/关于) |
|
|
| 单文件过大 | 按类拆,先生成接口再分实现 |
|
|
| 契约全文加载 | 改用锚点引用 |
|
|
| 需要参考其他项目 | 只读契约,不读源码 |
|
|
| UI 与逻辑耦合 | UI 只调用已定义接口(GameScreen 不做 DTW 计算) |
|
|
| 测试与实现同任务 | 测试单独任务,共享接口摘要 |
|