1
$\begingroup$

https://stackoverflow.com/q/38541723/2495562

I posted the question on stackoverflow ealier before I realised here might be the right place to ask blender related questions.


I'm using blender 2.49 because the script was originally written for that version.

I'm trying to create animations using some transform data.

The original data contains a sequence of joints. Each joint has its own rotation and translation values, it may or may not have a parent joint. This sounds pretty much like bones in blender, right?

To set up the skeleton:

#pseudocode
for joint in joints:
    v = Vector(0,0,0)
    j=joint
    while j:
        v = j.rotation*v
        v = v + j.location
        j = j.parent
    joint.position = v

To process a certain frame:

#pseudocode
for joint in joints:
    v = Vector(0,0,0)
    j=joint
    while j:
        rot=j.rotation+j.curFrame.dRotation
        loc=j.location+j.curFrame.dLocation
        v = rot*v
        v = v + loc
        j = j.parent
    joint.position = v

To make things simple, I convert each joint into a small bone.

    for i in range(0, len(bones)):
        bone = Blender.Armature.Editbone()
        bone.head = Mathutils.Vector(0,0,0)
        bone.tail = Mathutils.Vector(0,1,0)
        bone.name = 'Bone.' + str(i)
        bone.parent = armature.bones['Bone.' + str(bones[i].parent)]
        armature.bones[bone.name] = bone

Then I move the bones to their desired locations, using the posebone trick to create the skeleton:

    pose=armObject.getPose()
    pose_bones=pose.bones
    #pose the bones
    for i in range(0, len(bones)):
        name = 'Bone.'+str(i)
        tran = transforms[i]
        pose.bones[name].quat = Mathutils.Euler(tran.rotX,tran.rotY,tran.rotZ).toQuat()
        pose.bones[name].loc = Mathutils.Vector(tran.locX, tran.locY, tran.locZ)
    pose.update()
    #update editbones
    armature.makeEditable()
    for i in range(0, len(bones)):
        name = 'Bone.'+str(i)
        armature.bones[name].matrix = pose.bones[name].poseMatrix
    armature.update()
    #reset pose
    for i in range(0, len(bones)):
        name = 'Bone.'+str(i)
        pose.bones[name].quat = Mathutils.Euler(0,0,0).toQuat()
        pose.bones[name].loc = Mathutils.Vector(0,0,0)
    pose.update()

So far so good. But when I apply the transform to a certain frame, the results are incorrect.

    for i in range(0, len(bones)):
        name = 'Bone.'+str(i)
        tran = frame.dTransforms[i]
        pose.bones[name].quat = Mathutils.Euler(tran.rotX,tran.rotY,tran.rotZ).toQuat()
        pose.bones[name].loc = Mathutils.Vector(tran.locX, tran.locY, tran.locZ)

By incorrect I mean the rotations seem correct, but the translations are all wrong. I guess it is because the transforms should be applied to the posebone's local space(the skeleton is correct because all transforms start from the center )? But how do I do that?

$\endgroup$
1
$\begingroup$

Well I solved the problem already. I realized the transforms are done in the bone's local space, so they need to be calculated with the editbone's matrix before applying to the posebone.

for i in range(0, len(bones)):
    name = 'Bone.'+str(i)
    tran = frame.dTransforms[i]
    pb = pose.bones[name]
    eb = armature.bones[name]
    m1 = eb.matrix['BONESPACE'].rotationPart()
    e1 = m1.toEuler()
    e = Mathutils.Euler(tran.rotX,tran.rotY,tran.rotZ)
    e2 = Mathutils.Euler(e1.x+e.x,e1.y+e.y,e1.z+e.z)
    m2 = e2.toMatrix()
    m = m2*(m1.copy().invert())
    pb.quat = m.toQuat()
    pb.loc = m1*Mathutils.Vector(tran.locX,tran.locY,tran.locZ)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.