feat(model): humanoid 骨名映射对齐 MMD/中文(契约 skeleton-topology 0.2.0)
- CANDIDATES 由服务端表生成写入(与 model-inspector.ts 逐字一致,parity 测试断言) - normalize() 保留 CJK/假名并把全角 ASCII 折半角,修复 MMD 骨名归一化成空串导致 humanoid 覆盖率恒为 0/22 的问题 - contracts/ 同步至 0.5.0 / 0.2.0
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# contracts/skeleton-topology.md - 骨骼拓扑契约 v0.1.0
|
||||
# contracts/skeleton-topology.md - 骨骼拓扑契约 v0.2.0
|
||||
|
||||
**唯一拓扑:MediaPipe Pose 33 点。禁止引入 SMPL 及其衍生拓扑(许可风险)。**
|
||||
|
||||
@@ -123,3 +123,65 @@ spine = angle(neck, pelvis, midpoint(left_ankle, right_ankle))
|
||||
|
||||
**DTW 序列结构(冻结)**:每帧 = `[33 x (x, y, z), 9 个关节角余弦] = 108 维`。
|
||||
低置信度点(`visibility < 0.5`)在插值阶段由相邻帧线性补全,不参与代价计算。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 6. 内部动作标准与模型骨骼重绑定(v0.2.0)
|
||||
|
||||
**目的**:动作数据必须能匹配系统内的任意模型,因此把"关键点标准 + 骨架标准 + humanoid 标准"
|
||||
冻结成本节,模型上传时按此**重绑定骨骼**,再包装为 VRM。
|
||||
|
||||
### 6.1 三层标准
|
||||
|
||||
| 层 | 标准 | 权威实现 |
|
||||
|--|--|--|
|
||||
| 关键点 | MediaPipe Pose **33 点**(顺序见 §1),动作一律先转成关键点序列(NDJSON)再入库 | `preprocess/`(BVH / VMD / FBX -> 33 点) |
|
||||
| 动作骨架 | **MMD 标准骨架**(静止比例实测自参考 PMX; `足IK` 带位移时走两骨骼腿部 IK,否则 FK) | `preprocess/mmd-skeleton.ts` |
|
||||
| 模型骨架 | **22 根 humanoid 规范骨**(顺序即层级,父在前),其中 **16 根为必需**(§6.2) | `models/model-inspector.ts` 的 `HUMANOID_CANDIDATES` |
|
||||
|
||||
评分只依赖 33 点关键点序列,**与模型骨架解耦**;因此"动作能匹配任何模型"的充要条件是
|
||||
**模型可驱动**(16 根必需骨齐全,`drivable=true`)。
|
||||
|
||||
### 6.2 22 根 humanoid 规范骨与 16 根必需骨
|
||||
|
||||
```
|
||||
hips -> spine -> chest -> upperChest -> neck -> head
|
||||
├── leftShoulder -> leftUpperArm -> leftLowerArm -> leftHand
|
||||
└── rightShoulder -> rightUpperArm -> rightLowerArm -> rightHand
|
||||
hips -> leftUpperLeg -> leftLowerLeg -> leftFoot -> leftToes
|
||||
hips -> rightUpperLeg -> rightLowerLeg -> rightFoot -> rightToes
|
||||
```
|
||||
|
||||
必需 16 根(缺一即 `drivable=false`):`hips`、`spine`、`neck`、`head`、
|
||||
`leftUpperArm`、`leftLowerArm`、`leftHand`、`rightUpperArm`、`rightLowerArm`、`rightHand`、
|
||||
`leftUpperLeg`、`leftLowerLeg`、`leftFoot`、`rightUpperLeg`、`rightLowerLeg`、`rightFoot`。
|
||||
|
||||
### 6.3 重绑定规则(模型上传时执行,服务端与三端一致)
|
||||
|
||||
1. **归一化**:小写 → 只保留 `a-z0-9` + **中文/日文(CJK、平假名、片假名、长音符、々)**;
|
||||
**全角 ASCII(A-Z a-z 0-9)折成半角**(MMD 常写「足IK」「つま先IK」)。
|
||||
*v0.2.0 修正*:此前只保留 `a-z0-9`, MMD 骨名(`上半身`/`左ひじ`/`首`)被归一化成空串,
|
||||
humanoid 覆盖率恒为 **0/22**。
|
||||
2. **剥前缀**:只剥 `J_Bip` / `mixamorig` / `Bip01`; **不剥** `J_Aim_` / `J_Roll_` / `J_Sec_`
|
||||
(VRoid 的扭转辅助骨,剥了会与真正的骨骼撞名)。
|
||||
3. **变体**: `left/right` 与 `l/r` 互转(`leftupperarm` <-> `lupperarm`)。
|
||||
4. **精确匹配**:归一化+变体后的名字必须与候选表**完全相等**(前缀不匹配),
|
||||
因此 `左足IK`(-> `左足ik`)不会抢占 `左足`(`leftUpperLeg`)。
|
||||
5. **候选表覆盖四类命名**(顺序即优先级;服务端与客户端**逐字一致**,由测试断言):
|
||||
VRoid(`J_Bip_C_Hips` 等)、Mixamo(`mixamorig:LeftArm`)、
|
||||
**MMD 标准骨架(`下半身`/`上半身`/`上半身2`/`首`/`頭`/`左肩`/`左腕`/`左ひじ`/`左手首`/`左足`/`左ひざ`/`左足首`/`左つま先`)**、
|
||||
常见中文名(`臀部`/`头`/`脖子`/`左大臂`/`左小臂`/`左大腿`/`左脚` 等)。
|
||||
6. **结果写入 VRM**:命中结果写成 `VRMC_vrm.humanoid.humanBones` 的**节点索引**(VRM 规范
|
||||
不要求节点名固定,因此以索引为准,不改动几何与贴图);未命中的骨骼保留原名作为附加骨。
|
||||
7. **结论必须上报**: `models.stats.humanoidMapped` / `humanoidTotal` / `missingRequiredBones` /
|
||||
`drivable` 四项写库,审核界面展示;`usable` 与是否进入客户端目录见 model-formats.md 1.1。
|
||||
|
||||
### 6.4 实测(v0.2.0 重绑定后)
|
||||
|
||||
| 样本 | 重绑定前 | 重绑定后 | 结果 |
|
||||
|--|--|--|--|
|
||||
| `【奥黛塔】_by_原神.zip`(PMX,日文骨名) | 0/22,不可驱动 | **21/22, drivable=true** | 交付 **VRM** |
|
||||
| `模型_初音未来Hatsune Miku_by_Boku_Wa_Luka.zip`(PMX) | 0/22,不可驱动 | **19/22, drivable=true** | 交付 **VRM** |
|
||||
|
||||
未命中的 1-3 根均为非必需骨(如 `upperChest` / `leftToes`),不影响驱动与评分。
|
||||
|
||||
Reference in New Issue
Block a user