Advertisement

Reverse Engineering Skeletal Animation in an Old Game

Started by August 30, 2020 03:58 PM
2 comments, last by Anfaenger 4 years, 1 month ago

I'm writing a model viewer for a 20-year-old game. The file format has already been reverse-engineered (by other people much smarter than me), the problem now is playing back the animations. I can correctly display the mesh and skeleton in the bind-pose, but an animated skeleton looks like a jumbled mess of sticks.

1. Skeleton format.

The bind-pose skeleton is stored as an array of bones, each bone is stored as an orientation quaternion (float[4]) and position vector (float[3]) in model space (i.e. not relative to the parent bone), parent bone index (int32) and a name string. Strangely, the bones are not sorted in depth-first order, starting from the root, i.e. the root bone is not necessarily the first one in the array of bones and can be the 2nd, 4th, 10th, etc. - their order seems arbitrary.

Here's the bind-pose skeleton of the model named “Bat1”.

2. Skeletal animation format.

Animations are simply stored as arrays of key-frames (bone tracks?) for each bone.

A rotation key-frame is stored as a timestamp (uint32, in milliseconds) and four 16-bit unsigned integers (a quaternion?), a position key-frame - a timestamp and a position vector (3 floats).

I assume that rotation frames store quaternions, but when I build quaternions (by multiplying each number by (1.0f/65535.0f)), some of the resulting quaternions can be unnormalized (e.g. their length can be 0.249954, 0.842029, 1.029763, …), so I normalize them afterwards.

Each bone track always has the first and the last frame (at the beginning and the end of animation)

3. Questions.

So, after loading the mesh, I build a bone tree and build an array of bones sorted in depth-first order (so that I can concatenate parent → child transforms by walking the array). I assumed that keyframes store position and orientation in the bone local space (relative to the parent bone), but this clearly must be wrong, because the animated/interpolated frame skeleton looks like this:

Incorrectly animated frame skeleton

0) What is most probably wrong? Where should I look into?

1) What would be the most obvious and straightforward way to animate using the above data? Can anyone give me ideas of how the original game could do it or point me in the right direction? How was skeletal animation usually done back in the olden days?

I think we might be having some of the same problems. Not sure if it will be of help, but check out my post and see if it might help you out. If does not, let me know and I will remove the link so not too confuse more people. I am guessing you are messing up some of the transforms for the bones. https://gamedev.net/forums/topic/707908-animation-from-scratch-problem-with-meshes

Advertisement

I applied my lackluster reverse-engineering skills and found out that quaternions in rotation keyframes are stored as four signed 16-bit numbers. They are converted to floating-point quaternions by multiplying each component by 0.000061038882f (== 1.0f / 16383.0f).

Now I have to figure out how this keyframe data is used to animate the skeleton…

This topic is closed to new replies.

Advertisement