Exporting trouble. Bone tail and head positions change quaternion rotation

I managed to program a cute script to export animated models for Play Station Portable.

If all the bones are aligned with Y pointing up, It works perfect, But animating the models that way is a bit strange:

So I want to export models with bones not aligned like this:

But the bones rotated in edit mode, like the ones for the arms, are now rotating along their rotated Y axis, the exported quaternions are wrong when loaded in PSP and they rotate in flipped axis.

So... Is there a way to export the quaternions without the rotation added by the head-tail axis?. Like, multiply the quaternion by the head-tail vector... or something like that?

Thanks a lot!

Long answer: it likely isn't worth it.

You can do things like this by shifting the rotational axis of the animations once you have adjusted your bones as described by this question/comment set: Rotate a particular bone in edit mode without offsetting animation?

But, from experience, you should not make adjustments to your armature once animations are created.

• Thanks. I just wanted to do the math when exporting the bones. PSP just needs the position of the head and the quaternion.It will help – Mills Jun 9 '17 at 8:21
• Sorry I posted wrong... I was thinking it would also help drawing the bones as just balls at head position in blender, and keep them aligned in edit mode. But I could not find any settings to do this. – Mills Jun 9 '17 at 8:33

This is actually fairly easy. In your case, you will want to multiply your quat by the inverse of the rest pose. So you would do something like:

quat_key.cross(bone.matrix_local.transposed().inverted().to_quaternion())


You may have to swap the rest bone and your quaternion key (try both, one should work), and perhaps also first bring the rest bone into "parent space", which you can do by multiplying its matrix with its parent bone's matrix, inverted:

bone_in_parent_space = bone.matrix_local.transposed() * bone.parent.matrix_local.transposed()).inverted()


But the latter is probably not required for your case, since your script worked with your initial approach.