diff options
Diffstat (limited to 'rigify/rigs')
-rw-r--r-- | rigify/rigs/basic/copy_chain.py | 176 | ||||
-rw-r--r-- | rigify/rigs/basic/super_copy.py | 151 | ||||
-rw-r--r-- | rigify/rigs/chain_rigs.py | 387 | ||||
-rw-r--r-- | rigify/rigs/experimental/super_chain.py | 2 | ||||
-rw-r--r-- | rigify/rigs/faces/super_face.py | 2 | ||||
-rw-r--r-- | rigify/rigs/limbs/arm.py | 122 | ||||
-rw-r--r-- | rigify/rigs/limbs/leg.py | 130 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_limb.py | 2 | ||||
-rw-r--r-- | rigify/rigs/spines/super_spine.py | 10 |
9 files changed, 598 insertions, 384 deletions
diff --git a/rigify/rigs/basic/copy_chain.py b/rigify/rigs/basic/copy_chain.py index 4e426284..5145d735 100644 --- a/rigify/rigs/basic/copy_chain.py +++ b/rigify/rigs/basic/copy_chain.py @@ -20,124 +20,96 @@ import bpy -from ...utils import MetarigError -from ...utils import copy_bone -from ...utils import connected_children_names -from ...utils import strip_org, make_deformer_name -from ...utils import create_bone_widget +from ..chain_rigs import SimpleChainRig +from ...utils.errors import MetarigError +from ...utils.rig import connected_children_names +from ...utils.naming import strip_org, make_deformer_name +from ...utils.widgets_basic import create_bone_widget -class Rig: +from ...base_rig import BaseRig, stage + + +class Rig(SimpleChainRig): """ A "copy_chain" rig. All it does is duplicate the original bone chain and constrain it. This is a control and deformation rig. - """ - def __init__(self, obj, bone_name, params): + def initialize(self): + super().initialize() + """ Gather and validate data about the rig. """ - self.obj = obj - self.org_bones = [bone_name] + connected_children_names(obj, bone_name) - self.params = params - self.make_controls = params.make_controls - self.make_deforms = params.make_deforms + self.make_controls = self.params.make_controls + self.make_deforms = self.params.make_deforms - if len(self.org_bones) <= 1: - raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 2 or more bones" % (strip_org(bone_name))) + ############################## + # Control chain - def generate(self): - """ Generate the rig. - Do NOT modify any of the original bones, except for adding constraints. - The main armature should be selected and active before this is called. + @stage.generate_bones + def make_control_chain(self): + if self.make_controls: + super().make_control_chain() - """ - bpy.ops.object.mode_set(mode='EDIT') - - # Create the deformation and control bone chains. - # Just copies of the original chain. - def_chain = [] - ctrl_chain = [] - for i in range(len(self.org_bones)): - name = self.org_bones[i] - - # Control bone - if self.make_controls: - # Copy - ctrl_bone = copy_bone(self.obj, name) - eb = self.obj.data.edit_bones - ctrl_bone_e = eb[ctrl_bone] - # Name - ctrl_bone_e.name = strip_org(name) - # Parenting - if i == 0: - # First bone - ctrl_bone_e.parent = eb[self.org_bones[0]].parent - else: - # The rest - ctrl_bone_e.parent = eb[ctrl_chain[-1]] - # Add to list - ctrl_chain += [ctrl_bone_e.name] - else: - ctrl_chain += [None] - - # Deformation bone - if self.make_deforms: - # Copy - def_bone = copy_bone(self.obj, name) - eb = self.obj.data.edit_bones - def_bone_e = eb[def_bone] - # Name - def_bone_e.name = make_deformer_name(strip_org(name)) - # Parenting - if i == 0: - # First bone - def_bone_e.parent = eb[self.org_bones[0]].parent - else: - # The rest - def_bone_e.parent = eb[def_chain[-1]] - # Add to list - def_chain += [def_bone_e.name] - else: - def_chain += [None] - - bpy.ops.object.mode_set(mode='OBJECT') - pb = self.obj.pose.bones - - # Constraints for org and def - for org, ctrl, defrm in zip(self.org_bones, ctrl_chain, def_chain): - if self.make_controls: - con = pb[org].constraints.new('COPY_TRANSFORMS') - con.name = "copy_transforms" - con.target = self.obj - con.subtarget = ctrl - - if self.make_deforms: - con = pb[defrm].constraints.new('COPY_TRANSFORMS') - con.name = "copy_transforms" - con.target = self.obj - con.subtarget = org - - # Create control widgets + @stage.parent_bones + def parent_control_chain(self): if self.make_controls: - for bone in ctrl_chain: - create_bone_widget(self.obj, bone) + super().parent_control_chain() + @stage.configure_bones + def configure_control_chain(self): + if self.make_controls: + super().configure_control_chain() -def add_parameters(params): - """ Add the parameters of this rig type to the - RigifyParameters PropertyGroup - """ - params.make_controls = bpy.props.BoolProperty(name="Controls", default=True, description="Create control bones for the copy") - params.make_deforms = bpy.props.BoolProperty(name="Deform", default=True, description="Create deform bones for the copy") + @stage.generate_widgets + def make_control_widgets(self): + if self.make_controls: + super().make_control_widgets() + ############################## + # ORG chain -def parameters_ui(layout, params): - """ Create the ui for the rig parameters. - """ - r = layout.row() - r.prop(params, "make_controls") - r = layout.row() - r.prop(params, "make_deforms") + @stage.rig_bones + def rig_org_chain(self): + if self.make_controls: + super().rig_org_chain() + + ############################## + # Deform chain + + @stage.generate_bones + def make_deform_chain(self): + if self.make_deforms: + super().make_deform_chain() + + @stage.parent_bones + def parent_deform_chain(self): + if self.make_deforms: + super().parent_deform_chain() + + @stage.rig_bones + def rig_deform_chain(self): + if self.make_deforms: + super().rig_deform_chain() + + + @classmethod + def add_parameters(self, params): + """ Add the parameters of this rig type to the + RigifyParameters PropertyGroup + """ + params.make_controls = bpy.props.BoolProperty(name="Controls", default=True, description="Create control bones for the copy") + params.make_deforms = bpy.props.BoolProperty(name="Deform", default=True, description="Create deform bones for the copy") + + + @classmethod + def parameters_ui(self, layout, params): + """ Create the ui for the rig parameters. + """ + r = layout.row() + r.prop(params, "make_controls") + r = layout.row() + r.prop(params, "make_deforms") def create_sample(obj): diff --git a/rigify/rigs/basic/super_copy.py b/rigify/rigs/basic/super_copy.py index b2045346..5abbf22e 100644 --- a/rigify/rigs/basic/super_copy.py +++ b/rigify/rigs/basic/super_copy.py @@ -20,107 +20,112 @@ import bpy -from ...utils import copy_bone -from ...utils import strip_org, make_deformer_name -from ...utils import create_bone_widget, create_circle_widget +from ...base_rig import BaseRig +from ...utils.naming import strip_org, make_deformer_name +from ...utils.widgets_basic import create_bone_widget, create_circle_widget -class Rig: + +class Rig(BaseRig): """ A "copy" rig. All it does is duplicate the original bone and constrain it. This is a control and deformation rig. """ - def __init__(self, obj, bone, params): + def find_org_bones(self, pose_bone): + return pose_bone.name + + + def initialize(self): """ Gather and validate data about the rig. """ - self.obj = obj - self.org_bone = bone - self.org_name = strip_org(bone) - self.params = params - self.make_control = params.make_control - self.make_widget = params.make_widget - self.make_deform = params.make_deform - - def generate(self): - """ Generate the rig. - Do NOT modify any of the original bones, except for adding constraints. - The main armature should be selected and active before this is called. + self.org_name = strip_org(self.bones.org) - """ - bpy.ops.object.mode_set(mode='EDIT') + self.make_control = self.params.make_control + self.make_widget = self.params.make_widget + self.make_deform = self.params.make_deform + + + def generate_bones(self): + bones = self.bones # Make a control bone (copy of original). if self.make_control: - bone = copy_bone(self.obj, self.org_bone, self.org_name) + bones.ctrl = self.copy_bone(bones.org, self.org_name, parent=True) # Make a deformation bone (copy of original, child of original). if self.make_deform: - def_bone = copy_bone(self.obj, self.org_bone, make_deformer_name(self.org_name)) + bones.deform = self.copy_bone(bones.org, make_deformer_name(self.org_name), bbone=True) - # Get edit bones - eb = self.obj.data.edit_bones - # UNUSED - # if self.make_control: - # bone_e = eb[bone] - if self.make_deform: - def_bone_e = eb[def_bone] - # Parent + def parent_bones(self): + bones = self.bones + if self.make_deform: - def_bone_e.use_connect = False - def_bone_e.parent = eb[self.org_bone] + self.set_bone_parent(bones.deform, bones.org, use_connect=False) + - bpy.ops.object.mode_set(mode='OBJECT') - pb = self.obj.pose.bones + def configure_bones(self): + bones = self.bones + + if self.make_control: + self.copy_bone_properties(bones.org, bones.ctrl) + + + def rig_bones(self): + bones = self.bones if self.make_control: # Constrain the original bone. - con = pb[self.org_bone].constraints.new('COPY_TRANSFORMS') - con.name = "copy_transforms" - con.target = self.obj - con.subtarget = bone + self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl) + + def generate_widgets(self): + bones = self.bones + + if self.make_control: # Create control widget if self.make_widget: - create_circle_widget(self.obj, bone, radius=0.5) + create_circle_widget(self.obj, bones.ctrl, radius=0.5) else: - create_bone_widget(self.obj, bone) + create_bone_widget(self.obj, bones.ctrl) -def add_parameters(params): - """ Add the parameters of this rig type to the - RigifyParameters PropertyGroup - """ - params.make_control = bpy.props.BoolProperty( - name = "Control", - default = True, - description = "Create a control bone for the copy" - ) - - params.make_widget = bpy.props.BoolProperty( - name = "Widget", - default = True, - description = "Choose a widget for the bone control" - ) - - params.make_deform = bpy.props.BoolProperty( - name = "Deform", - default = True, - description = "Create a deform bone for the copy" - ) - - -def parameters_ui(layout, params): - """ Create the ui for the rig parameters. - """ - r = layout.row() - r.prop(params, "make_control") - r = layout.row() - r.prop(params, "make_widget") - r.enabled = params.make_control - r = layout.row() - r.prop(params, "make_deform") + @classmethod + def add_parameters(self, params): + """ Add the parameters of this rig type to the + RigifyParameters PropertyGroup + """ + params.make_control = bpy.props.BoolProperty( + name = "Control", + default = True, + description = "Create a control bone for the copy" + ) + + params.make_widget = bpy.props.BoolProperty( + name = "Widget", + default = True, + description = "Choose a widget for the bone control" + ) + + params.make_deform = bpy.props.BoolProperty( + name = "Deform", + default = True, + description = "Create a deform bone for the copy" + ) + + + @classmethod + def parameters_ui(self, layout, params): + """ Create the ui for the rig parameters. + """ + r = layout.row() + r.prop(params, "make_control") + r = layout.row() + r.prop(params, "make_widget") + r.enabled = params.make_control + r = layout.row() + r.prop(params, "make_deform") def create_sample(obj): @@ -159,3 +164,5 @@ def create_sample(obj): bone.select_head = True bone.select_tail = True arm.edit_bones.active = bone + + return bones diff --git a/rigify/rigs/chain_rigs.py b/rigify/rigs/chain_rigs.py new file mode 100644 index 00000000..3f53cd69 --- /dev/null +++ b/rigify/rigs/chain_rigs.py @@ -0,0 +1,387 @@ +#====================== BEGIN GPL LICENSE BLOCK ====================== +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +#======================= END GPL LICENSE BLOCK ======================== + +# <pep8 compliant> + +import bpy +from itertools import count + +from ..utils.rig import connected_children_names +from ..utils.naming import strip_org, make_derived_name +from ..utils.bones import put_bone, flip_bone, flip_bone_chain, is_same_position, is_connected_position +from ..utils.bones import copy_bone_position, connect_bbone_chain_handles +from ..utils.widgets_basic import create_bone_widget, create_sphere_widget +from ..utils.misc import map_list + +from ..base_rig import BaseRig, stage + + +class SimpleChainRig(BaseRig): + """A rig that consists of 3 connected chains of control, org and deform bones.""" + def find_org_bones(self, bone): + return [bone.name] + connected_children_names(self.obj, bone.name) + + def initialize(self): + if len(self.bones.org) <= 1: + self.raise_error("Input to rig type must be a chain of 2 or more bones.") + + def parent_bones(self): + self.rig_parent_bone = self.get_bone_parent(self.bones.org[0]) + + bbone_segments = None + + ############################## + # BONES + # + # org[]: + # ORG bones + # ctrl: + # fk[]: + # FK control chain. + # deform[]: + # DEF bones + # + ############################## + + ############################## + # Control chain + + @stage.generate_bones + def make_control_chain(self): + self.bones.ctrl.fk = map_list(self.make_control_bone, count(0), self.bones.org) + + def make_control_bone(self, i, org): + return self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True) + + @stage.parent_bones + def parent_control_chain(self): + self.parent_bone_chain(self.bones.ctrl.fk, use_connect=True) + + @stage.configure_bones + def configure_control_chain(self): + for args in zip(count(0), self.bones.ctrl.fk, self.bones.org): + self.configure_control_bone(*args) + + def configure_control_bone(self, i, ctrl, org): + self.copy_bone_properties(org, ctrl) + + @stage.generate_widgets + def make_control_widgets(self): + for ctrl in self.bones.ctrl.fk: + self.make_control_widget(ctrl) + + def make_control_widget(self, ctrl): + create_bone_widget(self.obj, ctrl) + + ############################## + # ORG chain + + @stage.parent_bones + def parent_org_chain(self): + pass + + @stage.rig_bones + def rig_org_chain(self): + for args in zip(count(0), self.bones.org, self.bones.ctrl.fk): + self.rig_org_bone(*args) + + def rig_org_bone(self, i, org, ctrl): + self.make_constraint(org, 'COPY_TRANSFORMS', ctrl) + + ############################## + # Deform chain + + @stage.generate_bones + def make_deform_chain(self): + self.bones.deform = map_list(self.make_deform_bone, count(0), self.bones.org) + + def make_deform_bone(self, i, org): + name = self.copy_bone(org, make_derived_name(org, 'def'), parent=True, bbone=True) + if self.bbone_segments: + self.get_bone(name).bbone_segments = self.bbone_segments + return name + + @stage.parent_bones + def parent_deform_chain(self): + self.parent_bone_chain(self.bones.deform, use_connect=True) + + @stage.rig_bones + def rig_deform_chain(self): + for args in zip(count(0), self.bones.deform, self.bones.org): + self.rig_deform_bone(*args) + + def rig_deform_bone(self, i, deform, org): + self.make_constraint(deform, 'COPY_TRANSFORMS', org) + + +class TweakChainRig(SimpleChainRig): + """A rig that adds tweak controls to the triple chain.""" + + ############################## + # BONES + # + # org[]: + # ORG bones + # ctrl: + # fk[]: + # FK control chain. + # tweak[]: + # Tweak control chain. + # deform[]: + # DEF bones + # + ############################## + + ############################## + # Tweak chain + + @stage.generate_bones + def make_tweak_chain(self): + orgs = self.bones.org + self.bones.ctrl.tweak = map_list(self.make_tweak_bone, count(0), orgs + orgs[-1:]) + + def make_tweak_bone(self, i, org): + name = self.copy_bone(org, 'tweak_' + strip_org(org), parent=False, scale=0.5) + + if i == len(self.bones.org): + put_bone(self.obj, name, self.get_bone(org).tail) + + return name + + @stage.parent_bones + def parent_tweak_chain(self): + ctrl = self.bones.ctrl + for tweak, main in zip(ctrl.tweak, ctrl.fk + ctrl.fk[-1:]): + self.set_bone_parent(tweak, main) + + @stage.configure_bones + def configure_tweak_chain(self): + for args in zip(count(0), self.bones.ctrl.tweak): + self.configure_tweak_bone(*args) + + def configure_tweak_bone(self, i, tweak): + tweak_pb = self.get_bone(tweak) + tweak_pb.rotation_mode = 'ZXY' + + if i == len(self.bones.org): + tweak_pb.lock_rotation_w = True + tweak_pb.lock_rotation = (True, True, True) + tweak_pb.lock_scale = (True, True, True) + else: + tweak_pb.lock_rotation_w = False + tweak_pb.lock_rotation = (True, False, True) + tweak_pb.lock_scale = (False, True, False) + + @stage.generate_widgets + def make_tweak_widgets(self): + for tweak in self.bones.ctrl.tweak: + self.make_tweak_widget(tweak) + + def make_tweak_widget(self, tweak): + create_sphere_widget(self.obj, tweak) + + ############################## + # ORG chain + + @stage.rig_bones + def rig_org_chain(self): + tweaks = self.bones.ctrl.tweak + for args in zip(count(0), self.bones.org, tweaks, tweaks[1:]): + self.rig_org_bone(*args) + + def rig_org_bone(self, i, org, tweak, next_tweak): + self.make_constraint(org, 'COPY_TRANSFORMS', tweak) + if next_tweak: + self.make_constraint(org, 'DAMPED_TRACK', next_tweak) + self.make_constraint(org, 'STRETCH_TO', next_tweak) + + +class ConnectingChainRig(TweakChainRig): + """Chain rig that can attach to an end of the parent, merging bbone chains.""" + + bbone_segments = 8 + use_connect_reverse = None + + def initialize(self): + super().initialize() + + self.use_connect_chain = self.params.connect_chain + self.connected_tweak = None + + if self.use_connect_chain: + first_org = self.bones.org[0] + parent = self.rigify_parent + parent_orgs = parent.bones.org + + if not isinstance(parent, SimpleChainRig): + self.raise_error("Cannot connect to non-chain parent rig.") + + ok_reverse = is_same_position(self.obj, parent_orgs[0], first_org) + ok_direct = is_connected_position(self.obj, parent_orgs[-1], first_org) + + if self.use_connect_reverse is None: + self.use_connect_reverse = ok_reverse and not ok_direct + + if not (ok_reverse if self.use_connect_reverse else ok_direct): + self.raise_error("Cannot connect chain - bone position is disjoint.") + + if isinstance(parent, ConnectingChainRig) and parent.use_connect_reverse: + self.raise_error("Cannot connect chain - parent is reversed.") + + def prepare_bones(self): + # Exactly match bone position to parent + if self.use_connect_chain: + first_bone = self.get_bone(self.bones.org[0]) + parent_orgs = self.rigify_parent.bones.org + + if self.use_connect_reverse: + first_bone.head = self.get_bone(parent_orgs[0]).head + else: + first_bone.head = self.get_bone(parent_orgs[-1]).tail + + def parent_bones(self): + # Use the parent of the shared tweak as the rig parent + root = self.connected_tweak or self.bones.org[0] + + self.rig_parent_bone = self.get_bone_parent(root) + + ############################## + # Control chain + + @stage.parent_bones + def parent_control_chain(self): + super().parent_control_chain() + + self.set_bone_parent(self.bones.ctrl.fk[0], self.rig_parent_bone) + + ############################## + # Tweak chain + + def check_connect_tweak(self, org): + """ Check if it is possible to share the last parent tweak control. """ + + assert self.connected_tweak is None + + if self.use_connect_chain and isinstance(self.rigify_parent, TweakChainRig): + # Share the last tweak bone of the parent rig + parent_tweaks = self.rigify_parent.bones.ctrl.tweak + index = 0 if self.use_connect_reverse else -1 + name = parent_tweaks[index] + + if not is_same_position(self.obj, name, org): + self.raise_error("Cannot connect tweaks - position mismatch.") + + if not self.use_connect_reverse: + copy_bone_position(self.obj, org, name, scale=0.5) + + name = self.rename_bone(name, 'tweak_' + strip_org(org)) + + self.connected_tweak = parent_tweaks[index] = name + + return name + else: + return None + + def make_tweak_bone(self, i, org): + if i == 0 and self.check_connect_tweak(org): + return self.connected_tweak + else: + return super().make_tweak_bone(i, org) + + @stage.parent_bones + def parent_tweak_chain(self): + ctrl = self.bones.ctrl + for i, tweak, main in zip(count(0), ctrl.tweak, ctrl.fk + ctrl.fk[-1:]): + if i > 0 or not (self.connected_tweak and self.use_connect_reverse): + self.set_bone_parent(tweak, main) + + def configure_tweak_bone(self, i, tweak): + super().configure_tweak_bone(i, tweak) + + if self.use_connect_chain and self.use_connect_reverse and i == len(self.bones.org): + tweak_pb = self.get_bone(tweak) + tweak_pb.lock_rotation_w = False + tweak_pb.lock_rotation = (True, False, True) + tweak_pb.lock_scale = (False, True, False) + + ############################## + # ORG chain + + @stage.parent_bones + def parent_org_chain(self): + if self.use_connect_chain and self.use_connect_reverse: + flip_bone_chain(self.obj, self.bones.org) + + for org, tweak in zip(self.bones.org, self.bones.ctrl.tweak[1:]): + self.set_bone_parent(org, tweak) + + else: + self.set_bone_parent(self.bones.org[0], self.rig_parent_bone) + + def rig_org_bone(self, i, org, tweak, next_tweak): + if self.use_connect_chain and self.use_connect_reverse: + self.make_constraint(org, 'DAMPED_TRACK', tweak) + self.make_constraint(org, 'STRETCH_TO', tweak) + else: + super().rig_org_bone(i, org, tweak, next_tweak) + + ############################## + # Deform chain + + def make_deform_bone(self, i, org): + name = super().make_deform_bone(i, org) + + if self.use_connect_chain and self.use_connect_reverse: + self.set_bone_parent(name, None) + flip_bone(self.obj, name) + + return name + + @stage.parent_bones + def parent_deform_chain(self): + if self.use_connect_chain: + deform = self.bones.deform + parent_deform = self.rigify_parent.bones.deform + + if self.use_connect_reverse: + self.set_bone_parent(deform[-1], self.bones.org[-1]) + self.parent_bone_chain(reversed(deform), use_connect=True) + + connect_bbone_chain_handles(self.obj, [ deform[0], parent_deform[0] ]) + return + + else: + self.set_bone_parent(deform[0], parent_deform[-1], use_connect=True) + + super().parent_deform_chain() + + ############################## + # Settings + + @classmethod + def add_parameters(self, params): + params.connect_chain = bpy.props.BoolProperty( + name='Connect chain', + default=False, + description='Connect the B-Bone chain to the parent rig' + ) + + @classmethod + def parameters_ui(self, layout, params): + r = layout.row() + r.prop(params, "connect_chain") diff --git a/rigify/rigs/experimental/super_chain.py b/rigify/rigs/experimental/super_chain.py index f3d0e182..592441fe 100644 --- a/rigify/rigs/experimental/super_chain.py +++ b/rigify/rigs/experimental/super_chain.py @@ -14,7 +14,7 @@ class Rig: def __init__(self, obj, bone_name, params): """ Chain with pivot Rig """ - eb = obj.data.edit_bones + eb = obj.data.bones self.obj = obj self.org_bones = [bone_name] + connected_children_names(obj, bone_name) diff --git a/rigify/rigs/faces/super_face.py b/rigify/rigs/faces/super_face.py index 7e36ce68..4eda647d 100644 --- a/rigify/rigs/faces/super_face.py +++ b/rigify/rigs/faces/super_face.py @@ -44,7 +44,7 @@ class Rig: grand_children += connected_children_names( self.obj, child ) self.org_bones = [bone_name] + children + grand_children - self.face_length = obj.data.edit_bones[ self.org_bones[0] ].length + self.face_length = obj.data.bones[ self.org_bones[0] ].length self.params = params if params.primary_layers_extra: diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 3b2f3658..aacc1e86 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -15,17 +15,8 @@ from ...utils.mechanism import make_property, make_driver from ..widgets import create_ikarrow_widget from math import trunc, pi -extra_script = """ -controls = [%s] -ctrl = '%s' - -if is_selected( controls ): - layout.prop( pose_bones[ ctrl ], '["%s"]') - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) -""" +from ...utils.switch_parent import SwitchParentBuilder + IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class # add_parameters and parameters_ui are unused for implementation classes @@ -561,35 +552,6 @@ class Rig: eb[ bones['ik']['mch_target'] ].parent = eb[ ctrl ] eb[ bones['ik']['mch_target'] ].use_connect = False - # MCH for ik control - ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket')) - eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head) - eb[ctrl_socket].parent = None - eb[ctrl].parent = eb[ctrl_socket] - - # MCH for pole ik control - ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket')) - eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head) - eb[ctrl_pole_socket].parent = None - eb[pole_target].parent = eb[ctrl_pole_socket] - - ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root')) - eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head) - eb[ctrl_root].use_connect = False - eb[ctrl_root].parent = eb['root'] - - if eb[org_bones[0]].parent: - arm_parent = eb[org_bones[0]].parent - ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent')) - eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head) - eb[ctrl_parent].use_connect = False - if eb[org_bones[0]].parent_recursive: - eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1] - else: - eb[ctrl_parent].parent = eb[org_bones[0]].parent - else: - arm_parent = None - mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) eb[mch_main_parent].length = eb[org_bones[0]].length / 12 @@ -597,30 +559,28 @@ class Rig: eb[mch_main_parent].roll = 0.0 eb[bones['main_parent']].parent = eb[mch_main_parent] - # Set up constraints + # Switchable parent + pbuilder = SwitchParentBuilder(self.rigify_generator) - # Constrain ik ctrl to root / parent + if eb[org_bones[0]].parent: + pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name) - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_root, - }) + pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True) - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_root, - }) + pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], ctrl, pole_target ] - if arm_parent: - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_parent, - }) + pbuilder.build_child( + self.rigify_wrapper, ctrl, + prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols, + ) - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_parent, - }) + pbuilder.build_child( + self.rigify_wrapper, pole_target, extra_parents=[ctrl], + prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols, + no_fix_rotation=True, no_fix_scale=True + ) + + # Set up constraints # Constrain mch target bone to the ik control and mch stretch make_constraint( self, bones['ik']['mch_target'], { @@ -675,10 +635,6 @@ class Rig: create_hand_widget(self.obj, ctrl, bone_transform_name=None) bones['ik']['ctrl']['terminal'] = [ctrl] - if arm_parent: - bones['ik']['mch_hand'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent] - else: - bones['ik']['mch_hand'] = [ctrl_socket, ctrl_pole_socket, ctrl_root] return bones @@ -687,13 +643,10 @@ class Rig: bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - ctrl = pb[bones['ik']['mch_hand'][0]] - ctrl_pole = pb[bones['ik']['mch_hand'][1]] - #owner = pb[bones['ik']['ctrl']['limb']] owner = pb[bones['main_parent']] - props = ["IK_follow", "root/parent", "pole_vector", "pole_follow"] + props = ["pole_vector"] for prop in props: @@ -723,30 +676,6 @@ class Rig: else: make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - elif prop == 'IK_follow': - make_property(owner, prop, True) - - make_driver(ctrl.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl.constraints) > 1: - make_driver(ctrl.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - make_driver(ctrl_pole.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl_pole.constraints) > 1: - make_driver(ctrl_pole.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - elif prop == 'root/parent': - if len(ctrl.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - - elif prop == 'pole_follow': - if len(ctrl_pole.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl_pole.constraints[1], "influence", variables=[(self.obj, owner, prop)]) @staticmethod def get_future_names(bones): @@ -822,22 +751,13 @@ class Rig: bones = self.create_arm(bones) self.create_drivers(bones) - controls = [bones['ik']['ctrl']['limb'], bones['ik']['ctrl']['terminal'][0]] - - controls.append(bones['main_parent']) - # Create UI - controls_string = ", ".join(["'" + x + "'" for x in controls]) - script = create_script(bones, 'arm') - script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', - 'pole_follow', 'pole_follow', 'root/parent', 'root/parent') return { 'script': [script], 'utilities': UTILITIES_RIG_ARM, 'register': REGISTER_RIG_ARM, - 'noparent_bones': [bones['ik']['mch_hand'][i] for i in [0,1]], } @@ -858,7 +778,7 @@ def add_parameters(params): default = 'automatic' ) - params.auto_align_extremity = bpy.BoolProperty( + params.auto_align_extremity = bpy.props.BoolProperty( name='auto_align_extremity', default=False, description="Auto Align Extremity Bone" diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index 2b846eca..59e6f799 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -17,17 +17,8 @@ from ...utils.mechanism import make_property, make_driver from ..widgets import create_ikarrow_widget from math import trunc, pi -extra_script = """ -controls = [%s] -ctrl = '%s' - -if is_selected( controls ): - layout.prop( pose_bones[ ctrl ], '["%s"]') - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) -""" +from ...utils.switch_parent import SwitchParentBuilder + IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class # add_parameters and parameters_ui are unused for implementation classes @@ -599,35 +590,6 @@ class Rig: eb[ctrl].parent = None eb[ctrl].use_connect = False - # MCH for ik control - ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket')) - eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head) - eb[ctrl_socket].parent = None - eb[ctrl].parent = eb[ctrl_socket] - - # MCH for pole ik control - ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket')) - eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head) - eb[ctrl_pole_socket].parent = None - eb[pole_target].parent = eb[ctrl_pole_socket] - - ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root')) - eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head) - eb[ctrl_root].use_connect = False - eb[ctrl_root].parent = eb['root'] - - if eb[org_bones[0]].parent: - leg_parent = eb[org_bones[0]].parent - ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent')) - eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head) - eb[ctrl_parent].use_connect = False - if eb[org_bones[0]].parent_recursive: - eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1] - else: - eb[ctrl_parent].parent = eb[org_bones[0]].parent - else: - leg_parent = None - mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) eb[mch_main_parent].length = eb[org_bones[0]].length / 12 @@ -658,6 +620,26 @@ class Rig: eb[ctrl].tail[2] = eb[ctrl].head[2] eb[ctrl].roll = 0 + # Switchable parent + pbuilder = SwitchParentBuilder(self.rigify_generator) + + if eb[org_bones[0]].parent: + pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name) + + pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True) + + pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], heel, ctrl, pole_target ] + + pbuilder.build_child( + self.rigify_wrapper, ctrl, + prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols, + ) + + pbuilder.build_child( + self.rigify_wrapper, pole_target, extra_parents=[(bones['ik']['mch_target'], ctrl)], + prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols, + no_fix_rotation=True, no_fix_scale=True + ) # Parent eb[ heel ].use_connect = False @@ -847,30 +829,6 @@ class Rig: # Set up constraints - # Constrain ik ctrl to root / parent - - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_root, - }) - - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_root, - }) - - if leg_parent: - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_parent, - 'influence' : 0.0, - }) - - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': bones['ik']['mch_target'], - }) - # Constrain mch target bone to the ik control and mch stretch make_constraint( self, bones['ik']['mch_target'], { 'constraint' : 'COPY_LOCATION', @@ -982,11 +940,6 @@ class Rig: bones['ik']['ctrl']['terminal'] += [ heel, ctrl ] - if leg_parent: - bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent] - else: - bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root] - return bones def create_drivers(self, bones): @@ -994,13 +947,10 @@ class Rig: bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - ctrl = pb[bones['ik']['mch_foot'][0]] - ctrl_pole = pb[bones['ik']['mch_foot'][1]] - #owner = pb[bones['ik']['ctrl']['limb']] owner = pb[bones['main_parent']] - props = ["IK_follow", "root/parent", "pole_vector", "pole_follow"] + props = ["pole_vector"] for prop in props: @@ -1031,31 +981,6 @@ class Rig: make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - elif prop == 'IK_follow': - make_property(owner, prop, True) - - make_driver(ctrl.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl.constraints) > 1: - make_driver(ctrl.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - make_driver(ctrl_pole.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl_pole.constraints) > 1: - make_driver(ctrl_pole.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - elif prop == 'root/parent': - if len(ctrl.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - - elif prop == 'pole_follow': - if len(ctrl_pole.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl_pole.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - @staticmethod def get_future_names(bones): @@ -1133,22 +1058,13 @@ class Rig: bones = self.create_leg(bones) self.create_drivers(bones) - controls = [bones['ik']['ctrl']['limb'], bones['ik']['ctrl']['terminal'][-1], bones['ik']['ctrl']['terminal'][-2] ] - - controls.append(bones['main_parent']) - # Create UI - controls_string = ", ".join(["'" + x + "'" for x in controls]) - script = create_script(bones, 'leg') - script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', - 'pole_follow', 'pole_follow', 'root/parent', 'root/parent') return { 'script': [script], 'utilities': UTILITIES_RIG_LEG, 'register': REGISTER_RIG_LEG, - 'noparent_bones': [bones['ik']['mch_foot'][i] for i in [0,1]], } diff --git a/rigify/rigs/limbs/super_limb.py b/rigify/rigs/limbs/super_limb.py index 3d2bb8e2..0d557bb7 100644 --- a/rigify/rigs/limbs/super_limb.py +++ b/rigify/rigs/limbs/super_limb.py @@ -21,6 +21,8 @@ class Rig: self.limb = pawRig(obj, bone_name, params) def generate(self): + self.limb.rigify_generator = self.rigify_generator + self.limb.rigify_wrapper = self.rigify_wrapper return self.limb.generate() diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py index 5afe15b0..ebc76fcb 100644 --- a/rigify/rigs/spines/super_spine.py +++ b/rigify/rigs/spines/super_spine.py @@ -8,6 +8,8 @@ from ...utils import MetarigError, make_mechanism_name, create_cube_widget from ...utils import ControlLayersOption from ...utils.mechanism import make_property, make_driver +from ...utils.switch_parent import SwitchParentBuilder + script = """ controls = [%s] torso = '%s' @@ -951,6 +953,14 @@ class Rig: bones['chest'] = self.create_chest(upper_torso_bones) bones['hips'] = self.create_hips(lower_torso_bones) + # Register viable parent bones + pbuilder = SwitchParentBuilder(self.rigify_generator) + pbuilder.register_parent(self.rigify_wrapper, bones['pivot']['ctrl'], name='Torso') + pbuilder.register_parent(self.rigify_wrapper, bone_chains['lower'][0], name='Hips') + pbuilder.register_parent(self.rigify_wrapper, bone_chains['upper'][-1], name='Chest') + if self.use_head: + pbuilder.register_parent(self.rigify_wrapper, bone_chains['neck'][-1], name='Head') + # TODO: Add create tail if tail_bones: bones['tail'] = self.create_tail(tail_bones) |