diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2019-03-30 22:00:55 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2019-09-14 09:29:26 +0300 |
commit | 3423174b37a0784dc12035ff3f2fb536835099e1 (patch) | |
tree | 3a54580902cdebdef5ebacd6099e86cc79ba75b3 /rigify/rigs/limbs | |
parent | 12af8a28c14b608e9b9b08568d981273c86590c1 (diff) |
Rigify: redesign generate.py and introduce a base rig class.
The main goals are to provide an official way for rigs to
interact in a structured way, and to remove mode switching
within rigs.
This involves introducing a base class for rigs that holds
rig-to-rig and rig-to-bone references, converting the main
generator into a class and passing it to rigs, and splitting
the single generate method into multiple passes.
For backward compatibility, old rigs are automatically handled
via a wrapper that translates between old and new API.
In addition, a way to create objects that receive the generate
callbacks that aren't rigs is introduced via the GeneratorPlugin
class. The UI script generation code is converted into a plugin.
Making generic rig 'template' classes that are intended to be
subclassed in specific rigs involves splitting operations done
in each stage into multiple methods that can be overridden
separately. The main callback thus ends up simply calling a
sequence of other methods.
To make such code cleaner it's better to allow registering
those methods as new callbacks that would be automatically
called by the system. This can be done via decorators.
A new metaclass used for all rig and generate plugin classes
builds and validates a table of all decorated methods, and
allows calling them all together with the main callback.
A new way to switch parents for IK bones based on the new
features is introduced, and used in the existing limb rigs.
Reviewers: icappiello campbellbarton
Differential Revision: https://developer.blender.org/D4624
Diffstat (limited to 'rigify/rigs/limbs')
-rw-r--r-- | rigify/rigs/limbs/arm.py | 122 | ||||
-rw-r--r-- | rigify/rigs/limbs/leg.py | 130 | ||||
-rw-r--r-- | rigify/rigs/limbs/super_limb.py | 2 |
3 files changed, 46 insertions, 208 deletions
diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 3b2f3658..aacc1e86 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -15,17 +15,8 @@ from ...utils.mechanism import make_property, make_driver from ..widgets import create_ikarrow_widget from math import trunc, pi -extra_script = """ -controls = [%s] -ctrl = '%s' - -if is_selected( controls ): - layout.prop( pose_bones[ ctrl ], '["%s"]') - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) -""" +from ...utils.switch_parent import SwitchParentBuilder + IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class # add_parameters and parameters_ui are unused for implementation classes @@ -561,35 +552,6 @@ class Rig: eb[ bones['ik']['mch_target'] ].parent = eb[ ctrl ] eb[ bones['ik']['mch_target'] ].use_connect = False - # MCH for ik control - ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket')) - eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head) - eb[ctrl_socket].parent = None - eb[ctrl].parent = eb[ctrl_socket] - - # MCH for pole ik control - ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket')) - eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head) - eb[ctrl_pole_socket].parent = None - eb[pole_target].parent = eb[ctrl_pole_socket] - - ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root')) - eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head) - eb[ctrl_root].use_connect = False - eb[ctrl_root].parent = eb['root'] - - if eb[org_bones[0]].parent: - arm_parent = eb[org_bones[0]].parent - ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent')) - eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head) - eb[ctrl_parent].use_connect = False - if eb[org_bones[0]].parent_recursive: - eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1] - else: - eb[ctrl_parent].parent = eb[org_bones[0]].parent - else: - arm_parent = None - mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) eb[mch_main_parent].length = eb[org_bones[0]].length / 12 @@ -597,30 +559,28 @@ class Rig: eb[mch_main_parent].roll = 0.0 eb[bones['main_parent']].parent = eb[mch_main_parent] - # Set up constraints + # Switchable parent + pbuilder = SwitchParentBuilder(self.rigify_generator) - # Constrain ik ctrl to root / parent + if eb[org_bones[0]].parent: + pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name) - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_root, - }) + pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True) - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_root, - }) + pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], ctrl, pole_target ] - if arm_parent: - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_parent, - }) + pbuilder.build_child( + self.rigify_wrapper, ctrl, + prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols, + ) - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_parent, - }) + pbuilder.build_child( + self.rigify_wrapper, pole_target, extra_parents=[ctrl], + prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols, + no_fix_rotation=True, no_fix_scale=True + ) + + # Set up constraints # Constrain mch target bone to the ik control and mch stretch make_constraint( self, bones['ik']['mch_target'], { @@ -675,10 +635,6 @@ class Rig: create_hand_widget(self.obj, ctrl, bone_transform_name=None) bones['ik']['ctrl']['terminal'] = [ctrl] - if arm_parent: - bones['ik']['mch_hand'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent] - else: - bones['ik']['mch_hand'] = [ctrl_socket, ctrl_pole_socket, ctrl_root] return bones @@ -687,13 +643,10 @@ class Rig: bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - ctrl = pb[bones['ik']['mch_hand'][0]] - ctrl_pole = pb[bones['ik']['mch_hand'][1]] - #owner = pb[bones['ik']['ctrl']['limb']] owner = pb[bones['main_parent']] - props = ["IK_follow", "root/parent", "pole_vector", "pole_follow"] + props = ["pole_vector"] for prop in props: @@ -723,30 +676,6 @@ class Rig: else: make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - elif prop == 'IK_follow': - make_property(owner, prop, True) - - make_driver(ctrl.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl.constraints) > 1: - make_driver(ctrl.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - make_driver(ctrl_pole.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl_pole.constraints) > 1: - make_driver(ctrl_pole.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - elif prop == 'root/parent': - if len(ctrl.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - - elif prop == 'pole_follow': - if len(ctrl_pole.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl_pole.constraints[1], "influence", variables=[(self.obj, owner, prop)]) @staticmethod def get_future_names(bones): @@ -822,22 +751,13 @@ class Rig: bones = self.create_arm(bones) self.create_drivers(bones) - controls = [bones['ik']['ctrl']['limb'], bones['ik']['ctrl']['terminal'][0]] - - controls.append(bones['main_parent']) - # Create UI - controls_string = ", ".join(["'" + x + "'" for x in controls]) - script = create_script(bones, 'arm') - script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', - 'pole_follow', 'pole_follow', 'root/parent', 'root/parent') return { 'script': [script], 'utilities': UTILITIES_RIG_ARM, 'register': REGISTER_RIG_ARM, - 'noparent_bones': [bones['ik']['mch_hand'][i] for i in [0,1]], } @@ -858,7 +778,7 @@ def add_parameters(params): default = 'automatic' ) - params.auto_align_extremity = bpy.BoolProperty( + params.auto_align_extremity = bpy.props.BoolProperty( name='auto_align_extremity', default=False, description="Auto Align Extremity Bone" diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index 2b846eca..59e6f799 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -17,17 +17,8 @@ from ...utils.mechanism import make_property, make_driver from ..widgets import create_ikarrow_widget from math import trunc, pi -extra_script = """ -controls = [%s] -ctrl = '%s' - -if is_selected( controls ): - layout.prop( pose_bones[ ctrl ], '["%s"]') - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) - if '%s' in pose_bones[ctrl].keys(): - layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True ) -""" +from ...utils.switch_parent import SwitchParentBuilder + IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class # add_parameters and parameters_ui are unused for implementation classes @@ -599,35 +590,6 @@ class Rig: eb[ctrl].parent = None eb[ctrl].use_connect = False - # MCH for ik control - ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket')) - eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head) - eb[ctrl_socket].parent = None - eb[ctrl].parent = eb[ctrl_socket] - - # MCH for pole ik control - ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket')) - eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head) - eb[ctrl_pole_socket].parent = None - eb[pole_target].parent = eb[ctrl_pole_socket] - - ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root')) - eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head) - eb[ctrl_root].use_connect = False - eb[ctrl_root].parent = eb['root'] - - if eb[org_bones[0]].parent: - leg_parent = eb[org_bones[0]].parent - ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent')) - eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head) - eb[ctrl_parent].use_connect = False - if eb[org_bones[0]].parent_recursive: - eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1] - else: - eb[ctrl_parent].parent = eb[org_bones[0]].parent - else: - leg_parent = None - mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket') mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name) eb[mch_main_parent].length = eb[org_bones[0]].length / 12 @@ -658,6 +620,26 @@ class Rig: eb[ctrl].tail[2] = eb[ctrl].head[2] eb[ctrl].roll = 0 + # Switchable parent + pbuilder = SwitchParentBuilder(self.rigify_generator) + + if eb[org_bones[0]].parent: + pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name) + + pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True) + + pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], heel, ctrl, pole_target ] + + pbuilder.build_child( + self.rigify_wrapper, ctrl, + prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols, + ) + + pbuilder.build_child( + self.rigify_wrapper, pole_target, extra_parents=[(bones['ik']['mch_target'], ctrl)], + prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols, + no_fix_rotation=True, no_fix_scale=True + ) # Parent eb[ heel ].use_connect = False @@ -847,30 +829,6 @@ class Rig: # Set up constraints - # Constrain ik ctrl to root / parent - - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_root, - }) - - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': ctrl_root, - }) - - if leg_parent: - make_constraint( self, ctrl_socket, { - 'constraint' : 'COPY_TRANSFORMS', - 'subtarget' : ctrl_parent, - 'influence' : 0.0, - }) - - make_constraint(self, ctrl_pole_socket, { - 'constraint': 'COPY_TRANSFORMS', - 'subtarget': bones['ik']['mch_target'], - }) - # Constrain mch target bone to the ik control and mch stretch make_constraint( self, bones['ik']['mch_target'], { 'constraint' : 'COPY_LOCATION', @@ -982,11 +940,6 @@ class Rig: bones['ik']['ctrl']['terminal'] += [ heel, ctrl ] - if leg_parent: - bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent] - else: - bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root] - return bones def create_drivers(self, bones): @@ -994,13 +947,10 @@ class Rig: bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - ctrl = pb[bones['ik']['mch_foot'][0]] - ctrl_pole = pb[bones['ik']['mch_foot'][1]] - #owner = pb[bones['ik']['ctrl']['limb']] owner = pb[bones['main_parent']] - props = ["IK_follow", "root/parent", "pole_vector", "pole_follow"] + props = ["pole_vector"] for prop in props: @@ -1031,31 +981,6 @@ class Rig: make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - elif prop == 'IK_follow': - make_property(owner, prop, True) - - make_driver(ctrl.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl.constraints) > 1: - make_driver(ctrl.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - make_driver(ctrl_pole.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - if len(ctrl_pole.constraints) > 1: - make_driver(ctrl_pole.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0]) - - elif prop == 'root/parent': - if len(ctrl.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - - elif prop == 'pole_follow': - if len(ctrl_pole.constraints) > 1: - make_property(owner, prop, 0.0) - - make_driver(ctrl_pole.constraints[1], "influence", variables=[(self.obj, owner, prop)]) - @staticmethod def get_future_names(bones): @@ -1133,22 +1058,13 @@ class Rig: bones = self.create_leg(bones) self.create_drivers(bones) - controls = [bones['ik']['ctrl']['limb'], bones['ik']['ctrl']['terminal'][-1], bones['ik']['ctrl']['terminal'][-2] ] - - controls.append(bones['main_parent']) - # Create UI - controls_string = ", ".join(["'" + x + "'" for x in controls]) - script = create_script(bones, 'leg') - script += extra_script % (controls_string, bones['main_parent'], 'IK_follow', - 'pole_follow', 'pole_follow', 'root/parent', 'root/parent') return { 'script': [script], 'utilities': UTILITIES_RIG_LEG, 'register': REGISTER_RIG_LEG, - 'noparent_bones': [bones['ik']['mch_foot'][i] for i in [0,1]], } diff --git a/rigify/rigs/limbs/super_limb.py b/rigify/rigs/limbs/super_limb.py index 3d2bb8e2..0d557bb7 100644 --- a/rigify/rigs/limbs/super_limb.py +++ b/rigify/rigs/limbs/super_limb.py @@ -21,6 +21,8 @@ class Rig: self.limb = pawRig(obj, bone_name, params) def generate(self): + self.limb.rigify_generator = self.rigify_generator + self.limb.rigify_wrapper = self.rigify_wrapper return self.limb.generate() |