Skip to content

Commit b791dff

Browse files
committed
super_finger & simple_tentacle: auto roll adjustment
1 parent 24912f1 commit b791dff

File tree

2 files changed

+124
-73
lines changed

2 files changed

+124
-73
lines changed

rigs/limbs/simple_tentacle.py

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import bpy
22
from ...utils import copy_bone
33
from ...utils import strip_org, make_deformer_name, connected_children_names
4-
from ...utils import make_mechanism_name, put_bone, create_sphere_widget
5-
from ...utils import create_widget, create_circle_widget
4+
from ...utils import put_bone, create_sphere_widget
5+
from ...utils import create_circle_widget, align_bone_x_axis
66
from ...utils import MetarigError
7-
from rna_prop_ui import rna_idprop_ui_prop_get
87

98

109
class Rig:
@@ -26,25 +25,46 @@ def __init__(self, obj, bone_name, params):
2625
"RIGIFY ERROR: invalid rig structure on bone: %s" % (strip_org(bone_name))
2726
)
2827

28+
def orient_org_bones(self):
29+
30+
bpy.ops.object.mode_set(mode='EDIT')
31+
eb = self.obj.data.edit_bones
32+
33+
if self.params.roll_alignment == "automatic":
34+
35+
first_bone = eb[self.org_bones[0]]
36+
last_bone = eb[self.org_bones[-1]]
37+
38+
# Orient uarm farm bones
39+
chain_y_axis = last_bone.tail - first_bone.head
40+
chain_rot_axis = first_bone.y_axis.cross(chain_y_axis) # ik-plane normal axis (rotation)
41+
if chain_rot_axis.length < first_bone.length/100:
42+
chain_rot_axis = first_bone.x_axis.normalized()
43+
else:
44+
chain_rot_axis = chain_rot_axis.normalized()
45+
46+
for bone in self.org_bones:
47+
align_bone_x_axis(self.obj, bone, chain_rot_axis)
48+
2949
def make_controls(self):
3050

31-
bpy.ops.object.mode_set(mode ='EDIT')
51+
bpy.ops.object.mode_set(mode='EDIT')
3252
org_bones = self.org_bones
3353

3454
ctrl_chain = []
35-
for i in range( len( org_bones ) ):
55+
for i in range(len(org_bones)):
3656
name = org_bones[i]
3757

38-
ctrl_bone = copy_bone(
58+
ctrl_bone = copy_bone(
3959
self.obj,
4060
name,
4161
strip_org(name)
4262
)
4363

44-
ctrl_chain.append( ctrl_bone )
64+
ctrl_chain.append(ctrl_bone)
4565

4666
# Make widgets
47-
bpy.ops.object.mode_set(mode ='OBJECT')
67+
bpy.ops.object.mode_set(mode='OBJECT')
4868

4969
for ctrl in ctrl_chain:
5070
create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
@@ -58,8 +78,8 @@ def make_tweaks(self):
5878
org_bones = self.org_bones
5979

6080
tweak_chain = []
61-
for i in range( len( org_bones ) + 1 ):
62-
if i == len( org_bones ):
81+
for i in range(len(org_bones) + 1):
82+
if i == len(org_bones):
6383
# Make final tweak at the tip of the tentacle
6484
name = org_bones[i-1]
6585
else:
@@ -71,32 +91,32 @@ def make_tweaks(self):
7191
"tweak_" + strip_org(name)
7292
)
7393

74-
tweak_e = eb[ tweak_bone ]
94+
tweak_e = eb[tweak_bone]
7595

76-
tweak_e.length /= 2 # Set size to half
96+
tweak_e.length /= 2 # Set size to half
7797

7898
if i == len( org_bones ):
7999
# Position final tweak at the tip
80-
put_bone( self.obj, tweak_bone, eb[ org_bones[-1]].tail )
100+
put_bone(self.obj, tweak_bone, eb[org_bones[-1]].tail)
81101

82-
tweak_chain.append( tweak_bone )
102+
tweak_chain.append(tweak_bone)
83103

