I solved a similar task by creating a pose library with all required poses (same rig in my case a MHX rig) and a control file which contains the information which character and group of bones should get a pose assigned on a specific keyframe.
The keyframes are added to an action. This way each character has its own animation which can be tweaked.
The control file looks like:
0 SET:A=r6839a_proxy
0 SET:B=r6839b_proxy
1 A:All=Stance
1 B:All=Stance
10 B:Arm.L=Punch,Arm.R=Block
10 A:Arm.L=Hook
The first number is the keyframe in line #0 the rig proxy is assigned to a variable A/B to quickly change the character.
Line #1 selects all bones and assigns a stance as starting position from a poselib that contains a pose called stance,
Line #10 Selects the left arm of the character B and assigns a Punch from the poselib.
Note: that I used forward kinematics for the arm and inverse kinematics for the legs.
The script that reads the control file:
import bpy
obj_map = {}
target_map = { "Root" : 0, "Spine" : 1, "ArmFK.L" : 3, "LegIK.L" : 4, "Fingers.L" : 6,
"Links.L" : 7, "ArmFK.R" : 19, "LegIK.R" : 20, "Fingers.R" :22, "Links.R" : 23 }
macros = { "Hand.L": ["Fingers.L", "Links.L"],
"Hand.R": [ "Fingers.R", "Links.R" ],
"All": ["Spine","ArmFK.L","ArmFK.R","LegIK.L","LegIK.R","Links.R","Fingers.R","Links.L","Fingers.L"],
"Stance": ["Spine","Root","LegIK.L","LegIK.R"],
"Arm.L": ["ArmFK.L","Links.L","Fingers.L"],
"Arm.R": ["ArmFK.R","Links.R","Fingers.R"] }
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 = [False]*32
print( targets )
for t in targets:
if t in target_map:
layers[target_map[ t ] ] = True
return tuple( 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 )
return
sel_layers = build_layers( targets )
bpy.ops.pose.armature_layers(layers=sel_layers)
bpy.ops.poselib.apply_pose(pose_index=idx)
bpy.ops.pose.select_all(action='SELECT')
#if "Root" in targets:
bpy.ops.anim.keyframe_insert(type='BUILTIN_KSI_LocRot')
#else:
#bpy.ops.anim.keyframe_insert(type='Rotation')
action="poon"
text=action + ".txt"
txt = bpy.data.texts[ text ].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(",")
if obj_name.upper() == "SET":
var,val = pose_list[0].split('=')
obj_map[var]=val
print( obj_map )
continue
bpy.context.scene.frame_set( int( sframe ))
for assignment in pose_list:
bone_group_name,pose_name=assignment.split("=")
if bone_group_name in macros:
targets = macros[ bone_group_name ]
else:
targets = [ bone_group_name ]
obj = bpy.data.objects.get( obj_map[ obj_name])
if obj == None:
print("obj name=" + obj_name + " not found.")
break
bpy.context.scene.objects.active = obj
obj.select = True
#print( obj.animation_data.action )
#if obj.animation_data.action == None:
# bpy.ops.action.new()
#print( obj.animation_data.action )
#obj.animation_data.action.name = action + obj_name
bpy.ops.object.mode_set(mode = 'POSE')
print("assign obj:%s bone_group:%s, pose:%s" % (obj, bone_group_name, pose_name))
apply( obj, targets, pose_name)
Some details:
target_map is a dictionary which maps names used in the control script to rig-layer numbers (MHX)
macros is a collection for rig-layer adressed by single name e.g. 'All' for all rig-layers and Stance covers the root bone and both legs, thats to keep the control file short.
Around line 50:
action="poon"
text=action + ".txt"
Is the name of the control file it is directly used from the internal text editor.
Related:
Can an action be mirrored or reused?