2
$\begingroup$

When the bpy.ops.poselib.apply_pose operator is applied from the UI it works fine, all selected bone groups get the pose applied.

enter image description here

Doing the same from the console or script seems to have no effect:

bpy.ops.poselib.apply_pose(0)
{'FINISHED'}

bpy.ops.poselib.apply_pose(2)
{'FINISHED'}

The full script: It should read a control file "pose.txt" and apply poses to selected bone groups for each defined frame

import bpy

# http://www.blender.org/documentation/blender_python_api_2_69_9/bpy.ops.pose.html

target_map = { "Root" : 0,      
 "Spine" : 1,
 "ArmFK.L" : 3,
 "LegIK.L" : 4,
 "Fingers.L" : 6,
 "Links.L" : 7,
 "ArmFK.R" : 20,
 "LegIK.R" : 21,
 "Fingers.R" :23,
 "Links.R" : 24 } 

def get_pose_index(obj, pose_name ):
    idx = 0
    for pm in obj.pose_library.pose_markers:
        if pose_name == pm.name:
            return idx
        idx += 1
    return None

def build_layers(targets):
    layers = []
    for i in range (0, 32):
        layers.append(False)
    for t in targets:
        idx = target_map[ t ]
        if idx is not None:
            layers[idx] = True
    layers = tuple( layers )
    return layers

def apply( obj, targets, pose_name):
    idx = get_pose_index( obj, pose_name )
    if idx is None:
        print("pose %s not found." % pose_name )
    sel_layers = build_layers( targets )
    print(sel_layers)
    bpy.ops.pose.armature_layers(layers=sel_layers)
    bpy.ops.pose.select_all(action='SELECT')
    print(idx)

    bpy.ops.anim.keyframe_insert(type='BUILTIN_KSI_LocRot')


txt = bpy.data.texts["pose.txt"].as_string()
for line in txt.splitlines():
    if line.find(" ") != -1 and line.find("#") == -1:
        sframe,rig_and_poses= line.split(" ")
        rest=rig_and_poses.split(":")
        print("frame :%s" % sframe )
        obj_name=rest[0]
        poses=rest[1]
        pose_list=poses.split(",")
        bpy.context.scene.frame_set( int( sframe ))
        for assignment in pose_list:
            targets = []

            bone_group_name,pose_name=assignment.split("=")
            if bone_group_name.startswith("Hand.L"):
                targets.append("Fingers.L")
                targets.append("Links.L")
            elif bone_group_name.startswith("Hand.R"):
                targets.append("Fingers.R")
                targets.append("Links.R")
            else:
                targets.append( bone_group_name )

            obj = bpy.data.objects.get(obj_name)
            if obj == None:
                print("obj name=" + obj_name + " not found.")
                break
            print("assign obj:%s bone_group:%s, pose:%s" % (obj, bone_group_name, pose_name))
            apply(  obj, targets, pose_name)

.blend file

Updated .blend file

$\endgroup$

3 Answers 3

2
$\begingroup$

You missed the call to bpy.ops.poselib.apply_pose() also the index has to be passed by name

def apply( obj, targets, pose_name):
    idx = get_pose_index( obj, pose_name )
    if idx is None:
        print("pose %s not found." % pose_name )
    sel_layers = build_layers( targets )
    print(sel_layers)
    bpy.ops.pose.armature_layers(layers=sel_layers)
    bpy.ops.pose.select_all(action='SELECT')
    print(idx)
    bpy.ops.poselib.apply_pose(pose_index=idx) # add this line <<<<<<<<
    bpy.ops.anim.keyframe_insert(type='BUILTIN_KSI_LocRot')
$\endgroup$
3
  • $\begingroup$ Thanks for you quick response, I don't know how I managed to omit this line, but this wasn't the only problem. $\endgroup$
    – stacker
    Feb 10, 2014 at 10:16
  • $\begingroup$ Just had another look apply_pose needs to use pose_index=idx I see proper animation with that line. $\endgroup$
    – sambler
    Feb 10, 2014 at 11:23
  • $\begingroup$ I had an offset error in my bone group to index map, now everything works. Thanks you so much. $\endgroup$
    – stacker
    Feb 10, 2014 at 12:37
3
$\begingroup$

If an operator is called from the UI it is implicitly given a context which depends on the area the operator has been called from and contains specific information about that area.

In your case you are calling an operator from the text area which is supposed to be called from the properties area. It is given the wrong context and can not retrieve the information it needs from it.

See

In the text context there is only edit_text available. The global context does not contain information about the active object and the selected pose bones, neither. But the screen context does.

However here is an example how to override the context in this case:

import bpy
#get your armature
obj = bpy.data.objects['Armature']
selected_bones = [pose_bone for pose_bone in obj.pose.bones if pose_bone.bone.select]

context = {}
context['scene'] = bpy.context.scene
context['active_object'] = obj
context['selected_pose_bones'] = selected_bones

bpy.ops.poselib.apply_pose(context, pose_index=1)

This is the minimal content which is required to run the operator. It still gives warnings. Messages about window, screen, area, region not being found often can be ignored. You might pass None for these entrys to suppress the warnings.

Example: How to refer to an area in the same screen where the operator is being run from

context['window'] = context.window
context['screen'] = context.screen
for area in context.screen.areas:
    if area.type == 'PROPERTIES':
         break
context['area'] = area
context['region'] = area.regions[1]
context['space_data'] = area.spaces[0]
$\endgroup$
2
  • $\begingroup$ Thanks this would explain why it doesn't work, I added the lines and now get 'RuntimeError: Operator bpy.ops.pose.armature_layers.poll() failed, context is in correct' I updated the .blend file attached to the question, I would be happy if you could take a look. $\endgroup$
    – stacker
    Feb 10, 2014 at 10:20
  • $\begingroup$ Thank you, I it now works without the context, but good to know when I really need this one time. $\endgroup$
    – stacker
    Feb 10, 2014 at 12:39
0
$\begingroup$

blender 2.93
set mode='POSE' is helped me

import bpy


#bpy.context.object.data.pose_position = 'REST'
bpy.context.object.data.pose_position = 'POSE'
# https://docs.blender.org/api/current/bpy.ops.object.html?highlight=mode_set#bpy.ops.object.mode_set
# bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.mode_set(mode='POSE', toggle=False)

bpy.ops.poselib.apply_pose(pose_index=1)
```
$\endgroup$

You must log in to answer this question.

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