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:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-10-15 19:21:25 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-10-16 13:41:48 +0300
commit358bc43ef460e97239bccc379086f98ef6d95472 (patch)
tree6456ee46d145dd7f8a7269eabeff61dfd686e81f /rigify/utils
parent465f3e3f581f7dc25b299a15c5be6cdc58bbe053 (diff)
Rigify: implement optional custom pivot controls.
- Add an optional custom pivot between torso and the rest of the spine. - Add a custom pivot rig that can be used as a parent of the spine. - Add an optional custom pivot under limb IK controls.
Diffstat (limited to 'rigify/utils')
-rw-r--r--rigify/utils/components.py85
-rw-r--r--rigify/utils/misc.py8
-rw-r--r--rigify/utils/switch_parent.py19
-rw-r--r--rigify/utils/widgets_basic.py2
4 files changed, 101 insertions, 13 deletions
diff --git a/rigify/utils/components.py b/rigify/utils/components.py
new file mode 100644
index 00000000..b99e183f
--- /dev/null
+++ b/rigify/utils/components.py
@@ -0,0 +1,85 @@
+import bpy
+
+from .naming import make_derived_name
+from .bones import put_bone, copy_bone_position, align_bone_orientation
+from .widgets_basic import create_pivot_widget
+from .misc import force_lazy
+
+from ..base_rig import RigComponent, stage
+
+
+class CustomPivotControl(RigComponent):
+ """
+ A utility that generates a pivot control with a custom position.
+
+ Generates a control bone, and a MCH output bone.
+ """
+
+ def __init__(
+ self, rig, id_name, org_bone, *,
+ name=None, parent=None, position=None, matrix=None, scale=1.0,
+ move_to=None, align_to=None, snap_to=None,
+ widget_axis=1.5, widget_cap=1.0, widget_square=True,
+ ):
+ super().__init__(rig)
+
+ assert rig.generator.stage == 'generate_bones'
+
+ self.bones = rig.bones
+ self.id_name = id_name
+
+ self.parent = parent
+ self.scale = scale or 1
+ self.move_to = move_to
+ self.align_to = align_to
+ self.snap_to = snap_to
+ self.widget_axis = widget_axis
+ self.widget_cap = widget_cap
+ self.widget_square = widget_square
+
+ name = name or make_derived_name(org_bone, 'ctrl', '_pivot')
+
+ self.do_make_bones(org_bone, name, position, matrix)
+
+ @property
+ def control(self):
+ return self.ctrl
+
+ @property
+ def output(self):
+ return self.mch
+
+ def do_make_bones(self, org, name, position, matrix):
+ self.bones.ctrl[self.id_name] = self.ctrl = self.copy_bone(org, name, parent=not self.parent, scale=self.scale)
+ self.bones.mch[self.id_name] = self.mch = self.copy_bone(org, make_derived_name(name, 'mch'), scale=self.scale * 0.7)
+
+ if position or matrix:
+ put_bone(self.obj, self.ctrl, position, matrix=matrix)
+ put_bone(self.obj, self.mch, position, matrix=matrix)
+
+ def parent_bones(self):
+ if self.snap_to:
+ bone = force_lazy(self.snap_to)
+ copy_bone_position(self.obj, bone, self.ctrl, scale=self.scale)
+ copy_bone_position(self.obj, bone, self.mch, scale=self.scale * 0.7)
+
+ if self.move_to:
+ pos = self.get_bone(force_lazy(self.move_to)).head
+ put_bone(self.obj, self.ctrl, pos)
+ put_bone(self.obj, self.mch, pos)
+
+ if self.align_to:
+ self.align_to = force_lazy(self.align_to)
+ align_bone_orientation(self.obj, self.ctrl, self.align_to)
+ align_bone_orientation(self.obj, self.mch, self.align_to)
+
+ if self.parent:
+ self.set_bone_parent(self.ctrl, force_lazy(self.parent))
+
+ self.set_bone_parent(self.mch, self.ctrl)
+
+ def rig_bones(self):
+ self.make_constraint(self.mch, 'COPY_LOCATION', self.ctrl, space='LOCAL', invert_xyz=(True,)*3)
+
+ def generate_widgets(self):
+ create_pivot_widget(self.obj, self.ctrl, axis_size=self.widget_axis, cap_size=self.widget_cap, square=self.widget_square)
diff --git a/rigify/utils/misc.py b/rigify/utils/misc.py
index 64367bb7..20fd6a08 100644
--- a/rigify/utils/misc.py
+++ b/rigify/utils/misc.py
@@ -156,6 +156,14 @@ def map_apply(func, *inputs):
# Misc
#=============================================
+
+def force_lazy(value):
+ if callable(value):
+ return value()
+ else:
+ return value
+
+
def copy_attributes(a, b):
keys = dir(a)
for key in keys:
diff --git a/rigify/utils/switch_parent.py b/rigify/utils/switch_parent.py
index 463398fc..d43e0830 100644
--- a/rigify/utils/switch_parent.py
+++ b/rigify/utils/switch_parent.py
@@ -8,18 +8,13 @@ import json
from .errors import MetarigError
from .naming import strip_prefix, make_derived_name
from .mechanism import MechanismUtilityMixin
-from .misc import map_list, map_apply
+from .misc import map_list, map_apply, force_lazy
from ..base_rig import *
from ..base_generate import GeneratorPlugin
from itertools import count, repeat
-def _auto_call(value):
- if callable(value):
- return value()
- else:
- return value
def _rig_is_child(rig, parent):
if parent is None:
@@ -206,7 +201,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
# Call lazy creation for parents
for parent in self.parent_list:
if parent['used']:
- parent['bone'] = _auto_call(parent['bone'])
+ parent['bone'] = force_lazy(parent['bone'])
def parent_bones(self):
for child in self.child_list:
@@ -243,7 +238,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
last_main_parent_bone = child['parents'][-1]['bone']
num_main_parents = len(parent_map.items())
- for parent in _auto_call(child['extra_parents'] or []):
+ for parent in force_lazy(child['extra_parents'] or []):
if not isinstance(parent, tuple):
parent = (parent, None)
if parent[0] not in parent_map:
@@ -253,7 +248,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
child['parent_bones'] = parent_bones
# Find which bone to select
- select_bone = _auto_call(child['select_parent']) or last_main_parent_bone
+ select_bone = force_lazy(child['select_parent']) or last_main_parent_bone
select_index = num_main_parents
try:
@@ -262,7 +257,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
print("RIGIFY ERROR: Can't find bone '%s' to select as default parent of '%s'\n" % (select_bone, bone))
# Create the controlling property
- prop_bone = child['prop_bone'] = _auto_call(child['prop_bone']) or bone
+ prop_bone = child['prop_bone'] = force_lazy(child['prop_bone']) or bone
prop_name = child['prop_name'] or child['prop_id'] or 'Parent Switch'
prop_id = child['prop_id'] = child['prop_id'] or 'parent_switch'
@@ -281,12 +276,12 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
no_fix = [ child[n] for n in ['no_fix_location', 'no_fix_rotation', 'no_fix_scale'] ]
- child['copy'] = [ _auto_call(child[n]) for n in ['copy_location', 'copy_rotation', 'copy_scale'] ]
+ child['copy'] = [ force_lazy(child[n]) for n in ['copy_location', 'copy_rotation', 'copy_scale'] ]
locks = tuple(bool(nofix or copy) for nofix, copy in zip(no_fix, child['copy']))
# Create the script for the property
- controls = _auto_call(child['controls']) or set([prop_bone, bone])
+ controls = force_lazy(child['controls']) or set([prop_bone, bone])
script = self.generator.script
panel = script.panel_with_selected_check(child['rig'], controls)
diff --git a/rigify/utils/widgets_basic.py b/rigify/utils/widgets_basic.py
index 2848e5bf..8aab5d7b 100644
--- a/rigify/utils/widgets_basic.py
+++ b/rigify/utils/widgets_basic.py
@@ -129,7 +129,7 @@ def create_bone_widget(rig, bone_name, r1=0.1, l1=0.0, r2=0.04, l2=1.0, bone_tra
mesh.update()
-def create_pivot_widget(rig, bone_name, axis_size=1.0, cap_size=1.0, square=False, bone_transform_name=None):
+def create_pivot_widget(rig, bone_name, axis_size=1.0, cap_size=1.0, square=True, bone_transform_name=None):
"""Creates a widget similar to Plain Axes empty, but with a cross or
a square on the end of each axis line.
"""