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')
-rw-r--r--rigify/rigs/basic/copy_chain.py33
-rw-r--r--rigify/rigs/basic/pivot.py236
-rw-r--r--rigify/rigs/basic/super_copy.py108
-rw-r--r--rigify/rigs/chain_rigs.py6
-rw-r--r--rigify/rigs/experimental/super_chain.py8
-rw-r--r--rigify/rigs/limbs/arm.py69
-rw-r--r--rigify/rigs/limbs/leg.py190
-rw-r--r--rigify/rigs/limbs/limb_rigs.py97
-rw-r--r--rigify/rigs/limbs/paw.py8
-rw-r--r--rigify/rigs/limbs/simple_tentacle.py2
-rw-r--r--rigify/rigs/limbs/super_finger.py42
-rw-r--r--rigify/rigs/limbs/super_palm.py3
-rw-r--r--rigify/rigs/spines/basic_spine.py145
-rw-r--r--rigify/rigs/spines/basic_tail.py7
-rw-r--r--rigify/rigs/spines/spine_rigs.py60
-rw-r--r--rigify/rigs/spines/super_head.py5
-rw-r--r--rigify/rigs/spines/super_spine.py4
17 files changed, 851 insertions, 172 deletions
diff --git a/rigify/rigs/basic/copy_chain.py b/rigify/rigs/basic/copy_chain.py
index 5145d735..a3920ced 100644
--- a/rigify/rigs/basic/copy_chain.py
+++ b/rigify/rigs/basic/copy_chain.py
@@ -22,9 +22,10 @@ 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 strip_org, make_deformer_name
+from ...utils.naming import make_derived_name
from ...utils.widgets_basic import create_bone_widget
from ...base_rig import BaseRig, stage
@@ -41,7 +42,12 @@ class Rig(SimpleChainRig):
""" Gather and validate data about the rig.
"""
self.make_controls = self.params.make_controls
- self.make_deforms = self.params.make_deforms
+
+ deform = self.params.make_deforms
+ rename = self.params.rename_to_deform
+
+ self.make_deforms = deform and not rename
+ self.rename_deforms = deform and rename
##############################
# Control chain
@@ -92,6 +98,20 @@ class Rig(SimpleChainRig):
if self.make_deforms:
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
def add_parameters(self, params):
@@ -101,6 +121,11 @@ 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):
@@ -111,6 +136,10 @@ 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/pivot.py b/rigify/rigs/basic/pivot.py
new file mode 100644
index 00000000..e5d31659
--- /dev/null
+++ b/rigify/rigs/basic/pivot.py
@@ -0,0 +1,236 @@
+#====================== 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 ...base_rig import BaseRig
+
+from ...utils.naming import make_derived_name
+from ...utils.bones import set_bone_widget_transform
+from ...utils.widgets_basic import create_cube_widget, create_pivot_widget
+from ...utils.switch_parent import SwitchParentBuilder
+
+
+class Rig(BaseRig):
+ """ A rig providing a rotation pivot control that can be moved. """
+ def find_org_bones(self, pose_bone):
+ return pose_bone.name
+
+
+ def initialize(self):
+ self.make_control = self.params.make_extra_control
+ self.make_pivot = self.params.make_control or not self.make_control
+ self.make_deform = self.params.make_extra_deform
+
+
+ def generate_bones(self):
+ org = self.bones.org
+
+ if self.make_control:
+ self.bones.ctrl.master = name = self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True)
+
+ if self.make_pivot:
+ self.bones.ctrl.pivot = self.copy_bone(org, make_derived_name(org, 'ctrl', '_pivot'))
+
+ if self.params.make_parent_switch:
+ self.build_parent_switch(name)
+
+ if self.params.register_parent:
+ self.register_parent(name, self.get_parent_tags())
+
+ else:
+ self.bones.ctrl.pivot = self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True)
+
+ if self.make_deform:
+ self.bones.deform = self.copy_bone(org, make_derived_name(org, 'def'), bbone=True)
+
+
+ def build_parent_switch(self, master_name):
+ pbuilder = SwitchParentBuilder(self.generator)
+
+ org_parent = self.get_bone_parent(self.bones.org)
+ parents = [org_parent] if org_parent else []
+
+ pbuilder.build_child(
+ self, master_name,
+ context_rig=self.rigify_parent, allow_self=True,
+ prop_name="Parent ({})".format(master_name),
+ extra_parents=parents, select_parent=org_parent,
+ controls=lambda: self.bones.ctrl.flatten()
+ )
+
+ def get_parent_tags(self):
+ tags = {t.strip() for t in self.params.register_parent_tags.split(',')}
+
+ if self.params.make_parent_switch:
+ tags.add('child')
+
+ tags.discard('')
+ return tags
+
+ def register_parent(self, master_name, tags):
+ pbuilder = SwitchParentBuilder(self.generator)
+
+ inject = self.rigify_parent if 'injected' in tags else None
+
+ pbuilder.register_parent(
+ self, self.bones.org, name=master_name,
+ inject_into=inject, tags=tags
+ )
+
+
+ def parent_bones(self):
+ ctrl = self.bones.ctrl
+
+ if self.make_pivot:
+ if self.make_control:
+ self.set_bone_parent(ctrl.pivot, ctrl.master, use_connect=False)
+
+ self.set_bone_parent(self.bones.org, ctrl.pivot, use_connect=False)
+
+ else:
+ self.set_bone_parent(self.bones.org, ctrl.master, use_connect=False)
+
+ if self.make_deform:
+ self.set_bone_parent(self.bones.deform, self.bones.org, use_connect=False)
+
+
+ def configure_bones(self):
+ if self.make_control:
+ self.copy_bone_properties(self.bones.org, self.bones.ctrl.master)
+
+ else:
+ self.copy_bone_properties(self.bones.org, self.bones.ctrl.pivot)
+
+
+ def rig_bones(self):
+ if self.make_pivot:
+ self.make_constraint(
+ self.bones.org, 'COPY_LOCATION', self.bones.ctrl.pivot,
+ space='LOCAL', invert_xyz=(True,)*3
+ )
+
+
+ def generate_widgets(self):
+ if self.make_pivot:
+ create_pivot_widget(self.obj, self.bones.ctrl.pivot, square=True, axis_size=2.0)
+
+ if self.make_control:
+ set_bone_widget_transform(self.obj, self.bones.ctrl.master, self.bones.org)
+
+ create_cube_widget(self.obj, self.bones.ctrl.master, radius=0.5)
+
+
+ @classmethod
+ def add_parameters(self, params):
+ params.make_control = bpy.props.BoolProperty(
+ name = "Control",
+ default = True,
+ description = "Create a control bone for the copy"
+ )
+
+ params.make_parent_switch = bpy.props.BoolProperty(
+ name = "Switchable Parent",
+ default = False,
+ description = "Allow switching the parent of the master control"
+ )
+
+ params.register_parent = bpy.props.BoolProperty(
+ name = "Register Parent",
+ default = False,
+ description = "Register the control as a switchable parent candidate"
+ )
+
+ params.register_parent_tags = bpy.props.StringProperty(
+ name = "Parent Tags",
+ default = "",
+ description = "Comma-separated tags to use for the registered parent"
+ )
+
+ params.make_extra_control = bpy.props.BoolProperty(
+ name = "Extra Control",
+ default = False,
+ description = "Create an optional control"
+ )
+
+ params.make_extra_deform = bpy.props.BoolProperty(
+ name = "Extra Deform",
+ default = False,
+ description = "Create an optional deform bone"
+ )
+
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ r = layout.row()
+ r.prop(params, "make_extra_control", text="Master Control")
+
+ if params.make_extra_control:
+ layout.prop(params, "make_parent_switch")
+ layout.prop(params, "register_parent")
+
+ r = layout.row()
+ r.active = params.register_parent
+ r.prop(params, "register_parent_tags", text="Tags")
+
+ layout.prop(params, "make_control", text="Pivot Control")
+
+ r = layout.row()
+ r.prop(params, "make_extra_deform", text="Deform Bone")
+
+
+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('pivot')
+ bone.head[:] = 0.0000, 0.0000, 0.0000
+ bone.tail[:] = 0.0000, 0.5000, 0.0000
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bones['pivot'] = bone.name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['pivot']]
+ pbone.rigify_type = 'basic.pivot'
+ 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 5abbf22e..f55dce68 100644
--- a/rigify/rigs/basic/super_copy.py
+++ b/rigify/rigs/basic/super_copy.py
@@ -22,9 +22,12 @@ 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
+
class Rig(BaseRig):
""" A "copy" rig. All it does is duplicate the original bone and
@@ -43,7 +46,14 @@ class Rig(BaseRig):
self.make_control = self.params.make_control
self.make_widget = self.params.make_widget
- self.make_deform = self.params.make_deform
+
+ 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
def generate_bones(self):
@@ -64,6 +74,18 @@ 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)
+
+ if self.make_control:
+ self.set_bone_parent(bones.ctrl, new_parent)
+
def configure_bones(self):
bones = self.bones
@@ -75,9 +97,53 @@ 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:])
+
if self.make_control:
# Constrain the original bone.
- self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl)
+ 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):
@@ -91,6 +157,15 @@ 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
@@ -114,6 +189,24 @@ 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"
+ )
+
@classmethod
def parameters_ui(self, layout, params):
@@ -127,6 +220,17 @@ 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")
+
def create_sample(obj):
""" Create a sample metarig for this rig type.
diff --git a/rigify/rigs/chain_rigs.py b/rigify/rigs/chain_rigs.py
index 3f53cd69..fc070eb1 100644
--- a/rigify/rigs/chain_rigs.py
+++ b/rigify/rigs/chain_rigs.py
@@ -82,10 +82,10 @@ class SimpleChainRig(BaseRig):
@stage.generate_widgets
def make_control_widgets(self):
- for ctrl in self.bones.ctrl.fk:
- self.make_control_widget(ctrl)
+ for args in zip(count(0), self.bones.ctrl.fk):
+ self.make_control_widget(*args)
- def make_control_widget(self, ctrl):
+ def make_control_widget(self, i, ctrl):
create_bone_widget(self.obj, ctrl)
##############################
diff --git a/rigify/rigs/experimental/super_chain.py b/rigify/rigs/experimental/super_chain.py
index df0facdf..3f7ca5d6 100644
--- a/rigify/rigs/experimental/super_chain.py
+++ b/rigify/rigs/experimental/super_chain.py
@@ -714,10 +714,10 @@ def add_parameters(params):
)
params.bbones = bpy.props.IntProperty(
- name='bbone segments',
- default=10,
- min=1,
- description='Number of segments'
+ name = 'B-Bone Segments',
+ default = 10,
+ min = 1,
+ description = 'Number of B-Bone segments'
)
params.wgt_offset = bpy.props.FloatProperty(
diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py
index 98a3c50f..e79edc5c 100644
--- a/rigify/rigs/limbs/arm.py
+++ b/rigify/rigs/limbs/arm.py
@@ -21,12 +21,15 @@
import bpy
from itertools import count
+from mathutils import Matrix
-from ...utils.bones import BoneDict, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis
+from ...utils.bones import put_bone, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis
from ...utils.naming import make_derived_name
from ...utils.misc import map_list
+from ...utils.widgets import adjust_widget_transform_mesh
from ..widgets import create_hand_widget
+from ...utils.widgets_basic import create_circle_widget
from ...base_rig import stage
@@ -42,6 +45,8 @@ class Rig(BaseLimbRig):
super().initialize()
+ self.make_wrist_pivot = self.params.make_ik_wrist_pivot
+
def prepare_bones(self):
orgs = self.bones.org.main
@@ -62,16 +67,76 @@ class Rig(BaseLimbRig):
def register_switch_parents(self, pbuilder):
super().register_switch_parents(pbuilder)
- pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True)
+ pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'})
def make_ik_ctrl_widget(self, ctrl):
create_hand_widget(self.obj, ctrl)
####################################################
+ # Palm Pivot
+
+ def get_ik_input_bone(self):
+ if self.make_wrist_pivot:
+ return self.bones.mch.ik_wrist
+ else:
+ return self.get_ik_control_output()
+
+ def get_extra_ik_controls(self):
+ controls = super().get_extra_ik_controls()
+ if self.make_wrist_pivot:
+ controls += [self.bones.ctrl.ik_wrist]
+ return controls
+
+ @stage.generate_bones
+ def make_wrist_pivot_control(self):
+ if self.make_wrist_pivot:
+ org = self.bones.org.main[2]
+ self.bones.ctrl.ik_wrist = self.make_wrist_pivot_bone(org)
+ self.bones.mch.ik_wrist = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_wrist'), scale=0.25)
+
+ def make_wrist_pivot_bone(self, org):
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik_wrist'), scale=0.5)
+ put_bone(self.obj, name, self.get_bone(org).tail)
+ return name
+
+ @stage.parent_bones
+ def parent_wrist_pivot_control(self):
+ if self.make_wrist_pivot:
+ ctrl = self.bones.ctrl.ik_wrist
+ self.set_bone_parent(ctrl, self.get_ik_control_output())
+ self.set_bone_parent(self.bones.mch.ik_wrist, ctrl)
+
+ @stage.generate_widgets
+ def make_wrist_pivot_widget(self):
+ if self.make_wrist_pivot:
+ ctrl = self.bones.ctrl.ik_wrist
+
+ if self.main_axis == 'x':
+ obj = create_circle_widget(self.obj, ctrl, head_tail=-0.3, head_tail_x=0.5)
+ else:
+ obj = create_circle_widget(self.obj, ctrl, head_tail=0.5, head_tail_x=-0.3)
+
+ if obj:
+ org_bone = self.get_bone(self.bones.org.main[2])
+ offset = org_bone.head - self.get_bone(ctrl).head
+ adjust_widget_transform_mesh(obj, Matrix.Translation(offset))
+
+ ####################################################
# Settings
@classmethod
+ def add_parameters(self, params):
+ super().add_parameters(params)
+
+ params.make_ik_wrist_pivot = bpy.props.BoolProperty(
+ name="IK Wrist Pivot", default=False,
+ description="Make an extra IK hand control pivoting around the tip of the hand"
+ )
+
+ @classmethod
def parameters_ui(self, layout, params):
+ layout.prop(params, "make_ik_wrist_pivot")
+
super().parameters_ui(layout, params, 'Hand')
diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py
index dbdd20cb..b409d009 100644
--- a/rigify/rigs/limbs/leg.py
+++ b/rigify/rigs/limbs/leg.py
@@ -22,13 +22,14 @@ import bpy
import math
from itertools import count
-from mathutils import Vector
+from mathutils import Vector, Matrix
from ...utils.rig import is_rig_base_bone
from ...utils.bones import align_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation
from ...utils.naming import make_derived_name
-from ...utils.misc import map_list
+from ...utils.misc import map_list, matrix_from_axis_roll, matrix_from_axis_pair
+from ...utils.widgets import adjust_widget_transform_mesh
from ..widgets import create_foot_widget, create_ballsocket_widget
@@ -62,10 +63,18 @@ class Rig(BaseLimbRig):
super().initialize()
+ self.pivot_type = self.params.foot_pivot_type
+ self.heel_euler_order = 'ZXY' if self.main_axis == 'x' else 'XZY'
+
+ assert self.pivot_type in {'ANKLE', 'TOE', 'ANKLE_TOE'}
+
def prepare_bones(self):
orgs = self.bones.org.main
+ foot = self.get_bone(orgs[2])
- foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, -1))
+ ik_y_axis = (0, 1, 0)
+ foot_y_axis = -self.vector_without_z(foot.y_axis)
+ foot_x = foot_y_axis.cross((0, 0, 1))
if self.params.rotation_axis == 'automatic':
align_chain_x_axis(self.obj, orgs[0:2])
@@ -84,6 +93,12 @@ class Rig(BaseLimbRig):
align_bone_z_axis(self.obj, orgs[2], foot_x)
align_bone_z_axis(self.obj, orgs[3], -foot_x)
+ else:
+ ik_y_axis = foot_y_axis
+
+ # Orientation of the IK main and roll control bones
+ self.ik_matrix = matrix_from_axis_roll(ik_y_axis, 0)
+ self.roll_matrix = matrix_from_axis_pair(ik_y_axis, foot_x, self.main_axis)
####################################################
# EXTRA BONES
@@ -92,6 +107,8 @@ class Rig(BaseLimbRig):
# heel:
# Heel location marker bone
# ctrl:
+ # ik_spin:
+ # Toe spin control.
# heel:
# Foot roll control
# mch:
@@ -104,31 +121,71 @@ class Rig(BaseLimbRig):
# IK controls
def get_extra_ik_controls(self):
- return [self.bones.ctrl.heel]
+ controls = super().get_extra_ik_controls() + [self.bones.ctrl.heel]
+ if self.pivot_type == 'ANKLE_TOE':
+ controls += [self.bones.ctrl.ik_spin]
+ return controls
def make_ik_control_bone(self, orgs):
name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
-
- if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
- align_bone_to_axis(self.obj, name, 'y', flip=True)
-
+ if self.pivot_type == 'TOE':
+ put_bone(self.obj, name, self.get_bone(name).tail, matrix=self.ik_matrix)
else:
- flip_bone(self.obj, name)
-
- bone = self.get_bone(name)
- bone.tail[2] = bone.head[2]
- bone.roll = 0
-
+ put_bone(self.obj, name, None, matrix=self.ik_matrix)
return name
+ def build_ik_pivot(self, ik_name, **args):
+ heel_bone = self.get_bone(self.bones.org.heel)
+ args = {
+ 'position': (heel_bone.head + heel_bone.tail)/2,
+ **args
+ }
+ return super().build_ik_pivot(ik_name, **args)
+
def register_switch_parents(self, pbuilder):
super().register_switch_parents(pbuilder)
- pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True)
+ pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'})
def make_ik_ctrl_widget(self, ctrl):
- create_foot_widget(self.obj, ctrl)
+ obj = create_foot_widget(self.obj, ctrl)
+ if self.pivot_type != 'TOE':
+ ctrl = self.get_bone(ctrl)
+ org = self.get_bone(self.bones.org.main[2])
+ offset = org.tail - (ctrl.custom_shape_transform or ctrl).head
+ adjust_widget_transform_mesh(obj, Matrix.Translation(offset))
+
+ ####################################################
+ # IK pivot controls
+
+ def get_ik_pivot_output(self):
+ if self.pivot_type == 'ANKLE_TOE':
+ return self.bones.ctrl.ik_spin
+ else:
+ return self.get_ik_control_output()
+
+ @stage.generate_bones
+ def make_ik_pivot_controls(self):
+ if self.pivot_type == 'ANKLE_TOE':
+ self.bones.ctrl.ik_spin = self.make_ik_spin_bone(self.bones.org.main)
+
+ def make_ik_spin_bone(self, orgs):
+ name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_spin_ik'))
+ put_bone(self.obj, name, self.get_bone(orgs[3]).head, matrix=self.ik_matrix, scale=0.5)
+ return name
+
+ @stage.parent_bones
+ def parent_ik_pivot_controls(self):
+ if self.pivot_type == 'ANKLE_TOE':
+ self.set_bone_parent(self.bones.ctrl.ik_spin, self.get_ik_control_output())
+
+ @stage.generate_widgets
+ def make_ik_spin_control_widget(self):
+ if self.pivot_type == 'ANKLE_TOE':
+ obj = create_ballsocket_widget(self.obj, self.bones.ctrl.ik_spin, size=0.75)
+ rotfix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper())
+ adjust_widget_transform_mesh(obj, rotfix, local=True)
####################################################
# Heel control
@@ -136,25 +193,19 @@ class Rig(BaseLimbRig):
@stage.generate_bones
def make_heel_control_bone(self):
org = self.bones.org.main[2]
- name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'), scale=1/2)
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'))
+ put_bone(self.obj, name, None, matrix=self.roll_matrix, scale=0.5)
self.bones.ctrl.heel = name
- self.align_roll_bone(org, name, -self.vector_without_z(self.get_bone(org).vector))
-
@stage.parent_bones
def parent_heel_control_bone(self):
- self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik)
+ self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_pivot_output(), inherit_scale='AVERAGE')
@stage.configure_bones
def configure_heel_control_bone(self):
bone = self.get_bone(self.bones.ctrl.heel)
bone.lock_location = True, True, True
-
- if self.main_axis == 'x':
- bone.lock_rotation = False, False, True
- else:
- bone.lock_rotation = True, False, False
-
+ bone.rotation_mode = self.heel_euler_order
bone.lock_scale = True, True, True
@stage.generate_widgets
@@ -173,34 +224,27 @@ class Rig(BaseLimbRig):
def make_roll_mch_bones(self, foot, toe, heel):
foot_bone = self.get_bone(foot)
heel_bone = self.get_bone(heel)
- axis = -self.vector_without_z(foot_bone.vector)
-
- roll1 = self.copy_bone(foot, make_derived_name(heel, 'mch', '_roll1'))
- flip_bone(self.obj, roll1)
- self.align_roll_bone(foot, roll1, -foot_bone.vector)
+ heel_middle = (heel_bone.head + heel_bone.tail) / 2
- roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=1/4)
-
- put_bone(self.obj, roll2, (heel_bone.head + heel_bone.tail) / 2)
- self.align_roll_bone(foot, roll2, -axis)
+ result = self.copy_bone(foot, make_derived_name(foot, 'mch', '_roll'), scale=0.25)
+ roll1 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll1'), scale=0.3)
+ roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=0.3)
rock1 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock1'))
-
- align_bone_to_axis(self.obj, rock1, 'y', roll=0, length=heel_bone.length/2, flip=True)
- align_bone_y_axis(self.obj, rock1, axis)
-
rock2 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock2'))
- align_bone_to_axis(self.obj, rock2, 'y', roll=0, length=heel_bone.length/2)
- align_bone_y_axis(self.obj, rock2, axis)
+ put_bone(self.obj, roll1, None, matrix=self.roll_matrix)
+ put_bone(self.obj, roll2, heel_middle, matrix=self.roll_matrix)
+ put_bone(self.obj, rock1, heel_bone.tail, matrix=self.roll_matrix, scale=0.5)
+ put_bone(self.obj, rock2, heel_bone.head, matrix=self.roll_matrix, scale=0.5)
- return [ rock2, rock1, roll2, roll1 ]
+ return [ rock2, rock1, roll2, roll1, result ]
@stage.parent_bones
def parent_roll_mch_chain(self):
chain = self.bones.mch.heel
- self.set_bone_parent(chain[0], self.bones.ctrl.ik)
+ self.set_bone_parent(chain[0], self.get_ik_pivot_output())
self.parent_bone_chain(chain)
@stage.rig_bones
@@ -208,28 +252,37 @@ class Rig(BaseLimbRig):
self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel)
def rig_roll_mch_bones(self, chain, heel, org_heel):
- rock2, rock1, roll2, roll1 = chain
+ rock2, rock1, roll2, roll1, result = chain
+
+ # This order is required for correct working of the constraints
+ for bone in chain:
+ self.get_bone(bone).rotation_mode = self.heel_euler_order
- self.make_constraint(roll1, 'COPY_ROTATION', heel, space='LOCAL')
- self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL')
+ self.make_constraint(roll1, 'COPY_ROTATION', heel, space='POSE')
if self.main_axis == 'x':
- self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_x=True, max_x=DEG_360, space='LOCAL')
- self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_x=-DEG_360, space='LOCAL')
+ self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(True, False, False))
+ self.make_constraint(roll2, 'LIMIT_ROTATION', min_x=-DEG_360, space='LOCAL')
else:
- self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_z=True, max_z=DEG_360, space='LOCAL')
- self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_z=-DEG_360, space='LOCAL')
+ self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(False, False, True))
+ self.make_constraint(roll2, 'LIMIT_ROTATION', min_z=-DEG_360, space='LOCAL')
direction = self.get_main_axis(self.get_bone(heel)).dot(self.get_bone(org_heel).vector)
if direction < 0:
rock2, rock1 = rock1, rock2
- self.make_constraint(rock1, 'COPY_ROTATION', heel, space='LOCAL')
- self.make_constraint(rock2, 'COPY_ROTATION', heel, space='LOCAL')
+ self.make_constraint(
+ rock1, 'COPY_ROTATION', heel, space='LOCAL',
+ use_xyz=(False, True, False),
+ )
+ self.make_constraint(
+ rock2, 'COPY_ROTATION', heel, space='LOCAL',
+ use_xyz=(False, True, False),
+ )
- self.make_constraint(rock1, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, max_y=DEG_360, space='LOCAL')
- self.make_constraint(rock2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_y=-DEG_360, space='LOCAL')
+ self.make_constraint(rock1, 'LIMIT_ROTATION', max_y=DEG_360, space='LOCAL')
+ self.make_constraint(rock2, 'LIMIT_ROTATION', min_y=-DEG_360, space='LOCAL')
####################################################
@@ -237,7 +290,7 @@ class Rig(BaseLimbRig):
def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
if i == 3:
- align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[-2])
+ align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[2])
self.set_bone_parent(parent_mch, prev_org, use_connect=True)
@@ -246,7 +299,7 @@ class Rig(BaseLimbRig):
def rig_fk_parent_bone(self, i, parent_mch, org):
if i == 3:
- con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[-2])
+ con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[2])
self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
@@ -257,8 +310,6 @@ class Rig(BaseLimbRig):
####################################################
# IK system MCH
- ik_input_head_tail = 1.0
-
def get_ik_input_bone(self):
return self.bones.mch.heel[-1]
@@ -266,14 +317,35 @@ class Rig(BaseLimbRig):
def parent_ik_mch_chain(self):
super().parent_ik_mch_chain()
- self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
+ self.set_bone_parent(self.bones.mch.ik_target, self.bones.mch.heel[-1])
####################################################
# Settings
@classmethod
+ def add_parameters(self, params):
+ super().add_parameters(params)
+
+ items = [
+ ('ANKLE', 'Ankle',
+ 'The foots pivots at the ankle'),
+ ('TOE', 'Toe',
+ 'The foot pivots around the base of the toe'),
+ ('ANKLE_TOE', 'Ankle and Toe',
+ 'The foots pivots at the ankle, with extra toe pivot'),
+ ]
+
+ params.foot_pivot_type = bpy.props.EnumProperty(
+ items = items,
+ name = "Foot Pivot",
+ default = 'ANKLE_TOE'
+ )
+
+ @classmethod
def parameters_ui(self, layout, params):
+ layout.prop(params, 'foot_pivot_type')
+
super().parameters_ui(layout, params, 'Foot')
diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py
index 81079c05..f1eb8639 100644
--- a/rigify/rigs/limbs/limb_rigs.py
+++ b/rigify/rigs/limbs/limb_rigs.py
@@ -23,12 +23,12 @@ import json
from ...utils.animation import add_generic_snap_fk_to_ik, add_fk_ik_snap_buttons
from ...utils.rig import connected_children_names
-from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation
-from ...utils.bones import align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
+from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation, set_bone_widget_transform
from ...utils.naming import strip_org, make_derived_name
from ...utils.layers import ControlLayersOption
from ...utils.misc import pairwise_nozip, padnone, map_list
from ...utils.switch_parent import SwitchParentBuilder
+from ...utils.components import CustomPivotControl
from ...base_rig import stage, BaseRig
@@ -64,6 +64,7 @@ class BaseLimbRig(BaseRig):
self.segments = self.params.segments
self.bbone_segments = self.params.bbones
+ self.use_ik_pivot = self.params.make_custom_pivot
rot_axis = self.params.rotation_axis
@@ -124,15 +125,6 @@ class BaseLimbRig(BaseRig):
bone = self.get_bone(org)
return bone.head + bone.vector * (seg / self.segments)
- def align_roll_bone(self, org, name, y_axis):
- if y_axis:
- align_bone_y_axis(self.obj, name, y_axis)
-
- if self.main_axis == 'x':
- align_bone_x_axis(self.obj, name, self.get_bone(org).x_axis)
- else:
- align_bone_z_axis(self.obj, name, self.get_bone(org).z_axis)
-
@staticmethod
def vector_without_z(vector):
return Vector((vector[0], vector[1], 0))
@@ -154,6 +146,8 @@ class BaseLimbRig(BaseRig):
# IK controls
# ik_vispole
# IK pole visualization.
+ # ik_pivot
+ # Custom IK pivot (optional).
# mch:
# master:
# Parent of the master control.
@@ -161,6 +155,8 @@ class BaseLimbRig(BaseRig):
# FK follow behavior.
# fk[]:
# FK chain parents (or None)
+ # ik_pivot
+ # Custom IK pivot result (optional).
# ik_stretch
# IK stretch switch implementation.
# ik_target
@@ -328,22 +324,30 @@ class BaseLimbRig(BaseRig):
# IK controls
def get_extra_ik_controls(self):
- return []
+ if self.component_ik_pivot:
+ return [self.component_ik_pivot.control]
+ else:
+ return []
def get_all_ik_controls(self):
ctrl = self.bones.ctrl
- return [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + self.get_extra_ik_controls()
+ controls = [ctrl.ik_base, ctrl.ik_pole, ctrl.ik]
+ return controls + self.get_extra_ik_controls()
@stage.generate_bones
def make_ik_controls(self):
orgs = self.bones.org.main
- self.bones.ctrl.ik_base = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik'))
+ self.bones.ctrl.ik_base = self.make_ik_base_bone(orgs)
self.bones.ctrl.ik_pole = self.make_ik_pole_bone(orgs)
- self.bones.ctrl.ik = self.make_ik_control_bone(orgs)
+ self.bones.ctrl.ik = ik_name = self.make_ik_control_bone(orgs)
+ self.component_ik_pivot = self.build_ik_pivot(ik_name)
self.build_ik_parent_switch(SwitchParentBuilder(self.generator))
+ def make_ik_base_bone(self, orgs):
+ return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik'))
+
def make_ik_pole_bone(self, orgs):
name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik_target'))
@@ -357,10 +361,25 @@ class BaseLimbRig(BaseRig):
def make_ik_control_bone(self, orgs):
return self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
+ def build_ik_pivot(self, ik_name, **args):
+ if self.use_ik_pivot:
+ return CustomPivotControl(self, 'ik_pivot', ik_name, parent=ik_name, **args)
+
+ def get_ik_control_output(self):
+ if self.component_ik_pivot:
+ return self.component_ik_pivot.output
+ else:
+ return self.bones.ctrl.ik
+
def register_switch_parents(self, pbuilder):
if self.rig_parent_bone:
pbuilder.register_parent(self, self.rig_parent_bone)
+ pbuilder.register_parent(
+ self, self.get_ik_control_output, name=self.bones.ctrl.ik,
+ exclude_self=True, tags={'limb_ik', 'child'},
+ )
+
def build_ik_parent_switch(self, pbuilder):
ctrl = self.bones.ctrl
@@ -398,9 +417,13 @@ class BaseLimbRig(BaseRig):
@stage.generate_widgets
def make_ik_control_widgets(self):
- self.make_ik_base_widget(self.bones.ctrl.ik_base)
- self.make_ik_pole_widget(self.bones.ctrl.ik_pole)
- self.make_ik_ctrl_widget(self.bones.ctrl.ik)
+ ctrl = self.bones.ctrl
+
+ set_bone_widget_transform(self.obj, ctrl.ik, self.get_ik_control_output())
+
+ self.make_ik_base_widget(ctrl.ik_base)
+ self.make_ik_pole_widget(ctrl.ik_pole)
+ self.make_ik_ctrl_widget(ctrl.ik)
def make_ik_base_widget(self, ctrl):
if self.main_axis == 'x':
@@ -453,7 +476,7 @@ class BaseLimbRig(BaseRig):
ik_input_head_tail = 0.0
def get_ik_input_bone(self):
- return self.bones.ctrl.ik
+ return self.get_ik_control_output()
def get_ik_output_chain(self):
return [self.bones.ctrl.ik_base, self.bones.mch.ik_end, self.bones.mch.ik_target]
@@ -670,7 +693,13 @@ class BaseLimbRig(BaseRig):
@stage.parent_bones
def parent_tweak_mch_chain(self):
- for mch, entry in zip(self.bones.mch.tweak, self.segment_table_tweak):
+ for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak):
+ self.parent_tweak_mch_bone(*args)
+
+ def parent_tweak_mch_bone(self, i, mch, entry):
+ if i == 0:
+ self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='FIX_SHEAR')
+ else:
self.set_bone_parent(mch, entry.org)
@stage.rig_bones
@@ -694,6 +723,10 @@ class BaseLimbRig(BaseRig):
elif entry.seg_idx is not None:
self.make_constraint(tweak, 'COPY_SCALE', 'root', use_make_uniform=True)
+ if i == 0:
+ self.make_constraint(tweak, 'COPY_LOCATION', entry.org)
+ self.make_constraint(tweak, 'DAMPED_TRACK', entry.org, head_tail=1)
+
####################################################
# Deform chain
@@ -786,17 +819,23 @@ class BaseLimbRig(BaseRig):
)
params.segments = bpy.props.IntProperty(
- name = 'limb segments',
+ name = 'Limb Segments',
default = 2,
min = 1,
- description = 'Number of segments'
+ description = 'Number of limb segments'
)
params.bbones = bpy.props.IntProperty(
- name = 'bbone segments',
+ name = 'B-Bone Segments',
default = 10,
min = 1,
- description = 'Number of segments'
+ description = 'Number of B-Bone segments'
+ )
+
+ params.make_custom_pivot = bpy.props.BoolProperty(
+ name = "Custom Pivot Control",
+ default = False,
+ description = "Create a rotation pivot control that can be repositioned arbitrarily"
)
# Setting up extra layers for the FK and tweak
@@ -820,6 +859,8 @@ class BaseLimbRig(BaseRig):
r = layout.row()
r.prop(params, "bbones")
+ layout.prop(params, 'make_custom_pivot', text="Custom IK Pivot")
+
ControlLayersOption.FK.parameters_ui(layout, params)
ControlLayersOption.TWEAK.parameters_ui(layout, params)
@@ -843,8 +884,6 @@ class RigifyLimbIk2FkBase:
ctrl_bones: StringProperty(name="IK Controls")
extra_ctrls: StringProperty(name="Extra IK Controls")
- keyflags = None
-
def init_execute(self, context):
if self.fk_bones:
self.fk_bone_list = json.loads(self.fk_bones)
@@ -921,13 +960,11 @@ class RigifyLimbIk2FkBase:
class POSE_OT_rigify_limb_ik2fk(RigifyLimbIk2FkBase, RigifySingleUpdateMixin, bpy.types.Operator):
bl_idname = "pose.rigify_limb_ik2fk_" + rig_id
bl_label = "Snap IK->FK"
- bl_options = {'UNDO', 'INTERNAL'}
bl_description = "Snap the IK chain to FK result"
class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
bl_idname = "pose.rigify_limb_ik2fk_bake_" + rig_id
bl_label = "Apply Snap IK->FK To Keyframes"
- bl_options = {'UNDO', 'INTERNAL'}
bl_description = "Snap the IK chain keyframes to FK result"
def execute_scan_curves(self, context, obj):
@@ -968,8 +1005,6 @@ SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + ['''
class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
use_pole: bpy.props.BoolProperty(name="Use Pole Vector")
- keyflags_switch = None
-
def save_frame_state(self, context, obj):
return get_chain_transform_matrices(obj, self.ik_bone_list)
@@ -1007,13 +1042,11 @@ class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
class POSE_OT_rigify_limb_toggle_pole(RigifyLimbTogglePoleBase, RigifySingleUpdateMixin, bpy.types.Operator):
bl_idname = "pose.rigify_limb_toggle_pole_" + rig_id
bl_label = "Toggle Pole"
- bl_options = {'UNDO', 'INTERNAL'}
bl_description = "Switch the IK chain between pole and rotation"
class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
bl_idname = "pose.rigify_limb_toggle_pole_bake_" + rig_id
bl_label = "Apply Toggle Pole To Keyframes"
- bl_options = {'UNDO', 'INTERNAL'}
bl_description = "Switch the IK chain between pole and rotation over a frame range"
def execute_scan_curves(self, context, obj):
diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py
index f8cb1f9f..28374eec 100644
--- a/rigify/rigs/limbs/paw.py
+++ b/rigify/rigs/limbs/paw.py
@@ -84,7 +84,7 @@ class Rig(BaseLimbRig):
# IK controls
def get_extra_ik_controls(self):
- return [self.bones.ctrl.heel]
+ return super().get_extra_ik_controls() + [self.bones.ctrl.heel]
def make_ik_control_bone(self, orgs):
name = self.copy_bone(orgs[3], make_derived_name(orgs[2], 'ctrl', '_ik'))
@@ -107,7 +107,7 @@ class Rig(BaseLimbRig):
def register_switch_parents(self, pbuilder):
super().register_switch_parents(pbuilder)
- pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True)
+ pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True, tags={'limb_end'})
def make_ik_ctrl_widget(self, ctrl):
create_foot_widget(self.obj, ctrl)
@@ -126,7 +126,7 @@ class Rig(BaseLimbRig):
@stage.parent_bones
def parent_heel_control_bone(self):
- self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik)
+ self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output())
@stage.configure_bones
def configure_heel_control_bone(self):
@@ -150,7 +150,7 @@ class Rig(BaseLimbRig):
def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
if i == 3:
self.set_bone_parent(parent_mch, prev_org, use_connect=True)
- self.set_bone_parent(self.bones.mch.toe_socket, self.bones.ctrl.ik)
+ self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output())
else:
super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
diff --git a/rigify/rigs/limbs/simple_tentacle.py b/rigify/rigs/limbs/simple_tentacle.py
index 10bdd2b5..25d26e86 100644
--- a/rigify/rigs/limbs/simple_tentacle.py
+++ b/rigify/rigs/limbs/simple_tentacle.py
@@ -78,7 +78,7 @@ class Rig(TweakChainRig):
)
# Widgets
- def make_control_widget(self, ctrl):
+ def make_control_widget(self, i, ctrl):
create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py
index 1a9171a7..0b3fcd8a 100644
--- a/rigify/rigs/limbs/super_finger.py
+++ b/rigify/rigs/limbs/super_finger.py
@@ -24,11 +24,12 @@ import re
from itertools import count
from ...utils.errors import MetarigError
-from ...utils.bones import flip_bone, align_chain_x_axis
+from ...utils.bones import put_bone, flip_bone, align_chain_x_axis, set_bone_widget_transform
from ...utils.naming import make_derived_name
from ...utils.widgets import create_widget
from ...utils.widgets_basic import create_circle_widget
from ...utils.misc import map_list
+from ...utils.layers import ControlLayersOption
from ...base_rig import stage
@@ -40,7 +41,7 @@ class Rig(SimpleChainRig):
def initialize(self):
super().initialize()
- self.bbone_segments = 8
+ self.bbone_segments = self.params.bbones
self.first_parent = self.get_bone_parent(self.bones.org[0])
def prepare_bones(self):
@@ -116,6 +117,8 @@ class Rig(SimpleChainRig):
for args in zip(count(0), self.bones.ctrl.fk, self.bones.org + [None]):
self.configure_control_bone(*args)
+ ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.fk)
+
def configure_control_bone(self, i, ctrl, org):
if org:
self.copy_bone_properties(org, ctrl)
@@ -125,11 +128,13 @@ class Rig(SimpleChainRig):
bone.lock_rotation = (True, True, True)
bone.lock_scale = (True, True, True)
- def make_control_widget(self, ctrl):
+ def make_control_widget(self, i, ctrl):
if ctrl == self.bones.ctrl.fk[-1]:
# Tip control
create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0)
else:
+ set_bone_widget_transform(self.obj, ctrl, self.bones.org[i])
+
create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
##############################
@@ -234,11 +239,12 @@ class Rig(SimpleChainRig):
def configure_master_properties(self):
master = self.bones.ctrl.master
- self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect")
+ if self.bbone_segments > 1:
+ self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect")
- # Create UI
- panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten())
- panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True)
+ # Create UI
+ panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten())
+ panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True)
def rig_deform_bone(self, i, deform, org):
master = self.bones.ctrl.master
@@ -246,8 +252,9 @@ class Rig(SimpleChainRig):
self.make_constraint(deform, 'COPY_TRANSFORMS', org)
- self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')])
- self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')])
+ if self.bbone_segments > 1:
+ self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')])
+ self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')])
###############
# OPTIONS
@@ -261,6 +268,15 @@ class Rig(SimpleChainRig):
('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')]
params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic')
+ params.bbones = bpy.props.IntProperty(
+ name = 'B-Bone Segments',
+ default = 10,
+ min = 1,
+ description = 'Number of B-Bone segments'
+ )
+
+ ControlLayersOption.TWEAK.add_parameters(params)
+
@classmethod
def parameters_ui(self, layout, params):
""" Create the ui for the rig parameters.
@@ -269,6 +285,10 @@ class Rig(SimpleChainRig):
r.label(text="Bend rotation axis:")
r.prop(params, "primary_rotation_axis", text="")
+ layout.prop(params, 'bbones')
+
+ ControlLayersOption.TWEAK.parameters_ui(layout, params)
+
def create_sample(obj):
# generated by rigify.utils.write_metarig
@@ -321,10 +341,6 @@ def create_sample(obj):
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
except AttributeError:
pass
diff --git a/rigify/rigs/limbs/super_palm.py b/rigify/rigs/limbs/super_palm.py
index 8bcbabf8..9c03b2fe 100644
--- a/rigify/rigs/limbs/super_palm.py
+++ b/rigify/rigs/limbs/super_palm.py
@@ -24,6 +24,7 @@ import re
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.widgets import create_widget
from rigify.utils.misc import map_list
@@ -43,7 +44,7 @@ def bone_siblings(obj, bone):
bones = []
for b in parent.children:
- if b.name != bone:
+ if b.name != bone and not is_rig_base_bone(obj, b.name):
bones += [b.name]
return bones
diff --git a/rigify/rigs/spines/basic_spine.py b/rigify/rigs/spines/basic_spine.py
index 269889cf..c2905463 100644
--- a/rigify/rigs/spines/basic_spine.py
+++ b/rigify/rigs/spines/basic_spine.py
@@ -19,13 +19,16 @@
# <pep8 compliant>
import bpy
+import math
from itertools import count, repeat
+from mathutils import Matrix
from ...utils.errors import MetarigError
from ...utils.layers import ControlLayersOption
-from ...utils.naming import strip_org, make_deformer_name, make_mechanism_name
-from ...utils.bones import BoneDict, put_bone, align_bone_to_axis
+from ...utils.naming import strip_org, make_deformer_name, make_mechanism_name, make_derived_name
+from ...utils.bones import BoneDict, put_bone, align_bone_to_axis, align_bone_orientation, set_bone_widget_transform
+from ...utils.widgets import adjust_widget_transform_mesh
from ...utils.widgets_basic import create_circle_widget
from ...utils.misc import map_list
@@ -43,6 +46,7 @@ class Rig(BaseSpineRig):
# Check if user provided the pivot position
self.pivot_pos = self.params.pivot_pos
+ self.use_fk = self.params.make_fk_controls
if not (0 < self.pivot_pos < len(self.bones.org)):
self.raise_error("Please specify a valid pivot bone position.")
@@ -55,6 +59,9 @@ class Rig(BaseSpineRig):
# ctrl:
# master, hips, chest:
# Main controls.
+ # fk:
+ # chest[], hips[]:
+ # FK controls.
# tweak[]:
# Tweak control chain.
# mch:
@@ -73,19 +80,15 @@ class Rig(BaseSpineRig):
####################################################
# Master control bone
- @stage.generate_bones
- def make_master_control(self):
- super().make_master_control()
-
- # Put the main control in the middle of the hip bone
- base_bone = self.get_bone(self.bones.org[0])
- put_bone(self.obj, self.bones.ctrl.master, (base_bone.head + base_bone.tail) / 2)
+ def get_master_control_pos(self, orgs):
+ base_bone = self.get_bone(orgs[0])
+ return (base_bone.head + base_bone.tail) / 2
####################################################
# Main control bones
@stage.generate_bones
- def make_control_chain(self):
+ def make_end_control_bones(self):
orgs = self.bones.org
pivot = self.pivot_pos
@@ -103,33 +106,90 @@ class Rig(BaseSpineRig):
return name
@stage.parent_bones
- def parent_control_chain(self):
+ def parent_end_control_bones(self):
ctrl = self.bones.ctrl
- self.set_bone_parent(ctrl.hips, ctrl.master)
- self.set_bone_parent(ctrl.chest, ctrl.master)
-
- @stage.configure_bones
- def configure_control_chain(self):
- pass
+ pivot = self.get_master_control_output()
+ self.set_bone_parent(ctrl.hips, pivot)
+ self.set_bone_parent(ctrl.chest, pivot)
@stage.generate_widgets
- def make_control_widgets(self):
+ def make_end_control_widgets(self):
ctrl = self.bones.ctrl
mch = self.bones.mch
- self.make_control_widget(ctrl.hips, mch.wgt_hips)
- self.make_control_widget(ctrl.chest, mch.wgt_chest)
+ self.make_end_control_widget(ctrl.hips, mch.wgt_hips)
+ self.make_end_control_widget(ctrl.chest, mch.wgt_chest)
+
+ def make_end_control_widget(self, ctrl, wgt_mch):
+ shape_bone = self.get_bone(wgt_mch)
+ is_horizontal = abs(shape_bone.z_axis.normalized().y) < 0.7
- def make_control_widget(self, ctrl, wgt_mch):
- self.get_bone(ctrl).custom_shape_transform = self.get_bone(wgt_mch)
+ set_bone_widget_transform(self.obj, ctrl, wgt_mch)
- create_circle_widget(
+ obj = create_circle_widget(
self.obj, ctrl,
- radius=1.0,
+ radius=1.2 if is_horizontal else 1.1,
head_tail=0.0,
head_tail_x=1.0,
with_line=False,
)
+ if is_horizontal:
+ # Tilt the widget toward the ground for horizontal (animal) spines
+ angle = math.copysign(28, shape_bone.x_axis.x)
+ rotmat = Matrix.Rotation(math.radians(angle), 4, 'X')
+ adjust_widget_transform_mesh(obj, rotmat, local=True)
+
+ ####################################################
+ # FK control bones
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ if self.use_fk:
+ orgs = self.bones.org
+ self.bones.ctrl.fk = self.fk_result = BoneDict(
+ hips = map_list(self.make_control_bone, count(0), orgs[0:self.pivot_pos], repeat(True)),
+ chest = map_list(self.make_control_bone, count(self.pivot_pos), orgs[self.pivot_pos:], repeat(False)),
+ )
+
+ def make_control_bone(self, i, org, is_hip):
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_fk'), parent=False)
+ if is_hip:
+ put_bone(self.obj, name, self.get_bone(name).tail)
+ return name
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ if self.use_fk:
+ chain = self.bones.mch.chain
+ fk = self.bones.ctrl.fk
+ for child, parent in zip(fk.hips, chain.hips):
+ self.set_bone_parent(child, parent)
+ for child, parent in zip(fk.chest, chain.chest):
+ self.set_bone_parent(child, parent)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ if self.use_fk:
+ fk = self.bones.ctrl.fk
+ for args in zip(count(0), fk.hips + fk.chest, self.bones.org):
+ self.configure_control_bone(*args)
+
+ ControlLayersOption.FK.assign_rig(self, fk.hips + fk.chest)
+
+ @stage.generate_widgets
+ def make_control_widgets(self):
+ if self.use_fk:
+ fk = self.bones.ctrl.fk
+ for ctrl in fk.hips:
+ self.make_control_widget(ctrl, True)
+ for ctrl in fk.chest:
+ self.make_control_widget(ctrl, False)
+
+ def make_control_widget(self, ctrl, is_hip):
+ obj = create_circle_widget(self.obj, ctrl, radius=1.0, head_tail=0.5)
+ if is_hip:
+ adjust_widget_transform_mesh(obj, Matrix.Diagonal((1, -1, 1, 1)), local=True)
+
####################################################
# MCH bones associated with main controls
@@ -153,16 +213,16 @@ class Rig(BaseSpineRig):
@stage.parent_bones
def parent_mch_control_bones(self):
mch = self.bones.mch
- self.set_bone_parent(mch.pivot, mch.chain.chest[0])
- self.set_bone_parent(mch.wgt_hips, mch.chain.hips[0])
- self.set_bone_parent(mch.wgt_chest, mch.chain.chest[-1])
+ fk = self.fk_result
+ self.set_bone_parent(mch.pivot, fk.chest[0])
+ self.set_bone_parent(mch.wgt_hips, fk.hips[0])
+ self.set_bone_parent(mch.wgt_chest, fk.chest[-1])
+ align_bone_orientation(self.obj, mch.pivot, fk.hips[-1])
@stage.rig_bones
def rig_mch_control_bones(self):
mch = self.bones.mch
- # Is it actually intending to compute average of these, or is this really intentional?
- # This effectively adds rotations of the hip and chest controls.
- self.make_constraint(mch.pivot, 'COPY_TRANSFORMS', mch.chain.hips[-1], space='LOCAL')
+ self.make_constraint(mch.pivot, 'COPY_TRANSFORMS', self.fk_result.hips[-1], influence=0.5)
####################################################
# MCH chain for distributing hip & chest transform
@@ -174,6 +234,8 @@ class Rig(BaseSpineRig):
hips = map_list(self.make_mch_bone, orgs[0:self.pivot_pos], repeat(True)),
chest = map_list(self.make_mch_bone, orgs[self.pivot_pos:], repeat(False)),
)
+ if not self.use_fk:
+ self.fk_result = self.bones.mch.chain
def make_mch_bone(self, org, is_hip):
name = self.copy_bone(org, make_mechanism_name(strip_org(org)), parent=False)
@@ -182,10 +244,13 @@ class Rig(BaseSpineRig):
@stage.parent_bones
def parent_mch_chain(self):
- master = self.bones.ctrl.master
+ master = self.get_master_control_output()
chain = self.bones.mch.chain
- self.parent_bone_chain([master, *reversed(chain.hips)])
- self.parent_bone_chain([master, *chain.chest])
+ fk = self.fk_result
+ for child, parent in zip(reversed(chain.hips), [master, *reversed(fk.hips)]):
+ self.set_bone_parent(child, parent)
+ for child, parent in zip(chain.chest, [master, *fk.chest]):
+ self.set_bone_parent(child, parent)
@stage.rig_bones
def rig_mch_chain(self):
@@ -205,7 +270,7 @@ class Rig(BaseSpineRig):
@stage.parent_bones
def parent_tweak_chain(self):
mch = self.bones.mch
- chain = mch.chain
+ chain = self.fk_result
parents = [chain.hips[0], *chain.hips[0:-1], mch.pivot, *chain.chest[1:], chain.chest[-1]]
for args in zip(self.bones.ctrl.tweak, parents):
self.set_bone_parent(*args)
@@ -224,6 +289,13 @@ class Rig(BaseSpineRig):
super().add_parameters(params)
+ params.make_fk_controls = bpy.props.BoolProperty(
+ name="FK Controls", default=True,
+ description="Generate an FK control chain"
+ )
+
+ ControlLayersOption.FK.add_parameters(params)
+
@classmethod
def parameters_ui(self, layout, params):
r = layout.row()
@@ -231,6 +303,11 @@ class Rig(BaseSpineRig):
super().parameters_ui(layout, params)
+ layout.prop(params, 'make_fk_controls')
+
+ if params.make_fk_controls:
+ ControlLayersOption.FK.parameters_ui(layout, params)
+
def create_sample(obj):
# generated by rigify.utils.write_metarig
diff --git a/rigify/rigs/spines/basic_tail.py b/rigify/rigs/spines/basic_tail.py
index 845c3ca3..be054e7d 100644
--- a/rigify/rigs/spines/basic_tail.py
+++ b/rigify/rigs/spines/basic_tail.py
@@ -23,7 +23,8 @@ import bpy
from itertools import count
from ...utils.naming import strip_org, make_derived_name
-from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles, align_bone_orientation
+from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles
+from ...utils.bones import align_bone_orientation, set_bone_widget_transform
from ...utils.widgets_basic import create_circle_widget
from ...utils.layers import ControlLayersOption
from ...utils.misc import map_list
@@ -69,7 +70,7 @@ class Rig(BaseHeadTailRig):
@stage.generate_widgets
def make_master_control_widget(self):
bone = self.bones.ctrl.master
- self.get_bone(bone).custom_shape_transform = self.get_bone(self.bones.ctrl.tweak[-1])
+ set_bone_widget_transform(self.obj, bone, self.bones.ctrl.tweak[-1])
create_ballsocket_widget(self.obj, bone, size=0.7)
####################################################
@@ -94,7 +95,7 @@ class Rig(BaseHeadTailRig):
)
# Widgets
- def make_control_widget(self, ctrl):
+ def make_control_widget(self, i, ctrl):
create_circle_widget(self.obj, ctrl, radius=0.5, head_tail=0.75)
####################################################
diff --git a/rigify/rigs/spines/spine_rigs.py b/rigify/rigs/spines/spine_rigs.py
index 6628289f..070a6bd3 100644
--- a/rigify/rigs/spines/spine_rigs.py
+++ b/rigify/rigs/spines/spine_rigs.py
@@ -24,9 +24,10 @@ from itertools import count
from ...utils.layers import ControlLayersOption
from ...utils.naming import make_derived_name
-from ...utils.bones import align_bone_orientation, align_bone_to_axis
+from ...utils.bones import align_bone_orientation, align_bone_to_axis, put_bone, set_bone_widget_transform
from ...utils.widgets_basic import create_cube_widget
from ...utils.switch_parent import SwitchParentBuilder
+from ...utils.components import CustomPivotControl
from ...base_rig import stage
@@ -44,6 +45,7 @@ class BaseSpineRig(TweakChainRig):
if len(self.bones.org) < 3:
self.raise_error("Input to rig type must be a chain of 3 or more bones.")
+ self.use_torso_pivot = self.params.make_custom_pivot
self.length = sum([self.get_bone(b).length for b in self.bones.org])
####################################################
@@ -52,6 +54,11 @@ class BaseSpineRig(TweakChainRig):
# ctrl:
# master
# Main control.
+ # master_pivot
+ # Custom pivot under the master control.
+ # mch:
+ # master_pivot
+ # Final output of the custom pivot.
#
####################################################
@@ -60,17 +67,43 @@ class BaseSpineRig(TweakChainRig):
@stage.generate_bones
def make_master_control(self):
- self.bones.ctrl.master = name = self.copy_bone(self.bones.org[0], 'torso')
+ self.bones.ctrl.master = name = self.make_master_control_bone(self.bones.org)
+ self.component_torso_pivot = self.build_master_pivot(name)
+ self.build_parent_switch(name)
+
+ def get_master_control_pos(self, orgs):
+ return self.get_bone(orgs[0]).head
+
+ def make_master_control_bone(self, orgs):
+ name = self.copy_bone(orgs[0], 'torso')
+ put_bone(self.obj, name, self.get_master_control_pos(orgs))
align_bone_to_axis(self.obj, name, 'y', length=self.length * 0.6)
+ return name
- self.build_parent_switch(name)
+ def build_master_pivot(self, master_name, **args):
+ if self.use_torso_pivot:
+ return CustomPivotControl(
+ self, 'master_pivot', master_name, parent=master_name, **args
+ )
+
+ def get_master_control_output(self):
+ if self.component_torso_pivot:
+ return self.component_torso_pivot.output
+ else:
+ return self.bones.ctrl.master
def build_parent_switch(self, master_name):
pbuilder = SwitchParentBuilder(self.generator)
- pbuilder.register_parent(self, master_name, name='Torso')
+
+ org_parent = self.get_bone_parent(self.bones.org[0])
+ parents = [org_parent] if org_parent else []
+
+ pbuilder.register_parent(self, self.get_master_control_output, name='Torso', tags={'torso', 'child'})
+
pbuilder.build_child(
self, master_name, exclude_self=True,
+ extra_parents=parents, select_parent=org_parent,
prop_id='torso_parent', prop_name='Torso Parent',
controls=lambda: self.bones.flatten('ctrl'),
)
@@ -78,8 +111,8 @@ class BaseSpineRig(TweakChainRig):
self.register_parent_bones(pbuilder)
def register_parent_bones(self, pbuilder):
- pbuilder.register_parent(self, self.bones.org[0], name='Hips', exclude_self=True)
- pbuilder.register_parent(self, self.bones.org[-1], name='Chest', exclude_self=True)
+ pbuilder.register_parent(self, self.bones.org[0], name='Hips', exclude_self=True, tags={'hips'})
+ pbuilder.register_parent(self, self.bones.org[-1], name='Chest', exclude_self=True, tags={'chest'})
@stage.parent_bones
def parent_master_control(self):
@@ -91,10 +124,9 @@ class BaseSpineRig(TweakChainRig):
@stage.generate_widgets
def make_master_control_widget(self):
- create_cube_widget(
- self.obj, self.bones.ctrl.master,
- radius=0.5,
- )
+ master = self.bones.ctrl.master
+ set_bone_widget_transform(self.obj, master, self.get_master_control_output())
+ create_cube_widget(self.obj, master, radius=0.5)
####################################################
# Tweak bones
@@ -117,11 +149,19 @@ class BaseSpineRig(TweakChainRig):
@classmethod
def add_parameters(self, params):
+ params.make_custom_pivot = bpy.props.BoolProperty(
+ name = "Custom Pivot Control",
+ default = False,
+ description = "Create a rotation pivot control that can be repositioned arbitrarily"
+ )
+
# Setting up extra layers for the FK and tweak
ControlLayersOption.TWEAK.add_parameters(params)
@classmethod
def parameters_ui(self, layout, params):
+ layout.prop(params, 'make_custom_pivot')
+
ControlLayersOption.TWEAK.parameters_ui(layout, params)
diff --git a/rigify/rigs/spines/super_head.py b/rigify/rigs/spines/super_head.py
index 9b85e5b5..15f011f7 100644
--- a/rigify/rigs/spines/super_head.py
+++ b/rigify/rigs/spines/super_head.py
@@ -322,7 +322,10 @@ class Rig(BaseHeadTailRig):
def register_parent_bones(self):
rig = self.rigify_parent or self
builder = SwitchParentBuilder(self.generator)
- builder.register_parent(rig, self.bones.org[-1], name='Head', exclude_self=True)
+ builder.register_parent(
+ self, self.bones.org[-1], name='Head',
+ inject_into=rig, exclude_self=True, tags={'head'},
+ )
@stage.configure_bones
def configure_bbone_chain(self):
diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py
index 5ed1588e..86021c84 100644
--- a/rigify/rigs/spines/super_spine.py
+++ b/rigify/rigs/spines/super_spine.py
@@ -81,7 +81,7 @@ class Rig(SubstitutionRig, BoneUtilityMixin):
bpy.ops.object.mode_set(mode='OBJECT')
# Create the parts
- self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos)
+ self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos, make_fk_controls=False)
result = [ self.instantiate_rig(basic_spine.Rig, spine_orgs[0]) ]
@@ -133,6 +133,8 @@ def add_parameters(params):
def parameters_ui(layout, params):
""" Create the ui for the rig parameters."""
+ layout.label(text="Note: this combined rig is deprecated.", icon='INFO')
+
r = layout.row(align=True)
r.prop(params, "use_head", toggle=True, text="Head")
r.prop(params, "use_tail", toggle=True, text="Tail")