Files
opendance-android/contracts/model-formats.md
T

84 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# contracts/model-formats.md — 模型与动作格式契约 v0.1.0
## 1. 角色模型(models)
| 格式 | 扩展名 | 支持级别 | 说明 |
|---|---|---|---|
| VRM | `.vrm` | **首选(P0)** | glTF 2.0 二进制 + VRM 扩展;Windows 端 godot-vrm 直接加载 |
| glTF Binary | `.glb` | P1 | 需含骨骼(skin);无骨骼则仅作静态展示 |
| glTF | `.gltf` (+ `.bin`, 贴图) | P2 | 多文件,管理端需打包为 zip 上传 |
| FBX | `.fbx` | P2 | 需 Assimp 转换,管理端仅归档,不保证重定向质量 |
**VRM 优先**的选取顺序见 `data-models.md` §4.1。
VRM 版本识别:读取 GLB 的 JSON chunk,检查 `extensions.VRM`(0.x)或
`extensions.VRMC_vrm`(1.0),写入 `models.vrm_version`。
## 2. 动作数据(motions)
| 格式 | 扩展名 | 预处理支持 | 说明 |
|---|---|---|---|
| BVH | `.bvh` | ✅ 内置纯 TS 解析器 | 文本格式,服务端直接解析 → FK → MediaPipe33 |
| FBX | `.fbx` | ⚠️ 需 Assimp | 服务端调用 `assimp` 可执行文件导出为 BVH/glTF 后再解析;未安装则 `preprocessState=failed` |
| glTF/GLB | `.gltf` / `.glb` | ⚠️ 需 Assimp | 同上 |
| 关键点 JSON | `.json` | ✅ 直通校验 | 已是 `mediapipe33@0.1.0` 结构,仅做校验与归一化 |
### 2.1 预处理产物(冻结)
- 格式:NDJSON(`application/x-ndjson`),每行一帧,UTF-8 无 BOM
- 一行结构:
```json
{"frame":0,"timeMs":0.0,"points":[[0.5,0.5,0.0,1.0],"…33 项"],"angles":[1.0,"…9 项"]}
```
- `points[i] = [x, y, z, confidence]`,语义与 `websocket-keypoints.md` 解码后完全一致
- `angles` 为 `skeleton-topology.md` §5 定义的 9 个关节角余弦,顺序固定:
`[shoulder_L, shoulder_R, elbow_L, elbow_R, hip_L, hip_R, knee_L, knee_R, spine]`
- 帧率:保留源帧率;`fps` 写入 `motions.fps`,缺省 30
- 坐标系换算:所有 3D 动作数据统一转到 **Y 轴向上、右手系、骨盆为原点**,
再投影到 MediaPipe 归一化图像空间:
`x_img = 0.5 + x_world * scale`,`y_img = 0.5 - y_world * scale`,`z_img = -z_world * scale`,
`scale = 0.35 / max(|x|,|y|,|z|)`(按整段动作的最大范围自适应,保证不出画)
- 缺失关节(BVH 中不存在对应骨骼):`confidence = 0.0`,坐标沿用最近可用父节点
### 2.2 BVH 关节名映射(默认表,可在 `web-server/src/preprocess/joint-map.ts` 扩展)
| MediaPipe 点 | 常见 BVH 关节名(不区分大小写,按序匹配) |
|---|---|
| 0 nose | `Head`, `Neck1`, `Head_Nub` |
| 11 left_shoulder | `LeftShoulder`, `LeftArm`, `LShoulder` |
| 12 right_shoulder | `RightShoulder`, `RightArm`, `RShoulder` |
| 13 left_elbow | `LeftForeArm`, `LeftElbow`, `LElbow` |
| 14 right_elbow | `RightForeArm`, `RightElbow`, `RElbow` |
| 15 left_wrist | `LeftHand`, `LeftWrist`, `LHand` |
| 16 right_wrist | `RightHand`, `RightWrist`, `RHand` |
| 23 left_hip | `LeftUpLeg`, `LeftHip`, `LHipJoint` |
| 24 right_hip | `RightUpLeg`, `RightHip`, `RHipJoint` |
| 25 left_knee | `LeftLeg`, `LeftKnee`, `LKnee` |
| 26 right_knee | `RightLeg`, `RightKnee`, `RKnee` |
| 27 left_ankle | `LeftFoot`, `LeftAnkle`, `LAnkle` |
| 28 right_ankle | `RightFoot`, `RightAnkle`, `RAnkle` |
| 31 left_foot_index | `LeftToeBase`, `LeftToe`, `LToe` |
| 32 right_foot_index | `RightToeBase`, `RightToe`, `RToe` |
未映射到的点按 `skeleton-topology.md` §5 的层级由父节点推算,
并置 `confidence` 降低(`0.5`),表示估算而非实测。
## 3. 上传限制
| 项 | 值 |
|---|---|
| 单文件上限 | 512 MiB(`UPLOAD_MAX_BYTES` 可覆盖) |
| 允许扩展名 | 上表全部;其他一律 422 |
| 存储路径 | `${STORAGE_DIR}/{kind}/{yyyy}/{mm}/{sha256前2位}/{sha256}.{ext}` |
| 去重 | 相同 sha256 复用同一 `assets` 记录,不重复落盘 |
| 文件名 | 服务端不使用原始文件名做路径,只存 `assets.original_name` |
## 4. 开源依赖与许可证(引用 `open-source-credits.md`)
- `bvh`(MIT)— BVH 解析参考实现
- `Assimp`(BSD-3-Clause)— FBX/glTF 转换,**可选外部依赖**
- `@pixiv/three-vrm`(MIT)— 管理端 VRM 预览
- `three`(MIT)— 管理端 3D 预览