Two new operators for easier retargeting: Auto scale performer, and a first attempt at auto hiearchy mapping

This commit is contained in:
Benjy Cook 2011-07-20 21:03:06 +00:00
parent 2c61949179
commit a08a510d65
3 changed files with 93 additions and 10 deletions

@ -573,7 +573,67 @@ def scale_fix_armature(performer_obj, enduser_obj):
perf_bones = performer_obj.data.bones
end_bones = enduser_obj.data.bones
#perf_avg = performer_obj.dimensions
def calculateBoundingRadius(bones):
center = Vector()
for bone in bones:
center += bone.head_local
center /= len(bones)
radius = 0
for bone in bones:
dist = (bone.head_local - center).length
if dist > radius:
radius = dist
return radius
perf_rad = calculateBoundingRadius(performer_obj.data.bones)
end_rad = calculateBoundingRadius(enduser_obj.data.bones)
#end_avg = enduser_obj.dimensions
#print(perf_avg, end_avg)
#performer_obj.scale /= (perf_avg / end_avg)
factor = end_rad / perf_rad * 1.2
performer_obj.scale *= factor
def guessMapping(performer_obj, enduser_obj):
perf_bones = performer_obj.data.bones
end_bones = enduser_obj.data.bones
root = perf_bones[0]
def findBoneSide(bone):
if "Left" in bone:
return "Left", bone.replace("Left", "").lower().replace(".", "")
if "Right" in bone:
return "Right", bone.replace("Right", "").lower().replace(".", "")
if "L" in bone:
return "Left", bone.replace("Left", "").lower().replace(".", "")
if "R" in bone:
return "Right", bone.replace("Right", "").lower().replace(".", "")
return "", bone
def nameMatch(bone_a, bone_b):
# nameMatch - recieves two strings, returns 2 if they are relatively the same, 1 if they are the same but R and L and 0 if no match at all
side_a, noside_a = findBoneSide(bone_a)
side_b, noside_b = findBoneSide(bone_b)
if side_a == side_b:
if noside_a in noside_b or noside_b in noside_a:
return 2
else:
if noside_a in noside_b or noside_b in noside_a:
return 1
return 0
def guessSingleMapping(perf_bone):
possible_bones = [end_bones[0]]
while possible_bones:
for end_bone in possible_bones:
match = nameMatch(perf_bone.name, end_bone.name)
if match == 2 and not perf_bone.map:
perf_bone.map = end_bone.name
newPossibleBones = []
for end_bone in possible_bones:
newPossibleBones += list(end_bone.children)
possible_bones = newPossibleBones
for child in perf_bone.children:
guessSingleMapping(child)
guessSingleMapping(root)

@ -143,7 +143,7 @@ def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene
for t in range(s_frame, e_frame):
if (t - s_frame) % 10 == 0:
print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame))
print("First pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame))
scene.frame_set(t)
for bone in inter_bones:
retargetPerfToInter(bone)
@ -202,7 +202,7 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene):
for t in range(s_frame, e_frame):
if (t - s_frame) % 10 == 0:
print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame))
print("Second pass: retargeting frame {0}/{1}".format(t, e_frame - s_frame))
scene.frame_set(t)
end_bone = end_bones[root]
end_bone.location = Vector((0, 0, 0))

@ -196,16 +196,17 @@ class MocapPanel(bpy.types.Panel):
row2.operator("mocap.looper", text='Loop animation')
row2.operator("mocap.limitdof", text='Constrain Rig')
self.layout.label("Retargeting")
row3 = self.layout.row(align=True)
column1 = row3.column(align=True)
column1.label("Performer Rig")
column2 = row3.column(align=True)
column2.label("Enduser Rig")
enduser_obj = bpy.context.active_object
performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj]
if enduser_obj is None or len(performer_obj) != 1:
self.layout.label("Select performer rig and target rig (as active)")
else:
self.layout.operator("mocap.guessmapping", text="Guess Hiearchy Mapping")
row3 = self.layout.row(align=True)
column1 = row3.column(align=True)
column1.label("Performer Rig")
column2 = row3.column(align=True)
column2.label("Enduser Rig")
performer_obj = performer_obj[0]
if performer_obj.data and enduser_obj.data:
if performer_obj.data.name in bpy.data.armatures and enduser_obj.data.name in bpy.data.armatures:
@ -532,6 +533,28 @@ class OBJECT_OT_UnbakeMocapConstraints(bpy.types.Operator):
return isinstance(context.active_object.data, bpy.types.Armature)
class OBJECT_OT_GuessHierachyMapping(bpy.types.Operator):
'''Attemps to auto figure out hierarchy mapping'''
bl_idname = "mocap.guessmapping"
bl_label = "Attemps to auto figure out hierarchy mapping"
def execute(self, context):
enduser_obj = bpy.context.active_object
performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0]
mocap_tools.guessMapping(performer_obj, enduser_obj)
return {"FINISHED"}
@classmethod
def poll(cls, context):
if context.active_object:
activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature)
performer_obj = [obj for obj in context.selected_objects if obj != context.active_object]
if performer_obj:
return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature)
else:
return False
def register():
bpy.utils.register_module(__name__)