Cleanup: quiet float argument to in type warning
[blender-addons.git] / rigify / rigs / limbs / paw.py
blob07cab2c72561f5e53719bed861e49f2dd2b72a0f
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 import bpy
5 from ...utils.bones import compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis
6 from ...utils.bones import align_bone_to_axis, flip_bone
7 from ...utils.naming import make_derived_name
8 from ...utils.widgets_basic import create_circle_widget, create_limb_widget
10 from ..widgets import create_foot_widget, create_ball_socket_widget
12 from ...base_rig import stage
14 from .limb_rigs import BaseLimbRig
17 class Rig(BaseLimbRig):
18 """Paw rig with an optional second heel control."""
20 segmented_orgs = 3
21 min_valid_orgs = 4
22 max_valid_orgs = 5
23 toe_bone_index = 3
25 use_heel2: bool
27 def initialize(self):
28 self.use_heel2 = len(self.bones.org.main) > 4
30 if self.use_heel2:
31 self.toe_bone_index = 4
32 self.fk_name_suffix_cutoff = 3
33 self.fk_ik_layer_cutoff = 4
35 super().initialize()
37 def prepare_bones(self):
38 orgs = self.bones.org.main
40 foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, 1))
42 if self.params.rotation_axis == 'automatic':
43 axis = compute_chain_x_axis(self.obj, orgs[0:2])
45 for bone in orgs:
46 align_bone_x_axis(self.obj, bone, axis)
48 elif self.params.auto_align_extremity:
49 if self.main_axis == 'x':
50 align_bone_x_axis(self.obj, orgs[2], foot_x)
51 align_bone_x_axis(self.obj, orgs[3], -foot_x)
52 else:
53 align_bone_z_axis(self.obj, orgs[2], foot_x)
54 align_bone_z_axis(self.obj, orgs[3], -foot_x)
56 ####################################################
57 # Utilities
59 def align_ik_control_bone(self, name: str):
60 if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
61 align_bone_to_axis(self.obj, name, 'y', flip=True)
63 else:
64 flip_bone(self.obj, name)
66 bone = self.get_bone(name)
67 bone.tail[2] = bone.head[2]
68 bone.roll = 0
70 ####################################################
71 # EXTRA BONES
73 class CtrlBones(BaseLimbRig.CtrlBones):
74 heel: str # Foot heel control
75 heel2: str # Second foot heel control (optional)
77 class MchBones(BaseLimbRig.MchBones):
78 toe_socket: str # IK toe orientation bone
79 ik_heel2: str # Final position of heel2 in the IK output
81 bones: BaseLimbRig.ToplevelBones[
82 BaseLimbRig.OrgBones,
83 'Rig.CtrlBones',
84 'Rig.MchBones',
85 list[str]
88 ####################################################
89 # IK controls
91 def get_middle_ik_controls(self):
92 return [self.bones.ctrl.heel] if self.use_heel2 else []
94 def get_extra_ik_controls(self):
95 extra = [self.bones.ctrl.heel2] if self.use_heel2 else [self.bones.ctrl.heel]
96 return super().get_extra_ik_controls() + extra
98 def make_ik_control_bone(self, orgs: list[str]):
99 return self.make_paw_ik_control_bone(orgs[-2], orgs[-1], orgs[2])
101 def make_paw_ik_control_bone(self, org_one: str, org_two: str, org_name: str):
102 name = self.copy_bone(org_two, make_derived_name(org_name, 'ctrl', '_ik'))
104 self.align_ik_control_bone(name)
106 vec = self.get_bone(org_two).tail - self.get_bone(org_one).head
107 self.get_bone(name).length = self.vector_without_z(vec).length
109 return name
111 def register_switch_parents(self, pbuilder):
112 super().register_switch_parents(pbuilder)
114 pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True, tags={'limb_end'})
116 def make_ik_ctrl_widget(self, ctrl):
117 create_foot_widget(self.obj, ctrl)
119 ####################################################
120 # Heel control
122 @stage.generate_bones
123 def make_heel_control_bone(self):
124 org = self.bones.org.main[2]
125 name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'))
126 self.bones.ctrl.heel = name
128 flip_bone(self.obj, name)
130 @stage.parent_bones
131 def parent_heel_control_bone(self):
132 if self.use_heel2:
133 self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.heel2)
134 else:
135 self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output())
137 @stage.configure_bones
138 def configure_heel_control_bone(self):
139 bone = self.get_bone(self.bones.ctrl.heel)
140 bone.lock_location = True, True, True
142 @stage.generate_widgets
143 def generate_heel_control_widget(self):
144 create_ball_socket_widget(self.obj, self.bones.ctrl.heel)
146 ####################################################
147 # Second Heel control
149 @stage.generate_bones
150 def make_heel2_control_bone(self):
151 if self.use_heel2:
152 org = self.bones.org.main[3]
153 name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik'))
154 self.bones.ctrl.heel2 = name
156 flip_bone(self.obj, name)
158 @stage.parent_bones
159 def parent_heel2_control_bone(self):
160 if self.use_heel2:
161 self.set_bone_parent(self.bones.ctrl.heel2, self.get_ik_control_output())
163 @stage.configure_bones
164 def configure_heel2_control_bone(self):
165 if self.use_heel2:
166 bone = self.get_bone(self.bones.ctrl.heel2)
167 bone.lock_location = True, True, True
169 @stage.generate_widgets
170 def generate_heel2_control_widget(self):
171 if self.use_heel2:
172 create_ball_socket_widget(self.obj, self.bones.ctrl.heel2)
174 ####################################################
175 # FK control chain
177 def make_fk_control_widget(self, i, ctrl):
178 if i < self.toe_bone_index - 1:
179 create_limb_widget(self.obj, ctrl)
180 elif i == self.toe_bone_index - 1:
181 create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.0)
182 else:
183 create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.5)
185 ####################################################
186 # FK parents MCH chain
188 @stage.generate_bones
189 def make_toe_socket_bone(self):
190 org = self.bones.org.main[self.toe_bone_index]
191 self.bones.mch.toe_socket = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_socket'))
193 @stage.parent_bones
194 def parent_toe_socket_bone(self):
195 self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output())
197 def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
198 if i == self.toe_bone_index:
199 self.set_bone_parent(parent_mch, prev_org, use_connect=True, inherit_scale='ALIGNED')
201 else:
202 super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
204 def rig_fk_parent_bone(self, i, parent_mch, org):
205 if i == self.toe_bone_index:
206 con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.toe_socket)
208 self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
210 else:
211 super().rig_fk_parent_bone(i, parent_mch, org)
213 ####################################################
214 # IK system MCH
216 ik_input_head_tail = 1.0
218 def get_ik_input_bone(self):
219 return self.bones.ctrl.heel
221 @stage.parent_bones
222 def parent_ik_mch_chain(self):
223 super().parent_ik_mch_chain()
225 self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
227 ####################################################
228 # IK heel2 output
230 def get_ik_output_chain(self):
231 tail = [self.bones.mch.ik_heel2] if self.use_heel2 else []
232 return super().get_ik_output_chain() + tail
234 @stage.generate_bones
235 def make_ik_heel2_bone(self):
236 if self.use_heel2:
237 orgs = self.bones.org.main
238 self.bones.mch.ik_heel2 = self.copy_bone(orgs[3], make_derived_name(orgs[3], 'mch', '_ik_out'))
240 @stage.parent_bones
241 def parent_ik_heel2_bone(self):
242 if self.use_heel2:
243 self.set_bone_parent(self.bones.mch.ik_heel2, self.bones.ctrl.heel2)
245 @stage.rig_bones
246 def rig_ik_heel2_bone(self):
247 if self.use_heel2:
248 self.make_constraint(self.bones.mch.ik_heel2, 'COPY_LOCATION', self.bones.mch.ik_target, head_tail=1)
250 ####################################################
251 # Deform chain
253 def rig_deform_bone(self, i, deform, entry, next_entry, tweak, next_tweak):
254 super().rig_deform_bone(i, deform, entry, next_entry, tweak, next_tweak)
256 if tweak and not (next_tweak or next_entry):
257 self.make_constraint(deform, 'STRETCH_TO', entry.org, head_tail=1.0, keep_axis='SWING_Y')
259 ####################################################
260 # Settings
262 @classmethod
263 def parameters_ui(cls, layout, params, end='Claw'):
264 super().parameters_ui(layout, params, end)
267 def create_sample(obj):
268 # generated by rigify.utils.write_metarig
269 bpy.ops.object.mode_set(mode='EDIT')
270 arm = obj.data
272 bones = {}
274 bone = arm.edit_bones.new('thigh.L')
275 bone.head[:] = 0.0000, 0.0017, 0.7379
276 bone.tail[:] = 0.0000, -0.0690, 0.4731
277 bone.roll = 0.0000
278 bone.use_connect = False
279 bones['thigh.L'] = bone.name
280 bone = arm.edit_bones.new('shin.L')
281 bone.head[:] = 0.0000, -0.0690, 0.4731
282 bone.tail[:] = 0.0000, 0.1364, 0.2473
283 bone.roll = 0.0000
284 bone.use_connect = True
285 bone.parent = arm.edit_bones[bones['thigh.L']]
286 bones['shin.L'] = bone.name
287 bone = arm.edit_bones.new('foot.L')
288 bone.head[:] = 0.0000, 0.1364, 0.2473
289 bone.tail[:] = 0.0000, 0.0736, 0.0411
290 bone.roll = -0.0002
291 bone.use_connect = True
292 bone.parent = arm.edit_bones[bones['shin.L']]
293 bones['foot.L'] = bone.name
294 bone = arm.edit_bones.new('toe.L')
295 bone.head[:] = 0.0000, 0.0736, 0.0411
296 bone.tail[:] = 0.0000, -0.0594, 0.0000
297 bone.roll = -3.1416
298 bone.use_connect = True
299 bone.parent = arm.edit_bones[bones['foot.L']]
300 bones['toe.L'] = bone.name
302 bpy.ops.object.mode_set(mode='OBJECT')
303 pbone = obj.pose.bones[bones['thigh.L']]
304 pbone.rigify_type = 'limbs.paw'
305 pbone.lock_location = (False, False, False)
306 pbone.lock_rotation = (False, False, False)
307 pbone.lock_rotation_w = False
308 pbone.lock_scale = (False, False, False)
309 pbone.rotation_mode = 'QUATERNION'
310 try:
311 pbone.rigify_parameters.fk_layers = [
312 False, False, False, False, False, False, False, False, False, False, False, False,
313 False, False, False, False, False, True, False, False, False, False, False, False,
314 False, False, False, False, False, False, False, False]
315 except AttributeError:
316 pass
317 try:
318 pbone.rigify_parameters.tweak_layers = [
319 False, False, False, False, False, False, False, False, False, False, False, False,
320 False, False, False, False, False, False, True, False, False, False, False, False,
321 False, False, False, False, False, False, False, False]
322 except AttributeError:
323 pass
324 try:
325 pbone.rigify_parameters.limb_type = "paw"
326 except AttributeError:
327 pass
328 try:
329 pbone.rigify_parameters.ik_local_location = False
330 except AttributeError:
331 pass
332 pbone = obj.pose.bones[bones['shin.L']]
333 pbone.rigify_type = ''
334 pbone.lock_location = (False, False, False)
335 pbone.lock_rotation = (False, False, False)
336 pbone.lock_rotation_w = False
337 pbone.lock_scale = (False, False, False)
338 pbone.rotation_mode = 'QUATERNION'
339 pbone = obj.pose.bones[bones['foot.L']]
340 pbone.rigify_type = ''
341 pbone.lock_location = (False, False, False)
342 pbone.lock_rotation = (False, False, False)
343 pbone.lock_rotation_w = False
344 pbone.lock_scale = (False, False, False)
345 pbone.rotation_mode = 'QUATERNION'
346 pbone = obj.pose.bones[bones['toe.L']]
347 pbone.rigify_type = ''
348 pbone.lock_location = (False, False, False)
349 pbone.lock_rotation = (False, False, False)
350 pbone.lock_rotation_w = False
351 pbone.lock_scale = (False, False, False)
352 pbone.rotation_mode = 'QUATERNION'
353 try:
354 pbone.rigify_parameters.limb_type = "paw"
355 except AttributeError:
356 pass
358 bpy.ops.object.mode_set(mode='EDIT')
359 for bone in arm.edit_bones:
360 bone.select = False
361 bone.select_head = False
362 bone.select_tail = False
363 for b in bones:
364 bone = arm.edit_bones[bones[b]]
365 bone.select = True
366 bone.select_head = True
367 bone.select_tail = True
368 arm.edit_bones.active = bone
370 return bones