Added calculation to determine change in root translation when retargeting - needs...
authorBenjy Cook <benjycook@hotmail.com>
Fri, 17 Jun 2011 11:47:45 +0000 (11:47 +0000)
committerBenjy Cook <benjycook@hotmail.com>
Fri, 17 Jun 2011 11:47:45 +0000 (11:47 +0000)
release/scripts/modules/retarget.py

index b081191d9a61d2f797506523cb4a8ab15d7ff9bb..b38e47a63ffa9a6b31428ea2cee2808a5da62e25 100644 (file)
@@ -15,27 +15,35 @@ scene = bpy.context.scene
 # dictionary of mapping
 # this is currently manuall input'ed, but will
 # be created from a more comfortable UI in the future
-bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"),
-            "LeftUpLeg": "DEF_Thigh.L",
-            "Hips": "DEF_Hip",
-            "LowerBack": "DEF_Spine",
-            "Spine": "DEF_Torso",
-            "Neck": "DEF_Neck",
-            "Neck1": "DEF_Neck",
-            "Head": "DEF_Head",
-            "LeftShoulder": "DEF_Shoulder.L",
-            "LeftArm": "DEF_Forearm.L",
-            "LeftForeArm": "DEF_Arm.L",
-            "LeftHand": "DEF_Hand.L",
-            "RightShoulder": "DEF_Shoulder.R",
-            "RightArm": "DEF_Forearm.R",
-            "RightForeArm": "DEF_Arm.R",
-            "RightHand": "DEF_Hand.R",
-            "RightFoot": ("DEF_Foot.R","DEF_Toes.R"),
-            "RightUpLeg": "DEF_Thigh.R",
-            "RightLeg": "DEF_Shin.R",
-            "LeftLeg": "DEF_Shin.L"}
+bonemap = { "Head": "Head",
+            "Neck": "Head",
+            "Spine1": "Chest",
+            "Spine2": "Chest",
+            "Spine3": "Chest",
+            "Spine": "Torso",
+            "Hips": "root",
+            "LeftUpLeg": "Thigh.L",
+            "LeftUpLegRoll": "Thigh.L",
+            "LeftLeg": "Shin.L",
+            "LeftLegRoll": "Shin.L",
+            "LeftFoot": "Foot.L",
+            "RightUpLeg": "Thigh.R",
+            "RightUpLegRoll": "Thigh.R",
+            "RightLeg": "Shin.R",
+            "RightLegRoll": "Shin.R",
+            "RightFoot": "Foot.R",
+            "LeftShoulder": "Shoulder.L",
+            "LeftArm": "HiArm.L",
+            "LeftArmRoll": "HiArm.L",
+            "LeftForeArm": "LoArm.L",
+            "LeftForeArmRoll": "LoArm.L",
+            "RightShoulder": "Shoulder.R",
+            "RightArm": "HiArm.R",
+            "RightArmRoll": "HiArm.R",
+            "RightForeArm": "LoArm.R",
+            "RightForeArmRoll": "LoArm.R" }
             
+root = "root"
 # creation of a reverse map
 # multiple keys get mapped to list values
 bonemapr = {}
@@ -76,7 +84,10 @@ def createIntermediate():
             empty.name = perf_bone.name+"Org"
         empty = bpy.data.objects[perf_bone.name+"Org"]
         offset = perf_bone.vector
-        scaling = perf_bone.length / inter_bone.length
+        if inter_bone.length == 0 or perf_bone.length == 0:
+            scaling = 1
+        else:
+            scaling = perf_bone.length / inter_bone.length
         offset/=scaling
         empty.location = inter_bone.head + offset
         empty.keyframe_insert("location")
@@ -147,7 +158,7 @@ def createIntermediate():
         
     for t in range(1,150):
         scene.frame_set(t)
-        inter_bone = inter_bones["DEF_Hip"]
+        inter_bone = inter_bones[root]
         retargetPerfToInter(inter_bone)
         
     return inter_obj,inter_arm
@@ -191,8 +202,73 @@ def retargetEnduser():
         
     for t in range(1,150):
         scene.frame_set(t)
-        end_bone = end_bones["DEF_Hip"]
+        end_bone = end_bones[root]
         bakeTransform(end_bone)
 
+#recieves the performer feet bones as a variable
+# by "feet" I mean those bones that have plants
+# (they don't move, despite root moving) somewhere in the animation.
+def copyTranslation(perfFeet):
+    endFeet = [bonemap[perfBone] for perfBone in perfFeet]
+    perfRoot = bonemapr[root][0]
+    locDictKeys = perfFeet+endFeet+[perfRoot]
+    perf_bones = performer_obj.pose.bones
+    end_bones = enduser_obj.pose.bones
+    
+    def tailLoc(bone):
+        return bone.center+(bone.vector/2)
+    
+    #Step 1 - we create a dict that contains these keys:
+    #(Performer) Hips, Feet
+    #(End user) Feet
+    # where the values are their world position on each (1,120) frame
+    
+    locDict = {}
+    for key in locDictKeys:
+        locDict[key] = []    
+    
+    for t in range(scene.frame_start,scene.frame_end):
+        scene.frame_set(t)
+        for bone in perfFeet:
+            locDict[bone].append(tailLoc(perf_bones[bone]))
+        locDict[perfRoot].append(tailLoc(perf_bones[perfRoot]))
+        for bone in endFeet:
+            locDict[bone].append(tailLoc(end_bones[bone]))
+            
+    # now we take our locDict and analyze it.
+    # we need to derive all chains 
+    
+    locDeriv = {}
+    for key in locDictKeys:
+        locDeriv[key] = []
+    
+    for key in locDict.keys():
+        graph = locDict[key]
+        for t in range(len(graph)-1):
+            x = graph[t]
+            xh = graph[t+1]
+            locDeriv[key].append(xh-x)
+            
+    # now find the plant frames, where perfFeet don't move much
+    
+    linearAvg = []
+    
+    for key in perfFeet:
+        for i in range(len(locDeriv[key])-1):
+            v = locDeriv[key][i]
+            hipV = locDeriv[perfRoot][i]
+            endV = locDeriv[bonemap[key]][i]
+            if (v.length<0.1):
+                #this is a plant frame.
+                #lets see what the original hip delta is, and the corresponding
+                #end bone's delta
+                if endV.length!=0:
+                    linearAvg.append(hipV.length/endV.length)
+    if linearAvg:
+        avg = sum(linearAvg)/len(linearAvg)
+        print("retargeted root motion should be "+ str(1/avg)+ " of original")
+    
+
 inter_obj, inter_arm = createIntermediate()
-retargetEnduser()
\ No newline at end of file
+retargetEnduser()
+copyTranslation(["RightFoot","LeftFoot"])
\ No newline at end of file