AnimAll: Rename UVMap and Vertex Group settings again
[blender-addons.git] / rigify / generate.py
blob3acc2e40bfbcb82439ed36973f5ba26f201bbb54
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 import bpy
4 import re
5 import time
7 from .utils.errors import MetarigError
8 from .utils.bones import new_bone
9 from .utils.layers import ORG_LAYER, MCH_LAYER, DEF_LAYER, ROOT_LAYER
10 from .utils.naming import ORG_PREFIX, MCH_PREFIX, DEF_PREFIX, ROOT_NAME, make_original_name, change_name_side, get_name_side, Side
11 from .utils.widgets import WGT_PREFIX
12 from .utils.widgets_special import create_root_widget
13 from .utils.mechanism import refresh_all_drivers
14 from .utils.misc import gamma_correct, select_object
15 from .utils.collections import ensure_collection, list_layer_collections, filter_layer_collections_by_object
16 from .utils.rig import get_rigify_type
18 from . import base_generate
19 from . import rig_ui_template
20 from . import rig_lists
22 RIG_MODULE = "rigs"
24 class Timer:
25 def __init__(self):
26 self.timez = time.time()
28 def tick(self, string):
29 t = time.time()
30 print(string + "%.3f" % (t - self.timez))
31 self.timez = t
34 class Generator(base_generate.BaseGenerator):
35 def __init__(self, context, metarig):
36 super().__init__(context, metarig)
38 self.id_store = context.window_manager
41 def find_rig_class(self, rig_type):
42 rig_module = rig_lists.rigs[rig_type]["module"]
44 return rig_module.Rig
47 def __switch_to_usable_collection(self, obj, fallback=False):
48 collections = filter_layer_collections_by_object(self.usable_collections, obj)
50 if collections:
51 self.layer_collection = collections[0]
52 elif fallback:
53 self.layer_collection = self.view_layer.layer_collection
55 self.collection = self.layer_collection.collection
58 def ensure_rig_object(self) -> bpy.types.Object:
59 """Check if the generated rig already exists, so we can
60 regenerate in the same object. If not, create a new
61 object to generate the rig in.
62 """
63 print("Fetch rig.")
64 meta_data = self.metarig.data
66 target_rig = meta_data.rigify_target_rig
67 if not target_rig:
68 if "metarig" in self.metarig.name:
69 rig_new_name = self.metarig.name.replace("metarig", "rig")
70 elif "META" in self.metarig.name:
71 rig_new_name = self.metarig.name.replace("META", "RIG")
72 else:
73 rig_new_name = "RIG-" + self.metarig.name
75 target_rig = bpy.data.objects.new(rig_new_name, bpy.data.armatures.new(rig_new_name))
76 target_rig.display_type = 'WIRE'
78 # If the object is already added to the scene, switch to its collection
79 if target_rig.name in self.context.scene.collection.all_objects:
80 self.__switch_to_usable_collection(target_rig)
81 else:
82 # Otherwise, add to the selected collection or the metarig collection if unusable
83 if (self.layer_collection not in self.usable_collections
84 or self.layer_collection == self.view_layer.layer_collection):
85 self.__switch_to_usable_collection(self.metarig, True)
87 self.collection.objects.link(target_rig)
89 # Configure and remember the object
90 meta_data.rigify_target_rig = target_rig
91 target_rig.data.pose_position = 'POSE'
93 return target_rig
96 def __unhide_rig_object(self, obj):
97 # Ensure the object is visible and selectable
98 obj.hide_set(False, view_layer=self.view_layer)
99 obj.hide_viewport = False
101 if not obj.visible_get(view_layer=self.view_layer):
102 raise Exception('Could not generate: Target rig is not visible')
104 obj.select_set(True, view_layer=self.view_layer)
106 if not obj.select_get(view_layer=self.view_layer):
107 raise Exception('Could not generate: Cannot select target rig')
109 if self.layer_collection not in self.usable_collections:
110 raise Exception('Could not generate: Could not find a usable collection.')
113 def __find_legacy_collection(self) -> bpy.types.Collection:
114 """For backwards comp, matching by name to find a legacy collection.
115 (For before there was a Widget Collection PointerProperty)
117 wgts_group_name = "WGTS_" + self.obj.name
118 old_collection = bpy.data.collections.get(wgts_group_name)
120 if not old_collection:
121 # Update the old 'Widgets' collection
122 legacy_collection = bpy.data.collections.get('Widgets')
124 if legacy_collection and wgts_group_name in legacy_collection.objects:
125 legacy_collection.name = wgts_group_name
126 old_collection = legacy_collection
128 if old_collection:
129 # Rename the collection
130 old_collection.name = wgts_group_name
132 return old_collection
134 def ensure_widget_collection(self):
135 # Create/find widget collection
136 self.widget_collection = self.metarig.data.rigify_widgets_collection
137 if not self.widget_collection:
138 self.widget_collection = self.__find_legacy_collection()
139 if not self.widget_collection:
140 wgts_group_name = "WGTS_" + self.obj.name.replace("RIG-", "")
141 self.widget_collection = ensure_collection(self.context, wgts_group_name, hidden=True)
143 self.metarig.data.rigify_widgets_collection = self.widget_collection
145 self.use_mirror_widgets = self.metarig.data.rigify_mirror_widgets
147 # Build tables for existing widgets
148 self.old_widget_table = {}
149 self.new_widget_table = {}
150 self.widget_mirror_mesh = {}
152 if self.metarig.data.rigify_force_widget_update:
153 # Remove widgets if force update is set
154 for obj in list(self.widget_collection.objects):
155 bpy.data.objects.remove(obj)
156 elif self.obj.pose:
157 # Find all widgets from the collection referenced by the old rig
158 known_widgets = set(obj.name for obj in self.widget_collection.objects)
160 for bone in self.obj.pose.bones:
161 if bone.custom_shape and bone.custom_shape.name in known_widgets:
162 self.old_widget_table[bone.name] = bone.custom_shape
164 # Rename widgets in case the rig was renamed
165 name_prefix = WGT_PREFIX + self.obj.name + "_"
167 for bone_name, widget in self.old_widget_table.items():
168 old_data_name = change_name_side(widget.name, get_name_side(widget.data.name))
170 widget.name = name_prefix + bone_name
172 # If the mesh name is the same as the object, rename it too
173 if widget.data.name == old_data_name:
174 widget.data.name = change_name_side(widget.name, get_name_side(widget.data.name))
176 # Find meshes for mirroring
177 if self.use_mirror_widgets:
178 for bone_name, widget in self.old_widget_table.items():
179 mid_name = change_name_side(bone_name, Side.MIDDLE)
180 if bone_name != mid_name:
181 self.widget_mirror_mesh[mid_name] = widget.data
184 def __duplicate_rig(self):
185 obj = self.obj
186 metarig = self.metarig
187 context = self.context
189 # Remove all bones from the generated rig armature.
190 bpy.ops.object.mode_set(mode='EDIT')
191 for bone in obj.data.edit_bones:
192 obj.data.edit_bones.remove(bone)
193 bpy.ops.object.mode_set(mode='OBJECT')
195 # Select and duplicate metarig
196 select_object(context, metarig, deselect_all=True)
198 bpy.ops.object.duplicate()
200 # Rename org bones in the temporary object
201 temp_obj = context.view_layer.objects.active
203 assert temp_obj and temp_obj != metarig
205 self.__freeze_driver_vars(temp_obj)
206 self.__rename_org_bones(temp_obj)
208 # Select the target rig and join
209 select_object(context, obj)
211 saved_matrix = obj.matrix_world.copy()
212 obj.matrix_world = metarig.matrix_world
214 bpy.ops.object.join()
216 obj.matrix_world = saved_matrix
218 # Select the generated rig
219 select_object(context, obj, deselect_all=True)
221 # Clean up animation data
222 if obj.animation_data:
223 obj.animation_data.action = None
225 for track in obj.animation_data.nla_tracks:
226 obj.animation_data.nla_tracks.remove(track)
229 def __freeze_driver_vars(self, obj):
230 if obj.animation_data:
231 # Freeze drivers referring to custom properties
232 for d in obj.animation_data.drivers:
233 for var in d.driver.variables:
234 for tar in var.targets:
235 # If a custom property
236 if var.type == 'SINGLE_PROP' \
237 and re.match(r'^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
238 tar.data_path = "RIGIFY-" + tar.data_path
241 def __rename_org_bones(self, obj):
242 #----------------------------------
243 # Make a list of the original bones so we can keep track of them.
244 original_bones = [bone.name for bone in obj.data.bones]
246 # Add the ORG_PREFIX to the original bones.
247 for i in range(0, len(original_bones)):
248 bone = obj.pose.bones[original_bones[i]]
250 # Preserve the root bone as is if present
251 if bone.name == ROOT_NAME:
252 if bone.parent:
253 raise MetarigError('Root bone must have no parent')
254 if get_rigify_type(bone) not in ('', 'basic.raw_copy'):
255 raise MetarigError('Root bone must have no rig, or use basic.raw_copy')
256 continue
258 # This rig type is special in that it preserves the name of the bone.
259 if get_rigify_type(bone) != 'basic.raw_copy':
260 bone.name = make_original_name(original_bones[i])
261 original_bones[i] = bone.name
263 self.original_bones = original_bones
266 def __create_root_bone(self):
267 obj = self.obj
268 metarig = self.metarig
270 if ROOT_NAME in obj.data.bones:
271 # Use the existing root bone
272 root_bone = ROOT_NAME
273 else:
274 # Create the root bone.
275 root_bone = new_bone(obj, ROOT_NAME)
276 spread = get_xy_spread(metarig.data.bones) or metarig.data.bones[0].length
277 spread = float('%.3g' % spread)
278 scale = spread/0.589
279 obj.data.edit_bones[root_bone].head = (0, 0, 0)
280 obj.data.edit_bones[root_bone].tail = (0, scale, 0)
281 obj.data.edit_bones[root_bone].roll = 0
283 self.root_bone = root_bone
284 self.bone_owners[root_bone] = None
285 self.noparent_bones.add(root_bone)
288 def __parent_bones_to_root(self):
289 eb = self.obj.data.edit_bones
291 # Parent loose bones to root
292 for bone in eb:
293 if bone.name in self.noparent_bones:
294 continue
295 elif bone.parent is None:
296 bone.use_connect = False
297 bone.parent = eb[self.root_bone]
300 def __lock_transforms(self):
301 # Lock transforms on all non-control bones
302 r = re.compile("[A-Z][A-Z][A-Z]-")
303 for pb in self.obj.pose.bones:
304 if r.match(pb.name):
305 pb.lock_location = (True, True, True)
306 pb.lock_rotation = (True, True, True)
307 pb.lock_rotation_w = True
308 pb.lock_scale = (True, True, True)
311 def __assign_layers(self):
312 pbones = self.obj.pose.bones
314 pbones[self.root_bone].bone.layers = ROOT_LAYER
316 # Every bone that has a name starting with "DEF-" make deforming. All the
317 # others make non-deforming.
318 for pbone in pbones:
319 bone = pbone.bone
320 name = bone.name
321 layers = None
323 bone.use_deform = name.startswith(DEF_PREFIX)
325 # Move all the original bones to their layer.
326 if name.startswith(ORG_PREFIX):
327 layers = ORG_LAYER
328 # Move all the bones with names starting with "MCH-" to their layer.
329 elif name.startswith(MCH_PREFIX):
330 layers = MCH_LAYER
331 # Move all the bones with names starting with "DEF-" to their layer.
332 elif name.startswith(DEF_PREFIX):
333 layers = DEF_LAYER
335 if layers is not None:
336 bone.layers = layers
338 # Remove custom shapes from non-control bones
339 pbone.custom_shape = None
341 bone.bbone_x = bone.bbone_z = bone.length * 0.05
344 def __restore_driver_vars(self):
345 obj = self.obj
347 # Alter marked driver targets
348 if obj.animation_data:
349 for d in obj.animation_data.drivers:
350 for v in d.driver.variables:
351 for tar in v.targets:
352 if tar.data_path.startswith("RIGIFY-"):
353 temp, bone, prop = tuple([x.strip('"]') for x in tar.data_path.split('["')])
354 if bone in obj.data.bones \
355 and prop in obj.pose.bones[bone].keys():
356 tar.data_path = tar.data_path[7:]
357 else:
358 org_name = make_original_name(bone)
359 org_name = self.org_rename_table.get(org_name, org_name)
360 tar.data_path = 'pose.bones["%s"]["%s"]' % (org_name, prop)
363 def __assign_widgets(self):
364 obj_table = {obj.name: obj for obj in self.scene.objects}
366 # Assign shapes to bones
367 # Object's with name WGT-<bone_name> get used as that bone's shape.
368 for bone in self.obj.pose.bones:
369 # First check the table built by create_widget
370 if bone.name in self.new_widget_table:
371 bone.custom_shape = self.new_widget_table[bone.name]
372 continue
374 # Object names are limited to 63 characters... arg
375 wgt_name = (WGT_PREFIX + self.obj.name + '_' + bone.name)[:63]
377 if wgt_name in obj_table:
378 bone.custom_shape = obj_table[wgt_name]
381 def __compute_visible_layers(self):
382 # Reveal all the layers with control bones on them
383 vis_layers = [False for n in range(0, 32)]
385 for bone in self.obj.data.bones:
386 for i in range(0, 32):
387 vis_layers[i] = vis_layers[i] or bone.layers[i]
389 for i in range(0, 32):
390 vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i] or DEF_LAYER[i])
392 self.obj.data.layers = vis_layers
395 def generate(self):
396 context = self.context
397 metarig = self.metarig
398 scene = self.scene
399 id_store = self.id_store
400 view_layer = self.view_layer
401 t = Timer()
403 self.usable_collections = list_layer_collections(view_layer.layer_collection, selectable=True)
405 bpy.ops.object.mode_set(mode='OBJECT')
407 #------------------------------------------
408 # Create/find the rig object and set it up
409 self.obj = obj = self.ensure_rig_object()
411 self.__unhide_rig_object(obj)
413 # Select the chosen working collection in case it changed
414 self.view_layer.active_layer_collection = self.layer_collection
416 # Get rid of anim data in case the rig already existed
417 print("Clear rig animation data.")
419 obj.animation_data_clear()
420 obj.data.animation_data_clear()
422 select_object(context, obj, deselect_all=True)
424 #------------------------------------------
425 # Create Widget Collection
426 self.ensure_widget_collection()
428 t.tick("Create main WGTS: ")
430 #------------------------------------------
431 # Get parented objects to restore later
432 childs = {} # {object: bone}
433 for child in obj.children:
434 childs[child] = child.parent_bone
436 #------------------------------------------
437 # Copy bones from metarig to obj (adds ORG_PREFIX)
438 self.__duplicate_rig()
440 obj.data.use_mirror_x = False
442 t.tick("Duplicate rig: ")
444 #------------------------------------------
445 # Put the rig_name in the armature custom properties
446 obj.data["rig_id"] = self.rig_id
448 self.script = rig_ui_template.ScriptGenerator(self)
450 #------------------------------------------
451 bpy.ops.object.mode_set(mode='OBJECT')
453 self.instantiate_rig_tree()
455 t.tick("Instantiate rigs: ")
457 #------------------------------------------
458 bpy.ops.object.mode_set(mode='OBJECT')
460 self.invoke_initialize()
462 t.tick("Initialize rigs: ")
464 #------------------------------------------
465 bpy.ops.object.mode_set(mode='EDIT')
467 self.invoke_prepare_bones()
469 t.tick("Prepare bones: ")
471 #------------------------------------------
472 bpy.ops.object.mode_set(mode='OBJECT')
473 bpy.ops.object.mode_set(mode='EDIT')
475 self.__create_root_bone()
477 self.invoke_generate_bones()
479 t.tick("Generate bones: ")
481 #------------------------------------------
482 bpy.ops.object.mode_set(mode='OBJECT')
483 bpy.ops.object.mode_set(mode='EDIT')
485 self.invoke_parent_bones()
487 self.__parent_bones_to_root()
489 t.tick("Parent bones: ")
491 #------------------------------------------
492 bpy.ops.object.mode_set(mode='OBJECT')
494 self.invoke_configure_bones()
496 t.tick("Configure bones: ")
498 #------------------------------------------
499 bpy.ops.object.mode_set(mode='OBJECT')
501 self.invoke_preapply_bones()
503 t.tick("Preapply bones: ")
505 #------------------------------------------
506 bpy.ops.object.mode_set(mode='EDIT')
508 self.invoke_apply_bones()
510 t.tick("Apply bones: ")
512 #------------------------------------------
513 bpy.ops.object.mode_set(mode='OBJECT')
515 self.invoke_rig_bones()
517 t.tick("Rig bones: ")
519 #------------------------------------------
520 bpy.ops.object.mode_set(mode='OBJECT')
522 self.invoke_generate_widgets()
524 # Generate the default root widget last in case it's rigged with raw_copy
525 create_root_widget(obj, self.root_bone)
527 t.tick("Generate widgets: ")
529 #------------------------------------------
530 bpy.ops.object.mode_set(mode='OBJECT')
532 self.__lock_transforms()
533 self.__assign_layers()
534 self.__compute_visible_layers()
535 self.__restore_driver_vars()
537 t.tick("Assign layers: ")
539 #------------------------------------------
540 bpy.ops.object.mode_set(mode='OBJECT')
542 self.invoke_finalize()
544 t.tick("Finalize: ")
546 #------------------------------------------
547 bpy.ops.object.mode_set(mode='OBJECT')
549 self.__assign_widgets()
551 # Create Selection Sets
552 create_selection_sets(obj, metarig)
554 # Create Bone Groups
555 create_bone_groups(obj, metarig, self.layer_group_priorities)
557 t.tick("The rest: ")
559 #----------------------------------
560 # Deconfigure
561 bpy.ops.object.mode_set(mode='OBJECT')
562 obj.data.pose_position = 'POSE'
564 # Restore parent to bones
565 for child, sub_parent in childs.items():
566 if sub_parent in obj.pose.bones:
567 mat = child.matrix_world.copy()
568 child.parent_bone = sub_parent
569 child.matrix_world = mat
571 # Clear any transient errors in drivers
572 refresh_all_drivers()
574 #----------------------------------
575 # Execute the finalize script
577 if metarig.data.rigify_finalize_script:
578 bpy.ops.object.mode_set(mode='OBJECT')
579 exec(metarig.data.rigify_finalize_script.as_string(), {})
580 bpy.ops.object.mode_set(mode='OBJECT')
582 #----------------------------------
583 # Restore active collection
584 view_layer.active_layer_collection = self.layer_collection
587 def generate_rig(context, metarig):
588 """ Generates a rig from a metarig.
591 # Initial configuration
592 rest_backup = metarig.data.pose_position
593 metarig.data.pose_position = 'REST'
595 try:
596 generator = Generator(context, metarig)
598 base_generate.BaseGenerator.instance = generator
600 generator.generate()
602 metarig.data.pose_position = rest_backup
604 except Exception as e:
605 # Cleanup if something goes wrong
606 print("Rigify: failed to generate rig.")
608 bpy.ops.object.mode_set(mode='OBJECT')
609 metarig.data.pose_position = rest_backup
611 # Continue the exception
612 raise e
614 finally:
615 base_generate.BaseGenerator.instance = None
618 def create_selection_set_for_rig_layer(
619 rig: bpy.types.Object,
620 set_name: str,
621 layer_idx: int
622 ) -> None:
623 """Create a single selection set on a rig.
625 The set will contain all bones on the rig layer with the given index.
627 selset = rig.selection_sets.add()
628 selset.name = set_name
630 for b in rig.pose.bones:
631 if not b.bone.layers[layer_idx] or b.name in selset.bone_ids:
632 continue
634 bone_id = selset.bone_ids.add()
635 bone_id.name = b.name
637 def create_selection_sets(obj, metarig):
638 """Create selection sets if the Selection Sets addon is enabled.
640 Whether a selection set for a rig layer is created is controlled in the
641 Rigify Layer Names panel.
643 # Check if selection sets addon is installed
644 if 'bone_selection_groups' not in bpy.context.preferences.addons \
645 and 'bone_selection_sets' not in bpy.context.preferences.addons:
646 return
648 obj.selection_sets.clear()
650 for i, name in enumerate(metarig.data.rigify_layers.keys()):
651 if name == '' or not metarig.data.rigify_layers[i].selset:
652 continue
654 create_selection_set_for_rig_layer(obj, name, i)
657 def create_bone_groups(obj, metarig, priorities={}):
659 bpy.ops.object.mode_set(mode='OBJECT')
660 pb = obj.pose.bones
661 layers = metarig.data.rigify_layers
662 groups = metarig.data.rigify_colors
663 dummy = {}
665 # Create BGs
666 for l in layers:
667 if l.group == 0:
668 continue
669 g_id = l.group - 1
670 name = groups[g_id].name
671 if name not in obj.pose.bone_groups.keys():
672 bg = obj.pose.bone_groups.new(name=name)
673 bg.color_set = 'CUSTOM'
674 bg.colors.normal = gamma_correct(groups[g_id].normal)
675 bg.colors.select = gamma_correct(groups[g_id].select)
676 bg.colors.active = gamma_correct(groups[g_id].active)
678 for b in pb:
679 try:
680 prios = priorities.get(b.name, dummy)
681 enabled = [ i for i, v in enumerate(b.bone.layers) if v ]
682 layer_index = max(enabled, key=lambda i: prios.get(i, 0))
683 except ValueError:
684 continue
685 if layer_index > len(layers) - 1: # bone is on reserved layers
686 continue
687 g_id = layers[layer_index].group - 1
688 if g_id >= 0:
689 name = groups[g_id].name
690 b.bone_group = obj.pose.bone_groups[name]
693 def get_xy_spread(bones):
694 x_max = 0
695 y_max = 0
696 for b in bones:
697 x_max = max((x_max, abs(b.head[0]), abs(b.tail[0])))
698 y_max = max((y_max, abs(b.head[1]), abs(b.tail[1])))
700 return max((x_max, y_max))
703 def param_matches_type(param_name, rig_type):
704 """ Returns True if the parameter name is consistent with the rig type.
706 if param_name.rsplit(".", 1)[0] == rig_type:
707 return True
708 else:
709 return False
712 def param_name(param_name, rig_type):
713 """ Get the actual parameter name, sans-rig-type.
715 return param_name[len(rig_type) + 1:]