From 36e8d00aec705b06008a0bc334fe266448b4f2c2 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 16 Feb 2019 13:57:57 +0300 Subject: Rigify: add support for user-defined rig packages and related utilities. As suggested by @icappielo, and after discussion with @meta-androcto, I start a public request to commit third-party contributions already accepted to https://github.com/eigen-value/rigify/tree/rigify_0.6_beta Specifically, this includes: * User-defined rig package (feature set) support by @pioverfour. This allows users to install pre-packaged rig sets via zip files, which become accessible together with built-in rigs, as discussed in T52758. https://github.com/eigen-value/rigify/pull/1 * Modularization of python script generation, allowing rigs to add their own utility functions and operators to the generated script. This is critical to make custom rig support really useful. https://github.com/eigen-value/rigify/pull/5 * The utils.py file is split into multiple modules with a backward compatibility proxy for old functions. * Automatic verification that different rigs don't try to create different rig settings with the same name to alleviate increased risk of namespace conflicts with custom rigs. https://github.com/eigen-value/rigify/pull/7 * New utility class that implements bone layer selection UI. https://github.com/eigen-value/rigify/pull/6 * New utilities to replace copy & pasted boilerplate code for creating custom properties, constraints and drivers. https://github.com/eigen-value/rigify/pull/11 Some other random changes by MAD have likely slipped through. These changes have already been extensively discussed and accepted into the branch by @luciorossi, so I see no reason not to commit them to the official repository to be tested during 2.8 beta. Reviewers: icappiello Differential Revision: https://developer.blender.org/D4364 --- rigify/generate.py | 87 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 31 deletions(-) (limited to 'rigify/generate.py') diff --git a/rigify/generate.py b/rigify/generate.py index 5b5f0e98..7eff06f3 100644 --- a/rigify/generate.py +++ b/rigify/generate.py @@ -24,17 +24,17 @@ import time import traceback import sys from rna_prop_ui import rna_idprop_ui_prop_get +from collections import OrderedDict -from .utils import MetarigError, new_bone, get_rig_type -from .utils import ORG_PREFIX, MCH_PREFIX, DEF_PREFIX, WGT_PREFIX, ROOT_NAME, make_original_name -from .utils import RIG_DIR +from .utils import MetarigError, new_bone +from .utils import MCH_PREFIX, DEF_PREFIX, WGT_PREFIX, ROOT_NAME, make_original_name from .utils import create_root_widget -from .utils import ensure_widget_collection +from .utils.collections import ensure_widget_collection from .utils import random_id from .utils import copy_attributes from .utils import gamma_correct -from .rig_ui_template import UI_SLIDERS, layers_ui, UI_REGISTER - +from . import rig_lists +from . import rig_ui_template RIG_MODULE = "rigs" ORG_LAYER = [n == 31 for n in range(0, 32)] # Armature layer that original bones should be moved to. @@ -123,6 +123,7 @@ def generate_rig(context, metarig): # Remove wgts if force update is set wgts_group_name = "WGTS_" + (rig_old_name or obj.name) if wgts_group_name in scene.objects and id_store.rigify_force_widget_update: + bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') for wgt in bpy.data.objects[wgts_group_name].children: wgt.select_set(True) @@ -301,6 +302,8 @@ def generate_rig(context, metarig): rna_idprop_ui_prop_get(obj.data, "rig_id", create=True) obj.data["rig_id"] = rig_id + t.tick("Create root bone: ") + # Create/find widge collection widget_collection = ensure_widget_collection(context) @@ -332,6 +335,10 @@ def generate_rig(context, metarig): # Generate all the rigs. ui_scripts = [] + ui_imports = rig_ui_template.UI_IMPORTS.copy() + ui_utilities = rig_ui_template.UI_UTILITIES.copy() + ui_register = rig_ui_template.UI_REGISTER.copy() + noparent_bones = [] for rig in rigs: # Go into editmode in the rig armature bpy.ops.object.mode_set(mode='OBJECT') @@ -339,9 +346,21 @@ def generate_rig(context, metarig): obj.select_set(True) bpy.ops.object.mode_set(mode='EDIT') scripts = rig.generate() - if scripts is not None: + if isinstance(scripts, dict): + if 'script' in scripts: + ui_scripts += scripts['script'] + if 'imports' in scripts: + ui_imports += scripts['imports'] + if 'utilities' in scripts: + ui_utilities += scripts['utilities'] + if 'register' in scripts: + ui_register += scripts['register'] + if 'noparent_bones' in scripts: + noparent_bones += scripts['noparent_bones'] + elif scripts is not None: ui_scripts += [scripts[0]] t.tick("Generate rigs: ") + except Exception as e: # Cleanup if something goes wrong print("Rigify: failed to generate rig.") @@ -358,25 +377,8 @@ def generate_rig(context, metarig): # Get a list of all the bones in the armature bones = [bone.name for bone in obj.data.bones] - # Parent any free-floating bones to the root excluding bones with child of constraint. - pbones = obj.pose.bones - - - ik_follow_drivers = [] - - if obj.animation_data: - for drv in obj.animation_data.drivers: - for var in drv.driver.variables: - if 'IK_follow' == var.name: - ik_follow_drivers.append(drv.data_path) - - noparent_bones = [] - for bone in bones: - # if 'IK_follow' in pbones[bone].keys(): - # noparent_bones += [bone] - for d in ik_follow_drivers: - if bone in d: - noparent_bones += [bone] + # Parent any free-floating bones to the root excluding noparent_bones + noparent_bones = dict.fromkeys(noparent_bones) bpy.ops.object.mode_set(mode='EDIT') for bone in bones: @@ -486,11 +488,23 @@ def generate_rig(context, metarig): id_store.rigify_rig_ui = script.name - script.write(UI_SLIDERS % rig_id) + for s in OrderedDict.fromkeys(ui_imports): + script.write(s + "\n") + script.write(rig_ui_template.UI_BASE_UTILITIES % rig_id) + for s in OrderedDict.fromkeys(ui_utilities): + script.write(s + "\n") + script.write(rig_ui_template.UI_SLIDERS) for s in ui_scripts: script.write("\n " + s.replace("\n", "\n ") + "\n") - script.write(layers_ui(vis_layers, layer_layout)) - script.write(UI_REGISTER) + script.write(rig_ui_template.layers_ui(vis_layers, layer_layout)) + script.write("\ndef register():\n") + ui_register = OrderedDict.fromkeys(ui_register) + for s in ui_register: + script.write(" bpy.utils.register_class("+s+");\n") + script.write("\ndef unregister():\n") + for s in ui_register: + script.write(" bpy.utils.unregister_class("+s+");\n") + script.write("\nregister()\n") script.use_module = True # Run UI script @@ -505,6 +519,16 @@ def generate_rig(context, metarig): # Add rig_ui to logic create_persistent_rig_ui(obj, script) + # Do final gluing + for rig in rigs: + if hasattr(rig, "glue"): + # update glue_bone rigs + bpy.ops.object.mode_set(mode='EDIT') + rig = rig.__class__(rig.obj, rig.base_bone, rig.params) + + rig.glue() + t.tick("Glue pass") + t.tick("The rest: ") #---------------------------------- # Deconfigure @@ -636,8 +660,9 @@ def get_bone_rigs(obj, bone_name, halt_on_missing=False): # Get the rig try: - rig = get_rig_type(rig_type).Rig(obj, bone_name, params) - except ImportError: + rig = rig_lists.rigs[rig_type]["module"] + rig = rig.Rig(obj, bone_name, params) + except (KeyError, ImportError): message = "Rig Type Missing: python module for type '%s' not found (bone: %s)" % (rig_type, bone_name) if halt_on_missing: raise MetarigError(message) -- cgit v1.2.3