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()
|