Activate A Pose Library Entry via Python Code?

Hi All,

I have some poses in a Pose Library which represent phonemes. I have created them inside this boy RIG.
I would like to activate them over time to make a lip synch tool that reads Papagayogenerated MOHO.dat file.

The problem I am running into is that I can not figure out what links a Pose Library entry to the bones the entry represents? And where is the transformational information for all the bones in a Pose Library entry?

Here is how I am fetching the Pose Library entry.


rig = bpy.data.objects.get("garoto_mov_rosto")
pl = rig.pose_library
if pl != None:
    # Print the name of markers in the Pose Library.
    pose_index = pl.pose_markers.find("blair_a_i")
    pm = pl.pose_markers[pose_index]
    print(pm.name)
    print(pm.frame)
    print(pm.camera)
    print(pm.select)

So all a Pose Library entry contains is a name, frame and camera. So how do I make use of this information to locate the bones associated with this entry?

I can find and select the bones associated with a Bone Group this way.


rig = bpy.data.objects.get("garoto_mov_rosto")
arm = rig.data
mouth_bones = []
mouth_group_name = "mouth"
#Find all the bones that belong to this bone group.
for ab in arm.bones:
    i = p.bones.find(ab.name)
    if i != -1:
        pb = p.bones[i]
        if pb.bone_group.name == mouth_group_name:
            mouth_bones.append(i)
            ab.select = True
        else:
            ab.select = False
    else:
        ab.select = False

Also, to add to the confusion it seems like Blender stores 3 types of bones. Armature bones, Edit Bones and Pose Bones.

So do I need to fetch from Pose Bones and assign to Armature Bones? Or is it the other way around…? I have been digging through bpy.data and searching for quite a while.

Thanks for any info on this topic:spin:

1 Like

Wow,

This one took a while to figure out. But in the process I learned quite a bit about the internal structure of the Armature, Bones and the Pose Library. This was always a mystery, to me. How things were internally linked.

The Pose Library is an Action.
The name of the library is the name of the action. The Pose Library is not actually linked to the armature. Instead it acts as a kind of single frame clipboard. When you add a pose to the Pose Library is gets assigned the next frame number in the action. If you delete and re-add entries to the Pose Library keyframes are not removed. The replace entry option will overwrite/update the existing entry keyframe, however. So list entry index vs what frame it is stored on can get skewed.

I tried to make this code generic but you do have to specify a group name (the bones in this group will receive the pose), an armature name and a valid index into the Pose Library list. I am still working with the example boy rig mentioned in the first post. I have created ten phonemes using the bones in the mouth bone group.

When I run this code the bones will change to the pose stored in the Pose Library. I can choose what pose I want by passing a different pose_library_index.
NOTE: It does not matter what mode the armature is in.
NOTE: The pose is only valid until the frame changes unless you insert a keyframe.


import bpy

def isKeyOnFrame(passedFcurve, passedFrame):
    result = False
    for k in passedFcurve.keyframe_points:
        if int(k.co.x) == int(passedFrame):
            result = True
            break
    return result

def returnBoneNamesInBoneGroup(passedPose, passedGroupName):
    result = []
    for b in passedPose.bones:
        if b.bone_group.name == passedGroupName:
            result.append(b.bone.name)
    return result

def assignPose (passedRigName,passedGroupName, passedPoseLibraryIndex):
    bones_to_move = []
    actions_for_bones = []
    rig = bpy.data.objects.get(passedRigName)
    if rig != None:
        p = rig.pose
        arm = rig.data
        p = rig.pose
        pl = rig.pose_library
        pm = pl.pose_markers[pose_library_index]
        bones_to_modify = returnBoneNamesInBoneGroup(p, passedGroupName)
        if len(bones_to_modify ) > 0:
            frame = pm.frame 
            action =  bpy.data.actions[pl.name]
            print("poselib_apply_pose: Operating upon [" + pl.name + "].")
            for agrp in action.groups:
                if agrp.name in bones_to_modify:
                    # check if group has any keyframes.
                    for fc in agrp.channels:
                        r = isKeyOnFrame(fc,frame)
                        if r == True:
                            tmpValue = fc.evaluate(frame)
                            i = p.bones.find(agrp.name)
                            if i != -1:
                                pb = p.bones[i]
                                # Determine where to assign this value based upon the data_path.
                                if fc.data_path.find("location") != -1:
                                    pb.location[fc.array_index] = tmpValue
                                if fc.data_path.find("rotation_quaternion") != -1:
                                    pb.rotation_quaternion[fc.array_index] = tmpValue
                                if fc.data_path.find("scale") != -1:
                                    pb.scale[fc.array_index] = tmpValue
        else:
            print("No bones found in group [" + passedGroupName + "].")


print("

Begin.")
mouth_group_name = "mouth"
rig_name = "garoto_mov_rosto"
pose_library_index = 6
assignPose(rig_name, mouth_group_name,pose_library_index)
print("End.")

Attachments


1 Like

Thanks for code!

Wouldn’t it be simpler to use the apply_pose() operator?

I rarely use Blender anymore.
Houdini Indie is only $200.00 and Apprentice is free!

Yeah, right…