diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2019-10-15 19:21:25 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2019-10-16 13:41:48 +0300 |
commit | 358bc43ef460e97239bccc379086f98ef6d95472 (patch) | |
tree | 6456ee46d145dd7f8a7269eabeff61dfd686e81f /rigify/utils | |
parent | 465f3e3f581f7dc25b299a15c5be6cdc58bbe053 (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.py | 85 | ||||
-rw-r--r-- | rigify/utils/misc.py | 8 | ||||
-rw-r--r-- | rigify/utils/switch_parent.py | 19 | ||||
-rw-r--r-- | rigify/utils/widgets_basic.py | 2 |
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. """ |