forked from bartvdbraak/blender
Two new operators for easier retargeting: Auto scale performer, and a first attempt at auto hiearchy mapping
This commit is contained in:
parent
2c61949179
commit
a08a510d65
@ -573,7 +573,67 @@ def scale_fix_armature(performer_obj, enduser_obj):
|
|||||||
perf_bones = performer_obj.data.bones
|
perf_bones = performer_obj.data.bones
|
||||||
end_bones = enduser_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
|
#end_avg = enduser_obj.dimensions
|
||||||
#print(perf_avg, end_avg)
|
factor = end_rad / perf_rad * 1.2
|
||||||
#performer_obj.scale /= (perf_avg / end_avg)
|
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):
|
for t in range(s_frame, e_frame):
|
||||||
if (t - s_frame) % 10 == 0:
|
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)
|
scene.frame_set(t)
|
||||||
for bone in inter_bones:
|
for bone in inter_bones:
|
||||||
retargetPerfToInter(bone)
|
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):
|
for t in range(s_frame, e_frame):
|
||||||
if (t - s_frame) % 10 == 0:
|
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)
|
scene.frame_set(t)
|
||||||
end_bone = end_bones[root]
|
end_bone = end_bones[root]
|
||||||
end_bone.location = Vector((0, 0, 0))
|
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.looper", text='Loop animation')
|
||||||
row2.operator("mocap.limitdof", text='Constrain Rig')
|
row2.operator("mocap.limitdof", text='Constrain Rig')
|
||||||
self.layout.label("Retargeting")
|
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
|
enduser_obj = bpy.context.active_object
|
||||||
performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj]
|
performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj]
|
||||||
if enduser_obj is None or len(performer_obj) != 1:
|
if enduser_obj is None or len(performer_obj) != 1:
|
||||||
self.layout.label("Select performer rig and target rig (as active)")
|
self.layout.label("Select performer rig and target rig (as active)")
|
||||||
else:
|
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]
|
performer_obj = performer_obj[0]
|
||||||
if performer_obj.data and enduser_obj.data:
|
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:
|
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)
|
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():
|
def register():
|
||||||
bpy.utils.register_module(__name__)
|
bpy.utils.register_module(__name__)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user