84104
# Make widgets
85-
bpy.ops.object.mode_set(mode = 'OBJECT')
105+
bpy.ops.object.mode_set(mode='OBJECT')
86106

87107
for tweak in tweak_chain:
88-
create_sphere_widget( self.obj, tweak )
108+
create_sphere_widget(self.obj, tweak)
89109

90-
tweak_pb = self.obj.pose.bones[ tweak ]
110+
tweak_pb = self.obj.pose.bones[tweak]
91111

92112
# Set locks
93-
if tweak_chain.index( tweak ) != len( tweak_chain ) - 1:
113+
if tweak_chain.index(tweak) != len(tweak_chain) - 1:
94114
tweak_pb.lock_rotation = (True, False, True)
95-
tweak_pb.lock_scale = (False, True, False)
115+
tweak_pb.lock_scale = (False, True, False)
96116
else:
97117
tweak_pb.lock_rotation_w = True
98-
tweak_pb.lock_rotation = (True, True, True)
99-
tweak_pb.lock_scale = (True, True, True)
118+
tweak_pb.lock_rotation = (True, True, True)
119+
tweak_pb.lock_scale = (True, True, True)
100120

101121
# Set up tweak bone layers
102122
if self.tweak_layers:
@@ -106,79 +126,78 @@ def make_tweaks(self):
106126

107127
def make_deform(self):
108128

109-
bpy.ops.object.mode_set(mode ='EDIT')
129+
bpy.ops.object.mode_set(mode='EDIT')
110130
org_bones = self.org_bones
111131

112132
def_chain = []
113-
for i in range( len( org_bones ) ):
133+
for i in range(len(org_bones)):
114134
name = org_bones[i]
115135

