|
1 |
| -import bpy, re |
2 |
| -from mathutils import Vector |
3 |
| -from ...utils import copy_bone, flip_bone, put_bone |
4 |
| -from ...utils import org, strip_org, strip_def, make_deformer_name, connected_children_names, make_mechanism_name |
5 |
| -from ...utils import create_circle_widget, create_sphere_widget, create_widget, create_cube_widget |
6 |
| -from ...utils import MetarigError |
7 |
| -from rna_prop_ui import rna_idprop_ui_prop_get |
8 |
| -from ..widgets import create_face_widget, create_eye_widget, create_eyes_widget, create_ear_widget, create_jaw_widget, create_teeth_widget |
| 1 | +import bpy |
| 2 | +import re |
| 3 | +from mathutils import Vector |
| 4 | +from ...utils import copy_bone, flip_bone, put_bone |
| 5 | +from ...utils import org, strip_org, strip_def, make_deformer_name, connected_children_names, make_mechanism_name |
| 6 | +from ...utils import create_circle_widget, create_sphere_widget, create_widget, create_cube_widget |
| 7 | +from ...utils import MetarigError |
| 8 | +from ...utils import make_constraints_from_string |
| 9 | +from rna_prop_ui import rna_idprop_ui_prop_get |
| 10 | +from ..widgets import create_face_widget, create_eye_widget, create_eyes_widget, create_ear_widget, create_jaw_widget, create_teeth_widget |
| 11 | +from .bendy_rig import BendyRig |
9 | 12 |
|
10 | 13 |
|
11 |
| -class Rig: |
12 |
| - |
13 |
| - CTRL_SCALE = 0.1 |
14 |
| - MCH_SCALE = 0.3 |
15 |
| - |
16 |
| - POSITION_RELATIVE_ERROR = 1e-3 # error below which two positions are considered equal (relative to bone len) |
| 14 | +class Rig(BendyRig): |
17 | 15 |
|
18 | 16 | def __init__(self, obj, bone_name, params):
|
19 |
| - self.obj = obj |
20 |
| - self.bones = dict() |
21 |
| - self.bones['org'] = [bone_name] |
22 |
| - |
23 |
| - for edit_bone in self.obj.data.edit_bones[bone_name].children_recursive: |
24 |
| - self.bones['org'].append(edit_bone.name) |
25 |
| - |
26 |
| - for edit_bone in self.obj.data.edit_bones[bone_name].children_recursive: |
27 |
| - if self.obj.pose.bones[edit_bone.name].rigify_type != "": |
28 |
| - self.bones['org'].remove(edit_bone.name) |
29 |
| - for child in edit_bone.children_recursive: |
30 |
| - self.bones['org'].remove(child.name) |
31 |
| - |
32 |
| - self.start_bones = self.get_start_bones() |
33 |
| - self.bones['ctrl'] = dict() |
34 |
| - self.bones['mch'] = dict() |
35 |
| - self.bones['def'] = dict() |
36 |
| - |
37 |
| - def create_mch(self): |
38 |
| - bpy.ops.object.mode_set(mode='EDIT') |
39 |
| - edit_bones = self.obj.data.edit_bones |
40 |
| - |
41 |
| - for name in self.start_bones: |
42 |
| - subchain = [name] |
43 |
| - subchain.extend(connected_children_names(self.obj, name)) |
44 |
| - self.bones['mch'][strip_org(name)] = [] |
45 |
| - |
46 |
| - for subname in subchain: |
47 |
| - mch = copy_bone(self.obj, subname, assign_name=make_mechanism_name(strip_org(subname))) |
48 |
| - edit_bones[mch].parent = None |
49 |
| - edit_bones[mch].length *= self.MCH_SCALE |
50 |
| - self.bones['mch'][strip_org(name)].append(mch) |
51 |
| - |
52 |
| - def create_def(self): |
53 |
| - bpy.ops.object.mode_set(mode='EDIT') |
54 |
| - edit_bones = self.obj.data.edit_bones |
55 |
| - |
56 |
| - for name in self.start_bones: |
57 |
| - subchain = [name] |
58 |
| - subchain.extend(connected_children_names(self.obj, name)) |
59 |
| - self.bones['def'][strip_org(name)] = [] |
60 |
| - |
61 |
| - for subname in subchain: |
62 |
| - def_bone = copy_bone(self.obj, subname, assign_name=make_deformer_name(strip_org(subname))) |
63 |
| - edit_bones[def_bone].parent = None |
64 |
| - self.bones['def'][strip_org(name)].append(def_bone) |
65 |
| - |
66 |
| - def create_controls(self): |
67 |
| - bpy.ops.object.mode_set(mode='EDIT') |
68 |
| - edit_bones = self.obj.data.edit_bones |
69 |
| - |
70 |
| - for name in self.start_bones: |
71 |
| - subchain = [name] |
72 |
| - subchain.extend(connected_children_names(self.obj, name)) |
73 |
| - self.bones['ctrl'][strip_org(name)] = [] |
74 |
| - |
75 |
| - for subname in subchain: |
76 |
| - ctrl = copy_bone(self.obj, self.bones['org'][0], assign_name=strip_org(subname)) |
77 |
| - put_bone(self.obj, ctrl, edit_bones[subname].head) |
78 |
| - edit_bones[ctrl].length *= self.CTRL_SCALE |
79 |
| - self.bones['ctrl'][strip_org(name)].append(ctrl) |
80 |
| - |
81 |
| - last_name = subchain[-1] |
82 |
| - last_ctrl = copy_bone(self.obj, self.bones['org'][0], assign_name=strip_org(last_name)) |
83 |
| - put_bone(self.obj, last_ctrl, edit_bones[last_name].tail) |
84 |
| - edit_bones[last_ctrl].length *= self.CTRL_SCALE |
85 |
| - self.bones['ctrl'][strip_org(name)].append(last_ctrl) |
86 |
| - |
87 |
| - self.aggregate_ctrls() |
88 |
| - |
89 |
| - bpy.ops.object.mode_set(mode='OBJECT') |
90 |
| - for subchain in self.bones['ctrl']: |
91 |
| - for ctrl in self.bones['ctrl'][subchain]: |
92 |
| - create_sphere_widget(self.obj, ctrl) |
93 |
| - |
94 |
| - def aggregate_ctrls(self): |
95 |
| - bpy.ops.object.mode_set(mode='EDIT') |
96 |
| - edit_bones = self.obj.data.edit_bones |
97 |
| - |
98 |
| - aggregates = [] |
99 |
| - |
100 |
| - all_ctrls = [] |
101 |
| - |
102 |
| - for subchain in self.start_bones: |
103 |
| - for ctrl in self.bones['ctrl'][strip_org(subchain)]: |
104 |
| - all_ctrls.append(ctrl) |
105 |
| - |
106 |
| - while 1: |
107 |
| - ctrl = all_ctrls[0] |
108 |
| - aggregate = [ctrl] |
109 |
| - for ctrl2 in all_ctrls[1:]: |
110 |
| - if edit_bones[ctrl].head == edit_bones[ctrl2].head: |
111 |
| - aggregate.append(ctrl2) |
112 |
| - for element in aggregate: |
113 |
| - all_ctrls.remove(element) |
114 |
| - if len(aggregate) > 1: |
115 |
| - aggregates.append(aggregate) |
116 |
| - if not all_ctrls: |
117 |
| - break |
118 |
| - |
119 |
| - if aggregates: |
120 |
| - self.bones['ctrl']['aggregate'] = [] |
121 |
| - |
122 |
| - for aggregate in aggregates: |
123 |
| - name = self.get_aggregate_name(aggregate) |
124 |
| - aggregate_ctrl = copy_bone(self.obj, aggregate[0], name) |
125 |
| - self.bones['ctrl']['aggregate'].append(aggregate_ctrl) |
126 |
| - for ctrl in aggregate: |
127 |
| - edit_bones.remove(edit_bones[ctrl]) |
128 |
| - for subchain in self.start_bones: |
129 |
| - if ctrl in self.bones['ctrl'][strip_org(subchain)]: |
130 |
| - self.bones['ctrl'][strip_org(subchain)].remove(ctrl) |
131 |
| - continue |
132 |
| - |
133 |
| - return True |
134 |
| - |
135 |
| - def make_constraints(self): |
136 |
| - """ |
137 |
| - Make constraints for each bone subgroup |
138 |
| - :return: |
139 |
| - """ |
140 |
| - |
141 |
| - bpy.ops.object.mode_set(mode='OBJECT') |
142 |
| - pose_bones = self.obj.pose.bones |
143 |
| - |
144 |
| - ### Constrain DEF-bones ### |
145 |
| - for subchain in self.bones['def']: |
146 |
| - for name in self.bones['def'][subchain]: |
147 |
| - owner_pb = pose_bones[name] |
148 |
| - |
149 |
| - subtarget = make_mechanism_name(strip_def(name)) |
150 |
| - const = owner_pb.constraints.new('COPY_LOCATION') |
151 |
| - const.target = self.obj |
152 |
| - const.subtarget = subtarget |
153 |
| - |
154 |
| - tail_subtargets = self.get_ctrls_by_position(owner_pb.bone.tail, subchain=subchain) |
155 |
| - |
156 |
| - if tail_subtargets: |
157 |
| - const = owner_pb.constraints.new('DAMPED_TRACK') |
158 |
| - const.target = self.obj |
159 |
| - const.subtarget = tail_subtargets[0] |
160 |
| - |
161 |
| - const = owner_pb.constraints.new('STRETCH_TO') |
162 |
| - const.target = self.obj |
163 |
| - const.subtarget = tail_subtargets[0] |
164 |
| - |
165 |
| - def parent_bones(self): |
166 |
| - """ |
167 |
| - Specify bone parenting |
168 |
| - :return: |
169 |
| - """ |
170 |
| - |
171 |
| - bpy.ops.object.mode_set(mode='EDIT') |
172 |
| - edit_bones = self.obj.data.edit_bones |
173 |
| - |
174 |
| - ### PARENT MCH-bones ### |
175 |
| - for subchain in self.bones['mch']: |
176 |
| - for name in self.bones['mch'][subchain]: |
177 |
| - mch_bone = edit_bones[name] |
178 |
| - parents = self.get_ctrls_by_position(mch_bone.head, subchain=subchain) |
179 |
| - |
180 |
| - if parents: |
181 |
| - mch_bone.parent = edit_bones[parents[0]] |
182 |
| - |
183 |
| - def get_aggregate_name(self, aggregate): |
184 |
| - |
185 |
| - total = '.'.join(aggregate) |
186 |
| - |
187 |
| - root = aggregate[0].split('.')[0] |
188 |
| - for name in aggregate[1:]: |
189 |
| - if name.split('.')[0] not in root: |
190 |
| - root = '.'.join([root, name.split('.')[0]]) |
191 |
| - |
192 |
| - name = root |
193 |
| - |
194 |
| - t_b = '' |
195 |
| - if 'T' in total and 'B' in total: |
196 |
| - t_b = '' |
197 |
| - elif 'T' in total: |
198 |
| - t_b = 'T' |
199 |
| - elif 'B' in total: |
200 |
| - t_b = 'B' |
201 |
| - |
202 |
| - if t_b: |
203 |
| - name = '.'.join([name, t_b]) |
204 |
| - |
205 |
| - l_r = '' |
206 |
| - if 'L' in total and 'R' in total: |
207 |
| - l_r = '' |
208 |
| - elif 'L' in total: |
209 |
| - l_r = 'L' |
210 |
| - elif 'R' in total: |
211 |
| - l_r = 'R' |
212 |
| - |
213 |
| - if l_r: |
214 |
| - name = '.'.join([name, l_r]) |
215 |
| - |
216 |
| - return name |
217 |
| - |
218 |
| - def get_start_bones(self): |
219 |
| - """ |
220 |
| - Returns all the bones starting a subchain of the face |
221 |
| - :return: |
222 |
| - """ |
223 |
| - |
224 |
| - bpy.ops.object.mode_set(mode='EDIT') |
225 |
| - edit_bones = self.obj.data.edit_bones |
226 |
| - |
227 |
| - start_bones = [] |
228 |
| - |
229 |
| - for name in self.bones['org'][1:]: |
230 |
| - if not edit_bones[name].use_connect: |
231 |
| - start_bones.append(name) |
232 |
| - |
233 |
| - return start_bones |
234 |
| - |
235 |
| - def get_ctrls_by_position(self, position, subchain='', relative_error=0): |
236 |
| - """ |
237 |
| - Returns the controls closest to position in given relative_error range and subchain |
238 |
| - checking subchain first and then aggregates |
239 |
| - :param subchain: |
240 |
| - :type subchain: str |
241 |
| - :param position: |
242 |
| - :type subchain: Vector |
243 |
| - :return: |
244 |
| - :rtype: list(str) |
245 |
| - """ |
246 |
| - |
247 |
| - bpy.ops.object.mode_set(mode='EDIT') |
248 |
| - edit_bones = self.obj.data.edit_bones |
249 |
| - |
250 |
| - bones_in_range = [] |
251 |
| - |
252 |
| - if subchain: |
253 |
| - keys = [subchain] |
254 |
| - if 'aggregate' in self.bones['ctrl']: |
255 |
| - keys.append('aggregate') |
256 |
| - else: |
257 |
| - keys = self.bones['ctrl'].keys() |
258 |
| - |
259 |
| - if not relative_error: |
260 |
| - relative_error = self.POSITION_RELATIVE_ERROR |
261 |
| - |
262 |
| - for chain in keys: |
263 |
| - for name in self.bones['ctrl'][chain]: |
264 |
| - error = edit_bones[name].length * relative_error |
265 |
| - if (edit_bones[name].head - position).magnitude <= error: |
266 |
| - bones_in_range.append(name) |
267 |
| - |
268 |
| - return bones_in_range |
| 17 | + super(Rig, self).__init__(obj, bone_name, params) |
269 | 18 |
|
270 | 19 | def generate(self):
|
271 | 20 |
|
|
0 commit comments