[Bf-extensions-cvs] [9ffc56b3] master: Rigify: extract skin parent mechanism mixing into a generator class.

Alexander Gavrilov noreply at git.blender.org
Wed Aug 18 12:54:40 CEST 2021


Commit: 9ffc56b3b7fbc1b76ff50d32ab791d27f28b2d2b
Author: Alexander Gavrilov
Date:   Wed Aug 18 13:46:45 2021 +0300
Branches: master
https://developer.blender.org/rBA9ffc56b3b7fbc1b76ff50d32ab791d27f28b2d2b

Rigify: extract skin parent mechanism mixing into a generator class.

This allows cleanly avoiding reparent propagation between mirror
siblings, which causes weird deformation in chains.

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

M	rigify/rigs/skin/skin_nodes.py
M	rigify/rigs/skin/skin_parents.py
M	rigify/rigs/skin/stretchy_chain.py

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

diff --git a/rigify/rigs/skin/skin_nodes.py b/rigify/rigs/skin/skin_nodes.py
index 9fddb168..7d3f65eb 100644
--- a/rigify/rigs/skin/skin_nodes.py
+++ b/rigify/rigs/skin/skin_nodes.py
@@ -32,7 +32,7 @@ from ...utils.rig import get_parent_rigs
 
 from ...utils.node_merger import MainMergeNode, QueryMergeNode
 
-from .skin_parents import ControlBoneParentLayer, ControlBoneWeakParentLayer
+from .skin_parents import ControlBoneParentLayer, ControlBoneWeakParentLayer, ControlBoneParentMix
 from .skin_rigs import BaseSkinRig, BaseSkinChainRig
 
 
@@ -253,6 +253,8 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
 
         if isinstance(parent, ControlBoneParentLayer):
             parent.parent = self.intern_parent(node, parent.parent)
+        elif isinstance(parent, ControlBoneParentMix):
+            parent.parents = [self.intern_parent(node, p) for p in parent.parents]
 
         return parent
 
@@ -267,11 +269,9 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
         if parent not in requests:
             # If the actual reparent would be generated, weak parent will be needed.
             if self.has_weak_parent and not self.use_weak_parent:
-                if self.use_mix_parent or parent != self.node_parent:
+                if parent is not self.node_parent:
                     self.use_weak_parent = True
-
-                    for weak_parent in self.node_parent_list_weak:
-                        self.register_use_parent(weak_parent)
+                    self.register_use_parent(self.node_parent_weak)
 
             self.register_use_parent(parent)
             requests.append(parent)
@@ -308,24 +308,34 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
             self.matrix.translation = self.point
 
             # Create parents and decide if mix would be needed
-            parent_list = [node.build_parent(use=False) for node in mirror_sibling_list]
+            weak_parent_list = [node.build_parent(use=False) for node in mirror_sibling_list]
 
-            if all(parent == self.node_parent for parent in parent_list):
-                self.use_mix_parent = False
-                parent_list = [self.node_parent]
+            if all(parent == self.node_parent for parent in weak_parent_list):
+                weak_parent_list = [self.node_parent]
+                self.node_parent_weak = self.node_parent
             else:
-                self.use_mix_parent = True
+                self.node_parent_weak = ControlBoneParentMix(self.rig, self, weak_parent_list)
 
             # Prepare parenting without weak layers
-            self.use_weak_parent = False
-            self.node_parent_list_weak = parent_list
+            parent_list = [ControlBoneWeakParentLayer.strip(p) for p in weak_parent_list]
 
-            self.node_parent_list = [ControlBoneWeakParentLayer.strip(p) for p in parent_list]
+            self.use_weak_parent = False
             self.has_weak_parent = any((p is not pw)
-                                       for p, pw in zip(self.node_parent_list, parent_list))
+                                       for p, pw in zip(weak_parent_list, parent_list))
+
+            if not self.has_weak_parent:
+                self.node_parent = self.node_parent_weak
+            elif len(parent_list) > 1:
+                self.node_parent = ControlBoneParentMix(
+                    self.rig, self, parent_list, suffix='_mix_base')
+            else:
+                self.node_parent = parent_list[0]
+
+            # Mirror siblings share the mixed parent for reparent
+            self.register_use_parent(self.node_parent)
 
-            for parent in self.node_parent_list:
-                self.register_use_parent(parent)
+            for node in mirror_sibling_list:
+                node.node_parent = self.node_parent
 
         # All nodes
         if self.node_needs_parent or self.node_needs_reparent:
@@ -392,16 +402,8 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
                 self.weak_parent_bone = self.make_bone(
                     make_derived_name(self._control_bone, 'mch', '_weak_parent'), 1/2)
 
-            # Make mix parent if needed
-            self.reparent_bones = {}
-
-            if self.use_mix_parent:
-                self.mix_parent_bone = self.make_bone(
-                    make_derived_name(self._control_bone, 'mch', '_mix_parent'), 1/2)
-            else:
-                self.reparent_bones[id(self.node_parent)] = self._control_bone
-
             # Make requested reparents
+            self.reparent_bones = {id(self.node_parent): self._control_bone}
             self.reparent_bones_fake = set(self.reparent_bones.values())
 
             for parent in self.reparent_requests:
