第 6B 章:Voxel Rig 骨骼扩展
Voxel Rig v1 由格式变更 26072801-voxel-rig-v1 引入。它为角色、宠物、机械臂等可动体素资产保存 bind pose、刚性单骨骼体素绑定和 TRS 动画关键帧。
它不是 VFP 1.3 的基础要求:不含 Rig 的文件仍是有效 VFP;不支持 Rig 的 Reader 也必须能够以 bind pose 展示含 Rig 的文件。
区段与职责
| 区段 | 必需性 | 职责 |
|---|---|---|
SKEL | Rig 资产必需 | 骨骼层级与 bind pose。 |
VSKN | Rig 资产必需 | 稀疏、刚性的一体素一骨骼绑定。 |
ANIM | 可选 | 骨骼平移、旋转、缩放关键帧。 |
所有 Rig 区段均为全局 chunkId=-1、codec=RAW8 (0)、flags=0。ANIM 是骨骼动画,不能与 VFP 载入表现缓存 ANM0 混淆。
兼容性
| 兼容项 | 结论 |
|---|---|
| 向后兼容 | 是。支持 Rig 的 Reader 对旧静态 VFP 返回“无 Rig”。 |
| 向前兼容 | 是。旧 VFP 1.3 Reader 忽略未知的可选 SKEL、VSKN、ANIM,按 VOX0 bind pose 展示。 |
| 升级要求 | 写入、严格校验或播放骨骼动画的实现需要升级;只读静态预览不需要。 |
| 降级行为 | 忽略整套 Rig,显示 bind pose;不能因缺少动画能力而拒绝权威 VOX0。 |
| 缓存影响 | 现有 MSH0/PMSH/RND0/PRVW 最多表示 bind pose;动画渲染必须按骨骼边界生成专用网格。 |
SKEL v1
SKEL 的 Header 为 36 B:
version:u8 = 1
reserved:u8 = 0
jointCount:u16
baseSourceHash:u8[32]
每个 joint 的固定前缀 <Hh3f4f3fB3x> 为 48 B,随后附加 UTF-8 名称。它保存 jointId、parentId、translation、rotation、scale 和 name。jointId 必须严格递增;parent 必须存在且层级不得有环;rotation 必须为单位四元数。
skeletonHash = SHA-256(SKEL payload)。它绑定 VSKN 与 ANIM,防止将动画错误应用到另一套骨架。
VSKN v1:刚性体素绑定
VSKN 使用稀疏记录。每个非空体素默认继承 defaultJointId,只有绑定到其它骨骼的体素才写出记录:
VSKN Header: <BBHHI32s32s> = 74 B
version:u8 = 1
encoding:u8 = 1 // SPARSE_INDEX_U16
defaultJointId:u16
reserved:u16 = 0
bindingCount:u32
baseSourceHash:u8[32]
skeletonHash:u8[32]
record: <IH> = 6 B
voxelOffset:u32
jointId:u16
voxelOffset 是 x-fastest 的线性 VOX0 索引,必须严格递增,并且只能指向非空体素。一个体素只允许一个 joint,因此 Voxel Rig v1 呈现的是积木式关节动画,而非软体拉伸。
ANIM v1:骨骼关键帧
ANIM Header 为 <BBH32s32s>,包含 version、clipCount、baseSourceHash 和 skeletonHash。clip 带有稳定 id、名称、duration;每条 track 绑定一个 joint;每个 key 保存 timeMs + translation.xyz + rotation.xyzw + scale.xyz。
key 的时间必须在 0..durationMs 内严格递增。格式只规定数据,不规定插值、动画混合、IK、约束或状态机;渲染器应公开自己的播放策略。
JSON 编译输入
Python VoxelKit 接受根级 rig:
{
"rig": {
"joints": [
{"id": 0, "name": "Root"},
{"id": 1, "parent": 0, "name": "Arm", "translation": [1, 0, 0]}
],
"default_joint": 0,
"bindings": [{"position": [4, 7, 3], "joint": 1}],
"animations": [{
"id": 0,
"name": "wave",
"duration_ms": 800,
"tracks": [{"joint": 1, "keys": [{"time_ms": 0}, {"time_ms": 800, "rotation": [0, 0, 0.7071, 0.7071]}]}]
}]
}
}
没有 rig 字段时,Writer 不会写入任何 Rig 区段;静态 VFP 的 sourceHash 与同一模型的 Rig 版本完全一致。
当前实现边界
Python VoxelKit 已支持 JSON → VFP 编译、解析和严格校验 SKEL/VSKN/ANIM。当前 HarmonyOS ArkGraphics Viewer 仍按 bind pose 读取,不声明实时骨骼渲染能力。将来实现动画渲染时,必须生成骨骼边界感知的网格,不能复用可能跨骨骼合面的普通贪心缓存。