From a50e8748493ac28723ce7dca502daf04de0afb0f Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 22 Dec 2019 18:27:27 +0300 Subject: Rigify: replace Rename To Deform with a new basic.raw_copy rig. Add a separate rig aimed at transferring bones from the metarig completely verbatim without the ORG prefix, and remove the hacky copy_chain/super_copy option for renaming ORG to DEF. Share the constraint retargeting feature between super_copy and raw_copy. --- rigify/rigs/basic/copy_chain.py | 30 +------ rigify/rigs/basic/raw_copy.py | 188 ++++++++++++++++++++++++++++++++++++++++ rigify/rigs/basic/super_copy.py | 109 ++--------------------- 3 files changed, 198 insertions(+), 129 deletions(-) create mode 100644 rigify/rigs/basic/raw_copy.py (limited to 'rigify/rigs') diff --git a/rigify/rigs/basic/copy_chain.py b/rigify/rigs/basic/copy_chain.py index a3920ced..232671f0 100644 --- a/rigify/rigs/basic/copy_chain.py +++ b/rigify/rigs/basic/copy_chain.py @@ -22,7 +22,6 @@ import bpy from ..chain_rigs import SimpleChainRig -from ...utils.layers import DEF_LAYER from ...utils.errors import MetarigError from ...utils.rig import connected_children_names from ...utils.naming import make_derived_name @@ -42,12 +41,7 @@ class Rig(SimpleChainRig): """ Gather and validate data about the rig. """ self.make_controls = self.params.make_controls - - deform = self.params.make_deforms - rename = self.params.rename_to_deform - - self.make_deforms = deform and not rename - self.rename_deforms = deform and rename + self.make_deforms = self.params.make_deforms ############################## # Control chain @@ -98,18 +92,6 @@ class Rig(SimpleChainRig): if self.make_deforms: super().rig_deform_chain() - ############################## - # Rename To Deform - - def finalize(self): - if self.rename_deform: - new_names = [ self.rename_bone(name, make_derived_name(name, 'def')) for name in self.bones.org ] - - for name in new_names: - bone = self.get_bone(name).bone - bone.use_deform = True - bone.layers = DEF_LAYER - ############################## # Parameter UI @@ -121,12 +103,6 @@ class Rig(SimpleChainRig): 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") - params.rename_to_deform = bpy.props.BoolProperty( - name = "Rename To Deform", - default = False, - description = "Rename the original bone itself to use as deform bone (advanced feature)" - ) - @classmethod def parameters_ui(self, layout, params): """ Create the ui for the rig parameters. @@ -136,10 +112,6 @@ class Rig(SimpleChainRig): r = layout.row() r.prop(params, "make_deforms") - if params.make_deforms: - r = layout.row() - r.prop(params, "rename_to_deform") - def create_sample(obj): """ Create a sample metarig for this rig type. diff --git a/rigify/rigs/basic/raw_copy.py b/rigify/rigs/basic/raw_copy.py new file mode 100644 index 00000000..3b45e090 --- /dev/null +++ b/rigify/rigs/basic/raw_copy.py @@ -0,0 +1,188 @@ +#====================== 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 ======================== + +# + +import bpy + +from ...utils.naming import strip_org, strip_prefix + +from ...base_rig import BaseRig +from ...base_generate import SubstitutionRig + +from itertools import repeat + + +class Rig(SubstitutionRig): + """ A raw copy rig, preserving the metarig bone as is, without the ORG prefix. """ + + def substitute(self): + # Strip the ORG prefix during the rig instantiation phase + new_name = strip_org(self.base_bone) + new_name = self.generator.rename_org_bone(self.base_bone, new_name) + + return [ self.instantiate_rig(InstanceRig, new_name) ] + + +class RelinkConstraintsMixin: + """ Utilities for constraint relinking. """ + + def relink_bone_constraints(self, bone_name): + if self.params.relink_constraints: + for con in self.get_bone(bone_name).constraints: + parts = con.name.split('@') + + if len(parts) > 1: + self.relink_constraint(con, parts[1:]) + + + def relink_bone_parent(self, bone_name): + if self.params.relink_constraints: + self.generator.disable_auto_parent(bone_name) + + parent_spec = self.params.parent_bone + if parent_spec: + old_parent = self.get_bone_parent(bone_name) + new_parent = self.find_relink_target(parent_spec, old_parent or '') or None + self.set_bone_parent(bone_name, new_parent) + return new_parent + + + def relink_constraint(self, con, specs): + if con.type == 'ARMATURE': + if len(specs) == 1: + specs = repeat(specs[0]) + elif len(specs) != len(con.targets): + self.report_error("Constraint {} actually has {} targets", con.name, len(con.targets)) + + for tgt, spec in zip(con.targets, specs): + tgt.subtarget = self.find_relink_target(spec, tgt.subtarget) + + else: + if len(specs) > 1: + self.report_error("Only the Armature constraint can have multiple '@' targets: {}", con.name) + + con.subtarget = self.find_relink_target(specs[0], con.subtarget) + + + def find_relink_target(self, spec, old_target): + if spec == '': + return old_target + elif spec == 'CTRL': + spec = strip_prefix(old_target) + elif spec in {'DEF', 'MCH'}: + spec = spec + '-' + strip_prefix(old_target) + + if spec not in self.obj.pose.bones: + self.report_error("Cannot find bone '{}' for relinking", spec) + + return spec + + + @classmethod + def add_relink_constraints_params(self, params): + params.relink_constraints = bpy.props.BoolProperty( + name = "Relink Constraints", + default = False, + description = "For constraints with names formed like 'base@bonename', use the part after '@' as the new subtarget after all bones are created. Use '@CTRL', '@DEF' or '@MCH' to simply replace the prefix" + ) + + params.parent_bone = bpy.props.StringProperty( + name = "Parent", + default = "", + description = "Replace the parent with a different bone after all bones are created. Using simply CTRL, DEF or MCH will replace the prefix instead" + ) + + @classmethod + def add_relink_constraints_ui(self, layout, params): + r = layout.row() + r.prop(params, "relink_constraints") + + if params.relink_constraints: + r = layout.row() + r.prop(params, "parent_bone") + + +class InstanceRig(BaseRig, RelinkConstraintsMixin): + def find_org_bones(self, pose_bone): + return pose_bone.name + + def initialize(self): + self.relink = self.params.relink_constraints + + def parent_bones(self): + self.relink_bone_parent(self.bones.org) + + def rig_bones(self): + self.relink_bone_constraints(self.bones.org) + + @classmethod + def add_parameters(self, params): + self.add_relink_constraints_params(params) + + @classmethod + def parameters_ui(self, layout, params): + col = layout.column() + col.label(text='This rig type does not add the ORG prefix.') + col.label(text='Manually add ORG, MCH or DEF as needed.') + + self.add_relink_constraints_ui(layout, params) + + +add_parameters = InstanceRig.add_parameters +parameters_ui = InstanceRig.parameters_ui + + +def create_sample(obj): + """ Create a sample metarig for this rig type. + """ + # generated by rigify.utils.write_metarig + bpy.ops.object.mode_set(mode='EDIT') + arm = obj.data + + bones = {} + + bone = arm.edit_bones.new('DEF-bone') + bone.head[:] = 0.0000, 0.0000, 0.0000 + bone.tail[:] = 0.0000, 0.0000, 0.2000 + bone.roll = 0.0000 + bone.use_connect = False + bones['DEF-bone'] = bone.name + + bpy.ops.object.mode_set(mode='OBJECT') + pbone = obj.pose.bones[bones['DEF-bone']] + pbone.rigify_type = 'basic.raw_copy' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + + bpy.ops.object.mode_set(mode='EDIT') + for bone in arm.edit_bones: + bone.select = False + bone.select_head = False + bone.select_tail = False + for b in bones: + bone = arm.edit_bones[bones[b]] + bone.select = True + bone.select_head = True + bone.select_tail = True + arm.edit_bones.active = bone + + return bones diff --git a/rigify/rigs/basic/super_copy.py b/rigify/rigs/basic/super_copy.py index f55dce68..07ad60b7 100644 --- a/rigify/rigs/basic/super_copy.py +++ b/rigify/rigs/basic/super_copy.py @@ -22,14 +22,13 @@ import bpy from ...base_rig import BaseRig -from ...utils.layers import DEF_LAYER from ...utils.naming import strip_org, make_deformer_name from ...utils.widgets_basic import create_bone_widget, create_circle_widget -from itertools import repeat +from .raw_copy import RelinkConstraintsMixin -class Rig(BaseRig): +class Rig(BaseRig, RelinkConstraintsMixin): """ A "copy" rig. All it does is duplicate the original bone and constrain it. This is a control and deformation rig. @@ -46,14 +45,7 @@ class Rig(BaseRig): self.make_control = self.params.make_control self.make_widget = self.params.make_widget - - deform = self.params.make_deform - rename = self.params.rename_to_deform - - self.make_deform = deform and not rename - self.rename_deform = deform and rename - - self.relink = self.params.relink_constraints + self.make_deform = self.params.make_deform def generate_bones(self): @@ -74,17 +66,10 @@ class Rig(BaseRig): if self.make_deform: self.set_bone_parent(bones.deform, bones.org, use_connect=False) - if self.relink: - self.generator.disable_auto_parent(bones.org) - - parent_spec = self.params.parent_bone - if parent_spec: - old_parent = self.get_bone_parent(bones.org) - new_parent = self.find_relink_target(parent_spec, old_parent or '') or None - self.set_bone_parent(bones.org, new_parent) + new_parent = self.relink_bone_parent(bones.org) - if self.make_control: - self.set_bone_parent(bones.ctrl, new_parent) + if self.make_control and new_parent: + self.set_bone_parent(bones.ctrl, new_parent) def configure_bones(self): @@ -97,54 +82,12 @@ class Rig(BaseRig): def rig_bones(self): bones = self.bones - if self.relink: - for con in self.get_bone(bones.org).constraints: - parts = con.name.split('@') - - if len(parts) > 1: - self.relink_constraint(con, parts[1:]) + self.relink_bone_constraints(bones.org) if self.make_control: # Constrain the original bone. self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl, insert_index=0) - def relink_constraint(self, con, specs): - if con.type == 'ARMATURE': - if len(specs) == 1: - specs = repeat(specs[0]) - elif len(specs) != len(con.specs): - self.report_error("Constraint {} actually has {} targets", con.name, len(con.targets)) - - for tgt, spec in zip(con.targets, specs): - tgt.subtarget = self.find_relink_target(spec, tgt.subtarget) - - else: - if len(specs) > 1: - self.report_error("Only the Armature constraint can have multiple '@' targets: {}", con.name) - - con.subtarget = self.find_relink_target(specs[0], con.subtarget) - - def find_relink_target(self, spec, old_target): - if spec == '': - return old_target - elif spec in {'DEF', 'MCH'}: - spec = spec + '-' + strip_org(old_target) - - if spec not in self.obj.pose.bones: - # Hack: allow referring to copy rigs using Rename To Deform as DEF - if old_target.startswith('ORG-') and spec == make_deformer_name(strip_org(old_target)): - from . import copy_chain - - owner = self.generator.bone_owners.get(old_target) - - if ((isinstance(owner, Rig) and owner.rename_deform) or - (isinstance(owner, copy_chain.Rig) and owner.rename_deforms)): - return old_target - - self.report_error("Cannot find bone '{}' for relinking", spec) - - return spec - def generate_widgets(self): bones = self.bones @@ -157,15 +100,6 @@ class Rig(BaseRig): create_bone_widget(self.obj, bones.ctrl) - def finalize(self): - if self.rename_deform: - new_name = self.rename_bone(self.bones.org, make_deformer_name(self.org_name)) - - bone = self.get_bone(new_name).bone - bone.use_deform = True - bone.layers = DEF_LAYER - - @classmethod def add_parameters(self, params): """ Add the parameters of this rig type to the @@ -189,23 +123,7 @@ class Rig(BaseRig): description = "Create a deform bone for the copy" ) - params.rename_to_deform = bpy.props.BoolProperty( - name = "Rename To Deform", - default = False, - description = "Rename the original bone itself to use as deform bone (advanced feature)" - ) - - params.relink_constraints = bpy.props.BoolProperty( - name = "Relink Constraints", - default = False, - description = "For constraints with names formed like 'base@bonename', use the part after '@' as the new subtarget after all bones are created. Use '@DEF' or '@MCH' to simply prepend the prefix" - ) - - params.parent_bone = bpy.props.StringProperty( - name = "Parent", - default = "", - description = "Replace the parent with a different bone after all bones are created. Using simply DEF or MCH will prepend the prefix instead" - ) + self.add_relink_constraints_params(params) @classmethod @@ -220,16 +138,7 @@ class Rig(BaseRig): r = layout.row() r.prop(params, "make_deform") - if params.make_deform: - r = layout.row() - r.prop(params, "rename_to_deform") - - r = layout.row() - r.prop(params, "relink_constraints") - - if params.relink_constraints: - r = layout.row() - r.prop(params, "parent_bone") + self.add_relink_constraints_ui(layout, params) def create_sample(obj): -- cgit v1.2.3