116-
def_bone = copy_bone(
136+
def_bone = copy_bone(
117137
self.obj,
118138
name,
119139
make_deformer_name(strip_org(name))
120140
)
121141

122-
def_chain.append( def_bone )
142+
def_chain.append(def_bone)
123143

124144
return def_chain
125145

126146
def parent_bones(self, all_bones):
127147

128-
bpy.ops.object.mode_set(mode ='EDIT')
148+
bpy.ops.object.mode_set(mode='EDIT')
129149
org_bones = self.org_bones
130-
eb = self.obj.data.edit_bones
150+
eb = self.obj.data.edit_bones
131151

132152
# Parent control bones
133153
for bone in all_bones['control'][1:]:
134-
previous_index = all_bones['control'].index( bone ) - 1
135-
eb[ bone ].parent = eb[ all_bones['control'][previous_index] ]
154+
previous_index = all_bones['control'].index(bone) - 1
155+
eb[bone].parent = eb[all_bones['control'][previous_index]]
136156

137157
# Parent tweak bones
138158
tweaks = all_bones['tweak']
139159
for tweak in all_bones['tweak']:
140160
parent = ''
141-
if tweaks.index( tweak ) == len( tweaks ) - 1:
142-
parent = all_bones['control'][ -1 ]
161+
if tweaks.index(tweak) == len(tweaks) - 1:
162+
parent = all_bones['control'][-1]
143163
else:
144-
parent = all_bones['control'][ tweaks.index( tweak ) ]
164+
parent = all_bones['control'][tweaks.index(tweak)]
145165

146-
eb[ tweak ].parent = eb[ parent ]
166+
eb[tweak].parent = eb[parent]
147167

148168
# Parent deform bones
149169
for bone in all_bones['deform'][1:]:
150-
previous_index = all_bones['deform'].index( bone ) - 1
170+
previous_index = all_bones['deform'].index(bone) - 1
151171

152-
eb[ bone ].parent = eb[ all_bones['deform'][previous_index] ]
153-
eb[ bone ].use_connect = True
172+
eb[bone].parent = eb[all_bones['deform'][previous_index]]
173+
eb[bone].use_connect = True
154174

155175
# Parent org bones ( to tweaks by default, or to the controls )
156-
for org, tweak in zip( org_bones, all_bones['tweak'] ):
157-
eb[ org ].parent = eb[ tweak ]
176+
for org, tweak in zip(org_bones, all_bones['tweak']):
177+
eb[org].parent = eb[tweak]
158178

159179
def make_constraints(self, all_bones):
160180

161-
bpy.ops.object.mode_set(mode ='OBJECT')
162-
org_bones = self.org_bones
163-
pb = self.obj.pose.bones
181+
bpy.ops.object.mode_set(mode='OBJECT')
182+
pb = self.obj.pose.bones
164183

165184
# Deform bones' constraints
166-
ctrls = all_bones['control']
167-
tweaks = all_bones['tweak' ]
168-
deforms = all_bones['deform' ]
185+
ctrls = all_bones['control']
186+
tweaks = all_bones['tweak']
187+
deforms = all_bones['deform']
169188

170189
for deform, tweak, ctrl in zip( deforms, tweaks, ctrls ):
171-
con = pb[deform].constraints.new('COPY_TRANSFORMS')
172-
con.target = self.obj
190+
con = pb[deform].constraints.new('COPY_TRANSFORMS')
191+
con.target = self.obj
173192
con.subtarget = tweak
174193

175-
con = pb[deform].constraints.new('DAMPED_TRACK')
176-
con.target = self.obj
177-
con.subtarget = tweaks[ tweaks.index( tweak ) + 1 ]
194+
con = pb[deform].constraints.new('DAMPED_TRACK')
195+
con.target = self.obj
196+
con.subtarget = tweaks[tweaks.index(tweak) + 1]
178197

179-
con = pb[deform].constraints.new('STRETCH_TO')
180-
con.target = self.obj
181-
con.subtarget = tweaks[ tweaks.index( tweak ) + 1 ]
198+
con = pb[deform].constraints.new('STRETCH_TO')
199+
con.target = self.obj
200+
con.subtarget = tweaks[tweaks.index(tweak) + 1]
182201

183202
# Control bones' constraints
184203
if ctrl != ctrls[0]:
@@ -195,23 +214,25 @@ def make_constraints(self, all_bones):
195214
con.owner_space = 'LOCAL'
196215

197216
def generate(self):
198-
bpy.ops.object.mode_set(mode ='EDIT')
217+
bpy.ops.object.mode_set(mode='EDIT')
199218
eb = self.obj.data.edit_bones
200219

220+
self.orient_org_bones()
221+
201222
# Clear all initial parenting
202223
for bone in self.org_bones:
203-
# eb[ bone ].parent = None
204-
eb[ bone ].use_connect = False
224+
# eb[ bone ].parent = None
225+
eb[bone].use_connect = False
205226

206227
# Creating all bones
207-
ctrl_chain = self.make_controls()
228+
ctrl_chain = self.make_controls()
208229
tweak_chain = self.make_tweaks()
209-
def_chain = self.make_deform()
230+
def_chain = self.make_deform()
210231

211232
all_bones = {
212-
'control' : ctrl_chain,
213-
'tweak' : tweak_chain,
214-
'deform' : def_chain
233+
'control': ctrl_chain,
234+
'tweak': tweak_chain,
235+
'deform': def_chain
215236
}
216237

217238
self.make_constraints(all_bones)
@@ -230,25 +251,29 @@ def add_parameters(params):
230251

231252
# Setting up extra tweak layers
232253
params.tweak_extra_layers = bpy.props.BoolProperty(
233-
name = "tweak_extra_layers",
234-
default = True,
235-
description = ""
254+
name="tweak_extra_layers",
255+
default=True,
256+
description=""
236257
)
237258

238259
params.tweak_layers = bpy.props.BoolVectorProperty(
239-
size = 32,
240-
description = "Layers for the tweak controls to be on",
241-
default = tuple( [ i == 1 for i in range(0, 32) ] )
260+
size=32,
261+
description="Layers for the tweak controls to be on",
262+
default=tuple([i == 1 for i in range(0, 32)])
242263
)
243264

265+
items = [('automatic', 'Automatic', ''), ('manual', 'Manual', '')]
266+
params.roll_alignment = bpy.props.EnumProperty(items=items, name="Bone roll alignment", default='automatic')
267+
244268

245269
def parameters_ui(layout, params):
246270
""" Create the ui for the rig parameters.
247271
"""
248272

249273
r = layout.row()
250-
col = r.column(align=True)
251-
row = col.row(align=True)
274+
r.prop(params, "roll_alignment")
275+
276+
row = layout.row(align=True)
252277
for i, axis in enumerate(['x', 'y', 'z']):
253278
row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis)
254279

