mirror of
https://github.com/blender/blender-addons.git
synced 2025-08-20 13:22:58 +00:00
Rigify: Clean up "Rigify Buttons" panel UX
The overall goal of this patch is to improve the UI/UX of the panel previously known as "Rigify Buttons" which presumably takes its name from the old "Buttons Panel" which is now known as the Properties Editor. Before: {F10511640} After: {F10511624} - Make Rigify less reliant on name matching when it comes to maintaining the link between the metarig, the UI script, the generated rig, and the widgets collection. (Use pointers only, names shouldn't matter!) - Change the "Advanced" toggle button into a real sub-panel. - Split up the "Rigify Buttons" panels into "Rigify Generation" and "Rigify Samples" panels in non-edit and edit mode respectively, to better describe what the user will find there. Changes in the Rigify Buttons panel: - Removed the "overwrite/new" enum. - If there is a target rig object, it will be overwritten. If not, it will be created. - If a rig object with the desired name already existed, but wasn't selected as the target rig, the "overwrite" option still overwrote that rig. I don't agree with that because this meant messing with data without indicating that that data is going to be messed with. Unaware users could lose data/work. With these changes, the worst thing that can happen is that your rig ends up with a .001 suffix. - Removed the "rig name" text input field. Before this patch, this would always rename your rig object and your rig script text datablock, which I think is more frustrating than useful. Now you can simply rename them after generation yourself, and the names will be kept in subsequent generations. - Single-column layout - Changed the "Advanced Options" into a sub-panel instead. On request: - Added an info message to show the name of the successfully generated rig: {F10159079} Feedback welcome. Reviewed By: angavrilov Differential Revision: https://developer.blender.org/D11356
This commit is contained in:

committed by
Demeter Dzadik

parent
c60fef3817
commit
ece39d809c
@ -512,20 +512,6 @@ def register():
|
|||||||
IDStore.rigify_types = CollectionProperty(type=RigifyName)
|
IDStore.rigify_types = CollectionProperty(type=RigifyName)
|
||||||
IDStore.rigify_active_type = IntProperty(name="Rigify Active Type", description="The selected rig type")
|
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",
|
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",
|
description="Forces Rigify to delete and rebuild all the rig widgets. if unset, only missing widgets will be created",
|
||||||
default=False)
|
default=False)
|
||||||
@ -533,6 +519,9 @@ def register():
|
|||||||
bpy.types.Armature.rigify_mirror_widgets = BoolProperty(name="Mirror Widgets",
|
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",
|
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)
|
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,
|
bpy.types.Armature.rigify_target_rig = PointerProperty(type=bpy.types.Object,
|
||||||
name="Rigify Target Rig",
|
name="Rigify Target Rig",
|
||||||
@ -546,11 +535,6 @@ def register():
|
|||||||
bpy.types.Armature.rigify_finalize_script = PointerProperty(type=bpy.types.Text,
|
bpy.types.Armature.rigify_finalize_script = PointerProperty(type=bpy.types.Text,
|
||||||
name="Finalize Script",
|
name="Finalize Script",
|
||||||
description="Run this script after generation to apply user-specific changes")
|
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(
|
IDStore.rigify_transfer_only_selected = BoolProperty(
|
||||||
name="Transfer Only Selected",
|
name="Transfer Only Selected",
|
||||||
description="Transfer selected bones only", default=True)
|
description="Transfer selected bones only", default=True)
|
||||||
@ -592,12 +576,9 @@ def unregister():
|
|||||||
del ArmStore.rigify_colors_index
|
del ArmStore.rigify_colors_index
|
||||||
del ArmStore.rigify_colors_lock
|
del ArmStore.rigify_colors_lock
|
||||||
del ArmStore.rigify_theme_to_add
|
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_force_widget_update
|
||||||
del ArmStore.rigify_target_rig
|
del ArmStore.rigify_target_rig
|
||||||
del ArmStore.rigify_rig_ui
|
del ArmStore.rigify_rig_ui
|
||||||
del ArmStore.rigify_rig_basename
|
|
||||||
|
|
||||||
IDStore = bpy.types.WindowManager
|
IDStore = bpy.types.WindowManager
|
||||||
del IDStore.rigify_collection
|
del IDStore.rigify_collection
|
||||||
|
@ -30,7 +30,7 @@ from .utils.widgets import WGT_PREFIX
|
|||||||
from .utils.widgets_special import create_root_widget
|
from .utils.widgets_special import create_root_widget
|
||||||
from .utils.mechanism import refresh_all_drivers
|
from .utils.mechanism import refresh_all_drivers
|
||||||
from .utils.misc import gamma_correct, select_object
|
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 .utils.rig import get_rigify_type
|
||||||
|
|
||||||
from . import base_generate
|
from . import base_generate
|
||||||
@ -55,9 +55,6 @@ class Generator(base_generate.BaseGenerator):
|
|||||||
|
|
||||||
self.id_store = context.window_manager
|
self.id_store = context.window_manager
|
||||||
|
|
||||||
self.rig_new_name = ""
|
|
||||||
self.rig_old_name = ""
|
|
||||||
|
|
||||||
|
|
||||||
def find_rig_class(self, rig_type):
|
def find_rig_class(self, rig_type):
|
||||||
rig_module = rig_lists.rigs[rig_type]["module"]
|
rig_module = rig_lists.rigs[rig_type]["module"]
|
||||||
@ -76,55 +73,42 @@ class Generator(base_generate.BaseGenerator):
|
|||||||
self.collection = self.layer_collection.collection
|
self.collection = self.layer_collection.collection
|
||||||
|
|
||||||
|
|
||||||
def __create_rig_object(self):
|
def ensure_rig_object(self) -> bpy.types.Object:
|
||||||
scene = self.scene
|
"""Check if the generated rig already exists, so we can
|
||||||
id_store = self.id_store
|
regenerate in the same object. If not, create a new
|
||||||
|
object to generate the rig in.
|
||||||
|
"""
|
||||||
|
print("Fetch rig.")
|
||||||
meta_data = self.metarig.data
|
meta_data = self.metarig.data
|
||||||
|
|
||||||
# Check if the generated rig already exists, so we can
|
target_rig = meta_data.rigify_target_rig
|
||||||
# regenerate in the same object. If not, create a new
|
if not target_rig:
|
||||||
# object to generate the rig in.
|
if "metarig" in self.metarig.name:
|
||||||
print("Fetch rig.")
|
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
|
||||||
|
|
||||||
self.rig_new_name = name = meta_data.rigify_rig_basename or "rig"
|
target_rig = bpy.data.objects.new(rig_new_name, bpy.data.armatures.new(rig_new_name))
|
||||||
|
target_rig.display_type = 'WIRE'
|
||||||
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]
|
|
||||||
|
|
||||||
# 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'
|
|
||||||
|
|
||||||
# If the object is already added to the scene, switch to its collection
|
# If the object is already added to the scene, switch to its collection
|
||||||
if obj.name in self.context.scene.collection.all_objects:
|
if target_rig.name in self.context.scene.collection.all_objects:
|
||||||
self.__switch_to_usable_collection(obj)
|
self.__switch_to_usable_collection(target_rig)
|
||||||
else:
|
else:
|
||||||
# Otherwise, add to the selected collection or the metarig collection if unusable
|
# Otherwise, add to the selected collection or the metarig collection if unusable
|
||||||
if (self.layer_collection not in self.usable_collections
|
if (self.layer_collection not in self.usable_collections
|
||||||
or self.layer_collection == self.view_layer.layer_collection):
|
or self.layer_collection == self.view_layer.layer_collection):
|
||||||
self.__switch_to_usable_collection(self.metarig, True)
|
self.__switch_to_usable_collection(self.metarig, True)
|
||||||
|
|
||||||
self.collection.objects.link(obj)
|
self.collection.objects.link(target_rig)
|
||||||
|
|
||||||
# Configure and remember the object
|
# Configure and remember the object
|
||||||
meta_data.rigify_target_rig = obj
|
meta_data.rigify_target_rig = target_rig
|
||||||
obj.data.pose_position = 'POSE'
|
target_rig.data.pose_position = 'POSE'
|
||||||
|
|
||||||
self.obj = obj
|
return target_rig
|
||||||
return obj
|
|
||||||
|
|
||||||
|
|
||||||
def __unhide_rig_object(self, obj):
|
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.')
|
raise Exception('Could not generate: Could not find a usable collection.')
|
||||||
|
|
||||||
|
|
||||||
def __create_widget_group(self):
|
def __find_legacy_collection(self) -> bpy.types.Collection:
|
||||||
new_group_name = "WGTS_" + self.obj.name
|
"""For backwards comp, matching by name to find a legacy collection.
|
||||||
wgts_group_name = "WGTS_" + (self.rig_old_name or self.obj.name)
|
(For before there was a Widget Collection PointerProperty)
|
||||||
|
"""
|
||||||
# Find the old widgets collection
|
wgts_group_name = "WGTS_" + self.obj.name
|
||||||
old_collection = bpy.data.collections.get(wgts_group_name)
|
old_collection = bpy.data.collections.get(wgts_group_name)
|
||||||
|
|
||||||
if not old_collection:
|
if not old_collection:
|
||||||
@ -160,16 +144,22 @@ class Generator(base_generate.BaseGenerator):
|
|||||||
old_collection = legacy_collection
|
old_collection = legacy_collection
|
||||||
|
|
||||||
if old_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
|
# 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
|
# 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
|
self.use_mirror_widgets = self.metarig.data.rigify_mirror_widgets
|
||||||
|
|
||||||
# Build tables for existing widgets
|
# Build tables for existing widgets
|
||||||
@ -177,7 +167,11 @@ class Generator(base_generate.BaseGenerator):
|
|||||||
self.new_widget_table = {}
|
self.new_widget_table = {}
|
||||||
self.widget_mirror_mesh = {}
|
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
|
# Find all widgets from the collection referenced by the old rig
|
||||||
known_widgets = set(obj.name for obj in self.widget_collection.objects)
|
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
|
# 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)
|
self.__unhide_rig_object(obj)
|
||||||
|
|
||||||
@ -446,8 +440,8 @@ class Generator(base_generate.BaseGenerator):
|
|||||||
select_object(context, obj, deselect_all=True)
|
select_object(context, obj, deselect_all=True)
|
||||||
|
|
||||||
#------------------------------------------
|
#------------------------------------------
|
||||||
# Create Group widget
|
# Create Widget Collection
|
||||||
self.__create_widget_group()
|
self.ensure_widget_collection()
|
||||||
|
|
||||||
t.tick("Create main WGTS: ")
|
t.tick("Create main WGTS: ")
|
||||||
|
|
||||||
|
@ -1167,27 +1167,10 @@ class ScriptGenerator(base_generate.GeneratorPlugin):
|
|||||||
layer_layout += [(l.name, l.row)]
|
layer_layout += [(l.name, l.row)]
|
||||||
|
|
||||||
# Generate the UI script
|
# Generate the UI script
|
||||||
if metarig.data.rigify_rig_basename:
|
script = metarig.data.rigify_rig_ui
|
||||||
rig_ui_name = metarig.data.rigify_rig_basename + '_ui.py'
|
if not script:
|
||||||
else:
|
script = bpy.data.texts.new("rig_ui.py")
|
||||||
rig_ui_name = 'rig_ui.py'
|
metarig.data.rigify_rig_ui = script
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
for s in OrderedDict.fromkeys(self.ui_imports):
|
for s in OrderedDict.fromkeys(self.ui_imports):
|
||||||
script.write(s + "\n")
|
script.write(s + "\n")
|
||||||
|
134
rigify/ui.py
134
rigify/ui.py
@ -60,27 +60,27 @@ def build_type_list(context, rigify_types):
|
|||||||
a.name = r
|
a.name = r
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_rigify_buttons(bpy.types.Panel):
|
class DATA_PT_rigify_generate(bpy.types.Panel):
|
||||||
bl_label = "Rigify Buttons"
|
bl_label = "Rigify Generation"
|
||||||
bl_space_type = 'PROPERTIES'
|
bl_space_type = 'PROPERTIES'
|
||||||
bl_region_type = 'WINDOW'
|
bl_region_type = 'WINDOW'
|
||||||
bl_context = "data"
|
bl_context = "data"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
|
obj = context.object
|
||||||
if not context.object:
|
if not context.object:
|
||||||
return False
|
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):
|
def draw(self, context):
|
||||||
C = context
|
C = context
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
obj = context.object
|
obj = C.object
|
||||||
id_store = C.window_manager
|
|
||||||
|
|
||||||
if obj.mode in {'POSE', 'OBJECT'}:
|
if obj.mode in {'POSE', 'OBJECT'}:
|
||||||
armature_id_store = C.object.data
|
|
||||||
|
|
||||||
WARNING = "Warning: Some features may change after generation"
|
WARNING = "Warning: Some features may change after generation"
|
||||||
show_warning = False
|
show_warning = False
|
||||||
show_update_metarig = False
|
show_update_metarig = False
|
||||||
@ -110,7 +110,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
|
|||||||
if show_warning:
|
if show_warning:
|
||||||
layout.label(text=WARNING, icon='ERROR')
|
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:
|
if show_not_updatable:
|
||||||
layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR')
|
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()
|
col.separator()
|
||||||
row = col.row()
|
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:
|
class DATA_PT_rigify_generate_advanced(bpy.types.Panel):
|
||||||
icon = 'UNLOCKED'
|
bl_space_type = 'PROPERTIES'
|
||||||
else:
|
bl_region_type = 'WINDOW'
|
||||||
icon = 'LOCKED'
|
bl_context = "data"
|
||||||
|
bl_label = "Advanced"
|
||||||
|
bl_parent_id = 'DATA_PT_rigify_generate'
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
col = layout.column()
|
def draw(self, context):
|
||||||
col.enabled = enable_generate_and_advanced
|
layout = self.layout
|
||||||
row = col.row()
|
layout.use_property_split = True
|
||||||
row.prop(armature_id_store, "rigify_advanced_generation", toggle=True, icon=icon)
|
layout.use_property_decorate = False
|
||||||
|
|
||||||
if armature_id_store.rigify_advanced_generation:
|
armature_id_store = context.object.data
|
||||||
|
|
||||||
row = col.row(align=True)
|
col = layout.column()
|
||||||
row.prop(armature_id_store, "rigify_generate_mode", expand=True)
|
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")
|
||||||
|
|
||||||
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)
|
class DATA_PT_rigify_samples(bpy.types.Panel):
|
||||||
row.prop(armature_id_store, "rigify_rig_basename", text="", icon="SORTALPHA")
|
bl_label = "Rigify Samples"
|
||||||
|
bl_space_type = 'PROPERTIES'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_context = "data"
|
||||||
|
|
||||||
row = col2.row(align=True)
|
@classmethod
|
||||||
row.prop(armature_id_store, "rigify_target_rig", text="")
|
def poll(cls, context):
|
||||||
row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
|
obj = context.object
|
||||||
|
if not obj:
|
||||||
|
return False
|
||||||
|
return obj.type == 'ARMATURE' \
|
||||||
|
and obj.data.get("rig_id") is None \
|
||||||
|
and obj.mode == 'EDIT'
|
||||||
|
|
||||||
row = col2.row()
|
def draw(self, context):
|
||||||
row.prop(armature_id_store, "rigify_rig_ui", text="", icon='TEXT')
|
layout = self.layout
|
||||||
row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
|
layout.use_property_split = True
|
||||||
|
layout.use_property_decorate = False
|
||||||
|
obj = context.object
|
||||||
|
id_store = context.window_manager
|
||||||
|
|
||||||
row = col.row()
|
# Build types list
|
||||||
row.prop(armature_id_store, "rigify_force_widget_update")
|
build_type_list(context, id_store.rigify_types)
|
||||||
if armature_id_store.rigify_generate_mode == 'new':
|
|
||||||
row.enabled = False
|
|
||||||
|
|
||||||
col.prop(armature_id_store, "rigify_mirror_widgets")
|
if id_store.rigify_active_type > len(id_store.rigify_types):
|
||||||
col.prop(armature_id_store, "rigify_finalize_script", text="Run Script")
|
id_store.rigify_active_type = 0
|
||||||
|
|
||||||
elif obj.mode == 'EDIT':
|
# Rig type list
|
||||||
# Build types list
|
if len(feature_set_list.get_installed_list()) > 0:
|
||||||
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")
|
|
||||||
row = layout.row()
|
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 = layout.operator("armature.metarig_sample_add", text="Add sample")
|
||||||
props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
|
props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_rigify_layer_names(bpy.types.Panel):
|
class DATA_PT_rigify_layer_names(bpy.types.Panel):
|
||||||
@ -791,8 +794,9 @@ class Generate(bpy.types.Operator):
|
|||||||
return is_metarig(context.object)
|
return is_metarig(context.object)
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
metarig = context.object
|
||||||
try:
|
try:
|
||||||
generate.generate_rig(context, context.object)
|
generate.generate_rig(context, metarig)
|
||||||
except MetarigError as rig_exception:
|
except MetarigError as rig_exception:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@ -803,6 +807,8 @@ class Generate(bpy.types.Operator):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
self.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception))
|
self.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception))
|
||||||
|
else:
|
||||||
|
self.report({'INFO'}, 'Successfully generated: "' + metarig.data.rigify_target_rig.name + '"')
|
||||||
finally:
|
finally:
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
@ -930,8 +936,10 @@ class VIEW3D_MT_rigify(bpy.types.Menu):
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
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':
|
if context.mode == 'EDIT_ARMATURE':
|
||||||
layout.separator()
|
layout.separator()
|
||||||
@ -1381,7 +1389,9 @@ classes = (
|
|||||||
DATA_MT_rigify_bone_groups_context_menu,
|
DATA_MT_rigify_bone_groups_context_menu,
|
||||||
DATA_PT_rigify_bone_groups,
|
DATA_PT_rigify_bone_groups,
|
||||||
DATA_PT_rigify_layer_names,
|
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,
|
BONE_PT_rigify_buttons,
|
||||||
VIEW3D_PT_rigify_animation_tools,
|
VIEW3D_PT_rigify_animation_tools,
|
||||||
VIEW3D_PT_tools_rigify_dev,
|
VIEW3D_PT_tools_rigify_dev,
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
# <pep8 compliant>
|
# <pep8 compliant>
|
||||||
|
|
||||||
import bpy
|
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()]
|
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
|
view_layer = context.view_layer
|
||||||
layer_collection = bpy.context.layer_collection
|
active_layer_coll = bpy.context.layer_collection
|
||||||
collection = layer_collection.collection
|
active_collection = active_layer_coll.collection
|
||||||
|
|
||||||
widget_collection = bpy.data.collections.get(wgts_collection_name)
|
collection = bpy.data.collections.get(collection_name)
|
||||||
if not widget_collection:
|
if not collection:
|
||||||
# ------------------------------------------
|
# Create the collection
|
||||||
# Create the widget collection
|
collection = bpy.data.collections.new(collection_name)
|
||||||
widget_collection = bpy.data.collections.new(wgts_collection_name)
|
collection.hide_viewport = hidden
|
||||||
widget_collection.hide_viewport = True
|
collection.hide_render = hidden
|
||||||
widget_collection.hide_render = True
|
|
||||||
|
|
||||||
widget_layer_collection = None
|
layer_collection = None
|
||||||
else:
|
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:
|
if not layer_collection:
|
||||||
# Add the widget collection to the tree
|
# Let the new collection be a child of the active one.
|
||||||
collection.children.link(widget_collection)
|
active_collection.children.link(collection)
|
||||||
widget_layer_collection = [c for c in layer_collection.children if c.collection == widget_collection][0]
|
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
|
# Make the new collection active.
|
||||||
view_layer.active_layer_collection = widget_layer_collection
|
view_layer.active_layer_collection = layer_collection
|
||||||
return widget_collection
|
return collection
|
||||||
|
@ -27,7 +27,7 @@ from mathutils import Matrix, Vector, Euler
|
|||||||
from itertools import count
|
from itertools import count
|
||||||
|
|
||||||
from .errors import MetarigError
|
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
|
from .naming import change_name_side, get_name_side, Side
|
||||||
|
|
||||||
WGT_PREFIX = "WGT-" # Prefix for widget objects
|
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:
|
if generator:
|
||||||
collection = generator.widget_collection
|
collection = generator.widget_collection
|
||||||
else:
|
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
|
use_mirror = generator and generator.use_mirror_widgets
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user