From 7120e9c9e08720c20833a334fee197ed9a11dc64 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 11 Feb 2022 23:27:26 +0300 Subject: Rigify: allow aligning IK control location channels to world space. For IK controls that move freely in space without being tied to a parent it makes sense to align the location channels to world (or root), while keeping rotation channels aligned to the limb end orientation. Blender already has a Local Location parenting option for this very use case, but Rigify wasn't using it. This adjusts the switchable parent mechanism so that the option works as intended, and provides a Rigify option that controls its value for IK controls. Note that now it is possible to enable the Local Location option directly on the control bones after generation and it will work correctly - it is not required to enable IK Local Location. --- rigify/rigs/face/skin_eye.py | 2 ++ rigify/rigs/limbs/limb_rigs.py | 13 +++++++++++++ rigify/rigs/limbs/super_finger.py | 15 +++++++++++++++ rigify/utils/bones.py | 14 ++++++++++++++ rigify/utils/switch_parent.py | 8 +++++++- 5 files changed, 51 insertions(+), 1 deletion(-) (limited to 'rigify') diff --git a/rigify/rigs/face/skin_eye.py b/rigify/rigs/face/skin_eye.py index 2d1f6c2f..4955df6b 100644 --- a/rigify/rigs/face/skin_eye.py +++ b/rigify/rigs/face/skin_eye.py @@ -593,6 +593,8 @@ class EyeClusterControl(RigComponent): def parent_bones(self): if self.rig_count > 1: + self.get_bone(self.master_bone).use_local_location = False + for child in self.child_bones: self.set_bone_parent(child, self.master_bone) diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py index 2b4723a4..b72e9d40 100644 --- a/rigify/rigs/limbs/limb_rigs.py +++ b/rigify/rigs/limbs/limb_rigs.py @@ -432,6 +432,12 @@ class BaseLimbRig(BaseRig): else: self.set_bone_parent(self.bones.ctrl.ik_base, self.bones.mch.ik_swing) + self.set_ik_local_location(self.bones.ctrl.ik) + self.set_ik_local_location(self.bones.ctrl.ik_pole) + + def set_ik_local_location(self, ctrl): + self.get_bone(ctrl).use_local_location = self.params.ik_local_location + @stage.configure_bones def configure_ik_controls(self): base = self.get_bone(self.bones.ctrl.ik_base) @@ -927,6 +933,12 @@ class BaseLimbRig(BaseRig): description = "Create a rotation pivot control that can be repositioned arbitrarily" ) + params.ik_local_location = bpy.props.BoolProperty( + name = "IK Local Location", + default = True, + description = "Specifies the value of the Local Location option for IK controls, which decides if the location channels are aligned to the local control orientation or world", + ) + # Setting up extra layers for the FK and tweak ControlLayersOption.FK.add_parameters(params) ControlLayersOption.TWEAK.add_parameters(params) @@ -949,6 +961,7 @@ class BaseLimbRig(BaseRig): r.prop(params, "bbones") layout.prop(params, 'make_custom_pivot', text="Custom IK Pivot") + layout.prop(params, 'ik_local_location') ControlLayersOption.FK.parameters_ui(layout, params) ControlLayersOption.TWEAK.parameters_ui(layout, params) diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py index 9eed5415..2229c0c0 100644 --- a/rigify/rigs/limbs/super_finger.py +++ b/rigify/rigs/limbs/super_finger.py @@ -152,6 +152,12 @@ class Rig(SimpleChainRig): no_fix_rotation=True, no_fix_scale=True, ) + @stage.parent_bones + def parent_ik_control(self): + if self.make_ik: + bone = self.get_bone(self.bones.ctrl.ik) + bone.use_local_location = self.params.ik_local_location + @stage.configure_bones def configure_ik_control(self): if self.make_ik: @@ -366,6 +372,12 @@ class Rig(SimpleChainRig): description = "Create an optional IK control" ) + params.ik_local_location = bpy.props.BoolProperty( + name = 'IK Local Location', + default = True, + description = "Specifies the value of the Local Location option for IK controls, which decides if the location channels are aligned to the local control orientation or world", + ) + ControlLayersOption.TWEAK.add_parameters(params) ControlLayersOption.EXTRA_IK.add_parameters(params) @@ -380,6 +392,9 @@ class Rig(SimpleChainRig): layout.prop(params, 'bbones') layout.prop(params, 'make_extra_ik_control', text='IK Control') + if params.make_extra_ik_control: + layout.prop(params, 'ik_local_location') + ControlLayersOption.TWEAK.parameters_ui(layout, params) if params.make_extra_ik_control: diff --git a/rigify/utils/bones.py b/rigify/utils/bones.py index 16cf62de..10a8926d 100644 --- a/rigify/utils/bones.py +++ b/rigify/utils/bones.py @@ -482,6 +482,20 @@ def align_bone_orientation(obj, bone_name, target_bone_name): bone1_e.roll = bone2_e.roll +def set_bone_orientation(obj, bone_name, orientation): + """ Aligns the orientation of bone to target bone or matrix. """ + if isinstance(orientation, str): + align_bone_orientation(obj, bone_name, orientation) + + else: + bone_e = obj.data.edit_bones[bone_name] + + matrix = Matrix(orientation).to_4x4() + matrix.translation = bone_e.head + + bone_e.matrix = matrix + + def align_bone_roll(obj, bone1, bone2): """ Aligns the roll of two bones. """ diff --git a/rigify/utils/switch_parent.py b/rigify/utils/switch_parent.py index 405008b9..ff5217b4 100644 --- a/rigify/utils/switch_parent.py +++ b/rigify/utils/switch_parent.py @@ -7,6 +7,7 @@ import json from .errors import MetarigError from .naming import strip_prefix, make_derived_name +from .bones import set_bone_orientation from .mechanism import MechanismUtilityMixin from .rig import rig_is_child from .misc import map_list, map_apply, force_lazy @@ -16,6 +17,7 @@ from ..base_generate import GeneratorPlugin from collections import defaultdict from itertools import count, repeat, chain +from mathutils import Matrix class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): @@ -80,7 +82,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): self.local_parents[id(rig)].append(entry) - def build_child(self, rig, bone, *, use_parent_mch=True, **options): + def build_child(self, rig, bone, *, use_parent_mch=True, mch_orientation=None, **options): """ Build a switchable parent mechanism for the specified bone. @@ -89,6 +91,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): bone Name of the child bone. extra_parents List of bone names or (name, user_name) pairs to use as additional parents. use_parent_mch Create an intermediate MCH bone for the constraints and parent the child to it. + mch_orientation Orientation matrix or bone name to align the MCH bone to; defaults to world. select_parent Select the specified bone instead of the last one. select_tags List of parent tags to try for default selection. ignore_global Ignore the is_global flag of potential parents. @@ -120,6 +123,9 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): # Create MCH proxy if use_parent_mch: mch_bone = rig.copy_bone(bone, make_derived_name(bone, 'mch', '.parent'), scale=1/3) + + set_bone_orientation(rig.obj, mch_bone, mch_orientation or Matrix.Identity(4)) + else: mch_bone = bone -- cgit v1.2.3