@@ -286,7 +311,7 @@ def parameters_ui(layout, params):
286311

287312
row = col.row(align=True)
288313

289-
for i in range( 24, 32 ): # Layers 24-31
314+
for i in range(24, 32): # Layers 24-31
290315
icon = "NONE"
291316
if bone_layers[i]:
292317
icon = "LAYER_ACTIVE"

rigs/limbs/super_finger.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ...utils import copy_bone, flip_bone
33
from ...utils import strip_org, make_deformer_name, connected_children_names, make_mechanism_name
44
from ...utils import create_circle_widget, create_widget
5-
from ...utils import MetarigError
5+
from ...utils import MetarigError, align_bone_x_axis
66
from rna_prop_ui import rna_idprop_ui_prop_get
77

88
script = """
@@ -23,20 +23,43 @@ def __init__(self, obj, bone_name, params):
2323
if len(self.org_bones) <= 1:
2424
raise MetarigError("RIGIFY ERROR: Bone '%s': listen bro, that finger rig jusaint put tugetha rite. A little hint, use more than one bone!!" % (strip_org(bone_name)))
2525

26+
def orient_org_bones(self):
27+
28+
bpy.ops.object.mode_set(mode='EDIT')
29+
eb = self.obj.data.edit_bones
30+
31+
if self.params.primary_rotation_axis == 'automatic':
32+
33+
first_bone = eb[self.org_bones[0]]
34+
last_bone = eb[self.org_bones[-1]]
35+
36+
# Orient uarm farm bones
37+
chain_y_axis = last_bone.tail - first_bone.head
38+
chain_rot_axis = first_bone.y_axis.cross(chain_y_axis) # ik-plane normal axis (rotation)
39+
if chain_rot_axis.length < first_bone.length/100:
40+
chain_rot_axis = first_bone.x_axis.normalized()
41+
else:
42+
chain_rot_axis = chain_rot_axis.normalized()
43+
44+
for bone in self.org_bones:
45+
align_bone_x_axis(self.obj, bone, chain_rot_axis)
46+
2647
def generate(self):
2748
org_bones = self.org_bones
2849

2950
bpy.ops.object.mode_set(mode='EDIT')
3051
eb = self.obj.data.edit_bones
3152

53+
self.orient_org_bones()
54+
3255
# Bone name lists
3356
ctrl_chain = []
3457
def_chain = []
3558
mch_chain = []
3659
mch_drv_chain = []
3760

3861
# Create ctrl master bone
39-
org_name = self.org_bones[0]
62+
org_name = self.org_bones[0]
4063
temp_name = strip_org(self.org_bones[0])
4164

4265
if temp_name[-2:] == '.L' or temp_name[-2:] == '.R':
@@ -222,6 +245,8 @@ def generate(self):
222245
else:
223246
# Match axis to expression
224247
options = {
248+
"automatic": {"axis": 0,
249+
"expr": '(1-sy)*pi'},
225250
"X": {"axis": 0,
226251
"expr": '(1-sy)*pi'},
227252
"-X": {"axis": 0,
@@ -302,8 +327,9 @@ def add_parameters(params):
302327
""" Add the parameters of this rig type to the
303328
RigifyParameters PropertyGroup
304329
"""
305-
items = [('X', 'X', ''), ('Y', 'Y', ''), ('Z', 'Z', ''), ('-X', '-X', ''), ('-Y', '-Y', ''), ('-Z', '-Z', '')]
306-
params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='X')
330+
items = [('automatic', 'Automatic', ''), ('X', 'X manual', ''), ('Y', 'Y manual', ''), ('Z', 'Z manual', ''),
331+
('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')]
332+
params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic')
307333

308334

309335
def parameters_ui(layout, params):

0 commit comments

Comments
 (0)