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.
This commit is contained in:
parent
db23ff3d34
commit
da8877fa8b
Notes:
blender-bot
2023-02-14 18:53:22 +01:00
Referenced by issue #78193, Rigify: Strange Palm behavior when parent's Rig Type is set manually
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
####################################################
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue