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
diff options
context:
space:
mode:
Diffstat (limited to 'rigify/rigs/skin/skin_rigs.py')
-rw-r--r--rigify/rigs/skin/skin_rigs.py241
1 files changed, 241 insertions, 0 deletions
diff --git a/rigify/rigs/skin/skin_rigs.py b/rigify/rigs/skin/skin_rigs.py
new file mode 100644
index 00000000..a4bc361e
--- /dev/null
+++ b/rigify/rigs/skin/skin_rigs.py
@@ -0,0 +1,241 @@
+# ====================== 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 make_derived_name
+from ...utils.misc import force_lazy, LazyRef
+
+from ...base_rig import BaseRig, stage
+
+from .skin_parents import ControlBoneParentOrg
+
+
+class BaseSkinRig(BaseRig):
+ """
+ Base type for all rigs involved in the skin system.
+ This includes chain rigs and the parent provider rigs.
+ """
+
+ def initialize(self):
+ self.rig_parent_bone = self.get_bone_parent(self.base_bone)
+
+ ##########################
+ # Utilities
+
+ def get_parent_skin_rig(self):
+ """Find the closest BaseSkinRig parent."""
+ parent = self.rigify_parent
+
+ while parent:
+ if isinstance(parent, BaseSkinRig):
+ return parent
+ parent = parent.rigify_parent
+
+ return None
+
+ def get_all_parent_skin_rigs(self):
+ """Get a list of all BaseSkinRig parents, starting with this rig."""
+ items = []
+ current = self
+ while current:
+ items.append(current)
+ current = current.get_parent_skin_rig()
+ return items
+
+ def get_child_chain_parent_next(self, rig):
+ """
+ Retrieves the parent bone for the child chain rig
+ as determined by the parent skin rig.
+ """
+ if isinstance(self.rigify_parent, BaseSkinRig):
+ return self.rigify_parent.get_child_chain_parent(rig, self.rig_parent_bone)
+ else:
+ return self.rig_parent_bone
+
+ def build_control_node_parent_next(self, node):
+ """
+ Retrieves the parent mechanism generator for the child control node
+ as determined by the parent skin rig.
+ """
+ if isinstance(self.rigify_parent, BaseSkinRig):
+ return self.rigify_parent.build_control_node_parent(node, self.rig_parent_bone)
+ else:
+ return ControlBoneParentOrg(self.rig_parent_bone)
+
+ ##########################
+ # Methods to override
+
+ def get_child_chain_parent(self, rig, parent_bone):
+ """
+ Returns the (lazy) parent bone to use for the given child chain rig.
+ The parent_bone argument specifies the actual parent bone from caller.
+ """
+ return parent_bone
+
+ def build_control_node_parent(self, node, parent_bone):
+ """
+ Returns the parent mechanism generator for the child control node.
+ The parent_bone argument specifies the actual parent bone from caller.
+ Called during the initialize stage.
+ """
+ return ControlBoneParentOrg(self.get_child_chain_parent(node.rig, parent_bone))
+
+ def build_own_control_node_parent(self, node):
+ """
+ Returns the parent mechanism generator for nodes directly owned by this rig.
+ Called during the initialize stage.
+ """
+ return self.build_control_node_parent_next(node)
+
+ def extend_control_node_parent(self, parent, node):
+ """
+ First callback pass of adjustments to the parent mechanism generator for the given node.
+ Called for all BaseSkinRig parents in parent to child order during the initialize stage.
+ """
+ return parent
+
+ def extend_control_node_parent_post(self, parent, node):
+ """
+ Second callback pass of adjustments to the parent mechanism generator for the given node.
+ Called for all BaseSkinRig parents in child to parent order during the initialize stage.
+ """
+ return parent
+
+ def extend_control_node_rig(self, node):
+ """
+ A callback pass for adding constraints directly to the generated control.
+ Called for all BaseSkinRig parents in parent to child order during the rig stage.
+ """
+ pass
+
+
+def get_bone_quaternion(obj, bone):
+ return obj.pose.bones[bone].bone.matrix_local.to_quaternion()
+
+
+class BaseSkinChainRig(BaseSkinRig):
+ """
+ Base type for all skin rigs that can own control nodes, rather than
+ only modifying nodes of their children or other rigs.
+ """
+
+ chain_priority = 0
+
+ def initialize(self):
+ super().initialize()
+
+ if type(self).chain_priority is None:
+ self.chain_priority = self.params.skin_chain_priority
+
+ def parent_bones(self):
+ self.rig_parent_bone = force_lazy(self.get_child_chain_parent_next(self))
+
+ def get_final_control_node_rotation(self, node):
+ """Returns the orientation to use for the given control node owned by this rig."""
+ return self.get_control_node_rotation(node)
+
+ ##########################
+ # Methods to override
+
+ def get_control_node_rotation(self, node):
+ """
+ Returns the rig-specific orientation to use for the given control node of this rig,
+ if not overridden by the Orientation Bone option.
+ """
+ return get_bone_quaternion(self.obj, self.base_bone)
+
+ def get_control_node_layers(self, node):
+ """Returns the armature layers to use for the given control node owned by this rig."""
+ return self.get_bone(self.base_bone).bone.layers
+
+ def make_control_node_widget(self, node):
+ """Called to generate the widget for nodes with ControlNodeIcon.CUSTOM."""
+ raise NotImplementedError()
+
+ ##########################
+ # UI
+
+ @classmethod
+ def add_parameters(self, params):
+ params.skin_chain_priority = bpy.props.IntProperty(
+ name='Chain Priority',
+ min=-10, max=10, default=0,
+ description='When merging controls, chains with higher priority always win'
+ )
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ if self.chain_priority is None:
+ layout.prop(params, "skin_chain_priority")
+
+
+class BaseSkinChainRigWithRotationOption(BaseSkinChainRig):
+ """
+ Skin chain rig with an option to override the orientation to use
+ for controls via specifying an arbitrary template bone.
+ """
+
+ use_skin_control_orientation_bone = True
+
+ def get_final_control_node_rotation(self, node):
+ bone_name = self.params.skin_control_orientation_bone
+
+ if bone_name and self.use_skin_control_orientation_bone:
+ # Retrieve the orientation from the specified ORG bone
+ try:
+ org_name = make_derived_name(bone_name, 'org')
+
+ if org_name not in self.obj.pose.bones:
+ org_name = bone_name
+
+ return get_bone_quaternion(self.obj, org_name)
+
+ except KeyError:
+ self.raise_error('Could not find orientation bone {}', bone_name)
+
+ else:
+ # Use the rig-specific orientation
+ return self.get_control_node_rotation(node)
+
+ @classmethod
+ def add_parameters(self, params):
+ params.skin_control_orientation_bone = bpy.props.StringProperty(
+ name="Orientation Bone",
+ description="If set, control orientation is taken from the specified bone",
+ )
+
+ super().add_parameters(params)
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ if self.use_skin_control_orientation_bone:
+ from rigify.operators.copy_mirror_parameters import make_copy_parameter_button
+
+ row = layout.row()
+ row.prop_search(params, "skin_control_orientation_bone",
+ bpy.context.active_object.pose, "bones", text="Orientation")
+
+ make_copy_parameter_button(
+ row, "skin_control_orientation_bone", mirror_bone=True,
+ base_class=BaseSkinChainRigWithRotationOption
+ )
+
+ super().parameters_ui(layout, params)