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:
-rw-r--r--rigify/__init__.py25
-rw-r--r--rigify/generate.py104
-rw-r--r--rigify/rig_ui_template.py25
-rw-r--r--rigify/ui.py148
-rw-r--r--rigify/utils/collections.py45
-rw-r--r--rigify/utils/widgets.py4
6 files changed, 159 insertions, 192 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py
index 019adb48..20e18a42 100644
--- a/rigify/__init__.py
+++ b/rigify/__init__.py
@@ -512,20 +512,6 @@ def register():
IDStore.rigify_types = CollectionProperty(type=RigifyName)
IDStore.rigify_active_type = IntProperty(name="Rigify Active Type", description="The selected rig type")
- bpy.types.Armature.rigify_advanced_generation = BoolProperty(name="Advanced Options",
- description="Enables/disables advanced options for Rigify rig generation",
- default=False)
-
- def update_mode(self, context):
- if self.rigify_generate_mode == 'new':
- self.rigify_force_widget_update = False
-
- bpy.types.Armature.rigify_generate_mode = EnumProperty(name="Rigify Generate Rig Mode",
- description="'Generate Rig' mode. In 'overwrite' mode the features of the target rig will be updated as defined by the metarig. In 'new' mode a new rig will be created as defined by the metarig. Current mode",
- update=update_mode,
- items=( ('overwrite', 'overwrite', ''),
- ('new', 'new', '')))
-
bpy.types.Armature.rigify_force_widget_update = BoolProperty(name="Force Widget Update",
description="Forces Rigify to delete and rebuild all the rig widgets. if unset, only missing widgets will be created",
default=False)
@@ -533,6 +519,9 @@ def register():
bpy.types.Armature.rigify_mirror_widgets = BoolProperty(name="Mirror Widgets",
description="Make widgets for left and right side bones linked duplicates with negative X scale for the right side, based on bone name symmetry",
default=True)
+ bpy.types.Armature.rigify_widgets_collection = PointerProperty(type=bpy.types.Collection,
+ name="Widgets Collection",
+ description="Defines which collection to place widget objects in. If unset, a new one will be created based on the name of the rig")
bpy.types.Armature.rigify_target_rig = PointerProperty(type=bpy.types.Object,
name="Rigify Target Rig",
@@ -546,11 +535,6 @@ def register():
bpy.types.Armature.rigify_finalize_script = PointerProperty(type=bpy.types.Text,
name="Finalize Script",
description="Run this script after generation to apply user-specific changes")
-
- bpy.types.Armature.rigify_rig_basename = StringProperty(name="Rigify Rig Name",
- description="Defines the name of the Rig. If unset, in 'new' mode 'rig' will be used, in 'overwrite' mode the target rig name will be used",
- default="")
-
IDStore.rigify_transfer_only_selected = BoolProperty(
name="Transfer Only Selected",
description="Transfer selected bones only", default=True)
@@ -592,12 +576,9 @@ def unregister():
del ArmStore.rigify_colors_index
del ArmStore.rigify_colors_lock
del ArmStore.rigify_theme_to_add
- del ArmStore.rigify_advanced_generation
- del ArmStore.rigify_generate_mode
del ArmStore.rigify_force_widget_update
del ArmStore.rigify_target_rig
del ArmStore.rigify_rig_ui
- del ArmStore.rigify_rig_basename
IDStore = bpy.types.WindowManager
del IDStore.rigify_collection
diff --git a/rigify/generate.py b/rigify/generate.py
index 501c335f..a674ade4 100644
--- a/rigify/generate.py
+++ b/rigify/generate.py
@@ -30,7 +30,7 @@ from .utils.widgets import WGT_PREFIX
from .utils.widgets_special import create_root_widget
from .utils.mechanism import refresh_all_drivers
from .utils.misc import gamma_correct, select_object
-from .utils.collections import ensure_widget_collection, list_layer_collections, filter_layer_collections_by_object
+from .utils.collections import ensure_collection, list_layer_collections, filter_layer_collections_by_object
from .utils.rig import get_rigify_type
from . import base_generate
@@ -55,9 +55,6 @@ class Generator(base_generate.BaseGenerator):
self.id_store = context.window_manager
- self.rig_new_name = ""
- self.rig_old_name = ""
-
def find_rig_class(self, rig_type):
rig_module = rig_lists.rigs[rig_type]["module"]
@@ -76,55 +73,42 @@ class Generator(base_generate.BaseGenerator):
self.collection = self.layer_collection.collection
- def __create_rig_object(self):
- scene = self.scene
- id_store = self.id_store
- meta_data = self.metarig.data
-
- # Check if the generated rig already exists, so we can
- # regenerate in the same object. If not, create a new
- # object to generate the rig in.
+ def ensure_rig_object(self) -> bpy.types.Object:
+ """Check if the generated rig already exists, so we can
+ regenerate in the same object. If not, create a new
+ object to generate the rig in.
+ """
print("Fetch rig.")
+ meta_data = self.metarig.data
- self.rig_new_name = name = meta_data.rigify_rig_basename or "rig"
-
- obj = None
-
- # Try existing object if overwriting
- if meta_data.rigify_generate_mode == 'overwrite':
- obj = meta_data.rigify_target_rig
-
- if obj:
- self.rig_old_name = obj.name
-
- obj.name = name
- obj.data.name = obj.name
-
- elif name in bpy.data.objects:
- obj = bpy.data.objects[name]
+ target_rig = meta_data.rigify_target_rig
+ if not target_rig:
+ if "metarig" in self.metarig.name:
+ rig_new_name = self.metarig.name.replace("metarig", "rig")
+ elif "META" in self.metarig.name:
+ rig_new_name = self.metarig.name.replace("META", "RIG")
+ else:
+ rig_new_name = "RIG-" + self.metarig.name
- # Create a new object if not found
- if not obj:
- obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
- obj.display_type = 'WIRE'
+ target_rig = bpy.data.objects.new(rig_new_name, bpy.data.armatures.new(rig_new_name))
+ target_rig.display_type = 'WIRE'
# If the object is already added to the scene, switch to its collection
- if obj.name in self.context.scene.collection.all_objects:
- self.__switch_to_usable_collection(obj)
+ if target_rig.name in self.context.scene.collection.all_objects:
+ self.__switch_to_usable_collection(target_rig)
else:
# Otherwise, add to the selected collection or the metarig collection if unusable
if (self.layer_collection not in self.usable_collections
or self.layer_collection == self.view_layer.layer_collection):
self.__switch_to_usable_collection(self.metarig, True)
- self.collection.objects.link(obj)
+ self.collection.objects.link(target_rig)
# Configure and remember the object
- meta_data.rigify_target_rig = obj
- obj.data.pose_position = 'POSE'
+ meta_data.rigify_target_rig = target_rig
+ target_rig.data.pose_position = 'POSE'
- self.obj = obj
- return obj
+ return target_rig
def __unhide_rig_object(self, obj):
@@ -144,11 +128,11 @@ class Generator(base_generate.BaseGenerator):
raise Exception('Could not generate: Could not find a usable collection.')
- def __create_widget_group(self):
- new_group_name = "WGTS_" + self.obj.name
- wgts_group_name = "WGTS_" + (self.rig_old_name or self.obj.name)
-
- # Find the old widgets collection
+ def __find_legacy_collection(self) -> bpy.types.Collection:
+ """For backwards comp, matching by name to find a legacy collection.
+ (For before there was a Widget Collection PointerProperty)
+ """
+ wgts_group_name = "WGTS_" + self.obj.name
old_collection = bpy.data.collections.get(wgts_group_name)
if not old_collection:
@@ -160,16 +144,22 @@ class Generator(base_generate.BaseGenerator):
old_collection = legacy_collection
if old_collection:
- # Remove widgets if force update is set
- if self.metarig.data.rigify_force_widget_update:
- for obj in list(old_collection.objects):
- bpy.data.objects.remove(obj)
-
# Rename the collection
- old_collection.name = new_group_name
+ old_collection.name = wgts_group_name
+
+ return old_collection
+ def ensure_widget_collection(self):
# Create/find widget collection
- self.widget_collection = ensure_widget_collection(self.context, new_group_name)
+ self.widget_collection = self.metarig.data.rigify_widgets_collection
+ if not self.widget_collection:
+ self.widget_collection = self.__find_legacy_collection()
+ if not self.widget_collection:
+ wgts_group_name = "WGTS_" + self.obj.name.replace("RIG-", "")
+ self.widget_collection = ensure_collection(self.context, wgts_group_name, hidden=True)
+
+ self.metarig.data.rigify_widgets_collection = self.widget_collection
+
self.use_mirror_widgets = self.metarig.data.rigify_mirror_widgets
# Build tables for existing widgets
@@ -177,7 +167,11 @@ class Generator(base_generate.BaseGenerator):
self.new_widget_table = {}
self.widget_mirror_mesh = {}
- if not self.metarig.data.rigify_force_widget_update and self.obj.pose:
+ if self.metarig.data.rigify_force_widget_update:
+ # Remove widgets if force update is set
+ for obj in list(self.widget_collection.objects):
+ bpy.data.objects.remove(obj)
+ elif self.obj.pose:
# Find all widgets from the collection referenced by the old rig
known_widgets = set(obj.name for obj in self.widget_collection.objects)
@@ -430,7 +424,7 @@ class Generator(base_generate.BaseGenerator):
#------------------------------------------
# Create/find the rig object and set it up
- obj = self.__create_rig_object()
+ self.obj = obj = self.ensure_rig_object()
self.__unhide_rig_object(obj)
@@ -446,8 +440,8 @@ class Generator(base_generate.BaseGenerator):
select_object(context, obj, deselect_all=True)
#------------------------------------------
- # Create Group widget
- self.__create_widget_group()
+ # Create Widget Collection
+ self.ensure_widget_collection()
t.tick("Create main WGTS: ")
diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py
index c83dd02b..8780461d 100644
--- a/rigify/rig_ui_template.py
+++ b/rigify/rig_ui_template.py
@@ -1167,27 +1167,10 @@ class ScriptGenerator(base_generate.GeneratorPlugin):
layer_layout += [(l.name, l.row)]
# Generate the UI script
- if metarig.data.rigify_rig_basename:
- rig_ui_name = metarig.data.rigify_rig_basename + '_ui.py'
- else:
- rig_ui_name = 'rig_ui.py'
-
- script = None
-
- if metarig.data.rigify_generate_mode == 'overwrite':
- script = metarig.data.rigify_rig_ui
-
- if not script and rig_ui_name in bpy.data.texts:
- script = bpy.data.texts[rig_ui_name]
-
- if script:
- script.clear()
- script.name = rig_ui_name
-
- if script is None:
- script = bpy.data.texts.new(rig_ui_name)
-
- metarig.data.rigify_rig_ui = script
+ script = metarig.data.rigify_rig_ui
+ if not script:
+ script = bpy.data.texts.new("rig_ui.py")
+ metarig.data.rigify_rig_ui = script
for s in OrderedDict.fromkeys(self.ui_imports):
script.write(s + "\n")
diff --git a/rigify/ui.py b/rigify/ui.py
index c801ac25..59dbf9b6 100644
--- a/rigify/ui.py
+++ b/rigify/ui.py
@@ -60,27 +60,27 @@ def build_type_list(context, rigify_types):
a.name = r
-class DATA_PT_rigify_buttons(bpy.types.Panel):
- bl_label = "Rigify Buttons"
+class DATA_PT_rigify_generate(bpy.types.Panel):
+ bl_label = "Rigify Generation"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
+ obj = context.object
if not context.object:
return False
- return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None
+ return obj.type == 'ARMATURE' \
+ and obj.data.get("rig_id") is None \
+ and obj.mode in {'POSE', 'OBJECT'}
def draw(self, context):
C = context
layout = self.layout
- obj = context.object
- id_store = C.window_manager
+ obj = C.object
if obj.mode in {'POSE', 'OBJECT'}:
- armature_id_store = C.object.data
-
WARNING = "Warning: Some features may change after generation"
show_warning = False
show_update_metarig = False
@@ -110,7 +110,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
if show_warning:
layout.label(text=WARNING, icon='ERROR')
- enable_generate_and_advanced = not (show_not_updatable or show_update_metarig)
+ enable_generate = not (show_not_updatable or show_update_metarig)
if show_not_updatable:
layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR')
@@ -131,71 +131,74 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
col.separator()
row = col.row()
- row.operator("pose.rigify_generate", text="Generate Rig", icon='POSE_HLT')
+ text = "Re-Generate Rig" if obj.data.rigify_target_rig else "Generate Rig"
+ row.operator("pose.rigify_generate", text=text, icon='POSE_HLT')
+ row.enabled = enable_generate
- row.enabled = enable_generate_and_advanced
- if armature_id_store.rigify_advanced_generation:
- icon = 'UNLOCKED'
- else:
- icon = 'LOCKED'
+class DATA_PT_rigify_generate_advanced(bpy.types.Panel):
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+ bl_label = "Advanced"
+ bl_parent_id = 'DATA_PT_rigify_generate'
+ bl_options = {'DEFAULT_CLOSED'}
- col = layout.column()
- col.enabled = enable_generate_and_advanced
- row = col.row()
- row.prop(armature_id_store, "rigify_advanced_generation", toggle=True, icon=icon)
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
- if armature_id_store.rigify_advanced_generation:
+ armature_id_store = context.object.data
- row = col.row(align=True)
- row.prop(armature_id_store, "rigify_generate_mode", expand=True)
-
- main_row = col.row(align=True).split(factor=0.3)
- col1 = main_row.column()
- col2 = main_row.column()
- col1.label(text="Rig Name")
- row = col1.row()
- row.label(text="Target Rig")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
- row = col1.row()
- row.label(text="Target UI")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col2.row(align=True)
- row.prop(armature_id_store, "rigify_rig_basename", text="", icon="SORTALPHA")
-
- row = col2.row(align=True)
- row.prop(armature_id_store, "rigify_target_rig", text="")
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col2.row()
- row.prop(armature_id_store, "rigify_rig_ui", text="", icon='TEXT')
- row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
-
- row = col.row()
- row.prop(armature_id_store, "rigify_force_widget_update")
- if armature_id_store.rigify_generate_mode == 'new':
- row.enabled = False
-
- col.prop(armature_id_store, "rigify_mirror_widgets")
- col.prop(armature_id_store, "rigify_finalize_script", text="Run Script")
-
- elif obj.mode == 'EDIT':
- # Build types list
- build_type_list(context, id_store.rigify_types)
-
- if id_store.rigify_active_type > len(id_store.rigify_types):
- id_store.rigify_active_type = 0
-
- # Rig type list
- if len(feature_set_list.get_installed_list()) > 0:
- row = layout.row()
- row.prop(context.object.data, "active_feature_set")
+ col = layout.column()
+ col.row().prop(armature_id_store, "rigify_target_rig", text="Target Rig")
+ col.row().prop(armature_id_store, "rigify_rig_ui", text="Rig UI Script")
+ col.separator()
+ col.row().prop(armature_id_store, "rigify_widgets_collection")
+ col.row().prop(armature_id_store, "rigify_force_widget_update")
+ col.row().prop(armature_id_store, "rigify_mirror_widgets")
+ col.separator()
+ col.row().prop(armature_id_store, "rigify_finalize_script", text="Run Script")
+
+
+class DATA_PT_rigify_samples(bpy.types.Panel):
+ bl_label = "Rigify Samples"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ obj = context.object
+ if not obj:
+ return False
+ return obj.type == 'ARMATURE' \
+ and obj.data.get("rig_id") is None \
+ and obj.mode == 'EDIT'
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False
+ obj = context.object
+ id_store = context.window_manager
+
+ # Build types list
+ build_type_list(context, id_store.rigify_types)
+
+ if id_store.rigify_active_type > len(id_store.rigify_types):
+ id_store.rigify_active_type = 0
+
+ # Rig type list
+ if len(feature_set_list.get_installed_list()) > 0:
row = layout.row()
- row.template_list("UI_UL_list", "rigify_types", id_store, "rigify_types", id_store, 'rigify_active_type')
+ row.prop(context.object.data, "active_feature_set")
+ row = layout.row()
+ row.template_list("UI_UL_list", "rigify_types", id_store, "rigify_types", id_store, 'rigify_active_type')
- props = layout.operator("armature.metarig_sample_add", text="Add sample")
- props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
+ props = layout.operator("armature.metarig_sample_add", text="Add sample")
+ props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
class DATA_PT_rigify_layer_names(bpy.types.Panel):
@@ -791,8 +794,9 @@ class Generate(bpy.types.Operator):
return is_metarig(context.object)
def execute(self, context):
+ metarig = context.object
try:
- generate.generate_rig(context, context.object)
+ generate.generate_rig(context, metarig)
except MetarigError as rig_exception:
import traceback
traceback.print_exc()
@@ -803,6 +807,8 @@ class Generate(bpy.types.Operator):
traceback.print_exc()
self.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception))
+ else:
+ self.report({'INFO'}, 'Successfully generated: "' + metarig.data.rigify_target_rig.name + '"')
finally:
bpy.ops.object.mode_set(mode='OBJECT')
@@ -930,8 +936,10 @@ class VIEW3D_MT_rigify(bpy.types.Menu):
def draw(self, context):
layout = self.layout
+ obj = context.object
- layout.operator(Generate.bl_idname, text="Generate")
+ text = "Re-Generate Rig" if obj.data.rigify_target_rig else "Generate Rig"
+ layout.operator(Generate.bl_idname, text=text)
if context.mode == 'EDIT_ARMATURE':
layout.separator()
@@ -1381,7 +1389,9 @@ classes = (
DATA_MT_rigify_bone_groups_context_menu,
DATA_PT_rigify_bone_groups,
DATA_PT_rigify_layer_names,
- DATA_PT_rigify_buttons,
+ DATA_PT_rigify_generate,
+ DATA_PT_rigify_generate_advanced,
+ DATA_PT_rigify_samples,
BONE_PT_rigify_buttons,
VIEW3D_PT_rigify_animation_tools,
VIEW3D_PT_tools_rigify_dev,
diff --git a/rigify/utils/collections.py b/rigify/utils/collections.py
index a172b984..a19b9da1 100644
--- a/rigify/utils/collections.py
+++ b/rigify/utils/collections.py
@@ -19,9 +19,6 @@
# <pep8 compliant>
import bpy
-import math
-
-from .errors import MetarigError
#=============================================
@@ -65,30 +62,32 @@ def filter_layer_collections_by_object(layer_collections, obj):
return [lc for lc in layer_collections if obj in lc.collection.objects.values()]
-def ensure_widget_collection(context, wgts_collection_name):
+def ensure_collection(context, collection_name, hidden=False) -> bpy.types.Collection:
+ """Check if a collection with a certain name exists.
+ If yes, return it, if not, create it in the scene root collection.
+ """
view_layer = context.view_layer
- layer_collection = bpy.context.layer_collection
- collection = layer_collection.collection
+ active_layer_coll = bpy.context.layer_collection
+ active_collection = active_layer_coll.collection
- widget_collection = bpy.data.collections.get(wgts_collection_name)
- if not widget_collection:
- # ------------------------------------------
- # Create the widget collection
- widget_collection = bpy.data.collections.new(wgts_collection_name)
- widget_collection.hide_viewport = True
- widget_collection.hide_render = True
+ collection = bpy.data.collections.get(collection_name)
+ if not collection:
+ # Create the collection
+ collection = bpy.data.collections.new(collection_name)
+ collection.hide_viewport = hidden
+ collection.hide_render = hidden
- widget_layer_collection = None
+ layer_collection = None
else:
- widget_layer_collection = find_layer_collection_by_collection(view_layer.layer_collection, widget_collection)
+ layer_collection = find_layer_collection_by_collection(view_layer.layer_collection, collection)
- if not widget_layer_collection:
- # Add the widget collection to the tree
- collection.children.link(widget_collection)
- widget_layer_collection = [c for c in layer_collection.children if c.collection == widget_collection][0]
+ if not layer_collection:
+ # Let the new collection be a child of the active one.
+ active_collection.children.link(collection)
+ layer_collection = [c for c in active_layer_coll.children if c.collection == collection][0]
- widget_layer_collection.exclude = True
+ layer_collection.exclude = True
- # Make the widget the active collection for the upcoming added (widget) objects
- view_layer.active_layer_collection = widget_layer_collection
- return widget_collection
+ # Make the new collection active.
+ view_layer.active_layer_collection = layer_collection
+ return collection
diff --git a/rigify/utils/widgets.py b/rigify/utils/widgets.py
index 3f0bf252..b3715f80 100644
--- a/rigify/utils/widgets.py
+++ b/rigify/utils/widgets.py
@@ -27,7 +27,7 @@ from mathutils import Matrix, Vector, Euler
from itertools import count
from .errors import MetarigError
-from .collections import ensure_widget_collection
+from .collections import ensure_collection
from .naming import change_name_side, get_name_side, Side
WGT_PREFIX = "WGT-" # Prefix for widget objects
@@ -79,7 +79,7 @@ def create_widget(rig, bone_name, bone_transform_name=None, *, widget_name=None,
if generator:
collection = generator.widget_collection
else:
- collection = ensure_widget_collection(bpy.context, 'WGTS_' + rig.name)
+ collection = ensure_collection(bpy.context, 'WGTS_' + rig.name, hidden=True)
use_mirror = generator and generator.use_mirror_widgets