I have an animated object which consists of a set of linked transforms. Think of them as bones. This object is animated - external to my software - and an API streams the local rotations - as quaternions - for every bone.

I want to map this onto another target object. The issue is that this object has a different setup where its root has a different default orientation and the child "bones" do as well. I can't modify the target bone structure, and the goal is to have it map onto any arbitrary bone structure. To give a simplified illustration, here are the first two bones in the hierarchy.

As you can see, if the root in the original (O_Root) rotates around the z axis, to match that on the target, its root should rotate around its -x axis. Similarly, if the child in the original (O_Child) rotates around the x axis, that should result in a rotation around y for the target's child.

I have this working for the root, by computing the quaternion transform needed to take me from original root to target root, with which I then multiply the incoming data. But for some reason I can't wrap my head around how to go down the hierarchy and correctly transform the local rotation data I receive to something which correctly applies to the target.

How would I approach this data conversion, assuming I know the default orientations in either hierarchy?


1 Answer 1


First, we need to convert the animated local rotation quaternion q into the coordinate space of the new parent. We do that by remapping each axis individually. If changing handedness, we would also apply an extra negation to x,y,z, but that doesn't appear to apply here according to your diagrams.

var converted = new Quaternion(
    -q.z, // T_Parent.x = -O_Parent.z
    -q.x, // T_Parent.y = -O_Parent.x
    -q.y, // T_Parent.z = -O_Parent.y
     q.w  // angle identical

Applying this converted local rotation to a child under a parent with orientation T_Parent will yield a net orientation equivalent to O_Child (ie. its z+ axis points in the direction indicated by O_Child.z), which is not yet quite what we want.

So then we need to apply an extra twist to account for the difference between O_Child and T_Child:

var adapter = Quaternion.LookRotation(
    Vector3.up,   // T_Child.z+ = O_Child.y+
    Vector3.right // T_Child.y+ = O_Child.x+

Then we can chain these two effects:

var result = converted * adapter;

It's still early morning so there's a risk I've inverted one of these operations, but a solution following that rough outline should get you going in the right direction.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .