Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/rigify
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-12-22 18:27:27 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-12-22 18:52:04 +0300
commita50e8748493ac28723ce7dca502daf04de0afb0f (patch)
tree4e5d5d0ac3036ec1a760a2245480f9f8339c60e8 /rigify
parent86e03ba498290f2f6b9ae7a29defc2b290232260 (diff)
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.
Diffstat (limited to 'rigify')
-rw-r--r--rigify/base_generate.py28
-rw-r--r--rigify/generate.py4
-rw-r--r--rigify/rigs/basic/copy_chain.py30
-rw-r--r--rigify/rigs/basic/raw_copy.py188
-rw-r--r--rigify/rigs/basic/super_copy.py109
5 files changed, 227 insertions, 132 deletions
diff --git a/rigify/base_generate.py b/rigify/base_generate.py
index 651e0612..ea1415c9 100644
--- a/rigify/base_generate.py
+++ b/rigify/base_generate.py
@@ -219,6 +219,9 @@ class BaseGenerator:
# different rigs don't collide id's
self.rig_id = random_id(16)
+ # Table of renamed ORG bones
+ self.org_rename_table = dict()
+
def disable_auto_parent(self, bone_name):
"""Prevent automatically parenting the bone to root if parentless."""
@@ -231,6 +234,20 @@ class BaseGenerator:
self.layer_group_priorities[bone_name][i] = priority
+ def rename_org_bone(self, old_name, new_name):
+ assert self.stage == 'instantiate'
+ assert old_name == self.org_rename_table.get(old_name, None)
+ assert old_name not in self.bone_owners
+
+ bone = self.obj.data.bones[old_name]
+
+ bone.name = new_name
+ new_name = bone.name
+
+ self.org_rename_table[old_name] = new_name
+ return new_name
+
+
def __run_object_stage(self, method_name):
assert(self.context.active_object == self.obj)
assert(self.obj.mode == 'OBJECT')
@@ -431,9 +448,16 @@ class BaseGenerator:
assert(self.context.active_object == self.obj)
assert(self.obj.mode == 'OBJECT')
+ self.stage = 'instantiate'
+
+ # Compute the list of bones
+ bone_list = list_bone_names_depth_first_sorted(self.obj)
+
+ self.org_rename_table = {n: n for n in bone_list}
+
# Construct the rig instances
- for name in list_bone_names_depth_first_sorted(self.obj):
- self.__create_rigs(name, halt_on_missing)
+ for name in bone_list:
+ self.__create_rigs(self.org_rename_table[name], halt_on_missing)
# Connect rigs and bones into a tree
handled = {}
diff --git a/rigify/generate.py b/rigify/generate.py
index 8e3ca0f0..0fe89175 100644
--- a/rigify/generate.py
+++ b/rigify/generate.py
@@ -287,7 +287,9 @@ class Generator(base_generate.BaseGenerator):
and prop in obj.pose.bones[bone].keys():
tar.data_path = tar.data_path[7:]
else:
- tar.data_path = 'pose.bones["%s"]["%s"]' % (make_original_name(bone), prop)
+ org_name = make_original_name(bone)
+ org_name = self.org_rename_table.get(org_name, org_name)
+ tar.data_path = 'pose.bones["%s"]["%s"]' % (org_name, prop)
def __assign_widgets(self):
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
@@ -99,18 +93,6 @@ class Rig(SimpleChainRig):
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
@classmethod
@@ -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 ========================
+
+# <pep8 compliant>
+
+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):