Skeletal animation, 2D to 3D

Hi, I’ve recently got an simple skeletal animation editor up and running but its not quite working how i’d like. At the moment I can create a series of bones from a root bone and by rotating each bone ( in any order ) I can set a pose and store the changes in their quaternions at the time of the frame. This all works fine providing all the rotations are applied to the same axis on each bone, so if I rotate all the bones on the z-axis only I can set my pose at the time sellected and then slerp between the default pose and the stored pose.

The problem is, if I rotate any of the quaternions by another axis the animation gets warped, the out of axis bone tends to get flipped and the animation is incorrect. So, does anyone know how I can avoid this and what i’d doing wrong here? I’m guessing I’m not understanding how quats work properly and that the rotation order has something to do here.

Some extra info that may be of help:
My bone structure just has one quaternion for its orientation, keyframes for transformed bones are stored like so: stored keyframeQuat = editedBoneQuat * editedParentBoneQuat.inverted. The bones are then transformed like so: for each animated bone, slerp between its default quat to stored quat based on the selected time. So the animations are applied in the oder they are stored, I have tried changing the order in which that are applied but it didn’t make any differnce.

Hope this makes sense, thanks for your help.

[edit] sorry for posting this in the wrong section, should have been in Math and Algorithms. doh

Try concatenating matrices instead of quaternions. Those matrices are generated from the quats. (in the bone’s local coord-space).

Also, you should be slerp-ing between 2 neighbouring keyframe values, not one of the keyframes and the bindpose-frame.

Alternatively, this might help, without moving to matrices:


Quat::Quat(float RotX,float RotY,float RotZ){
	float cosX, cosY, cosZ;
	float sinX, sinY, sinZ;
	float cosXY, sinXY;

	sinX = sinf(RotX * 0.5f);
	cosX = cosf(RotX * 0.5f);

	sinY = sinf(RotY * 0.5f);
	cosY = cosf(RotY * 0.5f);

	sinZ = sinf(RotZ * 0.5f);
	cosZ = cosf(RotZ * 0.5f);

	cosXY = cosX * cosY;
	sinXY = sinX * sinY;

	x = sinX * cosY * cosZ - cosX * sinY * sinZ;
	y = cosX * sinY * cosZ + sinX * cosY * sinZ;
	z = cosXY * sinZ - sinXY * cosZ;
	w = cosXY * cosZ + sinXY * sinZ; 

}

Thanks for your help, unfortunately something has come up and I won’t get time to work on this now till the weekend.

I think that my main problem here is how I’m storing the keyframe quats. I’m trying to store the difference in rotations between the default or last quat and the new edited quat. Should i just be storing the edited quats as they are at that pose time? Also, in the keyframe should i be storing all of the bones quats at that frame or just the bones that have been transformed?

Thanks again tho, i’ve got a few ideas to try at the weekend anyway, cheers.

I’m trying to store the difference in rotations between the default or last quat and the new edited quat. Should i just be storing the edited quats as they are at that pose time?

Well, that depends. What you’re talking about is effectively compression. So, first question: do you need the data to be compressed?

If you have a specific need for compression, then you probably also have some specific target in mind for animation compression. That is, some ratio or size target that you need to meet.

The very first compression you should be doing for quaternions is field compression. Rather than storing floating-point values, you should store signed shorts. Also, you can chop off the real part and reconstitute it with a square-root, since you can ensure that the real part of the quaternion is positive (negate the quaternion when compressing it if its real part is negative).

If that doesn’t get you the targets you need, only then should you be considering things like delta-compression. And even that is going to require more than you’ve done here to be effective.

So, first question: do you need the data to be compressed?

No, what you’ve suggested sounds way beyond my ability and needs :smiley:

I think my problem here is that i was trying to store the minimum data to the animation files (its my first attempt at this so i did blindly dive in). So, if i had four bones, RABC, if i rotated B at my first keyframe to create a new pose, i’d just store B’s new quat. I think if i store the entire new pose (RABC’s quats) at the new keyframe i should be able to get it working. This will increase the animation file size but not by much as i only intend on using smallish skeletons anyway. Roll on the weekend when i can hopefully try this out.

Cheers

Just to let you know that when you finally get 3D skeletal animation working (parsing a file for keyframe data, doing all the transforms, and skinning using a shader), you will feel an enormous relief and satisfaction of doing it all yourself. This was one of the most complex tasks I ever did when writing my home grown rendering engine. The rush of seeing everything work for the very first time after days of debugging was intense.

You will join a select brotherhood of programmers if you manage to do this on your own. Good luck.