@@ -421,21 +423,12 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
 
     def parent_bones(self):
         if self.is_master_node:
-            if self.use_mix_parent:
-                self.set_bone_parent(self._control_bone, self.mix_parent_bone,
-                                     inherit_scale='AVERAGE')
-                self.rig.generator.disable_auto_parent(self.mix_parent_bone)
-            else:
-                self.set_bone_parent(self._control_bone, self.node_parent_list[0].output_bone,
-                                     inherit_scale='AVERAGE')
+            self.set_bone_parent(
+                self._control_bone, self.node_parent.output_bone, inherit_scale='AVERAGE')
 
             if self.use_weak_parent:
-                if self.use_mix_parent:
-                    self.rig.generator.disable_auto_parent(self.weak_parent_bone)
-                else:
-                    parent = self.node_parent_list_weak[0]
-                    self.set_bone_parent(self.weak_parent_bone, parent.output_bone,
-                                         inherit_scale=parent.inherit_scale_mode)
+                self.set_bone_parent(
+                    self.weak_parent_bone, self.node_parent_weak.output_bone, inherit_scale='FULL')
 
             for parent in self.reparent_requests:
                 bone = self.reparent_bones[id(parent)]
@@ -454,12 +447,6 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
 
     def rig_bones(self):
         if self.is_master_node:
-            # Rig the mixed parent
-            if self.use_mix_parent:
-                targets = [parent.output_bone for parent in self.node_parent_list]
-                self.make_constraint(self.mix_parent_bone, 'ARMATURE',
-                                     targets=targets, use_deform_preserve_volume=True)
-
             # Invoke parent rig callbacks
             for rig in reversed(self.rig.get_all_parent_skin_rigs()):
                 rig.extend_control_node_rig(self)
@@ -473,11 +460,6 @@ class ControlBoneNode(MainMergeNode, BaseSkinNode):
                 self.make_constraint(reparent_source, 'COPY_TRANSFORMS',
                                      self.control_bone, space='LOCAL')
 
-                if self.use_mix_parent:
-                    targets = [parent.output_bone for parent in self.node_parent_list_weak]
-                    self.make_constraint(self.weak_parent_bone, 'ARMATURE',
-                                         targets=targets, use_deform_preserve_volume=True)
-
                 set_bone_widget_transform(self.obj, self.control_bone, reparent_source)
 
             for parent in self.reparent_requests:
diff --git a/rigify/rigs/skin/skin_parents.py b/rigify/rigs/skin/skin_parents.py
index 0cfaec36..956c5ca3 100644
--- a/rigify/rigs/skin/skin_parents.py
+++ b/rigify/rigs/skin/skin_parents.py
@@ -145,6 +145,66 @@ class ControlBoneParentArmature(ControlBoneParentBase):
             self.make_constraint(self.output_bone, 'COPY_SCALE', self.copy_scale)
 
 
+class ControlBoneParentMix(ControlBoneParentBase):
+    """Combine multiple parent mechanisms using the Armature constraint."""
+
+    def __init__(self, rig, node, parents, *, suffix=None):
+        super().__init__(rig, node)
+
+        self.parents = []
+        self.parent_weights = []
+        self.suffix = suffix
+
+        self.add_parents(parents)
+
+    def add_parents(self, parents):
+        for item in parents:
+            if isinstance(item, tuple):
+                parent, weight = item
+            else:
+                parent, weight = item, 1
+
+            for i, cur in enumerate(self.parents):
+                if parent == cur:
+                    self.parent_weights[i] += weight
+                    break
+            else:
+                self.parents.append(parent)
+                self.parent_weights.append(weight)
+
+    def enable_component(self):
+        for parent in self.parents:
+            parent.enable_component()
+
+        super().enable_component()
+
+    def __eq__(self, other):
+        return (
+            isinstance(other, ControlBoneParentMix) and
+            self.parents == other.parents and
+            self.parent_weights == other.parent_weights
+        )
+
+    def generate_bones(self):
+        self.output_bone = self.node.make_bone(
+            make_derived_name(self.node.name, 'mch', self.suffix or '_mix'), 1/2, rig=self.rig)
+
+        self.rig.generator.disable_auto_parent(self.output_bone)
+
+    def parent_bones(self):
+        if len(self.parents) == 1:
+            self.set_bone_parent(self.output_bone, target)
+
+    def rig_bones(self):
+        if len(self.parents) > 1:
+            targets = [(p.output_bone, w) for p, w in zip(self.parents, self.parent_weights)]
+
+            self.make_constraint(
+                self.output_bone, 'ARMATURE', targets=targets,
+                use_deform_preserve_volume=True
+            )
+
+
 class ControlBoneParentLayer(ControlBoneParentBase):
     """Base class for parent generators that build on top of another mechanism."""
 
@@ -164,9 +224,6 @@ class ControlBoneWeakParentLayer(ControlBoneParentLayer):
     that have controls merged into this one.
     """
 
-    # Inherit mode used to parent the pseudo-control to the output of this generator.
-    inherit_scale_mode = 'AVERAGE'
-
     @staticmethod
     def strip(parent):
         while isinstance(parent, ControlBoneWeakParentLayer):
diff --git a/rigify/rigs/skin/stretchy_chain.py b/rigify/rigs/skin/str

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list