-
Notifications
You must be signed in to change notification settings - Fork 0
/
rigutils.py
115 lines (85 loc) · 3.95 KB
/
rigutils.py
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
import bpy
def get_armature_modifier(ob):
return next((mod for mod in ob.modifiers if mod.type == 'ARMATURE'), None)
def copy_weights(ob_list, ob_source, apply_modifier=True):
src_mod = get_armature_modifier(ob_source)
src_mod.show_viewport = False
src_mod.show_render = False
ob_source.hide_viewport = True
ob_source.hide_render = True
for ob in ob_list:
remove_modifiers(ob)
transf = ob.modifiers.new('weight_transf', 'DATA_TRANSFER')
if not transf:
continue
transf.object = ob_source
transf.use_vert_data = True
transf.data_types_verts = {'VGROUP_WEIGHTS'}
transf.vert_mapping = 'POLY_NEAREST'
arm = ob.modifiers.new('Armature', 'ARMATURE')
arm.object = src_mod.object
arm.show_in_editmode = True
arm.show_on_cage = True
bpy.context.view_layer.objects.active = ob
bpy.ops.object.datalayout_transfer(modifier=transf.name)
if apply_modifier:
bpy.ops.object.modifier_apply(modifier=transf.name)
def remove_modifiers(ob, type_list=('DATA_TRANSFER', 'ARMATURE')):
for mod in reversed(ob.modifiers):
if mod.type in type_list:
ob.modifiers.remove(mod)
class ArmatureGenerator(object):
def __init__(self, info, mesh=None):
self._info = info
self._mesh = mesh
def generate(self, matrix=None):
basename = self._mesh.name if self._mesh else ""
arm_data = bpy.data.armatures.new(basename + "_armature")
arm_obj = bpy.data.objects.new('brignet_rig', arm_data)
bpy.context.collection.objects.link(arm_obj)
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='EDIT')
this_level = [self._info.root]
hier_level = 1
while this_level:
next_level = []
for p_node in this_level:
pos = p_node.pos
parent = p_node.parent.name if p_node.parent is not None else None
e_bone = arm_data.edit_bones.new(p_node.name)
if self._mesh and e_bone.name not in self._mesh.vertex_groups:
self._mesh.vertex_groups.new(name=e_bone.name)
e_bone.head.x, e_bone.head.z, e_bone.head.y = pos[0], pos[2], pos[1]
if parent:
e_bone.parent = arm_data.edit_bones[parent]
if e_bone.parent.tail == e_bone.head:
e_bone.use_connect = True
if len(p_node.children) == 1:
pos = p_node.children[0].pos
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
elif len(p_node.children) > 1:
x_offset = [abs(c_node.pos[0] - pos[0]) for c_node in p_node.children]
idx = x_offset.index(min(x_offset))
pos = p_node.children[idx].pos
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
elif e_bone.parent:
offset = e_bone.head - e_bone.parent.head
e_bone.tail = e_bone.head + offset / 2
else:
e_bone.tail.x, e_bone.tail.z, e_bone.tail.y = pos[0], pos[2], pos[1]
e_bone.tail.y += .1
for c_node in p_node.children:
next_level.append(c_node)
this_level = next_level
hier_level += 1
if matrix:
arm_data.transform(matrix)
bpy.ops.object.mode_set(mode='POSE')
if self._mesh:
for v_skin in self._info.joint_skin:
v_idx = int(v_skin.pop(0))
for i in range(0, len(v_skin), 2):
self._mesh.vertex_groups[v_skin[i]].add([v_idx], float(v_skin[i + 1]), 'REPLACE')
arm_obj.matrix_world = self._mesh.matrix_world
mod = self._mesh.modifiers.new('rignet', 'ARMATURE')
mod.object = arm_obj