[Bf-extensions-cvs] [da8877fa] master: Fix T78193 (Rigify): use bone history tracking to find derived DEF bones.

Alexander Gavrilov noreply at git.blender.org
Mon Jun 29 19:45:53 CEST 2020


Commit: da8877fa8b295afba5a986bc710b862777fcfba3
Author: Alexander Gavrilov
Date:   Mon Jun 29 20:19:52 2020 +0300
Branches: master
https://developer.blender.org/rBAda8877fa8b295afba5a986bc710b862777fcfba3

Fix T78193 (Rigify): use bone history tracking to find derived DEF bones.

It is not really safe to assume that by swapping ORG to DEF you will
get a deform bone derived from the given ORG bone. The new base rig
API already tracks copying of bones, so polish it up and use here.

Note however that this tracking doesn't work with bones created
without self.copy_bone, e.g. by legacy rigs.

===================================================================

M	rigify/base_generate.py
M	rigify/base_rig.py
M	rigify/rigs/basic/raw_copy.py
M	rigify/rigs/limbs/super_palm.py
M	rigify/utils/naming.py

===================================================================

diff --git a/rigify/base_generate.py b/rigify/base_generate.py
index 7141d77e..22a35eae 100644
--- a/rigify/base_generate.py
+++ b/rigify/base_generate.py
@@ -62,6 +62,8 @@ class GeneratorPlugin(base_rig.GenerateCallbackHost, metaclass=SingletonPluginMe
 
     def register_new_bone(self, new_name, old_name=None):
         self.generator.bone_owners[new_name] = None
+        if old_name:
+            self.generator.derived_bones[old_name].add(new_name)
 
 
 #=============================================
@@ -201,6 +203,7 @@ class BaseGenerator:
         self.root_rigs = []
         # Map from bone names to their rigs
         self.bone_owners = {}
+        self.derived_bones = collections.defaultdict(set)
 
         # Set of plugins
         self.plugin_list = []
@@ -228,6 +231,32 @@ class BaseGenerator:
         self.noparent_bones.add(bone_name)
 
 
+    def find_derived_bones(self, bone_name, *, by_owner=False, recursive=True):
+        """Find which bones were copied from the specified one."""
+        if by_owner:
+            owner = self.bone_owners.get(bone_name, None)
+            if not owner:
+                return {}
+
+            table = owner.rigify_derived_bones
+        else:
+            table = self.derived_bones
+
+        if recursive:
+            result = set()
+
+            def rec(name):
+                for child in table.get(name, {}):
+                    result.add(child)
+                    rec(child)
+
+            rec(bone_name)
+
+            return result
+        else:
+            return set(table.get(bone_name, {}))
+
+
     def set_layer_group_priority(self, bone_name, layers, priority):
         for i, val in enumerate(layers):
             if val:
diff --git a/rigify/base_rig.py b/rigify/base_rig.py
index c4ddc128..056c2785 100644
--- a/rigify/base_rig.py
+++ b/rigify/base_rig.py
@@ -18,6 +18,8 @@
 
 # <pep8 compliant>
 
+import collections
+
 from .utils.errors import RaiseErrorMixin
 from .utils.bones import BoneDict, BoneUtilityMixin
 from .utils.mechanism import MechanismUtilityMixin
@@ -190,11 +192,15 @@ class BaseRig(GenerateCallbackHost, RaiseErrorMixin, BoneUtilityMixin, Mechanism
         self.rigify_child_bones = set()
         # Bones created by the rig (mapped to original names)
         self.rigify_new_bones = dict()
+        self.rigify_derived_bones = collections.defaultdict(set)
 
     def register_new_bone(self, new_name, old_name=None):
         """Registers this rig as the owner of this new bone."""
         self.rigify_new_bones[new_name] = old_name
         self.generator.bone_owners[new_name] = self
+        if old_name:
+            self.rigify_derived_bones[old_name].add(new_name)
+            self.generator.derived_bones[old_name].add(new_name)
 
     ###########################################################
     # Bone ownership
diff --git a/rigify/rigs/basic/raw_copy.py b/rigify/rigs/basic/raw_copy.py
index 3b45e090..afea51fc 100644
--- a/rigify/rigs/basic/raw_copy.py
+++ b/rigify/rigs/basic/raw_copy.py
@@ -20,7 +20,7 @@
 
 import bpy
 
-from ...utils.naming import strip_org, strip_prefix
+from ...utils.naming import strip_org, strip_prefix, choose_derived_bone
 
 from ...base_rig import BaseRig
 from ...base_generate import SubstitutionRig
@@ -83,15 +83,17 @@ class RelinkConstraintsMixin:
     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
+        elif spec in {'CTRL', 'DEF', 'MCH'}:
+            result = choose_derived_bone(self.generator, old_target, spec.lower())
+            if not result:
+                result = choose_derived_bone(self.generator, old_target, spec.lower(), by_owner=False)
+            if not result:
+                self.report_error("Cannot find derived {} bone of bone '{}' for relinking", spec, old_target)
+            return result
+        else:
+            if spec not in self.obj.pose.bones:
+                self.report_error("Cannot find bone '{}' for relinking", spec)
+            return spec
 
 
     @classmethod
diff --git a/rigify/rigs/limbs/super_palm.py b/rigify/rigs/limbs/super_palm.py
index 9c03b2fe..5756348c 100644
--- a/rigify/rigs/limbs/super_palm.py
+++ b/rigify/rigs/limbs/super_palm.py
@@ -25,7 +25,7 @@ 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.naming import strip_org, make_derived_name, choose_derived_bone
 from rigify.utils.widgets import create_widget
 from rigify.utils.misc import map_list
 
@@ -81,9 +81,9 @@ class Rig(BaseRig):
         self.rig_parent_bone = self.get_bone_parent(self.bones.org[0])
 
         # Parent to the deform bone of the parent if exists
-        def_bone = make_derived_name(self.rig_parent_bone, 'def')
+        def_bone = choose_derived_bone(self.generator, self.rig_parent_bone, 'def')
 
-        if def_bone in self.obj.data.bones:
+        if def_bone:
             self.rig_parent_bone = def_bone
 
     ####################################################
diff --git a/rigify/utils/naming.py b/rigify/utils/naming.py
index e5c1c573..17d7496c 100644
--- a/rigify/utils/naming.py
+++ b/rigify/utils/naming.py
@@ -307,3 +307,20 @@ def random_id(length=8):
         text += random.choice(chars)
     text += str(hex(int(time.time())))[2:][-tlength:].rjust(tlength, '0')[::-1]
     return text
+
+
+def choose_derived_bone(generator, original, subtype, *, by_owner=True, recursive=True):
+    bones = generator.obj.pose.bones
+    names = generator.find_derived_bones(original, by_owner=by_owner, recursive=recursive)
+
+    direct = make_derived_name(original, subtype)
+    if direct in names and direct in bones:
+        return direct
+
+    prefix = _PREFIX_TABLE[subtype] + '-'
+    matching = [ name for name in names if name.startswith(prefix) and name in bones ]
+
+    if len(matching) > 0:
+        return matching[0]
+
+    return None



More information about the Bf-extensions-cvs mailing list