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/spines')
-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
5 files changed, 172 insertions, 49 deletions
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")