Convert animations between armatures

Sorry to barge in with a help request on my very first post.

I am attempting to write a script that can convert animatinos from one skeletal system to another.

The core idea is to compare the properties of two similar bones on different armatures and generate an appropriate transform (Matrix or Quat) that can be applied to transformations on the first bone to produce roghly similar results on the second bone.

Unfortunately, the transforms don’t appear to be working the way I expected.

I had hoped that a transform which would rotate the first bone into the orientation of the second bone could be used a s a generic key that could be applied to a bone rotation to produce the desired results. Unfortunately, and maybe it is my code, the results have been terrifying.

I’ve experimented with matrix, roll, head, and tail properties (and various combinations) without much success.

Does anyone have any suggestions or ideas how I should be approaching this problem?

Here’s an example of one of the thing’s I’ve tried.

v1 and v2 are vectors that define the direction of the first and second bone respectively. I’ve calculated them in various ways as I’ve tried ever stranger things in my debugging, for example, bone1.head - bone1.tail, derived them from the bone matrix, etc.

def getRotationQuaternion(v1, v2, add = False):
    '''Find the shortest rotation to rotate direction of vector v1 into direction of vector v2'''
    v1 = v1.normalize()
    v2 = v2.normalize()


    if v1.dot(v2) > 0.999999:
        if add:
            q = Quaternion(0,0,0,0)
        else:
            q = Quaternion(1,0,0,0)
    elif v1.dot(v2) < -0.999999:
        if add:
            q = Quaternion(0,0,0,0)
        else:
            q = Quaternion(-1,0,0,0)
    else:
        v = v1.cross(v2)
        w = sqrt((v1.length ** 2) * (v2.length ** 2)) + v1.dot(v2)
        if add:
            q = Quaternion(w,v[0],v[1],v[2]).normalize()
        else:
            q = Quaternion(w,v[0],v[1],v[2]).normalize()
    return q

I had hoped that I could then multiply the quat from each key frame of the animation by the returned quaternion, apply it to the second bone, and end up with a result that vaguely resembled the animation on the first bone.

I got so frustrated, I wrote my own Quaternion multiplication function:

def multiplyQuaternion(Quat1, Quat2):
   '''Multiply the first Quaternion by the second.  Return the product.'''


    w1 = Quat1.w
    w2 = Quat2.w
    x1 = Quat1.x
    x2 = Quat2.x
    y1 = Quat1.y
    y2 = Quat2.y
    z1 = Quat1.z
    z2 = Quat2.z


    w = (w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2)
    x = (w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2)
    y = (w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2)
    z = (w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2)


    quatProduct = Quaternion(w,x,y,z).normalize()
    return quatProduct

But I’m getting crazy twists and distortions that I can’t explain. I’m either missing something basic or something very very complicated. Does anyone have any ideas?

You are defining your quaternion by using a cross product. This produces a quaternion that is equivalent to three separate rotations about the three axes. The problem is that to rotate one vector into another requires only two rotations about two axes (called the tracking sequence). By using the cross product your quaternion has an extra bone roll (twist) rotation. This unwanted rotation can be factored out by using quaternion factors if you must use the cross product.

Thanks for the information, that is very helpful.

It looks like I need to learn more about quaternions and how to use them.

I knew I should have taken Linear Algebra when I had the chance.

Also you are using component values for Quaternion creation. If you want to use cross product for axis you need to use axis angle values for Quaternion creation. If v = axis and w = angle then use Quaternion(v, w).