Two new operators for easier retargeting: Auto scale performer, and a first attempt...
authorBenjy Cook <benjycook@hotmail.com>
Wed, 20 Jul 2011 21:03:06 +0000 (21:03 +0000)
committerBenjy Cook <benjycook@hotmail.com>
Wed, 20 Jul 2011 21:03:06 +0000 (21:03 +0000)
release/scripts/modules/mocap_tools.py
release/scripts/modules/retarget.py
release/scripts/startup/ui_mocap.py

index 1ce76dfbe6f99646855bae0db087a4c52f940859..ed945d4525176c95c6cfca9155c73dae0ff781f3 100644 (file)
@@ -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)
index d05fd71f8ce87893eb9458ae52379d5c98f31c37..f4ab6498e114a65fd9339c0d5096ae4572686161 100644 (file)
@@ -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))
index fe5ae72f2808f11bb0eff920023b048dbdf915ba..eabb003bdb900cd16bb06521a6c1b2695b2d7d00 100644 (file)
@@ -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__)