The VG Resource
ozz animation, concrete file format - Printable Version

+- The VG Resource (https://www.vg-resource.com)
+-- Forum: The Resources (https://www.vg-resource.com/forum-109.html)
+--- Forum: The Models Resource (https://www.vg-resource.com/forum-111.html)
+---- Forum: Ripping Help (https://www.vg-resource.com/forum-115.html)
+---- Thread: ozz animation, concrete file format (/thread-43286.html)



ozz animation, concrete file format - whantasqued - 12-23-2024

I'm having trouble decoding the ozz animation skeleton file format. It should be easy because it's open source (link), but I'm stumped by how the transformations of the bones are stored.

This is the structure of the start of the file:
The file starts with 0x01
The Null-terminated string ozz-skeleton
u32 version field (value 2)
u32 num_joints, which tells the number of joints in the file
u32 chars_count, which tells the length of the array of null-terminated bone names, in bytes. The number of names should match num_joints.
s16 array joint_parents , length 2 * num_joints bytes which tells the parents of each joint, 0xFFFF (-1) meaning "no parent"

This is where I'm stumped:
According to the source code, the rest of the file is the bind pose of the joints, expressed as transforms, I can't figure out the order of the fields and the correct length of the data.

What it should be is float x,y,z translation, float x,y,z,w quaternion rotation and float x,y,z scale.

Below is a sample file, both as a link and as a hex dump, that I get from adding a single bone in blender, then exporting that as an fbx, then converting the fbx to ozz skeleton. The bone in blender is named Bone, its head is at (x,y,z) 0,0,0 and its tail is at 0,0,1. The fbx export process adds a second bone named Bone_end, but I don't know its properties. When you import the file back into blender, it adds a second bone that is identical to the previous bone, so it might be a 0-length bone.

When I inspect the file, I find a float value for "0.01", which I assume is a Z coordinate, because there are 3 float values for "100" (0x0000C842), so I assume that the bone is exported at length 0.01 (0x0AD7233C) and scaled uniformly by 100. 

There are also 13 float "1"s (0x00008037) in the bind pose section, but I can't figure out what they should be. 
2 of them should be the W component of the "no rotation" quaternion for both bones.
Another 3 might be uniform 1 1 1 scale of the second bone, whose length is 0?

There is some C++ magic happening in the source code I linked and I can't figure out what exactly is happening when the file gets written or read. There is something about SoA (structs of arrays) for simd processing and something about data being processed depth first, but I don't understand what.

"default bone" ozz file:
link: https://file.io/Ukavuc3ZvtX1
Hex dump: (the FFFF0000 is the joint_parents part (-1, 0), the rest of the file after that is the bind pose part)

Code:
016F7A7A 2D736B65 6C65746F 6E000200 00000200 00000E00 0000426F 6E650042
6F6E655F 656E6400 FFFF0000 00000000 00000000 00000000 00000000 00000000
0AD7233C 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 0000803F 0000803F 0000803F 0000803F 0000C842
0000803F 0000803F 0000803F 0000C842 0000803F 0000803F 0000803F 0000C842
0000803F 0000803F 0000803F