diff options
Diffstat (limited to 'rigify/rigs/limbs')
-rw-r--r-- | rigify/rigs/limbs/arm.py | 69 | ||||
-rw-r--r-- | rigify/rigs/limbs/leg.py | 190 | ||||
-rw-r--r-- | rigify/rigs/limbs/limb_rigs.py | 97 | ||||
-rw-r--r-- | rigify/rigs/limbs/paw.py | 8 | ||||
-rw-r--r-- | rigify/rigs/limbs/simple_tentacle.py | 2 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_finger.py | 42 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_palm.py | 3 |
7 files changed, 299 insertions, 112 deletions
diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 98a3c50f..e79edc5c 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -21,12 +21,15 @@ import bpy from itertools import count +from mathutils import Matrix -from ...utils.bones import BoneDict, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis +from ...utils.bones import put_bone, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis from ...utils.naming import make_derived_name from ...utils.misc import map_list +from ...utils.widgets import adjust_widget_transform_mesh from ..widgets import create_hand_widget +from ...utils.widgets_basic import create_circle_widget from ...base_rig import stage @@ -42,6 +45,8 @@ class Rig(BaseLimbRig): super().initialize() + self.make_wrist_pivot = self.params.make_ik_wrist_pivot + def prepare_bones(self): orgs = self.bones.org.main @@ -62,16 +67,76 @@ class Rig(BaseLimbRig): def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): create_hand_widget(self.obj, ctrl) #################################################### + # Palm Pivot + + def get_ik_input_bone(self): + if self.make_wrist_pivot: + return self.bones.mch.ik_wrist + else: + return self.get_ik_control_output() + + def get_extra_ik_controls(self): + controls = super().get_extra_ik_controls() + if self.make_wrist_pivot: + controls += [self.bones.ctrl.ik_wrist] + return controls + + @stage.generate_bones + def make_wrist_pivot_control(self): + if self.make_wrist_pivot: + org = self.bones.org.main[2] + self.bones.ctrl.ik_wrist = self.make_wrist_pivot_bone(org) + self.bones.mch.ik_wrist = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_wrist'), scale=0.25) + + def make_wrist_pivot_bone(self, org): + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik_wrist'), scale=0.5) + put_bone(self.obj, name, self.get_bone(org).tail) + return name + + @stage.parent_bones + def parent_wrist_pivot_control(self): + if self.make_wrist_pivot: + ctrl = self.bones.ctrl.ik_wrist + self.set_bone_parent(ctrl, self.get_ik_control_output()) + self.set_bone_parent(self.bones.mch.ik_wrist, ctrl) + + @stage.generate_widgets + def make_wrist_pivot_widget(self): + if self.make_wrist_pivot: + ctrl = self.bones.ctrl.ik_wrist + + if self.main_axis == 'x': + obj = create_circle_widget(self.obj, ctrl, head_tail=-0.3, head_tail_x=0.5) + else: + obj = create_circle_widget(self.obj, ctrl, head_tail=0.5, head_tail_x=-0.3) + + if obj: + org_bone = self.get_bone(self.bones.org.main[2]) + offset = org_bone.head - self.get_bone(ctrl).head + adjust_widget_transform_mesh(obj, Matrix.Translation(offset)) + + #################################################### # Settings @classmethod + def add_parameters(self, params): + super().add_parameters(params) + + params.make_ik_wrist_pivot = bpy.props.BoolProperty( + name="IK Wrist Pivot", default=False, + description="Make an extra IK hand control pivoting around the tip of the hand" + ) + + @classmethod def parameters_ui(self, layout, params): + layout.prop(params, "make_ik_wrist_pivot") + super().parameters_ui(layout, params, 'Hand') diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index dbdd20cb..b409d009 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -22,13 +22,14 @@ import bpy import math from itertools import count -from mathutils import Vector +from mathutils import Vector, Matrix from ...utils.rig import is_rig_base_bone from ...utils.bones import align_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation from ...utils.naming import make_derived_name -from ...utils.misc import map_list +from ...utils.misc import map_list, matrix_from_axis_roll, matrix_from_axis_pair +from ...utils.widgets import adjust_widget_transform_mesh from ..widgets import create_foot_widget, create_ballsocket_widget @@ -62,10 +63,18 @@ class Rig(BaseLimbRig): super().initialize() + self.pivot_type = self.params.foot_pivot_type + self.heel_euler_order = 'ZXY' if self.main_axis == 'x' else 'XZY' + + assert self.pivot_type in {'ANKLE', 'TOE', 'ANKLE_TOE'} + def prepare_bones(self): orgs = self.bones.org.main + foot = self.get_bone(orgs[2]) - foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, -1)) + ik_y_axis = (0, 1, 0) + foot_y_axis = -self.vector_without_z(foot.y_axis) + foot_x = foot_y_axis.cross((0, 0, 1)) if self.params.rotation_axis == 'automatic': align_chain_x_axis(self.obj, orgs[0:2]) @@ -84,6 +93,12 @@ class Rig(BaseLimbRig): align_bone_z_axis(self.obj, orgs[2], foot_x) align_bone_z_axis(self.obj, orgs[3], -foot_x) + else: + ik_y_axis = foot_y_axis + + # Orientation of the IK main and roll control bones + self.ik_matrix = matrix_from_axis_roll(ik_y_axis, 0) + self.roll_matrix = matrix_from_axis_pair(ik_y_axis, foot_x, self.main_axis) #################################################### # EXTRA BONES @@ -92,6 +107,8 @@ class Rig(BaseLimbRig): # heel: # Heel location marker bone # ctrl: + # ik_spin: + # Toe spin control. # heel: # Foot roll control # mch: @@ -104,31 +121,71 @@ class Rig(BaseLimbRig): # IK controls def get_extra_ik_controls(self): - return [self.bones.ctrl.heel] + controls = super().get_extra_ik_controls() + [self.bones.ctrl.heel] + if self.pivot_type == 'ANKLE_TOE': + controls += [self.bones.ctrl.ik_spin] + return controls def make_ik_control_bone(self, orgs): name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik')) - - if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity: - align_bone_to_axis(self.obj, name, 'y', flip=True) - + if self.pivot_type == 'TOE': + put_bone(self.obj, name, self.get_bone(name).tail, matrix=self.ik_matrix) else: - flip_bone(self.obj, name) - - bone = self.get_bone(name) - bone.tail[2] = bone.head[2] - bone.roll = 0 - + put_bone(self.obj, name, None, matrix=self.ik_matrix) return name + def build_ik_pivot(self, ik_name, **args): + heel_bone = self.get_bone(self.bones.org.heel) + args = { + 'position': (heel_bone.head + heel_bone.tail)/2, + **args + } + return super().build_ik_pivot(ik_name, **args) + def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): - create_foot_widget(self.obj, ctrl) + obj = create_foot_widget(self.obj, ctrl) + if self.pivot_type != 'TOE': + ctrl = self.get_bone(ctrl) + org = self.get_bone(self.bones.org.main[2]) + offset = org.tail - (ctrl.custom_shape_transform or ctrl).head + adjust_widget_transform_mesh(obj, Matrix.Translation(offset)) + + #################################################### + # IK pivot controls + + def get_ik_pivot_output(self): + if self.pivot_type == 'ANKLE_TOE': + return self.bones.ctrl.ik_spin + else: + return self.get_ik_control_output() + + @stage.generate_bones + def make_ik_pivot_controls(self): + if self.pivot_type == 'ANKLE_TOE': + self.bones.ctrl.ik_spin = self.make_ik_spin_bone(self.bones.org.main) + + def make_ik_spin_bone(self, orgs): + name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_spin_ik')) + put_bone(self.obj, name, self.get_bone(orgs[3]).head, matrix=self.ik_matrix, scale=0.5) + return name + + @stage.parent_bones + def parent_ik_pivot_controls(self): + if self.pivot_type == 'ANKLE_TOE': + self.set_bone_parent(self.bones.ctrl.ik_spin, self.get_ik_control_output()) + + @stage.generate_widgets + def make_ik_spin_control_widget(self): + if self.pivot_type == 'ANKLE_TOE': + obj = create_ballsocket_widget(self.obj, self.bones.ctrl.ik_spin, size=0.75) + rotfix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper()) + adjust_widget_transform_mesh(obj, rotfix, local=True) #################################################### # Heel control @@ -136,25 +193,19 @@ class Rig(BaseLimbRig): @stage.generate_bones def make_heel_control_bone(self): org = self.bones.org.main[2] - name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'), scale=1/2) + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik')) + put_bone(self.obj, name, None, matrix=self.roll_matrix, scale=0.5) self.bones.ctrl.heel = name - self.align_roll_bone(org, name, -self.vector_without_z(self.get_bone(org).vector)) - @stage.parent_bones def parent_heel_control_bone(self): - self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_pivot_output(), inherit_scale='AVERAGE') @stage.configure_bones def configure_heel_control_bone(self): bone = self.get_bone(self.bones.ctrl.heel) bone.lock_location = True, True, True - - if self.main_axis == 'x': - bone.lock_rotation = False, False, True - else: - bone.lock_rotation = True, False, False - + bone.rotation_mode = self.heel_euler_order bone.lock_scale = True, True, True @stage.generate_widgets @@ -173,34 +224,27 @@ class Rig(BaseLimbRig): def make_roll_mch_bones(self, foot, toe, heel): foot_bone = self.get_bone(foot) heel_bone = self.get_bone(heel) - axis = -self.vector_without_z(foot_bone.vector) - - roll1 = self.copy_bone(foot, make_derived_name(heel, 'mch', '_roll1')) - flip_bone(self.obj, roll1) - self.align_roll_bone(foot, roll1, -foot_bone.vector) + heel_middle = (heel_bone.head + heel_bone.tail) / 2 - roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=1/4) - - put_bone(self.obj, roll2, (heel_bone.head + heel_bone.tail) / 2) - self.align_roll_bone(foot, roll2, -axis) + result = self.copy_bone(foot, make_derived_name(foot, 'mch', '_roll'), scale=0.25) + roll1 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll1'), scale=0.3) + roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=0.3) rock1 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock1')) - - align_bone_to_axis(self.obj, rock1, 'y', roll=0, length=heel_bone.length/2, flip=True) - align_bone_y_axis(self.obj, rock1, axis) - rock2 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock2')) - align_bone_to_axis(self.obj, rock2, 'y', roll=0, length=heel_bone.length/2) - align_bone_y_axis(self.obj, rock2, axis) + put_bone(self.obj, roll1, None, matrix=self.roll_matrix) + put_bone(self.obj, roll2, heel_middle, matrix=self.roll_matrix) + put_bone(self.obj, rock1, heel_bone.tail, matrix=self.roll_matrix, scale=0.5) + put_bone(self.obj, rock2, heel_bone.head, matrix=self.roll_matrix, scale=0.5) - return [ rock2, rock1, roll2, roll1 ] + return [ rock2, rock1, roll2, roll1, result ] @stage.parent_bones def parent_roll_mch_chain(self): chain = self.bones.mch.heel - self.set_bone_parent(chain[0], self.bones.ctrl.ik) + self.set_bone_parent(chain[0], self.get_ik_pivot_output()) self.parent_bone_chain(chain) @stage.rig_bones @@ -208,28 +252,37 @@ class Rig(BaseLimbRig): self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel) def rig_roll_mch_bones(self, chain, heel, org_heel): - rock2, rock1, roll2, roll1 = chain + rock2, rock1, roll2, roll1, result = chain + + # This order is required for correct working of the constraints + for bone in chain: + self.get_bone(bone).rotation_mode = self.heel_euler_order - self.make_constraint(roll1, 'COPY_ROTATION', heel, space='LOCAL') - self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL') + self.make_constraint(roll1, 'COPY_ROTATION', heel, space='POSE') if self.main_axis == 'x': - self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_x=True, max_x=DEG_360, space='LOCAL') - self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_x=-DEG_360, space='LOCAL') + self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(True, False, False)) + self.make_constraint(roll2, 'LIMIT_ROTATION', min_x=-DEG_360, space='LOCAL') else: - self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_z=True, max_z=DEG_360, space='LOCAL') - self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_z=-DEG_360, space='LOCAL') + self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(False, False, True)) + self.make_constraint(roll2, 'LIMIT_ROTATION', min_z=-DEG_360, space='LOCAL') direction = self.get_main_axis(self.get_bone(heel)).dot(self.get_bone(org_heel).vector) if direction < 0: rock2, rock1 = rock1, rock2 - self.make_constraint(rock1, 'COPY_ROTATION', heel, space='LOCAL') - self.make_constraint(rock2, 'COPY_ROTATION', heel, space='LOCAL') + self.make_constraint( + rock1, 'COPY_ROTATION', heel, space='LOCAL', + use_xyz=(False, True, False), + ) + self.make_constraint( + rock2, 'COPY_ROTATION', heel, space='LOCAL', + use_xyz=(False, True, False), + ) - self.make_constraint(rock1, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, max_y=DEG_360, space='LOCAL') - self.make_constraint(rock2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_y=-DEG_360, space='LOCAL') + self.make_constraint(rock1, 'LIMIT_ROTATION', max_y=DEG_360, space='LOCAL') + self.make_constraint(rock2, 'LIMIT_ROTATION', min_y=-DEG_360, space='LOCAL') #################################################### @@ -237,7 +290,7 @@ class Rig(BaseLimbRig): def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org): if i == 3: - align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[-2]) + align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[2]) self.set_bone_parent(parent_mch, prev_org, use_connect=True) @@ -246,7 +299,7 @@ class Rig(BaseLimbRig): def rig_fk_parent_bone(self, i, parent_mch, org): if i == 3: - con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[-2]) + con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[2]) self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0]) @@ -257,8 +310,6 @@ class Rig(BaseLimbRig): #################################################### # IK system MCH - ik_input_head_tail = 1.0 - def get_ik_input_bone(self): return self.bones.mch.heel[-1] @@ -266,14 +317,35 @@ class Rig(BaseLimbRig): def parent_ik_mch_chain(self): super().parent_ik_mch_chain() - self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel) + self.set_bone_parent(self.bones.mch.ik_target, self.bones.mch.heel[-1]) #################################################### # Settings @classmethod + def add_parameters(self, params): + super().add_parameters(params) + + items = [ + ('ANKLE', 'Ankle', + 'The foots pivots at the ankle'), + ('TOE', 'Toe', + 'The foot pivots around the base of the toe'), + ('ANKLE_TOE', 'Ankle and Toe', + 'The foots pivots at the ankle, with extra toe pivot'), + ] + + params.foot_pivot_type = bpy.props.EnumProperty( + items = items, + name = "Foot Pivot", + default = 'ANKLE_TOE' + ) + + @classmethod def parameters_ui(self, layout, params): + layout.prop(params, 'foot_pivot_type') + super().parameters_ui(layout, params, 'Foot') diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py index 81079c05..f1eb8639 100644 --- a/rigify/rigs/limbs/limb_rigs.py +++ b/rigify/rigs/limbs/limb_rigs.py @@ -23,12 +23,12 @@ import json from ...utils.animation import add_generic_snap_fk_to_ik, add_fk_ik_snap_buttons from ...utils.rig import connected_children_names -from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation -from ...utils.bones import align_bone_x_axis, align_bone_y_axis, align_bone_z_axis +from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation, set_bone_widget_transform from ...utils.naming import strip_org, make_derived_name from ...utils.layers import ControlLayersOption from ...utils.misc import pairwise_nozip, padnone, map_list from ...utils.switch_parent import SwitchParentBuilder +from ...utils.components import CustomPivotControl from ...base_rig import stage, BaseRig @@ -64,6 +64,7 @@ class BaseLimbRig(BaseRig): self.segments = self.params.segments self.bbone_segments = self.params.bbones + self.use_ik_pivot = self.params.make_custom_pivot rot_axis = self.params.rotation_axis @@ -124,15 +125,6 @@ class BaseLimbRig(BaseRig): bone = self.get_bone(org) return bone.head + bone.vector * (seg / self.segments) - def align_roll_bone(self, org, name, y_axis): - if y_axis: - align_bone_y_axis(self.obj, name, y_axis) - - if self.main_axis == 'x': - align_bone_x_axis(self.obj, name, self.get_bone(org).x_axis) - else: - align_bone_z_axis(self.obj, name, self.get_bone(org).z_axis) - @staticmethod def vector_without_z(vector): return Vector((vector[0], vector[1], 0)) @@ -154,6 +146,8 @@ class BaseLimbRig(BaseRig): # IK controls # ik_vispole # IK pole visualization. + # ik_pivot + # Custom IK pivot (optional). # mch: # master: # Parent of the master control. @@ -161,6 +155,8 @@ class BaseLimbRig(BaseRig): # FK follow behavior. # fk[]: # FK chain parents (or None) + # ik_pivot + # Custom IK pivot result (optional). # ik_stretch # IK stretch switch implementation. # ik_target @@ -328,22 +324,30 @@ class BaseLimbRig(BaseRig): # IK controls def get_extra_ik_controls(self): - return [] + if self.component_ik_pivot: + return [self.component_ik_pivot.control] + else: + return [] def get_all_ik_controls(self): ctrl = self.bones.ctrl - return [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + self.get_extra_ik_controls() + controls = [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + return controls + self.get_extra_ik_controls() @stage.generate_bones def make_ik_controls(self): orgs = self.bones.org.main - self.bones.ctrl.ik_base = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik')) + self.bones.ctrl.ik_base = self.make_ik_base_bone(orgs) self.bones.ctrl.ik_pole = self.make_ik_pole_bone(orgs) - self.bones.ctrl.ik = self.make_ik_control_bone(orgs) + self.bones.ctrl.ik = ik_name = self.make_ik_control_bone(orgs) + self.component_ik_pivot = self.build_ik_pivot(ik_name) self.build_ik_parent_switch(SwitchParentBuilder(self.generator)) + def make_ik_base_bone(self, orgs): + return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik')) + def make_ik_pole_bone(self, orgs): name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik_target')) @@ -357,10 +361,25 @@ class BaseLimbRig(BaseRig): def make_ik_control_bone(self, orgs): return self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik')) + def build_ik_pivot(self, ik_name, **args): + if self.use_ik_pivot: + return CustomPivotControl(self, 'ik_pivot', ik_name, parent=ik_name, **args) + + def get_ik_control_output(self): + if self.component_ik_pivot: + return self.component_ik_pivot.output + else: + return self.bones.ctrl.ik + def register_switch_parents(self, pbuilder): if self.rig_parent_bone: pbuilder.register_parent(self, self.rig_parent_bone) + pbuilder.register_parent( + self, self.get_ik_control_output, name=self.bones.ctrl.ik, + exclude_self=True, tags={'limb_ik', 'child'}, + ) + def build_ik_parent_switch(self, pbuilder): ctrl = self.bones.ctrl @@ -398,9 +417,13 @@ class BaseLimbRig(BaseRig): @stage.generate_widgets def make_ik_control_widgets(self): - self.make_ik_base_widget(self.bones.ctrl.ik_base) - self.make_ik_pole_widget(self.bones.ctrl.ik_pole) - self.make_ik_ctrl_widget(self.bones.ctrl.ik) + ctrl = self.bones.ctrl + + set_bone_widget_transform(self.obj, ctrl.ik, self.get_ik_control_output()) + + self.make_ik_base_widget(ctrl.ik_base) + self.make_ik_pole_widget(ctrl.ik_pole) + self.make_ik_ctrl_widget(ctrl.ik) def make_ik_base_widget(self, ctrl): if self.main_axis == 'x': @@ -453,7 +476,7 @@ class BaseLimbRig(BaseRig): ik_input_head_tail = 0.0 def get_ik_input_bone(self): - return self.bones.ctrl.ik + return self.get_ik_control_output() def get_ik_output_chain(self): return [self.bones.ctrl.ik_base, self.bones.mch.ik_end, self.bones.mch.ik_target] @@ -670,7 +693,13 @@ class BaseLimbRig(BaseRig): @stage.parent_bones def parent_tweak_mch_chain(self): - for mch, entry in zip(self.bones.mch.tweak, self.segment_table_tweak): + for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak): + self.parent_tweak_mch_bone(*args) + + def parent_tweak_mch_bone(self, i, mch, entry): + if i == 0: + self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='FIX_SHEAR') + else: self.set_bone_parent(mch, entry.org) @stage.rig_bones @@ -694,6 +723,10 @@ class BaseLimbRig(BaseRig): elif entry.seg_idx is not None: self.make_constraint(tweak, 'COPY_SCALE', 'root', use_make_uniform=True) + if i == 0: + self.make_constraint(tweak, 'COPY_LOCATION', entry.org) + self.make_constraint(tweak, 'DAMPED_TRACK', entry.org, head_tail=1) + #################################################### # Deform chain @@ -786,17 +819,23 @@ class BaseLimbRig(BaseRig): ) params.segments = bpy.props.IntProperty( - name = 'limb segments', + name = 'Limb Segments', default = 2, min = 1, - description = 'Number of segments' + description = 'Number of limb segments' ) params.bbones = bpy.props.IntProperty( - name = 'bbone segments', + name = 'B-Bone Segments', default = 10, min = 1, - description = 'Number of segments' + description = 'Number of B-Bone segments' + ) + + params.make_custom_pivot = bpy.props.BoolProperty( + name = "Custom Pivot Control", + default = False, + description = "Create a rotation pivot control that can be repositioned arbitrarily" ) # Setting up extra layers for the FK and tweak @@ -820,6 +859,8 @@ class BaseLimbRig(BaseRig): r = layout.row() r.prop(params, "bbones") + layout.prop(params, 'make_custom_pivot', text="Custom IK Pivot") + ControlLayersOption.FK.parameters_ui(layout, params) ControlLayersOption.TWEAK.parameters_ui(layout, params) @@ -843,8 +884,6 @@ class RigifyLimbIk2FkBase: ctrl_bones: StringProperty(name="IK Controls") extra_ctrls: StringProperty(name="Extra IK Controls") - keyflags = None - def init_execute(self, context): if self.fk_bones: self.fk_bone_list = json.loads(self.fk_bones) @@ -921,13 +960,11 @@ class RigifyLimbIk2FkBase: class POSE_OT_rigify_limb_ik2fk(RigifyLimbIk2FkBase, RigifySingleUpdateMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_ik2fk_" + rig_id bl_label = "Snap IK->FK" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Snap the IK chain to FK result" class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_ik2fk_bake_" + rig_id bl_label = "Apply Snap IK->FK To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Snap the IK chain keyframes to FK result" def execute_scan_curves(self, context, obj): @@ -968,8 +1005,6 @@ SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + [''' class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase): use_pole: bpy.props.BoolProperty(name="Use Pole Vector") - keyflags_switch = None - def save_frame_state(self, context, obj): return get_chain_transform_matrices(obj, self.ik_bone_list) @@ -1007,13 +1042,11 @@ class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase): class POSE_OT_rigify_limb_toggle_pole(RigifyLimbTogglePoleBase, RigifySingleUpdateMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_toggle_pole_" + rig_id bl_label = "Toggle Pole" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Switch the IK chain between pole and rotation" class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeKeyframesMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_toggle_pole_bake_" + rig_id bl_label = "Apply Toggle Pole To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Switch the IK chain between pole and rotation over a frame range" def execute_scan_curves(self, context, obj): diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py index f8cb1f9f..28374eec 100644 --- a/rigify/rigs/limbs/paw.py +++ b/rigify/rigs/limbs/paw.py @@ -84,7 +84,7 @@ class Rig(BaseLimbRig): # IK controls def get_extra_ik_controls(self): - return [self.bones.ctrl.heel] + return super().get_extra_ik_controls() + [self.bones.ctrl.heel] def make_ik_control_bone(self, orgs): name = self.copy_bone(orgs[3], make_derived_name(orgs[2], 'ctrl', '_ik')) @@ -107,7 +107,7 @@ class Rig(BaseLimbRig): def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): create_foot_widget(self.obj, ctrl) @@ -126,7 +126,7 @@ class Rig(BaseLimbRig): @stage.parent_bones def parent_heel_control_bone(self): - self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output()) @stage.configure_bones def configure_heel_control_bone(self): @@ -150,7 +150,7 @@ class Rig(BaseLimbRig): def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org): if i == 3: self.set_bone_parent(parent_mch, prev_org, use_connect=True) - self.set_bone_parent(self.bones.mch.toe_socket, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output()) else: super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org) diff --git a/rigify/rigs/limbs/simple_tentacle.py b/rigify/rigs/limbs/simple_tentacle.py index 10bdd2b5..25d26e86 100644 --- a/rigify/rigs/limbs/simple_tentacle.py +++ b/rigify/rigs/limbs/simple_tentacle.py @@ -78,7 +78,7 @@ class Rig(TweakChainRig): ) # Widgets - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py index 1a9171a7..0b3fcd8a 100644 --- a/rigify/rigs/limbs/super_finger.py +++ b/rigify/rigs/limbs/super_finger.py @@ -24,11 +24,12 @@ import re from itertools import count from ...utils.errors import MetarigError -from ...utils.bones import flip_bone, align_chain_x_axis +from ...utils.bones import put_bone, flip_bone, align_chain_x_axis, set_bone_widget_transform from ...utils.naming import make_derived_name from ...utils.widgets import create_widget from ...utils.widgets_basic import create_circle_widget from ...utils.misc import map_list +from ...utils.layers import ControlLayersOption from ...base_rig import stage @@ -40,7 +41,7 @@ class Rig(SimpleChainRig): def initialize(self): super().initialize() - self.bbone_segments = 8 + self.bbone_segments = self.params.bbones self.first_parent = self.get_bone_parent(self.bones.org[0]) def prepare_bones(self): @@ -116,6 +117,8 @@ class Rig(SimpleChainRig): for args in zip(count(0), self.bones.ctrl.fk, self.bones.org + [None]): self.configure_control_bone(*args) + ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.fk) + def configure_control_bone(self, i, ctrl, org): if org: self.copy_bone_properties(org, ctrl) @@ -125,11 +128,13 @@ class Rig(SimpleChainRig): bone.lock_rotation = (True, True, True) bone.lock_scale = (True, True, True) - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): if ctrl == self.bones.ctrl.fk[-1]: # Tip control create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0) else: + set_bone_widget_transform(self.obj, ctrl, self.bones.org[i]) + create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) ############################## @@ -234,11 +239,12 @@ class Rig(SimpleChainRig): def configure_master_properties(self): master = self.bones.ctrl.master - self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") + if self.bbone_segments > 1: + self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") - # Create UI - panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten()) - panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True) + # Create UI + panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten()) + panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True) def rig_deform_bone(self, i, deform, org): master = self.bones.ctrl.master @@ -246,8 +252,9 @@ class Rig(SimpleChainRig): self.make_constraint(deform, 'COPY_TRANSFORMS', org) - self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')]) - self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')]) + if self.bbone_segments > 1: + self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')]) + self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')]) ############### # OPTIONS @@ -261,6 +268,15 @@ class Rig(SimpleChainRig): ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')] params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic') + params.bbones = bpy.props.IntProperty( + name = 'B-Bone Segments', + default = 10, + min = 1, + description = 'Number of B-Bone segments' + ) + + ControlLayersOption.TWEAK.add_parameters(params) + @classmethod def parameters_ui(self, layout, params): """ Create the ui for the rig parameters. @@ -269,6 +285,10 @@ class Rig(SimpleChainRig): r.label(text="Bend rotation axis:") r.prop(params, "primary_rotation_axis", text="") + layout.prop(params, 'bbones') + + ControlLayersOption.TWEAK.parameters_ui(layout, params) + def create_sample(obj): # generated by rigify.utils.write_metarig @@ -321,10 +341,6 @@ def create_sample(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' try: - pbone.rigify_parameters.separate_extra_layers = True - except AttributeError: - pass - try: pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass diff --git a/rigify/rigs/limbs/super_palm.py b/rigify/rigs/limbs/super_palm.py index 8bcbabf8..9c03b2fe 100644 --- a/rigify/rigs/limbs/super_palm.py +++ b/rigify/rigs/limbs/super_palm.py @@ -24,6 +24,7 @@ import re from math import cos, pi from itertools import count, repeat +from rigify.utils.rig import is_rig_base_bone from rigify.utils.naming import strip_org, make_derived_name from rigify.utils.widgets import create_widget from rigify.utils.misc import map_list @@ -43,7 +44,7 @@ def bone_siblings(obj, bone): bones = [] for b in parent.children: - if b.name != bone: + if b.name != bone and not is_rig_base_bone(obj, b.name): bones += [b.name] return bones |