Skip to content

Commit 772337b

Browse files
committed
feat: experimental bendy_face
1 parent cafd248 commit 772337b

File tree

1 file changed

+130
-6
lines changed

1 file changed

+130
-6
lines changed

rigs/experimental/bendy_face.py

Lines changed: 130 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
class Rig:
1212

1313
CTRL_SCALE = 0.1
14+
MCH_SCALE = 0.3
1415

1516
def __init__(self, obj, bone_name, params):
1617
self.obj = obj
@@ -26,19 +27,45 @@ def __init__(self, obj, bone_name, params):
2627
for child in edit_bone.children_recursive:
2728
self.bones['org'].remove(child.name)
2829

30+
self.start_bones = self.get_start_bones()
2931
self.bones['ctrl'] = dict()
32+
self.bones['mch'] = dict()
33+
self.bones['def'] = dict()
3034

31-
def create_controls(self):
35+
def create_mch(self):
3236
bpy.ops.object.mode_set(mode='EDIT')
3337
edit_bones = self.obj.data.edit_bones
3438

35-
start_bones = []
39+
for name in self.start_bones:
40+
subchain = [name]
41+
subchain.extend(connected_children_names(self.obj, name))
42+
self.bones['mch'][strip_org(name)] = []
3643

37-
for name in self.bones['org'][1:]:
38-
if not edit_bones[name].use_connect:
39-
start_bones.append(name)
44+
for subname in subchain:
45+
mch = copy_bone(self.obj, subname, assign_name=make_mechanism_name(strip_org(subname)))
46+
edit_bones[mch].parent = None
47+
edit_bones[mch].length *= self.MCH_SCALE
48+
self.bones['mch'][strip_org(name)].append(mch)
49+
50+
def create_def(self):
51+
bpy.ops.object.mode_set(mode='EDIT')
52+
edit_bones = self.obj.data.edit_bones
4053

41-
for name in start_bones:
54+
for name in self.start_bones:
55+
subchain = [name]
56+
subchain.extend(connected_children_names(self.obj, name))
57+
self.bones['def'][strip_org(name)] = []
58+
59+
for subname in subchain:
60+
def_bone = copy_bone(self.obj, subname, assign_name=make_deformer_name(strip_org(subname)))
61+
edit_bones[def_bone].parent = None
62+
self.bones['def'][strip_org(name)].append(def_bone)
63+
64+
def create_controls(self):
65+
bpy.ops.object.mode_set(mode='EDIT')
66+
edit_bones = self.obj.data.edit_bones
67+
68+
for name in self.start_bones:
4269
subchain = [name]
4370
subchain.extend(connected_children_names(self.obj, name))
4471
self.bones['ctrl'][strip_org(name)] = []
@@ -55,13 +82,110 @@ def create_controls(self):
5582
edit_bones[last_ctrl].length *= self.CTRL_SCALE
5683
self.bones['ctrl'][strip_org(name)].append(last_ctrl)
5784

85+
self.aggregate_ctrls()
86+
5887
bpy.ops.object.mode_set(mode='OBJECT')
5988
for subchain in self.bones['ctrl']:
6089
for ctrl in self.bones['ctrl'][subchain]:
6190
create_sphere_widget(self.obj, ctrl)
6291

92+
def aggregate_ctrls(self):
93+
bpy.ops.object.mode_set(mode='EDIT')
94+
edit_bones = self.obj.data.edit_bones
95+
96+
aggregates = []
97+
98+
all_ctrls = []
99+
100+
for subchain in self.start_bones:
101+
for ctrl in self.bones['ctrl'][strip_org(subchain)]:
102+
all_ctrls.append(ctrl)
103+
104+
while 1:
105+
ctrl = all_ctrls[0]
106+
aggregate = [ctrl]
107+
for ctrl2 in all_ctrls[1:]:
108+
if edit_bones[ctrl].head == edit_bones[ctrl2].head:
109+
aggregate.append(ctrl2)
110+
for element in aggregate:
111+
all_ctrls.remove(element)
112+
if len(aggregate) > 1:
113+
aggregates.append(aggregate)
114+
if not all_ctrls:
115+
break
116+
117+
if aggregates:
118+
self.bones['ctrl']['aggregate'] = []
119+
120+
for aggregate in aggregates:
121+
name = self.get_aggregate_name(aggregate)
122+
aggregate_ctrl = copy_bone(self.obj, aggregate[0], name)
123+
self.bones['ctrl']['aggregate'].append(aggregate_ctrl)
124+
for ctrl in aggregate:
125+
edit_bones.remove(edit_bones[ctrl])
126+
for subchain in self.start_bones:
127+
if ctrl in self.bones['ctrl'][strip_org(subchain)]:
128+
self.bones['ctrl'][strip_org(subchain)].remove(ctrl)
129+
continue
130+
131+
return True
132+
133+
def get_aggregate_name(self, aggregate):
134+
135+
total = '.'.join(aggregate)
136+
137+
root = aggregate[0].split('.')[0]
138+
for name in aggregate[1:]:
139+
if name.split('.')[0] not in root:
140+
root = '.'.join([root, name.split('.')[0]])
141+
142+
name = root
143+
144+
t_b = ''
145+
if 'T' in total and 'B' in total:
146+
t_b = ''
147+
elif 'T' in total:
148+
t_b = 'T'
149+
elif 'B' in total:
150+
t_b = 'B'
151+
152+
if t_b:
153+
name = '.'.join([name, t_b])
154+
155+
l_r = ''
156+
if 'L' in total and 'R' in total:
157+
l_r = ''
158+
elif 'L' in total:
159+
l_r = 'L'
160+
elif 'R' in total:
161+
l_r = 'R'
162+
163+
if l_r:
164+
name = '.'.join([name, l_r])
165+
166+
return name
167+
168+
def get_start_bones(self):
169+
"""
170+
Returns all the bones starting a subchain of the face
171+
:return:
172+
"""
173+
174+
bpy.ops.object.mode_set(mode='EDIT')
175+
edit_bones = self.obj.data.edit_bones
176+
177+
start_bones = []
178+
179+
for name in self.bones['org'][1:]:
180+
if not edit_bones[name].use_connect:
181+
start_bones.append(name)
182+
183+
return start_bones
184+
63185
def generate(self):
64186

187+
self.create_mch()
188+
self.create_def()
65189
self.create_controls()
66190

67191
return [""]

0 commit comments

Comments
 (0)