Cleanup: trailing space
[blender-addons.git] / rigify / generate.py
blob0d99b708c5182463e25b2b1847144c0ef43dfabe
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # <pep8 compliant>
5 import bpy
6 import re
7 import time
9 from .utils.errors import MetarigError
10 from .utils.bones import new_bone
11 from .utils.layers import ORG_LAYER, MCH_LAYER, DEF_LAYER, ROOT_LAYER
12 from .utils.naming import ORG_PREFIX, MCH_PREFIX, DEF_PREFIX, ROOT_NAME, make_original_name, change_name_side, get_name_side, Side
13 from .utils.widgets import WGT_PREFIX
14 from .utils.widgets_special import create_root_widget
15 from .utils.mechanism import refresh_all_drivers
16 from .utils.misc import gamma_correct, select_object
17 from .utils.collections import ensure_collection, list_layer_collections, filter_layer_collections_by_object
18 from .utils.rig import get_rigify_type
20 from . import base_generate
21 from . import rig_ui_template
22 from . import rig_lists
24 RIG_MODULE = "rigs"
26 class Timer:
27 def __init__(self):
28 self.timez = time.time()
30 def tick(self, string):
31 t = time.time()
32 print(string + "%.3f" % (t - self.timez))
33 self.timez = t
36 class Generator(base_generate.BaseGenerator):
37 def __init__(self, context, metarig):
38 super().__init__(context, metarig)
40 self.id_store = context.window_manager
43 def find_rig_class(self, rig_type):
44 rig_module = rig_lists.rigs[rig_type]["module"]
46 return rig_module.Rig
49 def __switch_to_usable_collection(self, obj, fallback=False):
50 collections = filter_layer_collections_by_object(self.usable_collections, obj)
52 if collections:
53 self.layer_collection = collections[0]
54 elif fallback:
55 self.layer_collection = self.view_layer.layer_collection
57 self.collection = self.layer_collection.collection
60 def ensure_rig_object(self) -> bpy.types.Object:
61 """Check if the generated rig already exists, so we can
62 regenerate in the same object. If not, create a new
63 object to generate the rig in.
64 """
65 print("Fetch rig.")
66 meta_data = self.metarig.data
68 target_rig = meta_data.rigify_target_rig
69 if not target_rig:
70 if "metarig" in self.metarig.name:
71 rig_new_name = self.metarig.name.replace("metarig", "rig")
72 elif "META" in self.metarig.name:
73 rig_new_name = self.metarig.name.replace("META", "RIG")
74 else:
75 rig_new_name = "RIG-" + self.metarig.name
77 target_rig = bpy.data.objects.new(rig_new_name, bpy.data.armatures.new(rig_new_name))
78 target_rig.display_type = 'WIRE'
80 # If the object is already added to the scene, switch to its collection
81 if target_rig.name in self.context.scene.collection.all_objects:
82 self.__switch_to_usable_collection(target_rig)
83 else:
84 # Otherwise, add to the selected collection or the metarig collection if unusable
85 if (self.layer_collection not in self.usable_collections
86 or self.layer_collection == self.view_layer.layer_collection):
87 self.__switch_to_usable_collection(self.metarig, True)
89 self.collection.objects.link(target_rig)
91 # Configure and remember the object
92 meta_data.rigify_target_rig = target_rig
93 target_rig.data.pose_position = 'POSE'
95 return target_rig
98 def __unhide_rig_object(self, obj):
99 # Ensure the object is visible and selectable
100 obj.hide_set(False, view_layer=self.view_layer)
101 obj.hide_viewport = False
103 if not obj.visible_get(view_layer=self.view_layer):
104 raise Exception('Could not generate: Target rig is not visible')
106 obj.select_set(True, view_layer=self.view_layer)
108 if not obj.select_get(view_layer=self.view_layer):
109 raise Exception('Could not generate: Cannot select target rig')
111 if self.layer_collection not in self.usable_collections:
112 raise Exception('Could not generate: Could not find a usable collection.')
115 def __find_legacy_collection(self) -> bpy.types.Collection:
116 """For backwards comp, matching by name to find a legacy collection.
117 (For before there was a Widget Collection PointerProperty)
119 wgts_group_name = "WGTS_" + self.obj.name
120 old_collection = bpy.data.collections.get(wgts_group_name)
122 if not old_collection:
123 # Update the old 'Widgets' collection
124 legacy_collection = bpy.data.collections.get('Widgets')
126 if legacy_collection and wgts_group_name in legacy_collection.objects:
127 legacy_collection.name = wgts_group_name
128 old_collection = legacy_collection
130 if old_collection:
131 # Rename the collection
132 old_collection.name = wgts_group_name
134 return old_collection
136 def ensure_widget_collection(self):
137 # Create/find widget collection
138 self.widget_collection = self.metarig.data.rigify_widgets_collection
139 if not self.widget_collection:
140 self.widget_collection = self.__find_legacy_collection()
141 if not self.widget_collection:
142 wgts_group_name = "WGTS_" + self.obj.name.replace("RIG-", "")
143 self.widget_collection = ensure_collection(self.context, wgts_group_name, hidden=True)
145 self.metarig.data.rigify_widgets_collection = self.widget_collection
147 self.use_mirror_widgets = self.metarig.data.rigify_mirror_widgets
149 # Build tables for existing widgets
150 self.old_widget_table = {}
151 self.new_widget_table = {}
152 self.widget_mirror_mesh = {}
154 if self.metarig.data.rigify_force_widget_update:
155 # Remove widgets if force update is set
156 for obj in list(self.widget_collection.objects):
157 bpy.data.objects.remove(obj)
158 elif self.obj.pose:
159 # Find all widgets from the collection referenced by the old rig
160 known_widgets = set(obj.name for obj in self.widget_collection.objects)
162 for bone in self.obj.pose.bones:
163 if bone.custom_shape and bone.custom_shape.name in known_widgets:
164 self.old_widget_table[bone.name] = bone.custom_shape
166 # Rename widgets in case the rig was renamed
167 name_prefix = WGT_PREFIX + self.obj.name + "_"
169 for bone_name, widget in self.old_widget_table.items():
170 old_data_name = change_name_side(widget.name, get_name_side(widget.data.name))
172 widget.name = name_prefix + bone_name
174 # If the mesh name is the same as the object, rename it too
175 if widget.data.name == old_data_name:
176 widget.data.name = change_name_side(widget.name, get_name_side(widget.data.name))
178 # Find meshes for mirroring
179 if self.use_mirror_widgets:
180 for bone_name, widget in self.old_widget_table.items():
181 mid_name = change_name_side(bone_name, Side.MIDDLE)
182 if bone_name != mid_name:
183 self.widget_mirror_mesh[mid_name] = widget.data
186 def __duplicate_rig(self):
187 obj = self.obj
188 metarig = self.metarig
189 context = self.context
191 # Remove all bones from the generated rig armature.
192 bpy.ops.object.mode_set(mode='EDIT')
193 for bone in obj.data.edit_bones:
194 obj.data.edit_bones.remove(bone)
195 bpy.ops.object.mode_set(mode='OBJECT')
197 # Select and duplicate metarig
198 select_object(context, metarig, deselect_all=True)
200 bpy.ops.object.duplicate()
202 # Rename org bones in the temporary object
203 temp_obj = context.view_layer.objects.active
205 assert temp_obj and temp_obj != metarig
207 self.__freeze_driver_vars(temp_obj)
208 self.__rename_org_bones(temp_obj)
210 # Select the target rig and join
211 select_object(context, obj)
213 saved_matrix = obj.matrix_world.copy()
214 obj.matrix_world = metarig.matrix_world
216 bpy.ops.object.join()
218 obj.matrix_world = saved_matrix
220 # Select the generated rig
221 select_object(context, obj, deselect_all=True)
223 # Clean up animation data
224 if obj.animation_data:
225 obj.animation_data.action = None
227 for track in obj.animation_data.nla_tracks:
228 obj.animation_data.nla_tracks.remove(track)
231 def __freeze_driver_vars(self, obj):
232 if obj.animation_data:
233 # Freeze drivers referring to custom properties
234 for d in obj.animation_data.drivers:
235 for var in d.driver.variables:
236 for tar in var.targets:
237 # If a custom property
238 if var.type == 'SINGLE_PROP' \
239 and re.match(r'^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
240 tar.data_path = "RIGIFY-" + tar.data_path
243 def __rename_org_bones(self, obj):
244 #----------------------------------
245 # Make a list of the original bones so we can keep track of them.
246 original_bones = [bone.name for bone in obj.data.bones]
248 # Add the ORG_PREFIX to the original bones.
249 for i in range(0, len(original_bones)):
250 bone = obj.pose.bones[original_bones[i]]
252 # Preserve the root bone as is if present
253 if bone.name == ROOT_NAME:
254 if bone.parent:
255 raise MetarigError('Root bone must have no parent')
256 if get_rigify_type(bone) not in ('', 'basic.raw_copy'):
257 raise MetarigError('Root bone must have no rig, or use basic.raw_copy')
258 continue
260 # This rig type is special in that it preserves the name of the bone.
261 if get_rigify_type(bone) != 'basic.raw_copy':
262 bone.name = make_original_name(original_bones[i])
263 original_bones[i] = bone.name
265 self.original_bones = original_bones
268 def __create_root_bone(self):
269 obj = self.obj
270 metarig = self.metarig
272 if ROOT_NAME in obj.data.bones:
273 # Use the existing root bone
274 root_bone = ROOT_NAME
275 else:
276 # Create the root bone.
277 root_bone = new_bone(obj, ROOT_NAME)
278 spread = get_xy_spread(metarig.data.bones) or metarig.data.bones[0].length
279 spread = float('%.3g' % spread)
280 scale = spread/0.589
281 obj.data.edit_bones[root_bone].head = (0, 0, 0)
282 obj.data.edit_bones[root_bone].tail = (0, scale, 0)
283 obj.data.edit_bones[root_bone].roll = 0
285 self.root_bone = root_bone
286 self.bone_owners[root_bone] = None
287 self.noparent_bones.add(root_bone)
290 def __parent_bones_to_root(self):
291 eb = self.obj.data.edit_bones
293 # Parent loose bones to root
294 for bone in eb:
295 if bone.name in self.noparent_bones:
296 continue
297 elif bone.parent is None:
298 bone.use_connect = False
299 bone.parent = eb[self.root_bone]
302 def __lock_transforms(self):
303 # Lock transforms on all non-control bones
304 r = re.compile("[A-Z][A-Z][A-Z]-")
305 for pb in self.obj.pose.bones:
306 if r.match(pb.name):
307 pb.lock_location = (True, True, True)
308 pb.lock_rotation = (True, True, True)
309 pb.lock_rotation_w = True
310 pb.lock_scale = (True, True, True)
313 def __assign_layers(self):
314 pbones = self.obj.pose.bones
316 pbones[self.root_bone].bone.layers = ROOT_LAYER
318 # Every bone that has a name starting with "DEF-" make deforming. All the
319 # others make non-deforming.
320 for pbone in pbones:
321 bone = pbone.bone
322 name = bone.name
323 layers = None
325 bone.use_deform = name.startswith(DEF_PREFIX)
327 # Move all the original bones to their layer.
328 if name.startswith(ORG_PREFIX):
329 layers = ORG_LAYER
330 # Move all the bones with names starting with "MCH-" to their layer.
331 elif name.startswith(MCH_PREFIX):
332 layers = MCH_LAYER
333 # Move all the bones with names starting with "DEF-" to their layer.
334 elif name.startswith(DEF_PREFIX):
335 layers = DEF_LAYER
337 if layers is not None:
338 bone.layers = layers
340 # Remove custom shapes from non-control bones
341 pbone.custom_shape = None
343 bone.bbone_x = bone.bbone_z = bone.length * 0.05
346 def __restore_driver_vars(self):
347 obj = self.obj
349 # Alter marked driver targets
350 if obj.animation_data:
351 for d in obj.animation_data.drivers:
352 for v in d.driver.variables:
353 for tar in v.targets:
354 if tar.data_path.startswith("RIGIFY-"):
355 temp, bone, prop = tuple([x.strip('"]') for x in tar.data_path.split('["')])
356 if bone in obj.data.bones \
357 and prop in obj.pose.bones[bone].keys():
358 tar.data_path = tar.data_path[7:]
359 else:
360 org_name = make_original_name(bone)
361 org_name = self.org_rename_table.get(org_name, org_name)
362 tar.data_path = 'pose.bones["%s"]["%s"]' % (org_name, prop)
365 def __assign_widgets(self):
366 obj_table = {obj.name: obj for obj in self.scene.objects}
368 # Assign shapes to bones
369 # Object's with name WGT-<bone_name> get used as that bone's shape.
370 for bone in self.obj.pose.bones:
371 # First check the table built by create_widget
372 if bone.name in self.new_widget_table:
373 bone.custom_shape = self.new_widget_table[bone.name]
374 continue
376 # Object names are limited to 63 characters... arg
377 wgt_name = (WGT_PREFIX + self.obj.name + '_' + bone.name)[:63]
379 if wgt_name in obj_table:
380 bone.custom_shape = obj_table[wgt_name]
383 def __compute_visible_layers(self):
384 # Reveal all the layers with control bones on them
385 vis_layers = [False for n in range(0, 32)]
387 for bone in self.obj.data.bones:
388 for i in range(0, 32):
389 vis_layers[i] = vis_layers[i] or bone.layers[i]
391 for i in range(0, 32):
392 vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i] or DEF_LAYER[i])
394 self.obj.data.layers = vis_layers
397 def generate(self):
398 context = self.context
399 metarig = self.metarig
400 scene = self.scene
401 id_store = self.id_store
402 view_layer = self.view_layer
403 t = Timer()
405 self.usable_collections = list_layer_collections(view_layer.layer_collection, selectable=True)
407 bpy.ops.object.mode_set(mode='OBJECT')
409 #------------------------------------------
410 # Create/find the rig object and set it up
411 self.obj = obj = self.ensure_rig_object()
413 self.__unhide_rig_object(obj)
415 # Select the chosen working collection in case it changed
416 self.view_layer.active_layer_collection = self.layer_collection
418 # Get rid of anim data in case the rig already existed
419 print("Clear rig animation data.")
421 obj.animation_data_clear()
422 obj.data.animation_data_clear()
424 select_object(context, obj, deselect_all=True)
426 #------------------------------------------
427 # Create Widget Collection
428 self.ensure_widget_collection()
430 t.tick("Create main WGTS: ")
432 #------------------------------------------
433 # Get parented objects to restore later
434 childs = {} # {object: bone}
435 for child in obj.children:
436 childs[child] = child.parent_bone
438 #------------------------------------------
439 # Copy bones from metarig to obj (adds ORG_PREFIX)
440 self.__duplicate_rig()
442 obj.data.use_mirror_x = False
444 t.tick("Duplicate rig: ")
446 #------------------------------------------
447 # Put the rig_name in the armature custom properties
448 obj.data["rig_id"] = self.rig_id
450 self.script = rig_ui_template.ScriptGenerator(self)
452 #------------------------------------------
453 bpy.ops.object.mode_set(mode='OBJECT')
455 self.instantiate_rig_tree()
457 t.tick("Instantiate rigs: ")
459 #------------------------------------------
460 bpy.ops.object.mode_set(mode='OBJECT')
462 self.invoke_initialize()
464 t.tick("Initialize rigs: ")
466 #------------------------------------------
467 bpy.ops.object.mode_set(mode='EDIT')
469 self.invoke_prepare_bones()
471 t.tick("Prepare bones: ")
473 #------------------------------------------
474 bpy.ops.object.mode_set(mode='OBJECT')
475 bpy.ops.object.mode_set(mode='EDIT')
477 self.__create_root_bone()
479 self.invoke_generate_bones()
481 t.tick("Generate bones: ")
483 #------------------------------------------
484 bpy.ops.object.mode_set(mode='OBJECT')
485 bpy.ops.object.mode_set(mode='EDIT')
487 self.invoke_parent_bones()
489 self.__parent_bones_to_root()
491 t.tick("Parent bones: ")
493 #------------------------------------------
494 bpy.ops.object.mode_set(mode='OBJECT')
496 self.invoke_configure_bones()
498 t.tick("Configure bones: ")
500 #------------------------------------------
501 bpy.ops.object.mode_set(mode='OBJECT')
503 self.invoke_preapply_bones()
505 t.tick("Preapply bones: ")
507 #------------------------------------------
508 bpy.ops.object.mode_set(mode='EDIT')
510 self.invoke_apply_bones()
512 t.tick("Apply bones: ")
514 #------------------------------------------
515 bpy.ops.object.mode_set(mode='OBJECT')
517 self.invoke_rig_bones()
519 t.tick("Rig bones: ")
521 #------------------------------------------
522 bpy.ops.object.mode_set(mode='OBJECT')
524 self.invoke_generate_widgets()
526 # Generate the default root widget last in case it's rigged with raw_copy
527 create_root_widget(obj, self.root_bone)
529 t.tick("Generate widgets: ")
531 #------------------------------------------
532 bpy.ops.object.mode_set(mode='OBJECT')
534 self.__lock_transforms()
535 self.__assign_layers()
536 self.__compute_visible_layers()
537 self.__restore_driver_vars()
539 t.tick("Assign layers: ")
541 #------------------------------------------
542 bpy.ops.object.mode_set(mode='OBJECT')
544 self.invoke_finalize()
546 t.tick("Finalize: ")
548 #------------------------------------------
549 bpy.ops.object.mode_set(mode='OBJECT')
551 self.__assign_widgets()
553 # Create Selection Sets
554 create_selection_sets(obj, metarig)
556 # Create Bone Groups
557 create_bone_groups(obj, metarig, self.layer_group_priorities)
559 t.tick("The rest: ")
561 #----------------------------------
562 # Deconfigure
563 bpy.ops.object.mode_set(mode='OBJECT')
564 obj.data.pose_position = 'POSE'
566 # Restore parent to bones
567 for child, sub_parent in childs.items():
568 if sub_parent in obj.pose.bones:
569 mat = child.matrix_world.copy()
570 child.parent_bone = sub_parent
571 child.matrix_world = mat
573 # Clear any transient errors in drivers
574 refresh_all_drivers()
576 #----------------------------------
577 # Execute the finalize script
579 if metarig.data.rigify_finalize_script:
580 bpy.ops.object.mode_set(mode='OBJECT')
581 exec(metarig.data.rigify_finalize_script.as_string(), {})
582 bpy.ops.object.mode_set(mode='OBJECT')
584 #----------------------------------
585 # Restore active collection
586 view_layer.active_layer_collection = self.layer_collection
589 def generate_rig(context, metarig):
590 """ Generates a rig from a metarig.
593 # Initial configuration
594 rest_backup = metarig.data.pose_position
595 metarig.data.pose_position = 'REST'
597 try:
598 generator = Generator(context, metarig)
600 base_generate.BaseGenerator.instance = generator
602 generator.generate()
604 metarig.data.pose_position = rest_backup
606 except Exception as e:
607 # Cleanup if something goes wrong
608 print("Rigify: failed to generate rig.")
610 bpy.ops.object.mode_set(mode='OBJECT')
611 metarig.data.pose_position = rest_backup
613 # Continue the exception
614 raise e
616 finally:
617 base_generate.BaseGenerator.instance = None
620 def create_selection_set_for_rig_layer(
621 rig: bpy.types.Object,
622 set_name: str,
623 layer_idx: int
624 ) -> None:
625 """Create a single selection set on a rig.
627 The set will contain all bones on the rig layer with the given index.
629 selset = rig.selection_sets.add()
630 selset.name = set_name
632 for b in rig.pose.bones:
633 if not b.bone.layers[layer_idx] or b.name in selset.bone_ids:
634 continue
636 bone_id = selset.bone_ids.add()
637 bone_id.name = b.name
639 def create_selection_sets(obj, metarig):
640 """Create selection sets if the Selection Sets addon is enabled.
642 Whether a selection set for a rig layer is created is controlled in the
643 Rigify Layer Names panel.
645 # Check if selection sets addon is installed
646 if 'bone_selection_groups' not in bpy.context.preferences.addons \
647 and 'bone_selection_sets' not in bpy.context.preferences.addons:
648 return
650 obj.selection_sets.clear()
652 for i, name in enumerate(metarig.data.rigify_layers.keys()):
653 if name == '' or not metarig.data.rigify_layers[i].selset:
654 continue
656 create_selection_set_for_rig_layer(obj, name, i)
659 def create_bone_groups(obj, metarig, priorities={}):
661 bpy.ops.object.mode_set(mode='OBJECT')
662 pb = obj.pose.bones
663 layers = metarig.data.rigify_layers
664 groups = metarig.data.rigify_colors
665 dummy = {}
667 # Create BGs
668 for l in layers:
669 if l.group == 0:
670 continue
671 g_id = l.group - 1
672 name = groups[g_id].name
673 if name not in obj.pose.bone_groups.keys():
674 bg = obj.pose.bone_groups.new(name=name)
675 bg.color_set = 'CUSTOM'
676 bg.colors.normal = gamma_correct(groups[g_id].normal)
677 bg.colors.select = gamma_correct(groups[g_id].select)
678 bg.colors.active = gamma_correct(groups[g_id].active)
680 for b in pb:
681 try:
682 prios = priorities.get(b.name, dummy)
683 enabled = [ i for i, v in enumerate(b.bone.layers) if v ]
684 layer_index = max(enabled, key=lambda i: prios.get(i, 0))
685 except ValueError:
686 continue
687 if layer_index > len(layers) - 1: # bone is on reserved layers
688 continue
689 g_id = layers[layer_index].group - 1
690 if g_id >= 0:
691 name = groups[g_id].name
692 b.bone_group = obj.pose.bone_groups[name]
695 def get_xy_spread(bones):
696 x_max = 0
697 y_max = 0
698 for b in bones:
699 x_max = max((x_max, abs(b.head[0]), abs(b.tail[0])))
700 y_max = max((y_max, abs(b.head[1]), abs(b.tail[1])))
702 return max((x_max, y_max))
705 def param_matches_type(param_name, rig_type):
706 """ Returns True if the parameter name is consistent with the rig type.
708 if param_name.rsplit(".", 1)[0] == rig_type:
709 return True
710 else:
711 return False
714 def param_name(param_name, rig_type):
715 """ Get the actual parameter name, sans-rig-type.
717 return param_name[len(rig_type) + 1:]