Skip to content

Commit 12312ba

Browse files
committed
feat: BendyRig base class. Glue bone prop
rig_types: bendy_jaw
1 parent cc90d51 commit 12312ba

File tree

5 files changed

+661
-264
lines changed

5 files changed

+661
-264
lines changed

__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ def register():
301301

302302
bpy.types.PoseBone.rigify_type = bpy.props.StringProperty(name="Rigify Type", description="Rig type for this bone")
303303
bpy.types.PoseBone.rigify_parameters = bpy.props.PointerProperty(type=RigifyParameters)
304+
bpy.types.PoseBone.rigify_glue = bpy.props.StringProperty(name="Rigify Glue", description="Defines influence between controls")
304305

305306
bpy.types.Armature.rigify_colors = bpy.props.CollectionProperty(type=RigifyColorSet)
306307

@@ -395,6 +396,7 @@ def update_mode(self, context):
395396
def unregister():
396397
del bpy.types.PoseBone.rigify_type
397398
del bpy.types.PoseBone.rigify_parameters
399+
del bpy.types.PoseBone.rigify_glue
398400

399401
IDStore = bpy.types.WindowManager
400402
del IDStore.rigify_collection

rigs/experimental/bendy_face.py

Lines changed: 13 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -1,271 +1,20 @@
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
912

1013

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):
1715

1816
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)
26918

27019
def generate(self):
27120

0 commit comments

Comments
 (0)