Welcome to mirror list, hosted at ThFree Co, Russian Federation.

retarget.py « modules « scripts « release - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c7a482659ef6a90a079426ce4977fe23754b729e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import bpy
from mathutils import *
from math import radians, acos
performer_obj = bpy.data.objects["performer"]
enduser_obj = bpy.data.objects["enduser"]
scene = bpy.context.scene

# dictionary of mapping
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"}
# creation of a reverse map
# multiple keys get mapped to list values
bonemapr = {}
for key in bonemap.keys():
    if not bonemap[key] in bonemapr:
        if type(bonemap[key])==type((0,0)):
            for key_x in bonemap[key]:
                bonemapr[key_x] = [key]
        else:
            bonemapr[bonemap[key]] = [key]
    else:
        bonemapr[bonemap[key]].append(key)
        
# list of empties created to keep track of "original"
# position data
# in final product, these locations can be stored as custom props

constraints = []

#creation of intermediate armature
# the intermediate armature has the hiearchy of the end user,
# does not have rotation inheritence
# and bone roll is identical to the performer
# its purpose is to copy over the rotations
# easily while concentrating on the hierarchy changes
def createIntermediate():
    
    #creates and keyframes an empty with its location
    #the original position of the tail bone
    #useful for storing the important data in the original motion
    #i.e. using this empty to IK the chain to that pos.
    def locOfOriginal(inter_bone,perf_bone):
        if not perf_bone.name+"Org" in bpy.data.objects:
            bpy.ops.object.add()
            empty = bpy.context.active_object
            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
        offset/=scaling
        empty.location = inter_bone.head + offset
        empty.keyframe_insert("location")
    
    #Simple 1to1 retarget of a bone
    def singleBoneRetarget(inter_bone,perf_bone):
            perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world         
            inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world
            inter_world_base_inv = Matrix(inter_world_base_rotation)
            inter_world_base_inv.invert()
            return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4()
        
    #uses 1to1 and interpolation/averaging to match many to 1 retarget    
    def manyPerfToSingleInterRetarget(inter_bone,performer_bones_s):
        retarget_matrices = [singleBoneRetarget(inter_bone,perf_bone) for perf_bone in performer_bones_s]
        lerp_matrix = Matrix()
        for i in range(len(retarget_matrices)-1):
            first_mat = retarget_matrices[i]
            next_mat = retarget_matrices[i+1]
            lerp_matrix = first_mat.lerp(next_mat,0.5)
        return lerp_matrix
    
    #determines the type of hierachy change needed and calls the 
    #right function        
    def retargetPerfToInter(inter_bone):
        if inter_bone.name in bonemapr.keys():
            perf_bone_name = bonemapr[inter_bone.name]
            #is it a 1 to many?
            if type(bonemap[perf_bone_name[0]])==type((0,0)):
                perf_bone = performer_bones[perf_bone_name[0]]
                if inter_bone.name == bonemap[perf_bone_name[0]][0]:
                    locOfOriginal(inter_bone,perf_bone)
            else:
                # then its either a many to 1 or 1 to 1
                
                if len(perf_bone_name) > 1:
                    performer_bones_s = [performer_bones[name] for name in perf_bone_name]
                    #we need to map several performance bone to a single
                    inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s)
                else:
                    perf_bone = performer_bones[perf_bone_name[0]]
                    inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone)
                    
        inter_bone.keyframe_insert("rotation_quaternion")
        for child in inter_bone.children:
            retargetPerfToInter(child)
            
    #creates the intermediate armature object        
    bpy.ops.object.select_name(name="enduser",extend=False)
    bpy.ops.object.duplicate(linked=False)
    bpy.context.active_object.name = "intermediate"
    inter_obj = bpy.context.active_object
    bpy.ops.object.mode_set(mode='EDIT')
    #resets roll 
    bpy.ops.armature.calculate_roll(type='Z')
    bpy.ops.object.mode_set(mode="OBJECT")
    performer_bones = performer_obj.pose.bones
    inter_bones =  inter_obj.pose.bones
    
    #clears inheritance
    for inter_bone in inter_bones:
        inter_bone.bone.use_inherit_rotation = False
        
    for t in range(1,150):
        scene.frame_set(t)
        inter_bone = inter_bones["DEF_Hip"]
        retargetPerfToInter(inter_bone)
         
createIntermediate()