Rigify: store advanced options in armature instead of window manager.

By storing the Rigify advanced generation options (name, target rig,
target ui script) in the armature data instead of the window manager
as before, multiple rigs can have different options. Additionally,
these options are stored in the blend file, and not lost when reloading.

Also, the rig name is not automatically suffixed with `_rig`, which
doesn't make sense as far as I can tell.

Differential Revision: https://developer.blender.org/D5675
This commit is contained in:
Damien Picard 2019-10-15 13:31:12 +03:00 committed by Alexander Gavrilov
parent 0260327cff
commit 71565f82b2
Notes: blender-bot 2023-02-14 18:07:07 +01:00
Referenced by commit ed5b81f5: Fix T71678: Rigify crash if the Advanced mode is set to New.
Referenced by commit ed5b81f5, Fix T71678: Rigify crash if the Advanced mode is set to New.
4 changed files with 73 additions and 82 deletions

View File

@ -20,7 +20,7 @@
bl_info = {
"name": "Rigify",
"version": (0, 6, 0),
"version": (0, 6, 1),
"author": "Nathan Vegdahl, Lucio Rossi, Ivan Cappiello, Alexander Gavrilov",
"blender": (2, 81, 0),
"description": "Automatic rigging from building-block components",
@ -520,7 +520,7 @@ def register():
IDStore.rigify_types = CollectionProperty(type=RigifyName)
IDStore.rigify_active_type = IntProperty(name="Rigify Active Type", description="The selected rig type")
IDStore.rigify_advanced_generation = BoolProperty(name="Advanced Options",
bpy.types.Armature.rigify_advanced_generation = BoolProperty(name="Advanced Options",
description="Enables/disables advanced options for Rigify rig generation",
default=False)
@ -528,27 +528,26 @@ def register():
if self.rigify_generate_mode == 'new':
self.rigify_force_widget_update = False
IDStore.rigify_generate_mode = EnumProperty(name="Rigify Generate Rig Mode",
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', '')))
IDStore.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",
default=False)
IDStore.rigify_target_rigs = CollectionProperty(type=RigifyName)
IDStore.rigify_target_rig = StringProperty(name="Rigify Target Rig",
bpy.types.Armature.rigify_target_rig = PointerProperty(type=bpy.types.Object,
name="Rigify Target Rig",
description="Defines which rig to overwrite. If unset, a new one called 'rig' will be created",
default="")
poll=lambda self, obj: obj.type == 'ARMATURE' and obj.data is not self)
IDStore.rigify_rig_uis = CollectionProperty(type=RigifyName)
IDStore.rigify_rig_ui = StringProperty(name="Rigify Target Rig UI",
description="Defines the UI to overwrite. It should always be the same as the target rig. If unset, 'rig_ui.py' will be used",
default="")
bpy.types.Armature.rigify_rig_ui = PointerProperty(type=bpy.types.Text,
name="Rigify Target Rig UI",
description="Defines the UI to overwrite. If unset, 'rig_ui.py' will be used")
IDStore.rigify_rig_basename = StringProperty(name="Rigify Rig Name",
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="")
@ -602,19 +601,17 @@ 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
del IDStore.rigify_types
del IDStore.rigify_active_type
del IDStore.rigify_advanced_generation
del IDStore.rigify_generate_mode
del IDStore.rigify_force_widget_update
del IDStore.rigify_target_rig
del IDStore.rigify_target_rigs
del IDStore.rigify_rig_uis
del IDStore.rigify_rig_ui
del IDStore.rigify_rig_basename
del IDStore.rigify_transfer_only_selected
# Classes.

View File

@ -69,36 +69,45 @@ class Generator(base_generate.BaseGenerator):
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.
print("Fetch rig.")
if id_store.rigify_generate_mode == 'overwrite':
name = id_store.rigify_target_rig or "rig"
try:
self.rig_new_name = name = meta_data.rigify_rig_basename or "rig"
obj = None
if meta_data.rigify_generate_mode == 'overwrite':
obj = meta_data.rigify_target_rig
if not obj and name in scene.objects:
obj = scene.objects[name]
self.rig_old_name = name
obj.name = self.rig_new_name or name
if obj:
self.rig_old_name = obj.name
obj.name = name
obj.data.name = obj.name
rig_collections = filter_layer_collections_by_object(self.usable_collections, obj)
self.layer_collection = (rig_collections + [self.layer_collection])[0]
self.collection = self.layer_collection.collection
except KeyError:
self.rig_old_name = name
name = self.rig_new_name or name
obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
obj.display_type = 'WIRE'
self.collection.objects.link(obj)
else:
name = self.rig_new_name or "rig"
obj = bpy.data.objects.new(name, bpy.data.armatures.new(name)) # in case name 'rig' exists it will be rig.001
elif name in bpy.data.objects:
obj = bpy.data.objects[name]
if not obj:
obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
obj.display_type = 'WIRE'
self.collection.objects.link(obj)
id_store.rigify_target_rig = obj.name
elif obj.name not in self.collection.objects: # rig exists but was deleted
self.collection.objects.link(obj)
meta_data.rigify_target_rig = obj
obj.data.pose_position = 'POSE'
self.obj = obj
@ -114,8 +123,8 @@ class Generator(base_generate.BaseGenerator):
self.widget_collection = ensure_widget_collection(context)
# Remove wgts if force update is set
wgts_group_name = "WGTS_" + (self.rig_old_name or obj.name)
if wgts_group_name in scene.objects and id_store.rigify_force_widget_update:
wgts_group_name = "WGTS_" + (self.rig_old_name or self.obj.name)
if wgts_group_name in scene.objects and self.metarig.data.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:
@ -320,9 +329,6 @@ class Generator(base_generate.BaseGenerator):
#------------------------------------------
# Create/find the rig object and set it up
if id_store.rigify_rig_basename:
self.rig_new_name = id_store.rigify_rig_basename + "_rig"
obj = self.__create_rig_object()
# Get rid of anim data in case the rig already existed

View File

@ -1147,7 +1147,6 @@ class ScriptGenerator(base_generate.GeneratorPlugin):
def finalize(self):
metarig = self.generator.metarig
id_store = self.generator.id_store
rig_id = self.generator.rig_id
vis_layers = self.obj.data.layers
@ -1162,23 +1161,27 @@ class ScriptGenerator(base_generate.GeneratorPlugin):
layer_layout += [(l.name, l.row)]
# Generate the UI script
if id_store.rigify_generate_mode == 'overwrite':
rig_ui_name = id_store.rigify_rig_ui or 'rig_ui.py'
if metarig.data.rigify_rig_basename:
rig_ui_name = metarig.data.rigify_rig_basename + '_rig_ui.py'
else:
rig_ui_name = 'rig_ui.py'
if id_store.rigify_generate_mode == 'overwrite' and rig_ui_name in bpy.data.texts.keys():
script = bpy.data.texts[rig_ui_name]
script.clear()
else:
script = bpy.data.texts.new("rig_ui.py")
script = None
rig_ui_old_name = ""
if id_store.rigify_rig_basename:
rig_ui_old_name = script.name
script.name = id_store.rigify_rig_basename + "_rig_ui.py"
if metarig.data.rigify_generate_mode == 'overwrite':
script = metarig.data.rigify_rig_ui
id_store.rigify_rig_ui = script.name
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):
script.write(s + "\n")

View File

@ -77,6 +77,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
id_store = C.window_manager
if obj.mode in {'POSE', 'OBJECT'}:
armature_id_store = C.object.data
WARNING = "Warning: Some features may change after generation"
show_warning = False
@ -127,7 +128,7 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
row.enabled = enable_generate_and_advanced
if id_store.rigify_advanced_generation:
if armature_id_store.rigify_advanced_generation:
icon = 'UNLOCKED'
else:
icon = 'LOCKED'
@ -135,12 +136,12 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
col = layout.column()
col.enabled = enable_generate_and_advanced
row = col.row()
row.prop(id_store, "rigify_advanced_generation", toggle=True, icon=icon)
row.prop(armature_id_store, "rigify_advanced_generation", toggle=True, icon=icon)
if id_store.rigify_advanced_generation:
if armature_id_store.rigify_advanced_generation:
row = col.row(align=True)
row.prop(id_store, "rigify_generate_mode", expand=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()
@ -148,41 +149,25 @@ class DATA_PT_rigify_buttons(bpy.types.Panel):
col1.label(text="Rig Name")
row = col1.row()
row.label(text="Target Rig")
row.enabled = (id_store.rigify_generate_mode == "overwrite")
row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
row = col1.row()
row.label(text="Target UI")
row.enabled = (id_store.rigify_generate_mode == "overwrite")
row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
row = col2.row(align=True)
row.prop(id_store, "rigify_rig_basename", text="", icon="SORTALPHA")
row.prop(armature_id_store, "rigify_rig_basename", text="", icon="SORTALPHA")
row = col2.row(align=True)
for i in range(0, len(id_store.rigify_target_rigs)):
id_store.rigify_target_rigs.remove(0)
for ob in context.scene.objects:
if type(ob.data) == bpy.types.Armature and "rig_id" in ob.data:
id_store.rigify_target_rigs.add()
id_store.rigify_target_rigs[-1].name = ob.name
row.prop_search(id_store, "rigify_target_rig", id_store, "rigify_target_rigs", text="",
icon='OUTLINER_OB_ARMATURE')
row.enabled = (id_store.rigify_generate_mode == "overwrite")
for i in range(0, len(id_store.rigify_rig_uis)):
id_store.rigify_rig_uis.remove(0)
for t in bpy.data.texts:
id_store.rigify_rig_uis.add()
id_store.rigify_rig_uis[-1].name = t.name
row.prop(armature_id_store, "rigify_target_rig", text="")
row.enabled = (armature_id_store.rigify_generate_mode == "overwrite")
row = col2.row()
row.prop_search(id_store, "rigify_rig_ui", id_store, "rigify_rig_uis", text="", icon='TEXT')
row.enabled = (id_store.rigify_generate_mode == "overwrite")
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(id_store, "rigify_force_widget_update")
if id_store.rigify_generate_mode == 'new':
row.prop(armature_id_store, "rigify_force_widget_update")
if armature_id_store.rigify_generate_mode == 'new':
row.enabled = False
elif obj.mode == 'EDIT':