docs: 其余易混淆字符(x/>=/<=/~/OK 取代 × − ≥ ≤ ≈ ✓)
This commit is contained in:
@@ -53,9 +53,9 @@ Web 服务端 ──GET /api/catalog/export──────┤
|
|||||||
|
|
||||||
| 项 | 建议值 |
|
| 项 | 建议值 |
|
||||||
|--|--|
|
|--|--|
|
||||||
| 单任务文件数 | ≤ 6 |
|
| 单任务文件数 | <= 6 |
|
||||||
| 单任务代码行数 | ≤ 1500 |
|
| 单任务代码行数 | <= 1500 |
|
||||||
| 单任务 Token | ≤ 12K |
|
| 单任务 Token | <= 12K |
|
||||||
| 契约引用 | 只引用锚点,不加载全文 |
|
| 契约引用 | 只引用锚点,不加载全文 |
|
||||||
|
|
||||||
## 5. 目录结构
|
## 5. 目录结构
|
||||||
@@ -100,7 +100,7 @@ opendance-windows/
|
|||||||
1. **绝不让视频帧离开设备**:本端只接收 33 个关键点的坐标,不接收也不存储图像。
|
1. **绝不让视频帧离开设备**:本端只接收 33 个关键点的坐标,不接收也不存储图像。
|
||||||
2. **契约先行**:改交互先改 `opendance-web` 的 `contracts/`,再回本仓库同步快照。
|
2. **契约先行**:改交互先改 `opendance-web` 的 `contracts/`,再回本仓库同步快照。
|
||||||
3. **不假设骨骼轴向约定**:重定向基于「静止朝向 -> 目标朝向」的最小旋转,
|
3. **不假设骨骼轴向约定**:重定向基于「静止朝向 -> 目标朝向」的最小旋转,
|
||||||
`pose = parent_global_basis⁻¹ × desired` 这一合成公式由真实 VRM 实测标定,
|
`pose = parent_global_basis⁻¹ x desired` 这一合成公式由真实 VRM 实测标定,
|
||||||
有回归测试守护,不得凭记忆改写。
|
有回归测试守护,不得凭记忆改写。
|
||||||
4. **上传/下载的模型不入库**:真实 VRM 样例仅放在 `_scratch/`(已 gitignore),
|
4. **上传/下载的模型不入库**:真实 VRM 样例仅放在 `_scratch/`(已 gitignore),
|
||||||
版权原因不得提交。
|
版权原因不得提交。
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ OpenDance Studio **阶段二**:Windows 客户端(Godot 4)。
|
|||||||
|
|
||||||
| 验收项 | 结果 |
|
| 验收项 | 结果 |
|
||||||
|--|--|
|
|--|--|
|
||||||
| 脚本编译 | ✓ 全部通过(无 SCRIPT ERROR) |
|
| 脚本编译 | OK 全部通过(无 SCRIPT ERROR) |
|
||||||
| 无头测试 | ✓ **580 项全部通过**(8 个测试套件) |
|
| 无头测试 | OK **580 项全部通过**(8 个测试套件) |
|
||||||
| 应用启动 | ✓ 180 帧无运行时错误 |
|
| 应用启动 | OK 180 帧无运行时错误 |
|
||||||
| Windows 导出 | ✓ 生成 `OpenDance.exe`(104 MB,PE 头校验通过)+ `OpenDance.pck` |
|
| Windows 导出 | OK 生成 `OpenDance.exe`(104 MB,PE 头校验通过)+ `OpenDance.pck` |
|
||||||
| 真实 VRM 验证 | ✓ 154 骨骼 VRoid 模型,humanoid 覆盖率 **100%** |
|
| 真实 VRM 验证 | OK 154 骨骼 VRoid 模型,humanoid 覆盖率 **100%** |
|
||||||
| 骨骼重定向 | ✓ 关键点方向与骨骼实际指向点积 **1.0000** |
|
| 骨骼重定向 | OK 关键点方向与骨骼实际指向点积 **1.0000** |
|
||||||
| 跨实现交叉校验 | ✓ 关节角与 Web 服务端 TypeScript 实现**逐帧一致** |
|
| 跨实现交叉校验 | OK 关节角与 Web 服务端 TypeScript 实现**逐帧一致** |
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -173,7 +173,7 @@ OpenDance.exe 的用户看第一节即可。
|
|||||||
listen_host WebSocket 监听地址(默认 0.0.0.0)
|
listen_host WebSocket 监听地址(默认 0.0.0.0)
|
||||||
listen_port WebSocket 监听端口(默认 8765)
|
listen_port WebSocket 监听端口(默认 8765)
|
||||||
ws_subprotocol 子协议(默认 opendance.pose.v1)
|
ws_subprotocol 子协议(默认 opendance.pose.v1)
|
||||||
dtw_band DTW 带宽,单位帧(默认 15 ≈ 0.5 秒抖动容忍)
|
dtw_band DTW 带宽,单位帧(默认 15 ~ 0.5 秒抖动容忍)
|
||||||
score_tolerance 评分容差:平均每步代价达到该值即 0 分(默认 0.25)
|
score_tolerance 评分容差:平均每步代价达到该值即 0 分(默认 0.25)
|
||||||
mirror_preview 镜像预览
|
mirror_preview 镜像预览
|
||||||
|
|
||||||
@@ -193,12 +193,12 @@ OpenDance.exe 的用户看第一节即可。
|
|||||||
六、评分说明
|
六、评分说明
|
||||||
--
|
--
|
||||||
|
|
||||||
- 每帧特征 = 33 点 × (x,y,z) + 9 个关节角余弦 = 108 维
|
- 每帧特征 = 33 点 x (x,y,z) + 9 个关节角余弦 = 108 维
|
||||||
(与 Web 服务端预处理产物、Android 端推流结构完全一致)
|
(与 Web 服务端预处理产物、Android 端推流结构完全一致)
|
||||||
- 置信度低于 0.5 的关键点不参与代价计算,避免遮挡导致误判
|
- 置信度低于 0.5 的关键点不参与代价计算,避免遮挡导致误判
|
||||||
- 采用带约束 DTW(|i−j| ≤ band)对齐,能吸收一定的节奏快慢差异
|
- 采用带约束 DTW(|i-j| <= band)对齐,能吸收一定的节奏快慢差异
|
||||||
- 得分 = clamp(1 − 平均代价 / 容差, 0, 1) × 100,并做指数平滑
|
- 得分 = clamp(1 - 平均代价 / 容差, 0, 1) x 100,并做指数平滑
|
||||||
- 等级:S ≥ 95,A ≥ 85,B ≥ 70,C ≥ 55,D 其余
|
- 等级:S >= 95,A >= 85,B >= 70,C >= 55,D 其余
|
||||||
|
|
||||||
--
|
--
|
||||||
七、从源码构建
|
七、从源码构建
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ rejected 已驳回
|
|||||||
| 字段 | 类型 | 必填 | 说明 |
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|--|--|--|--|
|
|--|--|--|--|
|
||||||
| `id` | number | 读 | |
|
| `id` | number | 读 | |
|
||||||
| `title` | string | ✅ | 曲名,≤200 |
|
| `title` | string | ✅ | 曲名,<=200 |
|
||||||
| `artist` | string | ✅ | 演唱者,≤200 |
|
| `artist` | string | ✅ | 演唱者,<=200 |
|
||||||
| `album` | string | | 专辑,≤200 |
|
| `album` | string | | 专辑,<=200 |
|
||||||
| `language` | string | | `zh` / `en` / `ja` / `ko` / `instrumental` |
|
| `language` | string | | `zh` / `en` / `ja` / `ko` / `instrumental` |
|
||||||
| `durationMs` | number | | 时长毫秒 |
|
| `durationMs` | number | | 时长毫秒 |
|
||||||
| `bpm` | number | | 节拍 |
|
| `bpm` | number | | 节拍 |
|
||||||
@@ -74,7 +74,7 @@ rejected 已驳回
|
|||||||
|--|--|--|--|
|
|--|--|--|--|
|
||||||
| `id` | number | 读 | |
|
| `id` | number | 读 | |
|
||||||
| `songId` | number\|null | | 关联曲目 |
|
| `songId` | number\|null | | 关联曲目 |
|
||||||
| `name` | string | ✅ | 动作名称,≤200 |
|
| `name` | string | ✅ | 动作名称,<=200 |
|
||||||
| `format` | enum | ✅ | `bvh` / `vmd` / `fbx` / `gltf` / `glb` / `keypoints-json` |
|
| `format` | enum | ✅ | `bvh` / `vmd` / `fbx` / `gltf` / `glb` / `keypoints-json` |
|
||||||
| `fileUrl` | string | 读 | 原始动作文件 |
|
| `fileUrl` | string | 读 | 原始动作文件 |
|
||||||
| `fileSize` | number | 读 | 字节 |
|
| `fileSize` | number | 读 | 字节 |
|
||||||
@@ -95,7 +95,7 @@ rejected 已驳回
|
|||||||
| 字段 | 类型 | 必填 | 说明 |
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|--|--|--|--|
|
|--|--|--|--|
|
||||||
| `id` | number | 读 | |
|
| `id` | number | 读 | |
|
||||||
| `name` | string | ✅ | 模型名称,≤200 |
|
| `name` | string | ✅ | 模型名称,<=200 |
|
||||||
| `format` | enum | ✅ | `glb` / `vrm`(主力)/ `gltf` / `fbx`(历史数据)。上传的 PMX/FBX 会被服务端转换成 glb 或 vrm 再入库,见 model-formats.md 1.1 |
|
| `format` | enum | ✅ | `glb` / `vrm`(主力)/ `gltf` / `fbx`(历史数据)。上传的 PMX/FBX 会被服务端转换成 glb 或 vrm 再入库,见 model-formats.md 1.1 |
|
||||||
| `vrmVersion` | string\|null | 读 | `0.x` / `1.0`,非 VRM 为 null |
|
| `vrmVersion` | string\|null | 读 | `0.x` / `1.0`,非 VRM 为 null |
|
||||||
| `isPrimary` | boolean | | 全局默认模型;**同一时刻全库至多一个 `true`** |
|
| `isPrimary` | boolean | | 全局默认模型;**同一时刻全库至多一个 `true`** |
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ VRM 版本识别:读取 GLB 的 JSON chunk,检查 `extensions.VRM`(0.x)
|
|||||||
|
|
||||||
VMD 是二进制格式:文件头 `Vocaloid Motion Data 0002`(30 字节)+ 模型名(20 字节,
|
VMD 是二进制格式:文件头 `Vocaloid Motion Data 0002`(30 字节)+ 模型名(20 字节,
|
||||||
Shift-JIS)+ 骨骼关键帧数组(每条 **111 字节**:15 字节骨骼名、uint32 帧号、
|
Shift-JIS)+ 骨骼关键帧数组(每条 **111 字节**:15 字节骨骼名、uint32 帧号、
|
||||||
float32×3 位移、float32×4 旋转四元数、64 字节贝塞尔插值参数)+ morph / 相机 /
|
float32x3 位移、float32x4 旋转四元数、64 字节贝塞尔插值参数)+ morph / 相机 /
|
||||||
灯光 / 自阴影 / IK / 可见性段落。**VMD 不含骨骼长度**,只有旋转(少数骨骼带位移),
|
灯光 / 自阴影 / IK / 可见性段落。**VMD 不含骨骼长度**,只有旋转(少数骨骼带位移),
|
||||||
因此服务端必须自带一套标准 MMD 骨架才能做 FK。
|
因此服务端必须自带一套标准 MMD 骨架才能做 FK。
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ FK 旋转)。两份示例文件分别命中两种路径。
|
|||||||
**标准骨架数值来源**:解析参考模型的 PMX 骨骼段实测得到(而非凭经验估计),
|
**标准骨架数值来源**:解析参考模型的 PMX 骨骼段实测得到(而非凭经验估计),
|
||||||
再去掉模型自身原点偏移并抹平左右不对称。关键比例:足首 1.43 / ひざ 6.57 /
|
再去掉模型自身原点偏移并抹平左右不对称。关键比例:足首 1.43 / ひざ 6.57 /
|
||||||
髋 11.50 / センター 10.88 / 首 16.21 / 頭 17.16(总高约 19.4,髋高比约 59%);
|
髋 11.50 / センター 10.88 / 首 16.21 / 頭 17.16(总高约 19.4,髋高比约 59%);
|
||||||
大腿 4.94 + 小腿 5.15 ≈ 腿长 10.07。
|
大腿 4.94 + 小腿 5.15 ~ 腿长 10.07。
|
||||||
|
|
||||||
## 3. 上传限制
|
## 3. 上传限制
|
||||||
|
|
||||||
|
|||||||
@@ -121,5 +121,5 @@ spine = angle(neck, pelvis, midpoint(left_ankle, right_ankle))
|
|||||||
`angle(a, b, c)` = 向量 `ba` 与 `bc` 的夹角余弦,即
|
`angle(a, b, c)` = 向量 `ba` 与 `bc` 的夹角余弦,即
|
||||||
`dot(normalize(a-b), normalize(c-b))`,落在 `[-1, 1]`。
|
`dot(normalize(a-b), normalize(c-b))`,落在 `[-1, 1]`。
|
||||||
|
|
||||||
**DTW 序列结构(冻结)**:每帧 = `[33 × (x, y, z), 9 个关节角余弦] = 108 维`。
|
**DTW 序列结构(冻结)**:每帧 = `[33 x (x, y, z), 9 个关节角余弦] = 108 维`。
|
||||||
低置信度点(`visibility < 0.5`)在插值阶段由相邻帧线性补全,不参与代价计算。
|
低置信度点(`visibility < 0.5`)在插值阶段由相邻帧线性补全,不参与代价计算。
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ ws://<windows-host>:8765/pose
|
|||||||
bit2 = 上半身模式(仅 0..22 有效)
|
bit2 = 上半身模式(仅 0..22 有效)
|
||||||
bit3-7 保留,必须为 0
|
bit3-7 保留,必须为 0
|
||||||
4 4 frame_id u32 LE 单调递增,从 0 开始
|
4 4 frame_id u32 LE 单调递增,从 0 开始
|
||||||
8 231 keypoints 33 × 7B 见下
|
8 231 keypoints 33 x 7B 见下
|
||||||
--
|
--
|
||||||
合计 239
|
合计 239
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ src/net/keypoint_frame.gd
|
|||||||
2 1 version u8 = 1
|
2 1 version u8 = 1
|
||||||
3 1 flags u8 bit0 镜像 bit1 低置信度 bit2 上半身
|
3 1 flags u8 bit0 镜像 bit1 低置信度 bit2 上半身
|
||||||
4 4 frame_id u32 LE
|
4 4 frame_id u32 LE
|
||||||
8 231 keypoints 33 × 7B:s16 x, s16 y, s16 z, u8 conf
|
8 231 keypoints 33 x 7B:s16 x, s16 y, s16 z, u8 conf
|
||||||
合计 239
|
合计 239
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ src/net/keypoint_frame.gd
|
|||||||
## 关键实现
|
## 关键实现
|
||||||
|
|
||||||
- 归一化系数统一 32767,与 opendance-web 的 TypeScript 参考实现逐位对齐
|
- 归一化系数统一 32767,与 opendance-web 的 TypeScript 参考实现逐位对齐
|
||||||
- 编解码往返误差 < 1e-4(定点精度 1/32767 ≈ 3.05e-5)
|
- 编解码往返误差 < 1e-4(定点精度 1/32767 ~ 3.05e-5)
|
||||||
- `unmirrored_points()` 按 flags.bit0 翻转 x
|
- `unmirrored_points()` 按 flags.bit0 翻转 x
|
||||||
- 低置信度阈值 0.5:`is_reliable()` 与 `compute_low_confidence()`
|
- 低置信度阈值 0.5:`is_reliable()` 与 `compute_low_confidence()`
|
||||||
- 极值(±1.0)不溢出 int16
|
- 极值(±1.0)不溢出 int16
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ src/anim/skeleton_retarget.gd
|
|||||||
2. 取骨骼静止朝向 `rest_dir`(由该骨与首个子骨的位置差得出,**不假设模型骨骼轴向**)
|
2. 取骨骼静止朝向 `rest_dir`(由该骨与首个子骨的位置差得出,**不假设模型骨骼轴向**)
|
||||||
3. 目标朝向由两个关键点在世界空间的方向得出
|
3. 目标朝向由两个关键点在世界空间的方向得出
|
||||||
4. `delta` = rest_dir -> target_dir 的最小旋转四元数(保留扭转/roll)
|
4. `delta` = rest_dir -> target_dir 的最小旋转四元数(保留扭转/roll)
|
||||||
5. `desired = Basis(delta) × rest_global_basis`
|
5. `desired = Basis(delta) x rest_global_basis`
|
||||||
6. `pose_local = parent_global_basis⁻¹ × desired`
|
6. `pose_local = parent_global_basis⁻¹ x desired`
|
||||||
|
|
||||||
**第 6 步的合成公式是实测标定的**:Godot 文档未写明 rest/pose 的合成顺序,
|
**第 6 步的合成公式是实测标定的**:Godot 文档未写明 rest/pose 的合成顺序,
|
||||||
在真实 VRoid 模型上暴力枚举 5 种候选公式,只有该式误差为 1.9e-8(其余 ~0.14)。
|
在真实 VRoid 模型上暴力枚举 5 种候选公式,只有该式误差为 1.9e-8(其余 ~0.14)。
|
||||||
@@ -31,7 +31,7 @@ src/anim/skeleton_retarget.gd
|
|||||||
## 坐标转换
|
## 坐标转换
|
||||||
|
|
||||||
契约 4 的 MediaPipe 归一化坐标 -> Godot 世界方向:
|
契约 4 的 MediaPipe 归一化坐标 -> Godot 世界方向:
|
||||||
`Vector3(x × aspect, −y, −z × aspect)`(x/z 以图像宽为基准故乘宽高比)。
|
`Vector3(x x aspect, -y, -z x aspect)`(x/z 以图像宽为基准故乘宽高比)。
|
||||||
|
|
||||||
## 验收
|
## 验收
|
||||||
|
|
||||||
|
|||||||
@@ -20,20 +20,20 @@ src/score/scoring.gd
|
|||||||
|
|
||||||
## 特征(契约 5 冻结)
|
## 特征(契约 5 冻结)
|
||||||
|
|
||||||
每帧 = `[33 × (x,y,z), 9 个关节角余弦]` = **108 维**。
|
每帧 = `[33 x (x,y,z), 9 个关节角余弦]` = **108 维**。
|
||||||
低置信度点(conf < 0.5)对应维度**权重置 0**,不参与代价计算。
|
低置信度点(conf < 0.5)对应维度**权重置 0**,不参与代价计算。
|
||||||
|
|
||||||
## DTW
|
## DTW
|
||||||
|
|
||||||
- Sakoe-Chiba 带状约束 `|i − j| ≤ band`(默认 15 帧 ≈ 0.5 秒)
|
- Sakoe-Chiba 带状约束 `|i - j| <= band`(默认 15 帧 ~ 0.5 秒)
|
||||||
- `DtwMatcher.compute_full()` 离线段;`StreamingDtw` 逐帧流式推进,
|
- `DtwMatcher.compute_full()` 离线段;`StreamingDtw` 逐帧流式推进,
|
||||||
每帧只计算带内一行,总体复杂度 O(n·m·band) 但摊到每帧 O(m·band)
|
每帧只计算带内一行,总体复杂度 O(n m band) 但摊到每帧 O(m band)
|
||||||
- 归一化:代价 / max(i,j)+1,得到「平均每步代价」
|
- 归一化:代价 / max(i,j)+1,得到「平均每步代价」
|
||||||
|
|
||||||
## 评分规则(`scoring.gd`)
|
## 评分规则(`scoring.gd`)
|
||||||
|
|
||||||
`score = clamp(1 − cost/tolerance, 0, 1) × 100`,EMA 平滑抑制抖动,
|
`score = clamp(1 - cost/tolerance, 0, 1) x 100`,EMA 平滑抑制抖动,
|
||||||
等级 S(≥95) / A(≥85) / B(≥70) / C(≥55) / D,连击阈值 70。
|
等级 S(>=95) / A(>=85) / B(>=70) / C(>=55) / D,连击阈值 70。
|
||||||
|
|
||||||
## 验收
|
## 验收
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user