diff options
Diffstat (limited to 'rigify')
38 files changed, 1869 insertions, 920 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py index 803c19c0..8363d037 100644 --- a/rigify/__init__.py +++ b/rigify/__init__.py @@ -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. diff --git a/rigify/base_rig.py b/rigify/base_rig.py index 6b01c43a..b7a5d08c 100644 --- a/rigify/base_rig.py +++ b/rigify/base_rig.py @@ -258,6 +258,16 @@ class RigUtility(BoneUtilityMixin, MechanismUtilityMixin): self.owner.register_new_bone(new_name, old_name) +class RigComponent(GenerateCallbackHost, RigUtility): + """Base class for utility classes that generate part of a rig using callbacks.""" + def __init__(self, owner): + super().__init__(owner) + + self.owner.rigify_sub_objects = objects = self.owner.rigify_sub_objects or [] + + objects.append(self) + + #============================================= # Rig Stage Decorators #============================================= diff --git a/rigify/generate.py b/rigify/generate.py index 0d02c5c2..8e3ca0f0 100644 --- a/rigify/generate.py +++ b/rigify/generate.py @@ -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: @@ -327,9 +336,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 diff --git a/rigify/metarigs/Animals/bird.py b/rigify/metarigs/Animals/bird.py index a3331c29..eee6b38b 100644 --- a/rigify/metarigs/Animals/bird.py +++ b/rigify/metarigs/Animals/bird.py @@ -165,47 +165,19 @@ def create(obj): bones = {} - bone = arm.edit_bones.new('spine') - bone.head[:] = -0.0000, 0.1371, 0.0894 - bone.tail[:] = -0.0000, 0.1039, 0.0907 + bone = arm.edit_bones.new('spine.003') + bone.head[:] = -0.0000, 0.0451, 0.0845 + bone.tail[:] = -0.0000, 0.0192, 0.0888 bone.roll = 0.0000 bone.use_connect = False - bones['spine'] = bone.name - bone = arm.edit_bones.new('spine.001') - bone.head[:] = -0.0000, 0.1039, 0.0907 + bones['spine.003'] = bone.name + bone = arm.edit_bones.new('spine.002') + bone.head[:] = -0.0000, 0.0451, 0.0845 bone.tail[:] = -0.0000, 0.0757, 0.0880 bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine']] - bones['spine.001'] = bone.name - bone = arm.edit_bones.new('t_feather.L') - bone.head[:] = 0.0112, 0.1017, 0.0907 - bone.tail[:] = 0.0167, 0.1345, 0.0894 - bone.roll = 0.0032 - bone.use_connect = False - bone.parent = arm.edit_bones[bones['spine']] - bones['t_feather.L'] = bone.name - bone = arm.edit_bones.new('t_feather.R') - bone.head[:] = -0.0112, 0.1017, 0.0907 - bone.tail[:] = -0.0167, 0.1345, 0.0894 - bone.roll = -0.0032 bone.use_connect = False - bone.parent = arm.edit_bones[bones['spine']] - bones['t_feather.R'] = bone.name - bone = arm.edit_bones.new('spine.002') - bone.head[:] = -0.0000, 0.0757, 0.0880 - bone.tail[:] = -0.0000, 0.0451, 0.0845 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.001']] + bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.002'] = bone.name - bone = arm.edit_bones.new('spine.003') - bone.head[:] = -0.0000, 0.0451, 0.0845 - bone.tail[:] = -0.0000, 0.0192, 0.0888 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.002']] - bones['spine.003'] = bone.name bone = arm.edit_bones.new('spine.004') bone.head[:] = -0.0000, 0.0192, 0.0888 bone.tail[:] = -0.0000, -0.0106, 0.0979 @@ -213,6 +185,13 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.004'] = bone.name + bone = arm.edit_bones.new('spine.001') + bone.head[:] = -0.0000, 0.0757, 0.0880 + bone.tail[:] = -0.0000, 0.1039, 0.0907 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.002']] + bones['spine.001'] = bone.name bone = arm.edit_bones.new('spine.005') bone.head[:] = -0.0000, -0.0106, 0.0979 bone.tail[:] = -0.0000, -0.0298, 0.1158 @@ -248,6 +227,13 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.004']] bones['thigh.R'] = bone.name + bone = arm.edit_bones.new('spine') + bone.head[:] = -0.0000, 0.1039, 0.0907 + bone.tail[:] = -0.0000, 0.1371, 0.0894 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.001']] + bones['spine'] = bone.name bone = arm.edit_bones.new('shoulder.L') bone.head[:] = 0.0014, -0.0217, 0.0893 bone.tail[:] = 0.0076, -0.0020, 0.1179 @@ -283,6 +269,20 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['thigh.R']] bones['shin.R'] = bone.name + bone = arm.edit_bones.new('t_feather.L') + bone.head[:] = 0.0112, 0.1017, 0.0907 + bone.tail[:] = 0.0167, 0.1345, 0.0894 + bone.roll = 0.0032 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine']] + bones['t_feather.L'] = bone.name + bone = arm.edit_bones.new('t_feather.R') + bone.head[:] = -0.0112, 0.1017, 0.0907 + bone.tail[:] = -0.0167, 0.1345, 0.0894 + bone.roll = -0.0032 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine']] + bones['t_feather.R'] = bone.name bone = arm.edit_bones.new('Wing.L') bone.head[:] = 0.0089, 0.0141, 0.1157 bone.tail[:] = 0.0485, 0.0107, 0.1163 @@ -294,7 +294,7 @@ def create(obj): bone.head[:] = -0.0000, -0.0417, 0.1348 bone.tail[:] = -0.0000, -0.0458, 0.1429 bone.roll = 0.0001 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.006']] bones['neck.001'] = bone.name bone = arm.edit_bones.new('Wing.R') @@ -691,8 +691,8 @@ def create(obj): bones['tongue.003.L'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone = obj.pose.bones[bones['spine.003']] + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -700,70 +700,38 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.use_tail = True - except AttributeError: - pass - try: - pbone.rigify_parameters.tail_pos = 3 + pbone.rigify_parameters.pivot_pos = 1 except AttributeError: pass try: - pbone.rigify_parameters.pivot_pos = 4 - except AttributeError: - pass - try: - pbone.rigify_parameters.neck_pos = 8 - except AttributeError: - pass - try: - pbone.rigify_parameters.copy_rotation_axes = [True, False, True] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.001']] - pbone.rigify_type = '' + pbone = obj.pose.bones[bones['spine.002']] + pbone.rigify_type = 'spines.basic_tail' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['t_feather.L']] - pbone.rigify_type = 'basic.super_copy' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.make_widget = False + pbone.rigify_parameters.copy_rotation_axes = [True, False, True] except AttributeError: pass - pbone = obj.pose.bones[bones['t_feather.R']] - pbone.rigify_type = 'basic.super_copy' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.make_widget = False + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.002']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.003']] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + pbone = obj.pose.bones[bones['spine.004']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -771,7 +739,7 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.004']] + pbone = obj.pose.bones[bones['spine.001']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -859,6 +827,14 @@ def create(obj): pbone.rigify_parameters.fk_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass + pbone = obj.pose.bones[bones['spine']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -907,6 +883,30 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['t_feather.L']] + pbone.rigify_type = 'basic.super_copy' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.make_widget = False + except AttributeError: + pass + pbone = obj.pose.bones[bones['t_feather.R']] + pbone.rigify_type = 'basic.super_copy' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.make_widget = False + except AttributeError: + pass pbone = obj.pose.bones[bones['Wing.L']] pbone.rigify_type = 'limbs.simple_tentacle' pbone.lock_location = (False, False, False) @@ -914,20 +914,31 @@ def create(obj): pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.rigify_parameters.copy_rotation_axes = [False, False, False] pbone.bone.layers = [False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: + pbone.rigify_parameters.copy_rotation_axes = [False, False, False] + except AttributeError: + pass + try: pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass pbone = obj.pose.bones[bones['neck.001']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass pbone = obj.pose.bones[bones['Wing.R']] pbone.rigify_type = 'limbs.simple_tentacle' pbone.lock_location = (False, False, False) @@ -935,9 +946,12 @@ def create(obj): pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.rigify_parameters.copy_rotation_axes = [False, False, False] pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: + pbone.rigify_parameters.copy_rotation_axes = [False, False, False] + except AttributeError: + pass + try: pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass @@ -1488,9 +1502,12 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 7, 10, 13, 16, 21, 24]) for x in range(32)] + return bones + if __name__ == "__main__": create(bpy.context.active_object) diff --git a/rigify/metarigs/Animals/cat.py b/rigify/metarigs/Animals/cat.py index a065c432..66321116 100644 --- a/rigify/metarigs/Animals/cat.py +++ b/rigify/metarigs/Animals/cat.py @@ -165,40 +165,19 @@ def create(obj): bones = {} - bone = arm.edit_bones.new('tail.004') - bone.head[:] = -0.0000, 0.5531, 0.2488 - bone.tail[:] = -0.0000, 0.4543, 0.2321 - bone.roll = 0.0000 - bone.use_connect = False - bones['tail.004'] = bone.name - bone = arm.edit_bones.new('tail.003') - bone.head[:] = -0.0000, 0.4543, 0.2321 - bone.tail[:] = -0.0000, 0.3513, 0.2284 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['tail.004']] - bones['tail.003'] = bone.name - bone = arm.edit_bones.new('tail.002') - bone.head[:] = -0.0000, 0.3513, 0.2284 - bone.tail[:] = -0.0000, 0.2460, 0.2324 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['tail.003']] - bones['tail.002'] = bone.name - bone = arm.edit_bones.new('tail.001') - bone.head[:] = -0.0000, 0.2460, 0.2324 - bone.tail[:] = 0.0000, 0.1499, 0.2500 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['tail.002']] - bones['tail.001'] = bone.name bone = arm.edit_bones.new('spine') bone.head[:] = 0.0000, 0.1499, 0.2500 bone.tail[:] = 0.0000, 0.0769, 0.2272 bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['tail.001']] + bone.use_connect = False bones['spine'] = bone.name + bone = arm.edit_bones.new('tail.001') + bone.head[:] = 0.0000, 0.1499, 0.2500 + bone.tail[:] = -0.0000, 0.2460, 0.2324 + bone.roll = 0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine']] + bones['tail.001'] = bone.name bone = arm.edit_bones.new('spine.001') bone.head[:] = 0.0000, 0.0769, 0.2272 bone.tail[:] = 0.0000, 0.0180, 0.2240 @@ -227,6 +206,13 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine']] bones['pelvis.C'] = bone.name + bone = arm.edit_bones.new('tail.002') + bone.head[:] = -0.0000, 0.2460, 0.2324 + bone.tail[:] = -0.0000, 0.3513, 0.2284 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['tail.001']] + bones['tail.002'] = bone.name bone = arm.edit_bones.new('spine.002') bone.head[:] = 0.0000, 0.0180, 0.2240 bone.tail[:] = 0.0000, -0.0513, 0.2271 @@ -248,6 +234,13 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['pelvis.R']] bones['thigh.R'] = bone.name + bone = arm.edit_bones.new('tail.003') + bone.head[:] = -0.0000, 0.3513, 0.2284 + bone.tail[:] = -0.0000, 0.4543, 0.2321 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['tail.002']] + bones['tail.003'] = bone.name bone = arm.edit_bones.new('spine.003') bone.head[:] = 0.0000, -0.0513, 0.2271 bone.tail[:] = 0.0000, -0.1571, 0.2355 @@ -276,11 +269,18 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['thigh.R']] bones['shin.R'] = bone.name + bone = arm.edit_bones.new('tail.004') + bone.head[:] = -0.0000, 0.4543, 0.2321 + bone.tail[:] = -0.0000, 0.5531, 0.2488 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['tail.003']] + bones['tail.004'] = bone.name bone = arm.edit_bones.new('spine.004') bone.head[:] = 0.0000, -0.1571, 0.2355 bone.tail[:] = 0.0000, -0.1736, 0.2395 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.004'] = bone.name bone = arm.edit_bones.new('Breast.C') @@ -1384,52 +1384,24 @@ def create(obj): bones['brow.T.R.003'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['tail.004']] - pbone.rigify_type = 'spines.super_spine' + pbone = obj.pose.bones[bones['spine']] + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.use_tail = True - except AttributeError: - pass - try: - pbone.rigify_parameters.pivot_pos = 6 - except AttributeError: - pass - try: - pbone.rigify_parameters.neck_pos = 9 - except AttributeError: - pass + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tail_pos = 4 + pbone.rigify_parameters.tweak_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.copy_rotation_axes = [True, True, True] + pbone.rigify_parameters.fk_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['tail.003']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['tail.002']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['tail.001']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.basic_tail' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -1437,23 +1409,15 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 5 + pbone.rigify_parameters.copy_rotation_axes = [True, True, True] except AttributeError: pass try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.connect_chain = True except AttributeError: pass pbone = obj.pose.bones[bones['spine.001']] @@ -1504,6 +1468,14 @@ def create(obj): pbone.rigify_parameters.make_control = False except AttributeError: pass + pbone = obj.pose.bones[bones['tail.002']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.002']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -1556,6 +1528,14 @@ def create(obj): pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass + pbone = obj.pose.bones[bones['tail.003']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.003']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -1588,14 +1568,26 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.004']] + pbone = obj.pose.bones[bones['tail.004']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine.004']] + pbone.rigify_type = 'spines.super_head' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass pbone = obj.pose.bones[bones['Breast.C']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -2983,9 +2975,12 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 5, 7, 10, 13, 16, 19]) for x in range(32)] + return bones + if __name__ == "__main__": create(bpy.context.active_object) diff --git a/rigify/metarigs/Animals/horse.py b/rigify/metarigs/Animals/horse.py index 358a9ceb..6c94a19d 100644 --- a/rigify/metarigs/Animals/horse.py +++ b/rigify/metarigs/Animals/horse.py @@ -163,60 +163,38 @@ def create(obj): arm.rigify_layers[28].selset = False arm.rigify_layers[28].group = 1 - bones = {} - bone = arm.edit_bones.new('spine') - bone.head[:] = -0.0000, 1.7610, 1.1153 - bone.tail[:] = -0.0000, 1.5754, 1.1088 - bone.roll = -0.0000 - bone.use_connect = False - bones['spine'] = bone.name - bone = arm.edit_bones.new('spine.001') - bone.head[:] = -0.0000, 1.5754, 1.1088 - bone.tail[:] = -0.0000, 1.3779, 1.1589 - bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine']] - bones['spine.001'] = bone.name - bone = arm.edit_bones.new('spine.002') - bone.head[:] = -0.0000, 1.3779, 1.1589 - bone.tail[:] = -0.0000, 1.1423, 1.3128 - bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.001']] - bones['spine.002'] = bone.name - bone = arm.edit_bones.new('spine.003') - bone.head[:] = -0.0000, 1.1423, 1.3128 - bone.tail[:] = -0.0000, 1.0291, 1.4191 - bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.002']] - bones['spine.003'] = bone.name - bone = arm.edit_bones.new('spine.004') - bone.head[:] = -0.0000, 1.0291, 1.4191 - bone.tail[:] = -0.0000, 0.9228, 1.4526 - bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.003']] - bones['spine.004'] = bone.name bone = arm.edit_bones.new('spine.005') bone.head[:] = -0.0000, 0.9228, 1.4526 bone.tail[:] = -0.0000, 0.6989, 1.4910 bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.004']] + bone.use_connect = False bones['spine.005'] = bone.name + bone = arm.edit_bones.new('spine.004') + bone.head[:] = -0.0000, 0.9228, 1.4526 + bone.tail[:] = -0.0000, 1.0291, 1.4191 + bone.roll = -0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine.005']] + bones['spine.004'] = bone.name bone = arm.edit_bones.new('spine.006') bone.head[:] = -0.0000, 0.6989, 1.4910 - bone.tail[:] = -0.0000, 0.3824, 1.3801 + bone.tail[:] = 0.0000, 0.3824, 1.3801 bone.roll = -0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.005']] bones['spine.006'] = bone.name + bone = arm.edit_bones.new('spine.003') + bone.head[:] = -0.0000, 1.0291, 1.4191 + bone.tail[:] = -0.0000, 1.1423, 1.3128 + bone.roll = -0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.004']] + bones['spine.003'] = bone.name bone = arm.edit_bones.new('spine.007') - bone.head[:] = -0.0000, 0.3824, 1.3801 - bone.tail[:] = -0.0000, 0.1316, 1.3086 + bone.head[:] = 0.0000, 0.3824, 1.3801 + bone.tail[:] = 0.0000, 0.1316, 1.3086 bone.roll = 0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.006']] @@ -256,9 +234,16 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.006']] bones['pelvis'] = bone.name + bone = arm.edit_bones.new('spine.002') + bone.head[:] = -0.0000, 1.1423, 1.3128 + bone.tail[:] = -0.0000, 1.3779, 1.1589 + bone.roll = -0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.003']] + bones['spine.002'] = bone.name bone = arm.edit_bones.new('spine.008') - bone.head[:] = -0.0000, 0.1316, 1.3086 - bone.tail[:] = -0.0000, -0.1712, 1.2964 + bone.head[:] = 0.0000, 0.1316, 1.3086 + bone.tail[:] = 0.0000, -0.1712, 1.2964 bone.roll = 0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.007']] @@ -277,9 +262,16 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['thigh.R']] bones['shin.R'] = bone.name + bone = arm.edit_bones.new('spine.001') + bone.head[:] = -0.0000, 1.3779, 1.1589 + bone.tail[:] = -0.0000, 1.5754, 1.1088 + bone.roll = -0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.002']] + bones['spine.001'] = bone.name bone = arm.edit_bones.new('spine.009') - bone.head[:] = -0.0000, -0.1712, 1.2964 - bone.tail[:] = -0.0000, -0.4908, 1.3031 + bone.head[:] = 0.0000, -0.1712, 1.2964 + bone.tail[:] = 0.0000, -0.4908, 1.3031 bone.roll = 0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.008']] @@ -305,9 +297,16 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['shin.R']] bones['foot.R'] = bone.name + bone = arm.edit_bones.new('spine') + bone.head[:] = -0.0000, 1.5754, 1.1088 + bone.tail[:] = -0.0000, 1.7610, 1.1153 + bone.roll = -0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.001']] + bones['spine'] = bone.name bone = arm.edit_bones.new('spine.010') - bone.head[:] = -0.0000, -0.4908, 1.3031 - bone.tail[:] = -0.0000, -0.7593, 1.3786 + bone.head[:] = 0.0000, -0.4908, 1.3031 + bone.tail[:] = 0.0000, -0.7593, 1.3786 bone.roll = 0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.009']] @@ -362,10 +361,10 @@ def create(obj): bone.parent = arm.edit_bones[bones['foot.R']] bones['r_toe.R'] = bone.name bone = arm.edit_bones.new('spine.011') - bone.head[:] = -0.0000, -0.7593, 1.3786 - bone.tail[:] = -0.0000, -0.9004, 1.5475 + bone.head[:] = 0.0000, -0.7593, 1.3786 + bone.tail[:] = 0.0000, -0.9004, 1.5475 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.010']] bones['spine.011'] = bone.name bone = arm.edit_bones.new('hair_base.05') @@ -629,8 +628,8 @@ def create(obj): bones['jaw.001'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone = obj.pose.bones[bones['spine.005']] + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -638,7 +637,7 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 12 + pbone.rigify_parameters.pivot_pos = 3 except AttributeError: pass try: @@ -646,37 +645,37 @@ def create(obj): except AttributeError: pass try: - pbone.rigify_parameters.use_tail = True + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass + pbone = obj.pose.bones[bones['spine.004']] + pbone.rigify_type = 'spines.basic_tail' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.pivot_pos = 8 + pbone.rigify_parameters.copy_rotation_axes = [True, False, True] except AttributeError: pass try: - pbone.rigify_parameters.tail_pos = 5 + pbone.rigify_parameters.connect_chain = True except AttributeError: pass try: - pbone.rigify_parameters.copy_rotation_axes = [True, False, True] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.001']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.002']] + pbone = obj.pose.bones[bones['spine.006']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.003']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -685,30 +684,6 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.005']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.006']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.007']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -805,6 +780,14 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine.002']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.008']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -829,6 +812,14 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine.001']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.009']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -861,6 +852,14 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.010']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -934,13 +933,21 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.011']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['hair_base.05']] pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) @@ -1364,9 +1371,12 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 4, 7, 10, 13, 16, 19, 21]) for x in range(32)] + return bones + if __name__ == "__main__": create(bpy.context.active_object) diff --git a/rigify/metarigs/Animals/shark.py b/rigify/metarigs/Animals/shark.py index 1ee1d0d9..8b72a965 100644 --- a/rigify/metarigs/Animals/shark.py +++ b/rigify/metarigs/Animals/shark.py @@ -165,40 +165,40 @@ def create(obj): bones = {} - bone = arm.edit_bones.new('spine') - bone.head[:] = -0.0000, 1.3362, 0.4776 - bone.tail[:] = -0.0000, 1.0816, 0.4540 - bone.roll = 0.0000 + bone = arm.edit_bones.new('spine.003') + bone.head[:] = -0.0000, 0.3182, 0.4031 + bone.tail[:] = -0.0000, 0.0152, 0.3904 + bone.roll = 0.0001 bone.use_connect = False - bones['spine'] = bone.name - bone = arm.edit_bones.new('spine.001') - bone.head[:] = -0.0000, 1.0816, 0.4540 + bones['spine.003'] = bone.name + bone = arm.edit_bones.new('spine.002') + bone.head[:] = -0.0000, 0.3182, 0.4031 bone.tail[:] = -0.0000, 0.7152, 0.4305 bone.roll = -0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine']] - bones['spine.001'] = bone.name - bone = arm.edit_bones.new('back_fin.T.Bk') - bone.head[:] = 0.0000, 1.2501, 0.5345 - bone.tail[:] = 0.0000, 1.5211, 0.7594 - bone.roll = 0.0000 - bone.use_connect = False - bone.parent = arm.edit_bones[bones['spine']] - bones['back_fin.T.Bk'] = bone.name - bone = arm.edit_bones.new('back_fin.B.Bk') - bone.head[:] = 0.0000, 1.2305, 0.4158 - bone.tail[:] = 0.0000, 1.3289, 0.2452 - bone.roll = 0.0000 bone.use_connect = False - bone.parent = arm.edit_bones[bones['spine']] - bones['back_fin.B.Bk'] = bone.name - bone = arm.edit_bones.new('spine.002') + bone.parent = arm.edit_bones[bones['spine.003']] + bones['spine.002'] = bone.name + bone = arm.edit_bones.new('spine.001') bone.head[:] = -0.0000, 0.7152, 0.4305 - bone.tail[:] = -0.0000, 0.3182, 0.4031 + bone.tail[:] = -0.0000, 1.0816, 0.4540 bone.roll = -0.0000 bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.002']] + bones['spine.001'] = bone.name + bone = arm.edit_bones.new('spine.008') + bone.head[:] = -0.0000, 0.0152, 0.3904 + bone.tail[:] = 0.0000, -0.3259, 0.3967 + bone.roll = 0.0001 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.003']] + bones['spine.008'] = bone.name + bone = arm.edit_bones.new('spine') + bone.head[:] = -0.0000, 1.0816, 0.4540 + bone.tail[:] = -0.0000, 1.3362, 0.4776 + bone.roll = 0.0000 + bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.001']] - bones['spine.002'] = bone.name + bones['spine'] = bone.name bone = arm.edit_bones.new('mid_fin.Top') bone.head[:] = 0.0000, 0.7296, 0.5396 bone.tail[:] = 0.0000, 0.7709, 0.6351 @@ -213,41 +213,6 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.001']] bones['mid_fin.Bot'] = bone.name - bone = arm.edit_bones.new('back_fin.T.001.Bk') - bone.head[:] = 0.0000, 1.5211, 0.7594 - bone.tail[:] = 0.0000, 1.7667, 0.9633 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['back_fin.T.Bk']] - bones['back_fin.T.001.Bk'] = bone.name - bone = arm.edit_bones.new('back_fin.B.001.Bk') - bone.head[:] = 0.0000, 1.3289, 0.2452 - bone.tail[:] = 0.0000, 1.3818, 0.1513 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['back_fin.B.Bk']] - bones['back_fin.B.001.Bk'] = bone.name - bone = arm.edit_bones.new('spine.003') - bone.head[:] = -0.0000, 0.3182, 0.4031 - bone.tail[:] = -0.0000, 0.0152, 0.3904 - bone.roll = 0.0001 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.002']] - bones['spine.003'] = bone.name - bone = arm.edit_bones.new('back_fin.T.002.Bk') - bone.head[:] = 0.0000, 1.7667, 0.9633 - bone.tail[:] = 0.0000, 1.9489, 1.1145 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['back_fin.T.001.Bk']] - bones['back_fin.T.002.Bk'] = bone.name - bone = arm.edit_bones.new('spine.008') - bone.head[:] = -0.0000, 0.0152, 0.3904 - bone.tail[:] = 0.0000, -0.3259, 0.3967 - bone.roll = 0.0001 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.003']] - bones['spine.008'] = bone.name bone = arm.edit_bones.new('spine.004') bone.head[:] = 0.0000, -0.3259, 0.3967 bone.tail[:] = 0.0000, -0.5947, 0.4044 @@ -269,6 +234,20 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.008']] bones['chest_fin.Bot.R'] = bone.name + bone = arm.edit_bones.new('back_fin.T.Bk') + bone.head[:] = 0.0000, 1.2501, 0.5345 + bone.tail[:] = 0.0000, 1.5211, 0.7594 + bone.roll = 0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine']] + bones['back_fin.T.Bk'] = bone.name + bone = arm.edit_bones.new('back_fin.B.Bk') + bone.head[:] = 0.0000, 1.2305, 0.4158 + bone.tail[:] = 0.0000, 1.3289, 0.2452 + bone.roll = 0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine']] + bones['back_fin.B.Bk'] = bone.name bone = arm.edit_bones.new('spine.005') bone.head[:] = 0.0000, -0.5947, 0.4044 bone.tail[:] = 0.0000, -1.2084, 0.4328 @@ -283,11 +262,25 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.004']] bones['top_fin'] = bone.name + bone = arm.edit_bones.new('back_fin.T.001.Bk') + bone.head[:] = 0.0000, 1.5211, 0.7594 + bone.tail[:] = 0.0000, 1.7667, 0.9633 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['back_fin.T.Bk']] + bones['back_fin.T.001.Bk'] = bone.name + bone = arm.edit_bones.new('back_fin.B.001.Bk') + bone.head[:] = 0.0000, 1.3289, 0.2452 + bone.tail[:] = 0.0000, 1.3818, 0.1513 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['back_fin.B.Bk']] + bones['back_fin.B.001.Bk'] = bone.name bone = arm.edit_bones.new('spine.006') bone.head[:] = 0.0000, -1.2084, 0.4328 bone.tail[:] = 0.0000, -1.5634, 0.4275 bone.roll = -0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.005']] bones['spine.006'] = bone.name bone = arm.edit_bones.new('shoulder.L') @@ -311,6 +304,13 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['top_fin']] bones['top_fin.001'] = bone.name + bone = arm.edit_bones.new('back_fin.T.002.Bk') + bone.head[:] = 0.0000, 1.7667, 0.9633 + bone.tail[:] = 0.0000, 1.9489, 1.1145 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['back_fin.T.001.Bk']] + bones['back_fin.T.002.Bk'] = bone.name bone = arm.edit_bones.new('spine.007') bone.head[:] = 0.0000, -1.5634, 0.4275 bone.tail[:] = 0.0000, -2.0661, 0.4364 @@ -411,8 +411,8 @@ def create(obj): bones['jaw.003.R'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone = obj.pose.bones[bones['spine.002']] + pbone.rigify_type = 'spines.basic_tail' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -420,70 +420,34 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 8 - except AttributeError: - pass - try: pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.tail_pos = 3 - except AttributeError: - pass - try: - pbone.rigify_parameters.pivot_pos = 5 - except AttributeError: - pass - try: - pbone.rigify_parameters.use_tail = True + pbone.rigify_parameters.connect_chain = True except AttributeError: pass try: pbone.rigify_parameters.copy_rotation_axes = [True, False, True] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.001']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['back_fin.T.Bk']] - pbone.rigify_type = 'limbs.super_finger' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - except AttributeError: - pass - try: - pbone.rigify_parameters.primary_rotation_axis = "Z" - except AttributeError: - pass - pbone = obj.pose.bones[bones['back_fin.B.Bk']] - pbone.rigify_type = 'limbs.super_finger' + pbone = obj.pose.bones[bones['spine.003']] + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.primary_rotation_axis = "Z" + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.002']] + pbone = obj.pose.bones[bones['spine.001']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -491,23 +455,23 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['mid_fin.Top']] + pbone = obj.pose.bones[bones['spine.008']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['mid_fin.Bot']] + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['back_fin.T.001.Bk']] + pbone.bone.layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['mid_fin.Top']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -515,15 +479,15 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['back_fin.B.001.Bk']] + pbone = obj.pose.bones[bones['mid_fin.Bot']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.003']] + pbone.bone.layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine.004']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -531,32 +495,32 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['back_fin.T.002.Bk']] - pbone.rigify_type = '' + pbone = obj.pose.bones[bones['chest_fin.Bot.L']] + pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.008']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + pbone = obj.pose.bones[bones['chest_fin.Bot.R']] + pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['chest_fin.Bot.L']] - pbone.rigify_type = 'basic.super_copy' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + pbone = obj.pose.bones[bones['back_fin.T.Bk']] + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -564,11 +528,15 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['chest_fin.Bot.R']] - pbone.rigify_type = 'basic.super_copy' + try: + pbone.rigify_parameters.primary_rotation_axis = "Z" + except AttributeError: + pass + pbone = obj.pose.bones[bones['back_fin.B.Bk']] + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -576,7 +544,11 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + try: + pbone.rigify_parameters.primary_rotation_axis = "Z" except AttributeError: pass pbone = obj.pose.bones[bones['spine.005']] @@ -599,14 +571,38 @@ def create(obj): pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.006']] + pbone = obj.pose.bones[bones['back_fin.T.001.Bk']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['back_fin.B.001.Bk']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine.006']] + pbone.rigify_type = 'spines.super_head' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -639,6 +635,14 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['back_fin.T.002.Bk']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.007']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -786,9 +790,12 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 5, 6, 8, 10]) for x in range(32)] + return bones + if __name__ == "__main__": create(bpy.context.active_object) diff --git a/rigify/metarigs/Animals/wolf.py b/rigify/metarigs/Animals/wolf.py index 4cccf085..f6150c54 100644 --- a/rigify/metarigs/Animals/wolf.py +++ b/rigify/metarigs/Animals/wolf.py @@ -165,40 +165,19 @@ def create(obj): bones = {} - bone = arm.edit_bones.new('spine') - bone.head[:] = 0.0000, 1.1044, 0.7633 - bone.tail[:] = 0.0000, 0.9624, 0.7412 - bone.roll = 0.0000 - bone.use_connect = False - bones['spine'] = bone.name - bone = arm.edit_bones.new('spine.001') - bone.head[:] = 0.0000, 0.9624, 0.7412 - bone.tail[:] = 0.0000, 0.7755, 0.7418 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine']] - bones['spine.001'] = bone.name - bone = arm.edit_bones.new('spine.002') - bone.head[:] = 0.0000, 0.7755, 0.7418 - bone.tail[:] = 0.0000, 0.5547, 0.7568 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.001']] - bones['spine.002'] = bone.name - bone = arm.edit_bones.new('spine.003') - bone.head[:] = 0.0000, 0.5547, 0.7568 - bone.tail[:] = 0.0000, 0.4418, 0.7954 - bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.002']] - bones['spine.003'] = bone.name bone = arm.edit_bones.new('spine.004') bone.head[:] = 0.0000, 0.4418, 0.7954 bone.tail[:] = 0.0000, 0.3546, 0.8059 bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.003']] + bone.use_connect = False bones['spine.004'] = bone.name + bone = arm.edit_bones.new('spine.003') + bone.head[:] = 0.0000, 0.4418, 0.7954 + bone.tail[:] = 0.0000, 0.5547, 0.7568 + bone.roll = 0.0000 + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine.004']] + bones['spine.003'] = bone.name bone = arm.edit_bones.new('spine.005') bone.head[:] = 0.0000, 0.3546, 0.8059 bone.tail[:] = 0.0000, 0.1803, 0.7782 @@ -206,6 +185,13 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.004']] bones['spine.005'] = bone.name + bone = arm.edit_bones.new('spine.002') + bone.head[:] = 0.0000, 0.5547, 0.7568 + bone.tail[:] = 0.0000, 0.7755, 0.7418 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.003']] + bones['spine.002'] = bone.name bone = arm.edit_bones.new('spine.006') bone.head[:] = 0.0000, 0.1803, 0.7782 bone.tail[:] = 0.0000, 0.0319, 0.7731 @@ -241,6 +227,13 @@ def create(obj): bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.005']] bones['thigh.R'] = bone.name + bone = arm.edit_bones.new('spine.001') + bone.head[:] = 0.0000, 0.7755, 0.7418 + bone.tail[:] = 0.0000, 0.9624, 0.7412 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.002']] + bones['spine.001'] = bone.name bone = arm.edit_bones.new('spine.007') bone.head[:] = 0.0000, 0.0319, 0.7731 bone.tail[:] = 0.0000, -0.0980, 0.7945 @@ -262,6 +255,13 @@ def create(obj): bone.use_connect = True bone.parent = arm.edit_bones[bones['thigh.R']] bones['shin.R'] = bone.name + bone = arm.edit_bones.new('spine') + bone.head[:] = 0.0000, 0.9624, 0.7412 + bone.tail[:] = 0.0000, 1.1044, 0.7633 + bone.roll = 0.0000 + bone.use_connect = True + bone.parent = arm.edit_bones[bones['spine.001']] + bones['spine'] = bone.name bone = arm.edit_bones.new('spine.008') bone.head[:] = 0.0000, -0.0980, 0.7945 bone.tail[:] = 0.0000, -0.3618, 0.8375 @@ -287,7 +287,7 @@ def create(obj): bone.head[:] = 0.0000, -0.3618, 0.8375 bone.tail[:] = 0.0000, -0.4253, 0.8585 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.008']] bones['spine.009'] = bone.name bone = arm.edit_bones.new('shoulder.L') @@ -1496,63 +1496,63 @@ def create(obj): bones['brow.T.R.003'] = bone.name bpy.ops.object.mode_set(mode='OBJECT') - pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone = obj.pose.bones[bones['spine.004']] + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.pivot_pos = 4 except AttributeError: pass try: - pbone.rigify_parameters.use_tail = True + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.tail_pos = 4 + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass + pbone = obj.pose.bones[bones['spine.003']] + pbone.rigify_type = 'spines.basic_tail' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.pivot_pos = 8 + pbone.rigify_parameters.copy_rotation_axes = [True, False, True] except AttributeError: pass try: - pbone.rigify_parameters.neck_pos = 10 + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.copy_rotation_axes = [True, False, True] + pbone.rigify_parameters.connect_chain = True except AttributeError: pass - pbone = obj.pose.bones[bones['spine.001']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.002']] + pbone = obj.pose.bones[bones['spine.005']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.tweak_extra_layers = False + pbone.rigify_parameters.neck_pos = 5 except AttributeError: pass try: - pbone.rigify_parameters.tweak_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass - pbone = obj.pose.bones[bones['spine.003']] + pbone = obj.pose.bones[bones['spine.002']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) @@ -1560,28 +1560,8 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - pbone = obj.pose.bones[bones['spine.005']] - pbone.rigify_type = '' - pbone.lock_location = (False, False, False) - pbone.lock_rotation = (False, False, False) - pbone.lock_rotation_w = False - pbone.lock_scale = (False, False, False) - pbone.rotation_mode = 'QUATERNION' - pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 5 - except AttributeError: - pass - try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.tweak_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False] except AttributeError: pass pbone = obj.pose.bones[bones['spine.006']] @@ -1656,6 +1636,14 @@ def create(obj): pbone.rigify_parameters.limb_type = "paw" except AttributeError: pass + pbone = obj.pose.bones[bones['spine.001']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.007']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -1680,6 +1668,14 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone = obj.pose.bones[bones['spine']] + pbone.rigify_type = '' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.008']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -1705,13 +1701,21 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.009']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -3219,9 +3223,12 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 4, 5, 7, 10, 13, 16, 19]) for x in range(32)] + return bones + if __name__ == "__main__": create(bpy.context.active_object) diff --git a/rigify/metarigs/Basic/basic_human.py b/rigify/metarigs/Basic/basic_human.py index 01367a7b..01017cf4 100644 --- a/rigify/metarigs/Basic/basic_human.py +++ b/rigify/metarigs/Basic/basic_human.py @@ -252,7 +252,7 @@ def create(obj): bone.head[:] = 0.0000, 0.0114, 1.6582 bone.tail[:] = 0.0000, -0.0130, 1.7197 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.004'] = bone.name bone = arm.edit_bones.new('shoulder.L') @@ -370,7 +370,7 @@ def create(obj): bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -378,11 +378,11 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 5 + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass pbone = obj.pose.bones[bones['spine.001']] @@ -506,13 +506,21 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -676,6 +684,7 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [3, 7, 10, 13, 16]) for x in range(32)] diff --git a/rigify/metarigs/Basic/basic_quadruped.py b/rigify/metarigs/Basic/basic_quadruped.py index 5aa9f657..5282df25 100644 --- a/rigify/metarigs/Basic/basic_quadruped.py +++ b/rigify/metarigs/Basic/basic_quadruped.py @@ -165,40 +165,40 @@ def create(obj): bones = {} - bone = arm.edit_bones.new('spine') - bone.head[:] = 0.0000, 1.1044, 0.7633 - bone.tail[:] = 0.0000, 0.9624, 0.7412 + bone = arm.edit_bones.new('spine.004') + bone.head[:] = 0.0000, 0.4418, 0.7954 + bone.tail[:] = 0.0000, 0.3546, 0.8059 bone.roll = 0.0000 bone.use_connect = False - bones['spine'] = bone.name - bone = arm.edit_bones.new('spine.001') - bone.head[:] = 0.0000, 0.9624, 0.7412 - bone.tail[:] = 0.0000, 0.7755, 0.7418 + bones['spine.004'] = bone.name + bone = arm.edit_bones.new('spine.003') + bone.head[:] = 0.0000, 0.4418, 0.7954 + bone.tail[:] = 0.0000, 0.5547, 0.7568 bone.roll = 0.0000 - bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine']] - bones['spine.001'] = bone.name + bone.use_connect = False + bone.parent = arm.edit_bones[bones['spine.004']] + bones['spine.003'] = bone.name bone = arm.edit_bones.new('spine.002') - bone.head[:] = 0.0000, 0.7755, 0.7418 - bone.tail[:] = 0.0000, 0.5547, 0.7568 + bone.head[:] = 0.0000, 0.5547, 0.7568 + bone.tail[:] = 0.0000, 0.7755, 0.7418 bone.roll = 0.0000 bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.001']] + bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.002'] = bone.name - bone = arm.edit_bones.new('spine.003') - bone.head[:] = 0.0000, 0.5547, 0.7568 - bone.tail[:] = 0.0000, 0.4418, 0.7954 + bone = arm.edit_bones.new('spine.001') + bone.head[:] = 0.0000, 0.7755, 0.7418 + bone.tail[:] = 0.0000, 0.9624, 0.7412 bone.roll = 0.0000 bone.use_connect = True bone.parent = arm.edit_bones[bones['spine.002']] - bones['spine.003'] = bone.name - bone = arm.edit_bones.new('spine.004') - bone.head[:] = 0.0000, 0.4418, 0.7954 - bone.tail[:] = 0.0000, 0.3546, 0.8059 + bones['spine.001'] = bone.name + bone = arm.edit_bones.new('spine') + bone.head[:] = 0.0000, 0.9624, 0.7412 + bone.tail[:] = 0.0000, 1.1044, 0.7633 bone.roll = 0.0000 bone.use_connect = True - bone.parent = arm.edit_bones[bones['spine.003']] - bones['spine.004'] = bone.name + bone.parent = arm.edit_bones[bones['spine.001']] + bones['spine'] = bone.name bone = arm.edit_bones.new('spine.005') bone.head[:] = 0.0000, 0.3546, 0.8059 bone.tail[:] = 0.0000, 0.1803, 0.7782 @@ -287,7 +287,7 @@ def create(obj): bone.head[:] = 0.0000, -0.3618, 0.8375 bone.tail[:] = 0.0000, -0.4253, 0.8585 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.008']] bones['spine.009'] = bone.name bone = arm.edit_bones.new('shoulder.L') @@ -405,37 +405,13 @@ def create(obj): bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone.rigify_type = '' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - except AttributeError: - pass - try: - pbone.rigify_parameters.use_tail = True - except AttributeError: - pass - try: - pbone.rigify_parameters.tail_pos = 4 - except AttributeError: - pass - try: - pbone.rigify_parameters.pivot_pos = 8 - except AttributeError: - pass - try: - pbone.rigify_parameters.neck_pos = 10 - except AttributeError: - pass - try: - pbone.rigify_parameters.copy_rotation_axes = [True, False, True] - except AttributeError: - pass pbone = obj.pose.bones[bones['spine.001']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -452,30 +428,42 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.tweak_extra_layers = False - except AttributeError: - pass - try: - pbone.rigify_parameters.tweak_layers = [False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False] - except AttributeError: - pass pbone = obj.pose.bones[bones['spine.003']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.basic_tail' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.pivot_pos = 4 + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass + try: + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['spine.005']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -484,14 +472,6 @@ def create(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - try: - pbone.rigify_parameters.neck_pos = 5 - except AttributeError: - pass - try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] - except AttributeError: - pass pbone = obj.pose.bones[bones['spine.006']] pbone.rigify_type = '' pbone.lock_location = (False, False, False) @@ -613,13 +593,21 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.009']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -811,6 +799,7 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [3, 4, 7, 10, 13, 16, 19]) for x in range(32)] diff --git a/rigify/metarigs/human.py b/rigify/metarigs/human.py index bbba8eed..e4279982 100644 --- a/rigify/metarigs/human.py +++ b/rigify/metarigs/human.py @@ -70,10 +70,10 @@ def create(obj): arm.rigify_layers[5].row = 5 arm.rigify_layers[5].selset = False arm.rigify_layers[5].group = 6 - arm.rigify_layers[6].name = "Fingers (Tweak)" + arm.rigify_layers[6].name = "Fingers (Detail)" arm.rigify_layers[6].row = 6 arm.rigify_layers[6].selset = False - arm.rigify_layers[6].group = 4 + arm.rigify_layers[6].group = 5 arm.rigify_layers[7].name = "Arm.L (IK)" arm.rigify_layers[7].row = 7 arm.rigify_layers[7].selset = False @@ -252,7 +252,7 @@ def create(obj): bone.head[:] = 0.0000, 0.0114, 1.6582 bone.tail[:] = 0.0000, -0.0130, 1.7197 bone.roll = 0.0000 - bone.use_connect = True + bone.use_connect = False bone.parent = arm.edit_bones[bones['spine.003']] bones['spine.004'] = bone.name bone = arm.edit_bones.new('shoulder.L') @@ -1280,7 +1280,7 @@ def create(obj): bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones[bones['spine']] - pbone.rigify_type = 'spines.super_spine' + pbone.rigify_type = 'spines.basic_spine' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -1288,11 +1288,11 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] try: - pbone.rigify_parameters.neck_pos = 5 + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass try: - pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + pbone.rigify_parameters.fk_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass pbone = obj.pose.bones[bones['spine.001']] @@ -1416,13 +1416,21 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['spine.004']] - pbone.rigify_type = '' + pbone.rigify_type = 'spines.super_head' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + try: + pbone.rigify_parameters.connect_chain = True + except AttributeError: + pass + try: + pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] + except AttributeError: + pass pbone = obj.pose.bones[bones['shoulder.L']] pbone.rigify_type = 'basic.super_copy' pbone.lock_location = (False, False, False) @@ -1956,7 +1964,7 @@ def create(obj): pbone.rotation_mode = 'QUATERNION' pbone.bone.layers = [True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] pbone = obj.pose.bones[bones['f_index.01.L']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -1972,7 +1980,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['thumb.01.L']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -1988,7 +1996,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_middle.01.L']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2004,7 +2012,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_ring.01.L']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2020,7 +2028,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_pinky.01.L']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2036,7 +2044,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_index.01.R']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2052,7 +2060,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['thumb.01.R']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2068,7 +2076,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_middle.01.R']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2084,7 +2092,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_ring.01.R']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2100,7 +2108,7 @@ def create(obj): except AttributeError: pass pbone = obj.pose.bones[bones['f_pinky.01.R']] - pbone.rigify_type = 'limbs.simple_tentacle' + pbone.rigify_type = 'limbs.super_finger' pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False @@ -2710,6 +2718,7 @@ def create(obj): bone.select = True bone.select_head = True bone.select_tail = True + bone.bbone_x = bone.bbone_z = bone.length * 0.05 arm.edit_bones.active = bone arm.layers = [(x in [0, 3, 5, 7, 10, 13, 16]) for x in range(32)] diff --git a/rigify/rig_ui_template.py b/rigify/rig_ui_template.py index d7c2e870..bb5a9cbd 100644 --- a/rigify/rig_ui_template.py +++ b/rigify/rig_ui_template.py @@ -36,6 +36,7 @@ UI_IMPORTS = [ 'import math', 'import json', 'import collections', + 'import traceback', 'from math import pi', 'from bpy.props import StringProperty', 'from mathutils import Euler, Matrix, Quaternion, Vector', @@ -1147,7 +1148,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 +1162,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 + + 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 - 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 script is None: + script = bpy.data.texts.new(rig_ui_name) - id_store.rigify_rig_ui = script.name + metarig.data.rigify_rig_ui = script for s in OrderedDict.fromkeys(self.ui_imports): script.write(s + "\n") diff --git a/rigify/rigs/basic/copy_chain.py b/rigify/rigs/basic/copy_chain.py index 5145d735..a3920ced 100644 --- a/rigify/rigs/basic/copy_chain.py +++ b/rigify/rigs/basic/copy_chain.py @@ -22,9 +22,10 @@ import bpy from ..chain_rigs import SimpleChainRig +from ...utils.layers import DEF_LAYER from ...utils.errors import MetarigError from ...utils.rig import connected_children_names -from ...utils.naming import strip_org, make_deformer_name +from ...utils.naming import make_derived_name from ...utils.widgets_basic import create_bone_widget from ...base_rig import BaseRig, stage @@ -41,7 +42,12 @@ class Rig(SimpleChainRig): """ Gather and validate data about the rig. """ self.make_controls = self.params.make_controls - self.make_deforms = self.params.make_deforms + + deform = self.params.make_deforms + rename = self.params.rename_to_deform + + self.make_deforms = deform and not rename + self.rename_deforms = deform and rename ############################## # Control chain @@ -92,6 +98,20 @@ class Rig(SimpleChainRig): if self.make_deforms: super().rig_deform_chain() + ############################## + # Rename To Deform + + def finalize(self): + if self.rename_deform: + new_names = [ self.rename_bone(name, make_derived_name(name, 'def')) for name in self.bones.org ] + + for name in new_names: + bone = self.get_bone(name).bone + bone.use_deform = True + bone.layers = DEF_LAYER + + ############################## + # Parameter UI @classmethod def add_parameters(self, params): @@ -101,6 +121,11 @@ class Rig(SimpleChainRig): params.make_controls = bpy.props.BoolProperty(name="Controls", default=True, description="Create control bones for the copy") params.make_deforms = bpy.props.BoolProperty(name="Deform", default=True, description="Create deform bones for the copy") + params.rename_to_deform = bpy.props.BoolProperty( + name = "Rename To Deform", + default = False, + description = "Rename the original bone itself to use as deform bone (advanced feature)" + ) @classmethod def parameters_ui(self, layout, params): @@ -111,6 +136,10 @@ class Rig(SimpleChainRig): r = layout.row() r.prop(params, "make_deforms") + if params.make_deforms: + r = layout.row() + r.prop(params, "rename_to_deform") + def create_sample(obj): """ Create a sample metarig for this rig type. diff --git a/rigify/rigs/basic/pivot.py b/rigify/rigs/basic/pivot.py new file mode 100644 index 00000000..e5d31659 --- /dev/null +++ b/rigify/rigs/basic/pivot.py @@ -0,0 +1,236 @@ +#====================== BEGIN GPL LICENSE BLOCK ====================== +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +#======================= END GPL LICENSE BLOCK ======================== + +# <pep8 compliant> + +import bpy + +from ...base_rig import BaseRig + +from ...utils.naming import make_derived_name +from ...utils.bones import set_bone_widget_transform +from ...utils.widgets_basic import create_cube_widget, create_pivot_widget +from ...utils.switch_parent import SwitchParentBuilder + + +class Rig(BaseRig): + """ A rig providing a rotation pivot control that can be moved. """ + def find_org_bones(self, pose_bone): + return pose_bone.name + + + def initialize(self): + self.make_control = self.params.make_extra_control + self.make_pivot = self.params.make_control or not self.make_control + self.make_deform = self.params.make_extra_deform + + + def generate_bones(self): + org = self.bones.org + + if self.make_control: + self.bones.ctrl.master = name = self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True) + + if self.make_pivot: + self.bones.ctrl.pivot = self.copy_bone(org, make_derived_name(org, 'ctrl', '_pivot')) + + if self.params.make_parent_switch: + self.build_parent_switch(name) + + if self.params.register_parent: + self.register_parent(name, self.get_parent_tags()) + + else: + self.bones.ctrl.pivot = self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=True) + + if self.make_deform: + self.bones.deform = self.copy_bone(org, make_derived_name(org, 'def'), bbone=True) + + + def build_parent_switch(self, master_name): + pbuilder = SwitchParentBuilder(self.generator) + + org_parent = self.get_bone_parent(self.bones.org) + parents = [org_parent] if org_parent else [] + + pbuilder.build_child( + self, master_name, + context_rig=self.rigify_parent, allow_self=True, + prop_name="Parent ({})".format(master_name), + extra_parents=parents, select_parent=org_parent, + controls=lambda: self.bones.ctrl.flatten() + ) + + def get_parent_tags(self): + tags = {t.strip() for t in self.params.register_parent_tags.split(',')} + + if self.params.make_parent_switch: + tags.add('child') + + tags.discard('') + return tags + + def register_parent(self, master_name, tags): + pbuilder = SwitchParentBuilder(self.generator) + + inject = self.rigify_parent if 'injected' in tags else None + + pbuilder.register_parent( + self, self.bones.org, name=master_name, + inject_into=inject, tags=tags + ) + + + def parent_bones(self): + ctrl = self.bones.ctrl + + if self.make_pivot: + if self.make_control: + self.set_bone_parent(ctrl.pivot, ctrl.master, use_connect=False) + + self.set_bone_parent(self.bones.org, ctrl.pivot, use_connect=False) + + else: + self.set_bone_parent(self.bones.org, ctrl.master, use_connect=False) + + if self.make_deform: + self.set_bone_parent(self.bones.deform, self.bones.org, use_connect=False) + + + def configure_bones(self): + if self.make_control: + self.copy_bone_properties(self.bones.org, self.bones.ctrl.master) + + else: + self.copy_bone_properties(self.bones.org, self.bones.ctrl.pivot) + + + def rig_bones(self): + if self.make_pivot: + self.make_constraint( + self.bones.org, 'COPY_LOCATION', self.bones.ctrl.pivot, + space='LOCAL', invert_xyz=(True,)*3 + ) + + + def generate_widgets(self): + if self.make_pivot: + create_pivot_widget(self.obj, self.bones.ctrl.pivot, square=True, axis_size=2.0) + + if self.make_control: + set_bone_widget_transform(self.obj, self.bones.ctrl.master, self.bones.org) + + create_cube_widget(self.obj, self.bones.ctrl.master, radius=0.5) + + + @classmethod + def add_parameters(self, params): + params.make_control = bpy.props.BoolProperty( + name = "Control", + default = True, + description = "Create a control bone for the copy" + ) + + params.make_parent_switch = bpy.props.BoolProperty( + name = "Switchable Parent", + default = False, + description = "Allow switching the parent of the master control" + ) + + params.register_parent = bpy.props.BoolProperty( + name = "Register Parent", + default = False, + description = "Register the control as a switchable parent candidate" + ) + + params.register_parent_tags = bpy.props.StringProperty( + name = "Parent Tags", + default = "", + description = "Comma-separated tags to use for the registered parent" + ) + + params.make_extra_control = bpy.props.BoolProperty( + name = "Extra Control", + default = False, + description = "Create an optional control" + ) + + params.make_extra_deform = bpy.props.BoolProperty( + name = "Extra Deform", + default = False, + description = "Create an optional deform bone" + ) + + + @classmethod + def parameters_ui(self, layout, params): + r = layout.row() + r.prop(params, "make_extra_control", text="Master Control") + + if params.make_extra_control: + layout.prop(params, "make_parent_switch") + layout.prop(params, "register_parent") + + r = layout.row() + r.active = params.register_parent + r.prop(params, "register_parent_tags", text="Tags") + + layout.prop(params, "make_control", text="Pivot Control") + + r = layout.row() + r.prop(params, "make_extra_deform", text="Deform Bone") + + +def create_sample(obj): + """ Create a sample metarig for this rig type. + """ + # generated by rigify.utils.write_metarig + bpy.ops.object.mode_set(mode='EDIT') + arm = obj.data + + bones = {} + + bone = arm.edit_bones.new('pivot') + bone.head[:] = 0.0000, 0.0000, 0.0000 + bone.tail[:] = 0.0000, 0.5000, 0.0000 + bone.roll = 0.0000 + bone.use_connect = False + bones['pivot'] = bone.name + + bpy.ops.object.mode_set(mode='OBJECT') + pbone = obj.pose.bones[bones['pivot']] + pbone.rigify_type = 'basic.pivot' + pbone.lock_location = (False, False, False) + pbone.lock_rotation = (False, False, False) + pbone.lock_rotation_w = False + pbone.lock_scale = (False, False, False) + pbone.rotation_mode = 'QUATERNION' + + bpy.ops.object.mode_set(mode='EDIT') + for bone in arm.edit_bones: + bone.select = False + bone.select_head = False + bone.select_tail = False + for b in bones: + bone = arm.edit_bones[bones[b]] + bone.select = True + bone.select_head = True + bone.select_tail = True + arm.edit_bones.active = bone + + return bones diff --git a/rigify/rigs/basic/super_copy.py b/rigify/rigs/basic/super_copy.py index 5abbf22e..f55dce68 100644 --- a/rigify/rigs/basic/super_copy.py +++ b/rigify/rigs/basic/super_copy.py @@ -22,9 +22,12 @@ import bpy from ...base_rig import BaseRig +from ...utils.layers import DEF_LAYER from ...utils.naming import strip_org, make_deformer_name from ...utils.widgets_basic import create_bone_widget, create_circle_widget +from itertools import repeat + class Rig(BaseRig): """ A "copy" rig. All it does is duplicate the original bone and @@ -43,7 +46,14 @@ class Rig(BaseRig): self.make_control = self.params.make_control self.make_widget = self.params.make_widget - self.make_deform = self.params.make_deform + + deform = self.params.make_deform + rename = self.params.rename_to_deform + + self.make_deform = deform and not rename + self.rename_deform = deform and rename + + self.relink = self.params.relink_constraints def generate_bones(self): @@ -64,6 +74,18 @@ class Rig(BaseRig): if self.make_deform: self.set_bone_parent(bones.deform, bones.org, use_connect=False) + if self.relink: + self.generator.disable_auto_parent(bones.org) + + parent_spec = self.params.parent_bone + if parent_spec: + old_parent = self.get_bone_parent(bones.org) + new_parent = self.find_relink_target(parent_spec, old_parent or '') or None + self.set_bone_parent(bones.org, new_parent) + + if self.make_control: + self.set_bone_parent(bones.ctrl, new_parent) + def configure_bones(self): bones = self.bones @@ -75,9 +97,53 @@ class Rig(BaseRig): def rig_bones(self): bones = self.bones + if self.relink: + for con in self.get_bone(bones.org).constraints: + parts = con.name.split('@') + + if len(parts) > 1: + self.relink_constraint(con, parts[1:]) + if self.make_control: # Constrain the original bone. - self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl) + self.make_constraint(bones.org, 'COPY_TRANSFORMS', bones.ctrl, insert_index=0) + + def relink_constraint(self, con, specs): + if con.type == 'ARMATURE': + if len(specs) == 1: + specs = repeat(specs[0]) + elif len(specs) != len(con.specs): + self.report_error("Constraint {} actually has {} targets", con.name, len(con.targets)) + + for tgt, spec in zip(con.targets, specs): + tgt.subtarget = self.find_relink_target(spec, tgt.subtarget) + + else: + if len(specs) > 1: + self.report_error("Only the Armature constraint can have multiple '@' targets: {}", con.name) + + con.subtarget = self.find_relink_target(specs[0], con.subtarget) + + def find_relink_target(self, spec, old_target): + if spec == '': + return old_target + elif spec in {'DEF', 'MCH'}: + spec = spec + '-' + strip_org(old_target) + + if spec not in self.obj.pose.bones: + # Hack: allow referring to copy rigs using Rename To Deform as DEF + if old_target.startswith('ORG-') and spec == make_deformer_name(strip_org(old_target)): + from . import copy_chain + + owner = self.generator.bone_owners.get(old_target) + + if ((isinstance(owner, Rig) and owner.rename_deform) or + (isinstance(owner, copy_chain.Rig) and owner.rename_deforms)): + return old_target + + self.report_error("Cannot find bone '{}' for relinking", spec) + + return spec def generate_widgets(self): @@ -91,6 +157,15 @@ class Rig(BaseRig): create_bone_widget(self.obj, bones.ctrl) + def finalize(self): + if self.rename_deform: + new_name = self.rename_bone(self.bones.org, make_deformer_name(self.org_name)) + + bone = self.get_bone(new_name).bone + bone.use_deform = True + bone.layers = DEF_LAYER + + @classmethod def add_parameters(self, params): """ Add the parameters of this rig type to the @@ -114,6 +189,24 @@ class Rig(BaseRig): description = "Create a deform bone for the copy" ) + params.rename_to_deform = bpy.props.BoolProperty( + name = "Rename To Deform", + default = False, + description = "Rename the original bone itself to use as deform bone (advanced feature)" + ) + + params.relink_constraints = bpy.props.BoolProperty( + name = "Relink Constraints", + default = False, + description = "For constraints with names formed like 'base@bonename', use the part after '@' as the new subtarget after all bones are created. Use '@DEF' or '@MCH' to simply prepend the prefix" + ) + + params.parent_bone = bpy.props.StringProperty( + name = "Parent", + default = "", + description = "Replace the parent with a different bone after all bones are created. Using simply DEF or MCH will prepend the prefix instead" + ) + @classmethod def parameters_ui(self, layout, params): @@ -127,6 +220,17 @@ class Rig(BaseRig): r = layout.row() r.prop(params, "make_deform") + if params.make_deform: + r = layout.row() + r.prop(params, "rename_to_deform") + + r = layout.row() + r.prop(params, "relink_constraints") + + if params.relink_constraints: + r = layout.row() + r.prop(params, "parent_bone") + def create_sample(obj): """ Create a sample metarig for this rig type. diff --git a/rigify/rigs/chain_rigs.py b/rigify/rigs/chain_rigs.py index 3f53cd69..fc070eb1 100644 --- a/rigify/rigs/chain_rigs.py +++ b/rigify/rigs/chain_rigs.py @@ -82,10 +82,10 @@ class SimpleChainRig(BaseRig): @stage.generate_widgets def make_control_widgets(self): - for ctrl in self.bones.ctrl.fk: - self.make_control_widget(ctrl) + for args in zip(count(0), self.bones.ctrl.fk): + self.make_control_widget(*args) - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): create_bone_widget(self.obj, ctrl) ############################## diff --git a/rigify/rigs/experimental/super_chain.py b/rigify/rigs/experimental/super_chain.py index df0facdf..3f7ca5d6 100644 --- a/rigify/rigs/experimental/super_chain.py +++ b/rigify/rigs/experimental/super_chain.py @@ -714,10 +714,10 @@ def add_parameters(params): ) params.bbones = bpy.props.IntProperty( - name='bbone segments', - default=10, - min=1, - description='Number of segments' + name = 'B-Bone Segments', + default = 10, + min = 1, + description = 'Number of B-Bone segments' ) params.wgt_offset = bpy.props.FloatProperty( diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py index 98a3c50f..e79edc5c 100644 --- a/rigify/rigs/limbs/arm.py +++ b/rigify/rigs/limbs/arm.py @@ -21,12 +21,15 @@ import bpy from itertools import count +from mathutils import Matrix -from ...utils.bones import BoneDict, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis +from ...utils.bones import put_bone, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis from ...utils.naming import make_derived_name from ...utils.misc import map_list +from ...utils.widgets import adjust_widget_transform_mesh from ..widgets import create_hand_widget +from ...utils.widgets_basic import create_circle_widget from ...base_rig import stage @@ -42,6 +45,8 @@ class Rig(BaseLimbRig): super().initialize() + self.make_wrist_pivot = self.params.make_ik_wrist_pivot + def prepare_bones(self): orgs = self.bones.org.main @@ -62,16 +67,76 @@ class Rig(BaseLimbRig): def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): create_hand_widget(self.obj, ctrl) #################################################### + # Palm Pivot + + def get_ik_input_bone(self): + if self.make_wrist_pivot: + return self.bones.mch.ik_wrist + else: + return self.get_ik_control_output() + + def get_extra_ik_controls(self): + controls = super().get_extra_ik_controls() + if self.make_wrist_pivot: + controls += [self.bones.ctrl.ik_wrist] + return controls + + @stage.generate_bones + def make_wrist_pivot_control(self): + if self.make_wrist_pivot: + org = self.bones.org.main[2] + self.bones.ctrl.ik_wrist = self.make_wrist_pivot_bone(org) + self.bones.mch.ik_wrist = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_wrist'), scale=0.25) + + def make_wrist_pivot_bone(self, org): + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik_wrist'), scale=0.5) + put_bone(self.obj, name, self.get_bone(org).tail) + return name + + @stage.parent_bones + def parent_wrist_pivot_control(self): + if self.make_wrist_pivot: + ctrl = self.bones.ctrl.ik_wrist + self.set_bone_parent(ctrl, self.get_ik_control_output()) + self.set_bone_parent(self.bones.mch.ik_wrist, ctrl) + + @stage.generate_widgets + def make_wrist_pivot_widget(self): + if self.make_wrist_pivot: + ctrl = self.bones.ctrl.ik_wrist + + if self.main_axis == 'x': + obj = create_circle_widget(self.obj, ctrl, head_tail=-0.3, head_tail_x=0.5) + else: + obj = create_circle_widget(self.obj, ctrl, head_tail=0.5, head_tail_x=-0.3) + + if obj: + org_bone = self.get_bone(self.bones.org.main[2]) + offset = org_bone.head - self.get_bone(ctrl).head + adjust_widget_transform_mesh(obj, Matrix.Translation(offset)) + + #################################################### # Settings @classmethod + def add_parameters(self, params): + super().add_parameters(params) + + params.make_ik_wrist_pivot = bpy.props.BoolProperty( + name="IK Wrist Pivot", default=False, + description="Make an extra IK hand control pivoting around the tip of the hand" + ) + + @classmethod def parameters_ui(self, layout, params): + layout.prop(params, "make_ik_wrist_pivot") + super().parameters_ui(layout, params, 'Hand') diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py index dbdd20cb..b409d009 100644 --- a/rigify/rigs/limbs/leg.py +++ b/rigify/rigs/limbs/leg.py @@ -22,13 +22,14 @@ import bpy import math from itertools import count -from mathutils import Vector +from mathutils import Vector, Matrix from ...utils.rig import is_rig_base_bone from ...utils.bones import align_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation from ...utils.naming import make_derived_name -from ...utils.misc import map_list +from ...utils.misc import map_list, matrix_from_axis_roll, matrix_from_axis_pair +from ...utils.widgets import adjust_widget_transform_mesh from ..widgets import create_foot_widget, create_ballsocket_widget @@ -62,10 +63,18 @@ class Rig(BaseLimbRig): super().initialize() + self.pivot_type = self.params.foot_pivot_type + self.heel_euler_order = 'ZXY' if self.main_axis == 'x' else 'XZY' + + assert self.pivot_type in {'ANKLE', 'TOE', 'ANKLE_TOE'} + def prepare_bones(self): orgs = self.bones.org.main + foot = self.get_bone(orgs[2]) - foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, -1)) + ik_y_axis = (0, 1, 0) + foot_y_axis = -self.vector_without_z(foot.y_axis) + foot_x = foot_y_axis.cross((0, 0, 1)) if self.params.rotation_axis == 'automatic': align_chain_x_axis(self.obj, orgs[0:2]) @@ -84,6 +93,12 @@ class Rig(BaseLimbRig): align_bone_z_axis(self.obj, orgs[2], foot_x) align_bone_z_axis(self.obj, orgs[3], -foot_x) + else: + ik_y_axis = foot_y_axis + + # Orientation of the IK main and roll control bones + self.ik_matrix = matrix_from_axis_roll(ik_y_axis, 0) + self.roll_matrix = matrix_from_axis_pair(ik_y_axis, foot_x, self.main_axis) #################################################### # EXTRA BONES @@ -92,6 +107,8 @@ class Rig(BaseLimbRig): # heel: # Heel location marker bone # ctrl: + # ik_spin: + # Toe spin control. # heel: # Foot roll control # mch: @@ -104,31 +121,71 @@ class Rig(BaseLimbRig): # IK controls def get_extra_ik_controls(self): - return [self.bones.ctrl.heel] + controls = super().get_extra_ik_controls() + [self.bones.ctrl.heel] + if self.pivot_type == 'ANKLE_TOE': + controls += [self.bones.ctrl.ik_spin] + return controls def make_ik_control_bone(self, orgs): name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik')) - - if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity: - align_bone_to_axis(self.obj, name, 'y', flip=True) - + if self.pivot_type == 'TOE': + put_bone(self.obj, name, self.get_bone(name).tail, matrix=self.ik_matrix) else: - flip_bone(self.obj, name) - - bone = self.get_bone(name) - bone.tail[2] = bone.head[2] - bone.roll = 0 - + put_bone(self.obj, name, None, matrix=self.ik_matrix) return name + def build_ik_pivot(self, ik_name, **args): + heel_bone = self.get_bone(self.bones.org.heel) + args = { + 'position': (heel_bone.head + heel_bone.tail)/2, + **args + } + return super().build_ik_pivot(ik_name, **args) + def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): - create_foot_widget(self.obj, ctrl) + obj = create_foot_widget(self.obj, ctrl) + if self.pivot_type != 'TOE': + ctrl = self.get_bone(ctrl) + org = self.get_bone(self.bones.org.main[2]) + offset = org.tail - (ctrl.custom_shape_transform or ctrl).head + adjust_widget_transform_mesh(obj, Matrix.Translation(offset)) + + #################################################### + # IK pivot controls + + def get_ik_pivot_output(self): + if self.pivot_type == 'ANKLE_TOE': + return self.bones.ctrl.ik_spin + else: + return self.get_ik_control_output() + + @stage.generate_bones + def make_ik_pivot_controls(self): + if self.pivot_type == 'ANKLE_TOE': + self.bones.ctrl.ik_spin = self.make_ik_spin_bone(self.bones.org.main) + + def make_ik_spin_bone(self, orgs): + name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_spin_ik')) + put_bone(self.obj, name, self.get_bone(orgs[3]).head, matrix=self.ik_matrix, scale=0.5) + return name + + @stage.parent_bones + def parent_ik_pivot_controls(self): + if self.pivot_type == 'ANKLE_TOE': + self.set_bone_parent(self.bones.ctrl.ik_spin, self.get_ik_control_output()) + + @stage.generate_widgets + def make_ik_spin_control_widget(self): + if self.pivot_type == 'ANKLE_TOE': + obj = create_ballsocket_widget(self.obj, self.bones.ctrl.ik_spin, size=0.75) + rotfix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper()) + adjust_widget_transform_mesh(obj, rotfix, local=True) #################################################### # Heel control @@ -136,25 +193,19 @@ class Rig(BaseLimbRig): @stage.generate_bones def make_heel_control_bone(self): org = self.bones.org.main[2] - name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'), scale=1/2) + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik')) + put_bone(self.obj, name, None, matrix=self.roll_matrix, scale=0.5) self.bones.ctrl.heel = name - self.align_roll_bone(org, name, -self.vector_without_z(self.get_bone(org).vector)) - @stage.parent_bones def parent_heel_control_bone(self): - self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_pivot_output(), inherit_scale='AVERAGE') @stage.configure_bones def configure_heel_control_bone(self): bone = self.get_bone(self.bones.ctrl.heel) bone.lock_location = True, True, True - - if self.main_axis == 'x': - bone.lock_rotation = False, False, True - else: - bone.lock_rotation = True, False, False - + bone.rotation_mode = self.heel_euler_order bone.lock_scale = True, True, True @stage.generate_widgets @@ -173,34 +224,27 @@ class Rig(BaseLimbRig): def make_roll_mch_bones(self, foot, toe, heel): foot_bone = self.get_bone(foot) heel_bone = self.get_bone(heel) - axis = -self.vector_without_z(foot_bone.vector) - - roll1 = self.copy_bone(foot, make_derived_name(heel, 'mch', '_roll1')) - flip_bone(self.obj, roll1) - self.align_roll_bone(foot, roll1, -foot_bone.vector) + heel_middle = (heel_bone.head + heel_bone.tail) / 2 - roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=1/4) - - put_bone(self.obj, roll2, (heel_bone.head + heel_bone.tail) / 2) - self.align_roll_bone(foot, roll2, -axis) + result = self.copy_bone(foot, make_derived_name(foot, 'mch', '_roll'), scale=0.25) + roll1 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll1'), scale=0.3) + roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=0.3) rock1 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock1')) - - align_bone_to_axis(self.obj, rock1, 'y', roll=0, length=heel_bone.length/2, flip=True) - align_bone_y_axis(self.obj, rock1, axis) - rock2 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock2')) - align_bone_to_axis(self.obj, rock2, 'y', roll=0, length=heel_bone.length/2) - align_bone_y_axis(self.obj, rock2, axis) + put_bone(self.obj, roll1, None, matrix=self.roll_matrix) + put_bone(self.obj, roll2, heel_middle, matrix=self.roll_matrix) + put_bone(self.obj, rock1, heel_bone.tail, matrix=self.roll_matrix, scale=0.5) + put_bone(self.obj, rock2, heel_bone.head, matrix=self.roll_matrix, scale=0.5) - return [ rock2, rock1, roll2, roll1 ] + return [ rock2, rock1, roll2, roll1, result ] @stage.parent_bones def parent_roll_mch_chain(self): chain = self.bones.mch.heel - self.set_bone_parent(chain[0], self.bones.ctrl.ik) + self.set_bone_parent(chain[0], self.get_ik_pivot_output()) self.parent_bone_chain(chain) @stage.rig_bones @@ -208,28 +252,37 @@ class Rig(BaseLimbRig): self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel) def rig_roll_mch_bones(self, chain, heel, org_heel): - rock2, rock1, roll2, roll1 = chain + rock2, rock1, roll2, roll1, result = chain + + # This order is required for correct working of the constraints + for bone in chain: + self.get_bone(bone).rotation_mode = self.heel_euler_order - self.make_constraint(roll1, 'COPY_ROTATION', heel, space='LOCAL') - self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL') + self.make_constraint(roll1, 'COPY_ROTATION', heel, space='POSE') if self.main_axis == 'x': - self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_x=True, max_x=DEG_360, space='LOCAL') - self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_x=-DEG_360, space='LOCAL') + self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(True, False, False)) + self.make_constraint(roll2, 'LIMIT_ROTATION', min_x=-DEG_360, space='LOCAL') else: - self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_z=True, max_z=DEG_360, space='LOCAL') - self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_z=-DEG_360, space='LOCAL') + self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL', use_xyz=(False, False, True)) + self.make_constraint(roll2, 'LIMIT_ROTATION', min_z=-DEG_360, space='LOCAL') direction = self.get_main_axis(self.get_bone(heel)).dot(self.get_bone(org_heel).vector) if direction < 0: rock2, rock1 = rock1, rock2 - self.make_constraint(rock1, 'COPY_ROTATION', heel, space='LOCAL') - self.make_constraint(rock2, 'COPY_ROTATION', heel, space='LOCAL') + self.make_constraint( + rock1, 'COPY_ROTATION', heel, space='LOCAL', + use_xyz=(False, True, False), + ) + self.make_constraint( + rock2, 'COPY_ROTATION', heel, space='LOCAL', + use_xyz=(False, True, False), + ) - self.make_constraint(rock1, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, max_y=DEG_360, space='LOCAL') - self.make_constraint(rock2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_y=-DEG_360, space='LOCAL') + self.make_constraint(rock1, 'LIMIT_ROTATION', max_y=DEG_360, space='LOCAL') + self.make_constraint(rock2, 'LIMIT_ROTATION', min_y=-DEG_360, space='LOCAL') #################################################### @@ -237,7 +290,7 @@ class Rig(BaseLimbRig): def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org): if i == 3: - align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[-2]) + align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[2]) self.set_bone_parent(parent_mch, prev_org, use_connect=True) @@ -246,7 +299,7 @@ class Rig(BaseLimbRig): def rig_fk_parent_bone(self, i, parent_mch, org): if i == 3: - con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[-2]) + con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[2]) self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0]) @@ -257,8 +310,6 @@ class Rig(BaseLimbRig): #################################################### # IK system MCH - ik_input_head_tail = 1.0 - def get_ik_input_bone(self): return self.bones.mch.heel[-1] @@ -266,14 +317,35 @@ class Rig(BaseLimbRig): def parent_ik_mch_chain(self): super().parent_ik_mch_chain() - self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel) + self.set_bone_parent(self.bones.mch.ik_target, self.bones.mch.heel[-1]) #################################################### # Settings @classmethod + def add_parameters(self, params): + super().add_parameters(params) + + items = [ + ('ANKLE', 'Ankle', + 'The foots pivots at the ankle'), + ('TOE', 'Toe', + 'The foot pivots around the base of the toe'), + ('ANKLE_TOE', 'Ankle and Toe', + 'The foots pivots at the ankle, with extra toe pivot'), + ] + + params.foot_pivot_type = bpy.props.EnumProperty( + items = items, + name = "Foot Pivot", + default = 'ANKLE_TOE' + ) + + @classmethod def parameters_ui(self, layout, params): + layout.prop(params, 'foot_pivot_type') + super().parameters_ui(layout, params, 'Foot') diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py index 81079c05..f1eb8639 100644 --- a/rigify/rigs/limbs/limb_rigs.py +++ b/rigify/rigs/limbs/limb_rigs.py @@ -23,12 +23,12 @@ import json from ...utils.animation import add_generic_snap_fk_to_ik, add_fk_ik_snap_buttons from ...utils.rig import connected_children_names -from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation -from ...utils.bones import align_bone_x_axis, align_bone_y_axis, align_bone_z_axis +from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation, set_bone_widget_transform from ...utils.naming import strip_org, make_derived_name from ...utils.layers import ControlLayersOption from ...utils.misc import pairwise_nozip, padnone, map_list from ...utils.switch_parent import SwitchParentBuilder +from ...utils.components import CustomPivotControl from ...base_rig import stage, BaseRig @@ -64,6 +64,7 @@ class BaseLimbRig(BaseRig): self.segments = self.params.segments self.bbone_segments = self.params.bbones + self.use_ik_pivot = self.params.make_custom_pivot rot_axis = self.params.rotation_axis @@ -124,15 +125,6 @@ class BaseLimbRig(BaseRig): bone = self.get_bone(org) return bone.head + bone.vector * (seg / self.segments) - def align_roll_bone(self, org, name, y_axis): - if y_axis: - align_bone_y_axis(self.obj, name, y_axis) - - if self.main_axis == 'x': - align_bone_x_axis(self.obj, name, self.get_bone(org).x_axis) - else: - align_bone_z_axis(self.obj, name, self.get_bone(org).z_axis) - @staticmethod def vector_without_z(vector): return Vector((vector[0], vector[1], 0)) @@ -154,6 +146,8 @@ class BaseLimbRig(BaseRig): # IK controls # ik_vispole # IK pole visualization. + # ik_pivot + # Custom IK pivot (optional). # mch: # master: # Parent of the master control. @@ -161,6 +155,8 @@ class BaseLimbRig(BaseRig): # FK follow behavior. # fk[]: # FK chain parents (or None) + # ik_pivot + # Custom IK pivot result (optional). # ik_stretch # IK stretch switch implementation. # ik_target @@ -328,22 +324,30 @@ class BaseLimbRig(BaseRig): # IK controls def get_extra_ik_controls(self): - return [] + if self.component_ik_pivot: + return [self.component_ik_pivot.control] + else: + return [] def get_all_ik_controls(self): ctrl = self.bones.ctrl - return [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + self.get_extra_ik_controls() + controls = [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + return controls + self.get_extra_ik_controls() @stage.generate_bones def make_ik_controls(self): orgs = self.bones.org.main - self.bones.ctrl.ik_base = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik')) + self.bones.ctrl.ik_base = self.make_ik_base_bone(orgs) self.bones.ctrl.ik_pole = self.make_ik_pole_bone(orgs) - self.bones.ctrl.ik = self.make_ik_control_bone(orgs) + self.bones.ctrl.ik = ik_name = self.make_ik_control_bone(orgs) + self.component_ik_pivot = self.build_ik_pivot(ik_name) self.build_ik_parent_switch(SwitchParentBuilder(self.generator)) + def make_ik_base_bone(self, orgs): + return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik')) + def make_ik_pole_bone(self, orgs): name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik_target')) @@ -357,10 +361,25 @@ class BaseLimbRig(BaseRig): def make_ik_control_bone(self, orgs): return self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik')) + def build_ik_pivot(self, ik_name, **args): + if self.use_ik_pivot: + return CustomPivotControl(self, 'ik_pivot', ik_name, parent=ik_name, **args) + + def get_ik_control_output(self): + if self.component_ik_pivot: + return self.component_ik_pivot.output + else: + return self.bones.ctrl.ik + def register_switch_parents(self, pbuilder): if self.rig_parent_bone: pbuilder.register_parent(self, self.rig_parent_bone) + pbuilder.register_parent( + self, self.get_ik_control_output, name=self.bones.ctrl.ik, + exclude_self=True, tags={'limb_ik', 'child'}, + ) + def build_ik_parent_switch(self, pbuilder): ctrl = self.bones.ctrl @@ -398,9 +417,13 @@ class BaseLimbRig(BaseRig): @stage.generate_widgets def make_ik_control_widgets(self): - self.make_ik_base_widget(self.bones.ctrl.ik_base) - self.make_ik_pole_widget(self.bones.ctrl.ik_pole) - self.make_ik_ctrl_widget(self.bones.ctrl.ik) + ctrl = self.bones.ctrl + + set_bone_widget_transform(self.obj, ctrl.ik, self.get_ik_control_output()) + + self.make_ik_base_widget(ctrl.ik_base) + self.make_ik_pole_widget(ctrl.ik_pole) + self.make_ik_ctrl_widget(ctrl.ik) def make_ik_base_widget(self, ctrl): if self.main_axis == 'x': @@ -453,7 +476,7 @@ class BaseLimbRig(BaseRig): ik_input_head_tail = 0.0 def get_ik_input_bone(self): - return self.bones.ctrl.ik + return self.get_ik_control_output() def get_ik_output_chain(self): return [self.bones.ctrl.ik_base, self.bones.mch.ik_end, self.bones.mch.ik_target] @@ -670,7 +693,13 @@ class BaseLimbRig(BaseRig): @stage.parent_bones def parent_tweak_mch_chain(self): - for mch, entry in zip(self.bones.mch.tweak, self.segment_table_tweak): + for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak): + self.parent_tweak_mch_bone(*args) + + def parent_tweak_mch_bone(self, i, mch, entry): + if i == 0: + self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='FIX_SHEAR') + else: self.set_bone_parent(mch, entry.org) @stage.rig_bones @@ -694,6 +723,10 @@ class BaseLimbRig(BaseRig): elif entry.seg_idx is not None: self.make_constraint(tweak, 'COPY_SCALE', 'root', use_make_uniform=True) + if i == 0: + self.make_constraint(tweak, 'COPY_LOCATION', entry.org) + self.make_constraint(tweak, 'DAMPED_TRACK', entry.org, head_tail=1) + #################################################### # Deform chain @@ -786,17 +819,23 @@ class BaseLimbRig(BaseRig): ) params.segments = bpy.props.IntProperty( - name = 'limb segments', + name = 'Limb Segments', default = 2, min = 1, - description = 'Number of segments' + description = 'Number of limb segments' ) params.bbones = bpy.props.IntProperty( - name = 'bbone segments', + name = 'B-Bone Segments', default = 10, min = 1, - description = 'Number of segments' + description = 'Number of B-Bone segments' + ) + + params.make_custom_pivot = bpy.props.BoolProperty( + name = "Custom Pivot Control", + default = False, + description = "Create a rotation pivot control that can be repositioned arbitrarily" ) # Setting up extra layers for the FK and tweak @@ -820,6 +859,8 @@ class BaseLimbRig(BaseRig): r = layout.row() r.prop(params, "bbones") + layout.prop(params, 'make_custom_pivot', text="Custom IK Pivot") + ControlLayersOption.FK.parameters_ui(layout, params) ControlLayersOption.TWEAK.parameters_ui(layout, params) @@ -843,8 +884,6 @@ class RigifyLimbIk2FkBase: ctrl_bones: StringProperty(name="IK Controls") extra_ctrls: StringProperty(name="Extra IK Controls") - keyflags = None - def init_execute(self, context): if self.fk_bones: self.fk_bone_list = json.loads(self.fk_bones) @@ -921,13 +960,11 @@ class RigifyLimbIk2FkBase: class POSE_OT_rigify_limb_ik2fk(RigifyLimbIk2FkBase, RigifySingleUpdateMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_ik2fk_" + rig_id bl_label = "Snap IK->FK" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Snap the IK chain to FK result" class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_ik2fk_bake_" + rig_id bl_label = "Apply Snap IK->FK To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Snap the IK chain keyframes to FK result" def execute_scan_curves(self, context, obj): @@ -968,8 +1005,6 @@ SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + [''' class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase): use_pole: bpy.props.BoolProperty(name="Use Pole Vector") - keyflags_switch = None - def save_frame_state(self, context, obj): return get_chain_transform_matrices(obj, self.ik_bone_list) @@ -1007,13 +1042,11 @@ class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase): class POSE_OT_rigify_limb_toggle_pole(RigifyLimbTogglePoleBase, RigifySingleUpdateMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_toggle_pole_" + rig_id bl_label = "Toggle Pole" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Switch the IK chain between pole and rotation" class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeKeyframesMixin, bpy.types.Operator): bl_idname = "pose.rigify_limb_toggle_pole_bake_" + rig_id bl_label = "Apply Toggle Pole To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Switch the IK chain between pole and rotation over a frame range" def execute_scan_curves(self, context, obj): diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py index f8cb1f9f..28374eec 100644 --- a/rigify/rigs/limbs/paw.py +++ b/rigify/rigs/limbs/paw.py @@ -84,7 +84,7 @@ class Rig(BaseLimbRig): # IK controls def get_extra_ik_controls(self): - return [self.bones.ctrl.heel] + return super().get_extra_ik_controls() + [self.bones.ctrl.heel] def make_ik_control_bone(self, orgs): name = self.copy_bone(orgs[3], make_derived_name(orgs[2], 'ctrl', '_ik')) @@ -107,7 +107,7 @@ class Rig(BaseLimbRig): def register_switch_parents(self, pbuilder): super().register_switch_parents(pbuilder) - pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True) + pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True, tags={'limb_end'}) def make_ik_ctrl_widget(self, ctrl): create_foot_widget(self.obj, ctrl) @@ -126,7 +126,7 @@ class Rig(BaseLimbRig): @stage.parent_bones def parent_heel_control_bone(self): - self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.ctrl.heel, self.get_ik_control_output()) @stage.configure_bones def configure_heel_control_bone(self): @@ -150,7 +150,7 @@ class Rig(BaseLimbRig): def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org): if i == 3: self.set_bone_parent(parent_mch, prev_org, use_connect=True) - self.set_bone_parent(self.bones.mch.toe_socket, self.bones.ctrl.ik) + self.set_bone_parent(self.bones.mch.toe_socket, self.get_ik_control_output()) else: super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org) diff --git a/rigify/rigs/limbs/simple_tentacle.py b/rigify/rigs/limbs/simple_tentacle.py index 10bdd2b5..25d26e86 100644 --- a/rigify/rigs/limbs/simple_tentacle.py +++ b/rigify/rigs/limbs/simple_tentacle.py @@ -78,7 +78,7 @@ class Rig(TweakChainRig): ) # Widgets - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py index 1a9171a7..0b3fcd8a 100644 --- a/rigify/rigs/limbs/super_finger.py +++ b/rigify/rigs/limbs/super_finger.py @@ -24,11 +24,12 @@ import re from itertools import count from ...utils.errors import MetarigError -from ...utils.bones import flip_bone, align_chain_x_axis +from ...utils.bones import put_bone, flip_bone, align_chain_x_axis, set_bone_widget_transform from ...utils.naming import make_derived_name from ...utils.widgets import create_widget from ...utils.widgets_basic import create_circle_widget from ...utils.misc import map_list +from ...utils.layers import ControlLayersOption from ...base_rig import stage @@ -40,7 +41,7 @@ class Rig(SimpleChainRig): def initialize(self): super().initialize() - self.bbone_segments = 8 + self.bbone_segments = self.params.bbones self.first_parent = self.get_bone_parent(self.bones.org[0]) def prepare_bones(self): @@ -116,6 +117,8 @@ class Rig(SimpleChainRig): for args in zip(count(0), self.bones.ctrl.fk, self.bones.org + [None]): self.configure_control_bone(*args) + ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.fk) + def configure_control_bone(self, i, ctrl, org): if org: self.copy_bone_properties(org, ctrl) @@ -125,11 +128,13 @@ class Rig(SimpleChainRig): bone.lock_rotation = (True, True, True) bone.lock_scale = (True, True, True) - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): if ctrl == self.bones.ctrl.fk[-1]: # Tip control create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0) else: + set_bone_widget_transform(self.obj, ctrl, self.bones.org[i]) + create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) ############################## @@ -234,11 +239,12 @@ class Rig(SimpleChainRig): def configure_master_properties(self): master = self.bones.ctrl.master - self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") + if self.bbone_segments > 1: + self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") - # Create UI - panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten()) - panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True) + # Create UI + panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten()) + panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True) def rig_deform_bone(self, i, deform, org): master = self.bones.ctrl.master @@ -246,8 +252,9 @@ class Rig(SimpleChainRig): self.make_constraint(deform, 'COPY_TRANSFORMS', org) - self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')]) - self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')]) + if self.bbone_segments > 1: + self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')]) + self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')]) ############### # OPTIONS @@ -261,6 +268,15 @@ class Rig(SimpleChainRig): ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')] params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic') + params.bbones = bpy.props.IntProperty( + name = 'B-Bone Segments', + default = 10, + min = 1, + description = 'Number of B-Bone segments' + ) + + ControlLayersOption.TWEAK.add_parameters(params) + @classmethod def parameters_ui(self, layout, params): """ Create the ui for the rig parameters. @@ -269,6 +285,10 @@ class Rig(SimpleChainRig): r.label(text="Bend rotation axis:") r.prop(params, "primary_rotation_axis", text="") + layout.prop(params, 'bbones') + + ControlLayersOption.TWEAK.parameters_ui(layout, params) + def create_sample(obj): # generated by rigify.utils.write_metarig @@ -321,10 +341,6 @@ def create_sample(obj): pbone.lock_scale = (False, False, False) pbone.rotation_mode = 'QUATERNION' try: - pbone.rigify_parameters.separate_extra_layers = True - except AttributeError: - pass - try: pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False] except AttributeError: pass diff --git a/rigify/rigs/limbs/super_palm.py b/rigify/rigs/limbs/super_palm.py index 8bcbabf8..9c03b2fe 100644 --- a/rigify/rigs/limbs/super_palm.py +++ b/rigify/rigs/limbs/super_palm.py @@ -24,6 +24,7 @@ import re from math import cos, pi from itertools import count, repeat +from rigify.utils.rig import is_rig_base_bone from rigify.utils.naming import strip_org, make_derived_name from rigify.utils.widgets import create_widget from rigify.utils.misc import map_list @@ -43,7 +44,7 @@ def bone_siblings(obj, bone): bones = [] for b in parent.children: - if b.name != bone: + if b.name != bone and not is_rig_base_bone(obj, b.name): bones += [b.name] return bones diff --git a/rigify/rigs/spines/basic_spine.py b/rigify/rigs/spines/basic_spine.py index 269889cf..c2905463 100644 --- a/rigify/rigs/spines/basic_spine.py +++ b/rigify/rigs/spines/basic_spine.py @@ -19,13 +19,16 @@ # <pep8 compliant> import bpy +import math from itertools import count, repeat +from mathutils import Matrix from ...utils.errors import MetarigError from ...utils.layers import ControlLayersOption -from ...utils.naming import strip_org, make_deformer_name, make_mechanism_name -from ...utils.bones import BoneDict, put_bone, align_bone_to_axis +from ...utils.naming import strip_org, make_deformer_name, make_mechanism_name, make_derived_name +from ...utils.bones import BoneDict, put_bone, align_bone_to_axis, align_bone_orientation, set_bone_widget_transform +from ...utils.widgets import adjust_widget_transform_mesh from ...utils.widgets_basic import create_circle_widget from ...utils.misc import map_list @@ -43,6 +46,7 @@ class Rig(BaseSpineRig): # Check if user provided the pivot position self.pivot_pos = self.params.pivot_pos + self.use_fk = self.params.make_fk_controls if not (0 < self.pivot_pos < len(self.bones.org)): self.raise_error("Please specify a valid pivot bone position.") @@ -55,6 +59,9 @@ class Rig(BaseSpineRig): # ctrl: # master, hips, chest: # Main controls. + # fk: + # chest[], hips[]: + # FK controls. # tweak[]: # Tweak control chain. # mch: @@ -73,19 +80,15 @@ class Rig(BaseSpineRig): #################################################### # Master control bone - @stage.generate_bones - def make_master_control(self): - super().make_master_control() - - # Put the main control in the middle of the hip bone - base_bone = self.get_bone(self.bones.org[0]) - put_bone(self.obj, self.bones.ctrl.master, (base_bone.head + base_bone.tail) / 2) + def get_master_control_pos(self, orgs): + base_bone = self.get_bone(orgs[0]) + return (base_bone.head + base_bone.tail) / 2 #################################################### # Main control bones @stage.generate_bones - def make_control_chain(self): + def make_end_control_bones(self): orgs = self.bones.org pivot = self.pivot_pos @@ -103,33 +106,90 @@ class Rig(BaseSpineRig): return name @stage.parent_bones - def parent_control_chain(self): + def parent_end_control_bones(self): ctrl = self.bones.ctrl - self.set_bone_parent(ctrl.hips, ctrl.master) - self.set_bone_parent(ctrl.chest, ctrl.master) - - @stage.configure_bones - def configure_control_chain(self): - pass + pivot = self.get_master_control_output() + self.set_bone_parent(ctrl.hips, pivot) + self.set_bone_parent(ctrl.chest, pivot) @stage.generate_widgets - def make_control_widgets(self): + def make_end_control_widgets(self): ctrl = self.bones.ctrl mch = self.bones.mch - self.make_control_widget(ctrl.hips, mch.wgt_hips) - self.make_control_widget(ctrl.chest, mch.wgt_chest) + self.make_end_control_widget(ctrl.hips, mch.wgt_hips) + self.make_end_control_widget(ctrl.chest, mch.wgt_chest) + + def make_end_control_widget(self, ctrl, wgt_mch): + shape_bone = self.get_bone(wgt_mch) + is_horizontal = abs(shape_bone.z_axis.normalized().y) < 0.7 - def make_control_widget(self, ctrl, wgt_mch): - self.get_bone(ctrl).custom_shape_transform = self.get_bone(wgt_mch) + set_bone_widget_transform(self.obj, ctrl, wgt_mch) - create_circle_widget( + obj = create_circle_widget( self.obj, ctrl, - radius=1.0, + radius=1.2 if is_horizontal else 1.1, head_tail=0.0, head_tail_x=1.0, with_line=False, ) + if is_horizontal: + # Tilt the widget toward the ground for horizontal (animal) spines + angle = math.copysign(28, shape_bone.x_axis.x) + rotmat = Matrix.Rotation(math.radians(angle), 4, 'X') + adjust_widget_transform_mesh(obj, rotmat, local=True) + + #################################################### + # FK control bones + + @stage.generate_bones + def make_control_chain(self): + if self.use_fk: + orgs = self.bones.org + self.bones.ctrl.fk = self.fk_result = BoneDict( + hips = map_list(self.make_control_bone, count(0), orgs[0:self.pivot_pos], repeat(True)), + chest = map_list(self.make_control_bone, count(self.pivot_pos), orgs[self.pivot_pos:], repeat(False)), + ) + + def make_control_bone(self, i, org, is_hip): + name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_fk'), parent=False) + if is_hip: + put_bone(self.obj, name, self.get_bone(name).tail) + return name + + @stage.parent_bones + def parent_control_chain(self): + if self.use_fk: + chain = self.bones.mch.chain + fk = self.bones.ctrl.fk + for child, parent in zip(fk.hips, chain.hips): + self.set_bone_parent(child, parent) + for child, parent in zip(fk.chest, chain.chest): + self.set_bone_parent(child, parent) + + @stage.configure_bones + def configure_control_chain(self): + if self.use_fk: + fk = self.bones.ctrl.fk + for args in zip(count(0), fk.hips + fk.chest, self.bones.org): + self.configure_control_bone(*args) + + ControlLayersOption.FK.assign_rig(self, fk.hips + fk.chest) + + @stage.generate_widgets + def make_control_widgets(self): + if self.use_fk: + fk = self.bones.ctrl.fk + for ctrl in fk.hips: + self.make_control_widget(ctrl, True) + for ctrl in fk.chest: + self.make_control_widget(ctrl, False) + + def make_control_widget(self, ctrl, is_hip): + obj = create_circle_widget(self.obj, ctrl, radius=1.0, head_tail=0.5) + if is_hip: + adjust_widget_transform_mesh(obj, Matrix.Diagonal((1, -1, 1, 1)), local=True) + #################################################### # MCH bones associated with main controls @@ -153,16 +213,16 @@ class Rig(BaseSpineRig): @stage.parent_bones def parent_mch_control_bones(self): mch = self.bones.mch - self.set_bone_parent(mch.pivot, mch.chain.chest[0]) - self.set_bone_parent(mch.wgt_hips, mch.chain.hips[0]) - self.set_bone_parent(mch.wgt_chest, mch.chain.chest[-1]) + fk = self.fk_result + self.set_bone_parent(mch.pivot, fk.chest[0]) + self.set_bone_parent(mch.wgt_hips, fk.hips[0]) + self.set_bone_parent(mch.wgt_chest, fk.chest[-1]) + align_bone_orientation(self.obj, mch.pivot, fk.hips[-1]) @stage.rig_bones def rig_mch_control_bones(self): mch = self.bones.mch - # Is it actually intending to compute average of these, or is this really intentional? - # This effectively adds rotations of the hip and chest controls. - self.make_constraint(mch.pivot, 'COPY_TRANSFORMS', mch.chain.hips[-1], space='LOCAL') + self.make_constraint(mch.pivot, 'COPY_TRANSFORMS', self.fk_result.hips[-1], influence=0.5) #################################################### # MCH chain for distributing hip & chest transform @@ -174,6 +234,8 @@ class Rig(BaseSpineRig): hips = map_list(self.make_mch_bone, orgs[0:self.pivot_pos], repeat(True)), chest = map_list(self.make_mch_bone, orgs[self.pivot_pos:], repeat(False)), ) + if not self.use_fk: + self.fk_result = self.bones.mch.chain def make_mch_bone(self, org, is_hip): name = self.copy_bone(org, make_mechanism_name(strip_org(org)), parent=False) @@ -182,10 +244,13 @@ class Rig(BaseSpineRig): @stage.parent_bones def parent_mch_chain(self): - master = self.bones.ctrl.master + master = self.get_master_control_output() chain = self.bones.mch.chain - self.parent_bone_chain([master, *reversed(chain.hips)]) - self.parent_bone_chain([master, *chain.chest]) + fk = self.fk_result + for child, parent in zip(reversed(chain.hips), [master, *reversed(fk.hips)]): + self.set_bone_parent(child, parent) + for child, parent in zip(chain.chest, [master, *fk.chest]): + self.set_bone_parent(child, parent) @stage.rig_bones def rig_mch_chain(self): @@ -205,7 +270,7 @@ class Rig(BaseSpineRig): @stage.parent_bones def parent_tweak_chain(self): mch = self.bones.mch - chain = mch.chain + chain = self.fk_result parents = [chain.hips[0], *chain.hips[0:-1], mch.pivot, *chain.chest[1:], chain.chest[-1]] for args in zip(self.bones.ctrl.tweak, parents): self.set_bone_parent(*args) @@ -224,6 +289,13 @@ class Rig(BaseSpineRig): super().add_parameters(params) + params.make_fk_controls = bpy.props.BoolProperty( + name="FK Controls", default=True, + description="Generate an FK control chain" + ) + + ControlLayersOption.FK.add_parameters(params) + @classmethod def parameters_ui(self, layout, params): r = layout.row() @@ -231,6 +303,11 @@ class Rig(BaseSpineRig): super().parameters_ui(layout, params) + layout.prop(params, 'make_fk_controls') + + if params.make_fk_controls: + ControlLayersOption.FK.parameters_ui(layout, params) + def create_sample(obj): # generated by rigify.utils.write_metarig diff --git a/rigify/rigs/spines/basic_tail.py b/rigify/rigs/spines/basic_tail.py index 845c3ca3..be054e7d 100644 --- a/rigify/rigs/spines/basic_tail.py +++ b/rigify/rigs/spines/basic_tail.py @@ -23,7 +23,8 @@ import bpy from itertools import count from ...utils.naming import strip_org, make_derived_name -from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles, align_bone_orientation +from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles +from ...utils.bones import align_bone_orientation, set_bone_widget_transform from ...utils.widgets_basic import create_circle_widget from ...utils.layers import ControlLayersOption from ...utils.misc import map_list @@ -69,7 +70,7 @@ class Rig(BaseHeadTailRig): @stage.generate_widgets def make_master_control_widget(self): bone = self.bones.ctrl.master - self.get_bone(bone).custom_shape_transform = self.get_bone(self.bones.ctrl.tweak[-1]) + set_bone_widget_transform(self.obj, bone, self.bones.ctrl.tweak[-1]) create_ballsocket_widget(self.obj, bone, size=0.7) #################################################### @@ -94,7 +95,7 @@ class Rig(BaseHeadTailRig): ) # Widgets - def make_control_widget(self, ctrl): + def make_control_widget(self, i, ctrl): create_circle_widget(self.obj, ctrl, radius=0.5, head_tail=0.75) #################################################### diff --git a/rigify/rigs/spines/spine_rigs.py b/rigify/rigs/spines/spine_rigs.py index 6628289f..070a6bd3 100644 --- a/rigify/rigs/spines/spine_rigs.py +++ b/rigify/rigs/spines/spine_rigs.py @@ -24,9 +24,10 @@ from itertools import count from ...utils.layers import ControlLayersOption from ...utils.naming import make_derived_name -from ...utils.bones import align_bone_orientation, align_bone_to_axis +from ...utils.bones import align_bone_orientation, align_bone_to_axis, put_bone, set_bone_widget_transform from ...utils.widgets_basic import create_cube_widget from ...utils.switch_parent import SwitchParentBuilder +from ...utils.components import CustomPivotControl from ...base_rig import stage @@ -44,6 +45,7 @@ class BaseSpineRig(TweakChainRig): if len(self.bones.org) < 3: self.raise_error("Input to rig type must be a chain of 3 or more bones.") + self.use_torso_pivot = self.params.make_custom_pivot self.length = sum([self.get_bone(b).length for b in self.bones.org]) #################################################### @@ -52,6 +54,11 @@ class BaseSpineRig(TweakChainRig): # ctrl: # master # Main control. + # master_pivot + # Custom pivot under the master control. + # mch: + # master_pivot + # Final output of the custom pivot. # #################################################### @@ -60,17 +67,43 @@ class BaseSpineRig(TweakChainRig): @stage.generate_bones def make_master_control(self): - self.bones.ctrl.master = name = self.copy_bone(self.bones.org[0], 'torso') + self.bones.ctrl.master = name = self.make_master_control_bone(self.bones.org) + self.component_torso_pivot = self.build_master_pivot(name) + self.build_parent_switch(name) + + def get_master_control_pos(self, orgs): + return self.get_bone(orgs[0]).head + + def make_master_control_bone(self, orgs): + name = self.copy_bone(orgs[0], 'torso') + put_bone(self.obj, name, self.get_master_control_pos(orgs)) align_bone_to_axis(self.obj, name, 'y', length=self.length * 0.6) + return name - self.build_parent_switch(name) + def build_master_pivot(self, master_name, **args): + if self.use_torso_pivot: + return CustomPivotControl( + self, 'master_pivot', master_name, parent=master_name, **args + ) + + def get_master_control_output(self): + if self.component_torso_pivot: + return self.component_torso_pivot.output + else: + return self.bones.ctrl.master def build_parent_switch(self, master_name): pbuilder = SwitchParentBuilder(self.generator) - pbuilder.register_parent(self, master_name, name='Torso') + + org_parent = self.get_bone_parent(self.bones.org[0]) + parents = [org_parent] if org_parent else [] + + pbuilder.register_parent(self, self.get_master_control_output, name='Torso', tags={'torso', 'child'}) + pbuilder.build_child( self, master_name, exclude_self=True, + extra_parents=parents, select_parent=org_parent, prop_id='torso_parent', prop_name='Torso Parent', controls=lambda: self.bones.flatten('ctrl'), ) @@ -78,8 +111,8 @@ class BaseSpineRig(TweakChainRig): self.register_parent_bones(pbuilder) def register_parent_bones(self, pbuilder): - pbuilder.register_parent(self, self.bones.org[0], name='Hips', exclude_self=True) - pbuilder.register_parent(self, self.bones.org[-1], name='Chest', exclude_self=True) + pbuilder.register_parent(self, self.bones.org[0], name='Hips', exclude_self=True, tags={'hips'}) + pbuilder.register_parent(self, self.bones.org[-1], name='Chest', exclude_self=True, tags={'chest'}) @stage.parent_bones def parent_master_control(self): @@ -91,10 +124,9 @@ class BaseSpineRig(TweakChainRig): @stage.generate_widgets def make_master_control_widget(self): - create_cube_widget( - self.obj, self.bones.ctrl.master, - radius=0.5, - ) + master = self.bones.ctrl.master + set_bone_widget_transform(self.obj, master, self.get_master_control_output()) + create_cube_widget(self.obj, master, radius=0.5) #################################################### # Tweak bones @@ -117,11 +149,19 @@ class BaseSpineRig(TweakChainRig): @classmethod def add_parameters(self, params): + params.make_custom_pivot = bpy.props.BoolProperty( + name = "Custom Pivot Control", + default = False, + description = "Create a rotation pivot control that can be repositioned arbitrarily" + ) + # Setting up extra layers for the FK and tweak ControlLayersOption.TWEAK.add_parameters(params) @classmethod def parameters_ui(self, layout, params): + layout.prop(params, 'make_custom_pivot') + ControlLayersOption.TWEAK.parameters_ui(layout, params) diff --git a/rigify/rigs/spines/super_head.py b/rigify/rigs/spines/super_head.py index 9b85e5b5..15f011f7 100644 --- a/rigify/rigs/spines/super_head.py +++ b/rigify/rigs/spines/super_head.py @@ -322,7 +322,10 @@ class Rig(BaseHeadTailRig): def register_parent_bones(self): rig = self.rigify_parent or self builder = SwitchParentBuilder(self.generator) - builder.register_parent(rig, self.bones.org[-1], name='Head', exclude_self=True) + builder.register_parent( + self, self.bones.org[-1], name='Head', + inject_into=rig, exclude_self=True, tags={'head'}, + ) @stage.configure_bones def configure_bbone_chain(self): diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py index 5ed1588e..86021c84 100644 --- a/rigify/rigs/spines/super_spine.py +++ b/rigify/rigs/spines/super_spine.py @@ -81,7 +81,7 @@ class Rig(SubstitutionRig, BoneUtilityMixin): bpy.ops.object.mode_set(mode='OBJECT') # Create the parts - self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos) + self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos, make_fk_controls=False) result = [ self.instantiate_rig(basic_spine.Rig, spine_orgs[0]) ] @@ -133,6 +133,8 @@ def add_parameters(params): def parameters_ui(layout, params): """ Create the ui for the rig parameters.""" + layout.label(text="Note: this combined rig is deprecated.", icon='INFO') + r = layout.row(align=True) r.prop(params, "use_head", toggle=True, text="Head") r.prop(params, "use_tail", toggle=True, text="Tail") diff --git a/rigify/ui.py b/rigify/ui.py index caac09ab..005aed80 100644 --- a/rigify/ui.py +++ b/rigify/ui.py @@ -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': diff --git a/rigify/utils/animation.py b/rigify/utils/animation.py index 62042923..1355a0b6 100644 --- a/rigify/utils/animation.py +++ b/rigify/utils/animation.py @@ -377,20 +377,24 @@ TRANSFORM_PROPS_ROTATION = frozenset(['rotation_euler', 'rotation_quaternion', ' TRANSFORM_PROPS_SCALE = frozenset(['scale']) TRANSFORM_PROPS_ALL = frozenset(TRANSFORM_PROPS_LOCATION | TRANSFORM_PROPS_ROTATION | TRANSFORM_PROPS_SCALE) -class ActionCurveTable(object): +def transform_props_with_locks(lock_location, lock_rotation, lock_scale): + props = set() + if not lock_location: + props |= TRANSFORM_PROPS_LOCATION + if not lock_rotation: + props |= TRANSFORM_PROPS_ROTATION + if not lock_scale: + props |= TRANSFORM_PROPS_SCALE + return props + +class FCurveTable(object): "Table for efficient lookup of FCurves by properties." - def __init__(self, action): - from collections import defaultdict - self.action = find_action(action) - self.curve_map = defaultdict(dict) - self.index_action() + def __init__(self): + self.curve_map = collections.defaultdict(dict) - def index_action(self): - if not self.action: - return - - for curve in self.action.fcurves: + def index_curves(self, curves): + for curve in curves: index = curve.array_index if index < 0: index = 0 @@ -412,6 +416,24 @@ class ActionCurveTable(object): def get_custom_prop_curves(self, ptr, prop): return self.get_prop_curves(ptr, rna_idprop_quote_path(prop)) + +class ActionCurveTable(FCurveTable): + "Table for efficient lookup of Action FCurves by properties." + + def __init__(self, action): + super().__init__() + self.action = find_action(action) + if self.action: + self.index_curves(self.action.fcurves) + +class DriverCurveTable(FCurveTable): + "Table for efficient lookup of Driver FCurves by properties." + + def __init__(self, object): + super().__init__() + self.anim_data = object.animation_data + if self.anim_data: + self.index_curves(self.anim_data.drivers) '''] exec(SCRIPT_UTILITIES_CURVES[-1]) @@ -495,7 +517,23 @@ SCRIPT_UTILITIES_BAKE = SCRIPT_UTILITIES_KEYING + SCRIPT_UTILITIES_CURVES + [''' # Keyframe baking operator framework ## ####################################### -class RigifyBakeKeyframesMixin: +class RigifyOperatorMixinBase: + bl_options = {'UNDO', 'INTERNAL'} + + def init_invoke(self, context): + "Override to initialize the operator before invoke." + + def init_execute(self, context): + "Override to initialize the operator before execute." + + def before_save_state(self, context, rig): + "Override to prepare for saving state." + + def after_save_state(self, context, rig): + "Override to undo before_save_state." + + +class RigifyBakeKeyframesMixin(RigifyOperatorMixinBase): """Basic framework for an operator that updates a set of keyed frames.""" # Utilities @@ -566,6 +604,7 @@ class RigifyBakeKeyframesMixin: self.bake_state = dict() self.keyflags = get_keying_flags(context) + self.keyflags_switch = None if context.window_manager.rigify_transfer_use_all_keys: self.bake_add_curve_frames(self.bake_curve_table.curve_map) @@ -604,9 +643,15 @@ class RigifyBakeKeyframesMixin: scene = context.scene saved_state = self.bake_state - for frame in self.bake_frames: - scene.frame_set(frame) - saved_state[frame] = self.save_frame_state(context, rig) + try: + self.before_save_state(context, rig) + + for frame in self.bake_frames: + scene.frame_set(frame) + saved_state[frame] = self.save_frame_state(context, rig) + + finally: + self.after_save_state(context, rig) def bake_clean_curves_in_range(self, context, curves): "Deletes all keys from the given curves in the bake range." @@ -648,10 +693,6 @@ class RigifyBakeKeyframesMixin: "Override to execute code one time before the bake apply frame scan." pass - def init_execute(self, context): - "Override to initialize the operator." - pass - def execute(self, context): self.init_execute(context) self.bake_init(context) @@ -661,18 +702,20 @@ class RigifyBakeKeyframesMixin: if self.report_bake_empty(): return {'CANCELLED'} - self.bake_save_state(context) + try: + self.bake_save_state(context) - range, range_raw = self.bake_clean_curves_in_range(context, curves) + range, range_raw = self.bake_clean_curves_in_range(context, curves) - self.execute_before_apply(context, self.bake_rig, range, range_raw) + self.execute_before_apply(context, self.bake_rig, range, range_raw) - self.bake_apply_state(context) - return {'FINISHED'} + self.bake_apply_state(context) - def init_invoke(self, context): - "Override to initialize the operator." - pass + except Exception as e: + traceback.print_exc() + self.report({'ERROR'}, 'Exception: ' + str(e)) + + return {'FINISHED'} def invoke(self, context, event): self.init_invoke(context) @@ -683,22 +726,29 @@ class RigifyBakeKeyframesMixin: return context.window_manager.invoke_confirm(self, event) -class RigifySingleUpdateMixin: +class RigifySingleUpdateMixin(RigifyOperatorMixinBase): """Basic framework for an operator that updates only the current frame.""" - def init_execute(self, context): - pass - def execute(self, context): self.init_execute(context) obj = context.active_object self.keyflags = get_autokey_flags(context, ignore_keyset=True) self.keyflags_switch = add_flags_if_set(self.keyflags, {'INSERTKEY_AVAILABLE'}) - self.apply_frame_state(context, obj, self.save_frame_state(context, obj)) - return {'FINISHED'} - def init_invoke(self, context): - pass + try: + try: + self.before_save_state(context, obj) + state = self.save_frame_state(context, obj) + finally: + self.after_save_state(context, obj) + + self.apply_frame_state(context, obj, state) + + except Exception as e: + traceback.print_exc() + self.report({'ERROR'}, 'Exception: ' + str(e)) + + return {'FINISHED'} def invoke(self, context, event): self.init_invoke(context) @@ -773,51 +823,59 @@ def add_clear_keyframes_button(panel, *, bones=[], label='', text=''): # Generic Snap FK to IK operator ## ################################### -SCRIPT_REGISTER_OP_SNAP_FK_IK = ['POSE_OT_rigify_generic_fk2ik', 'POSE_OT_rigify_generic_fk2ik_bake'] +SCRIPT_REGISTER_OP_SNAP = ['POSE_OT_rigify_generic_snap', 'POSE_OT_rigify_generic_snap_bake'] -SCRIPT_UTILITIES_OP_SNAP_FK_IK = [''' -########################### -## Generic Snap FK to IK ## -########################### +SCRIPT_UTILITIES_OP_SNAP = [''' +############################# +## Generic Snap (FK to IK) ## +############################# -class RigifyGenericFk2IkBase: - fk_bones: StringProperty(name="FK Bone Chain") - ik_bones: StringProperty(name="IK Result Bone Chain") - ctrl_bones: StringProperty(name="IK Controls") +class RigifyGenericSnapBase: + input_bones: StringProperty(name="Input Chain") + output_bones: StringProperty(name="Output Chain") + ctrl_bones: StringProperty(name="Input Controls") + tooltip: StringProperty(name="Tooltip", default="FK to IK") + locks: bpy.props.BoolVectorProperty(name="Locked", size=3, default=[False,False,False]) undo_copy_scale: bpy.props.BoolProperty(name="Undo Copy Scale", default=False) - keyflags = None - def init_execute(self, context): - self.fk_bone_list = json.loads(self.fk_bones) - self.ik_bone_list = json.loads(self.ik_bones) + self.input_bone_list = json.loads(self.input_bones) + self.output_bone_list = json.loads(self.output_bones) self.ctrl_bone_list = json.loads(self.ctrl_bones) def save_frame_state(self, context, obj): - return get_chain_transform_matrices(obj, self.ik_bone_list) + return get_chain_transform_matrices(obj, self.input_bone_list) def apply_frame_state(self, context, obj, matrices): set_chain_transforms_from_matrices( - context, obj, self.fk_bone_list, matrices, - undo_copy_scale=self.undo_copy_scale, keyflags=self.keyflags + context, obj, self.output_bone_list, matrices, + undo_copy_scale=self.undo_copy_scale, keyflags=self.keyflags, + no_loc=self.locks[0], no_rot=self.locks[1], no_scale=self.locks[2], ) -class POSE_OT_rigify_generic_fk2ik(RigifyGenericFk2IkBase, RigifySingleUpdateMixin, bpy.types.Operator): - bl_idname = "pose.rigify_generic_fk2ik_" + rig_id - bl_label = "Snap FK->IK" - bl_options = {'UNDO', 'INTERNAL'} - bl_description = "Snap the FK chain to IK result" +class POSE_OT_rigify_generic_snap(RigifyGenericSnapBase, RigifySingleUpdateMixin, bpy.types.Operator): + bl_idname = "pose.rigify_generic_snap_" + rig_id + bl_label = "Snap Bones" + bl_description = "Snap on the current frame" -class POSE_OT_rigify_generic_fk2ik_bake(RigifyGenericFk2IkBase, RigifyBakeKeyframesMixin, bpy.types.Operator): - bl_idname = "pose.rigify_generic_fk2ik_bake_" + rig_id - bl_label = "Apply Snap FK->IK To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} - bl_description = "Snap the FK chain keyframes to IK result" + @classmethod + def description(cls, context, props): + return "Snap " + props.tooltip + " on the current frame" + +class POSE_OT_rigify_generic_snap_bake(RigifyGenericSnapBase, RigifyBakeKeyframesMixin, bpy.types.Operator): + bl_idname = "pose.rigify_generic_snap_bake_" + rig_id + bl_label = "Apply Snap To Keyframes" + bl_description = "Apply snap to keyframes" + + @classmethod + def description(cls, context, props): + return "Apply snap " + props.tooltip + " to keyframes" def execute_scan_curves(self, context, obj): + props = transform_props_with_locks(*self.locks) self.bake_add_bone_frames(self.ctrl_bone_list, TRANSFORM_PROPS_ALL) - return self.bake_get_all_bone_curves(self.fk_bone_list, TRANSFORM_PROPS_ALL) + return self.bake_get_all_bone_curves(self.output_bone_list, props) '''] def add_fk_ik_snap_buttons(panel, op_single, op_bake, *, label=None, rig_name='', properties=None, clear_bones=None, compact=None): @@ -840,25 +898,37 @@ def add_fk_ik_snap_buttons(panel, op_single, op_bake, *, label=None, rig_name='' row.operator(op_bake, text='Action', icon='ACTION_TWEAK', properties=properties) add_clear_keyframes_button(row, bones=clear_bones, text='Clear') -def add_generic_snap_fk_to_ik(panel, *, fk_bones=[], ik_bones=[], ik_ctrl_bones=[], label='FK->IK', rig_name='', undo_copy_scale=False, compact=None, clear=True): +def add_generic_snap(panel, *, output_bones=[], input_bones=[], input_ctrl_bones=[], label='Snap', rig_name='', undo_copy_scale=False, compact=None, clear=True, locks=None, tooltip=None): panel.use_bake_settings() - panel.script.add_utilities(SCRIPT_UTILITIES_OP_SNAP_FK_IK) - panel.script.register_classes(SCRIPT_REGISTER_OP_SNAP_FK_IK) + panel.script.add_utilities(SCRIPT_UTILITIES_OP_SNAP) + panel.script.register_classes(SCRIPT_REGISTER_OP_SNAP) op_props = { - 'fk_bones': json.dumps(fk_bones), - 'ik_bones': json.dumps(ik_bones), - 'ctrl_bones': json.dumps(ik_ctrl_bones), - 'undo_copy_scale': undo_copy_scale, + 'output_bones': json.dumps(output_bones), + 'input_bones': json.dumps(input_bones), + 'ctrl_bones': json.dumps(input_ctrl_bones or input_bones), } - clear_bones = fk_bones if clear else None + if undo_copy_scale: + op_props['undo_copy_scale'] = undo_copy_scale + if locks is not None: + op_props['locks'] = tuple(locks[0:3]) + if tooltip is not None: + op_props['tooltip'] = tooltip + + clear_bones = output_bones if clear else None add_fk_ik_snap_buttons( - panel, 'pose.rigify_generic_fk2ik_{rig_id}', 'pose.rigify_generic_fk2ik_bake_{rig_id}', + panel, 'pose.rigify_generic_snap_{rig_id}', 'pose.rigify_generic_snap_bake_{rig_id}', label=label, rig_name=rig_name, properties=op_props, clear_bones=clear_bones, compact=compact, ) +def add_generic_snap_fk_to_ik(panel, *, fk_bones=[], ik_bones=[], ik_ctrl_bones=[], label='FK->IK', rig_name='', undo_copy_scale=False, compact=None, clear=True): + add_generic_snap( + panel, output_bones=fk_bones, input_bones=ik_bones, input_ctrl_bones=ik_ctrl_bones, + label=label, rig_name=rig_name, undo_copy_scale=undo_copy_scale, compact=compact, clear=clear + ) + ############################### # Module register/unregister ## ############################### diff --git a/rigify/utils/bones.py b/rigify/utils/bones.py index 6a09cee1..854d4428 100644 --- a/rigify/utils/bones.py +++ b/rigify/utils/bones.py @@ -657,3 +657,17 @@ def align_bone_to_axis(obj, bone_name, axis, *, length=None, roll=0, flip=False) bone_e.tail = bone_e.head + vec bone_e.roll = roll + + +def set_bone_widget_transform(obj, bone_name, transform_bone, use_size=True, scale=1.0): + assert obj.mode != 'EDIT' + + bone = obj.pose.bones[bone_name] + + if transform_bone and transform_bone != bone_name: + bone.custom_shape_transform = obj.pose.bones[transform_bone] + else: + bone.custom_shape_transform = None + + bone.use_custom_shape_bone_size = use_size + bone.custom_shape_scale = scale diff --git a/rigify/utils/components.py b/rigify/utils/components.py new file mode 100644 index 00000000..5c1ebcb6 --- /dev/null +++ b/rigify/utils/components.py @@ -0,0 +1,87 @@ +import bpy + +from .naming import make_derived_name +from .bones import put_bone, copy_bone_position, align_bone_orientation +from .widgets_basic import create_pivot_widget +from .misc import force_lazy + +from ..base_rig import RigComponent, stage + + +class CustomPivotControl(RigComponent): + """ + A utility that generates a pivot control with a custom position. + + Generates a control bone, and a MCH output bone. + """ + + def __init__( + self, rig, id_name, org_bone, *, + name=None, parent=None, position=None, matrix=None, + scale=1.0, scale_mch=None, + move_to=None, align_to=None, snap_to=None, + widget_axis=1.5, widget_cap=1.0, widget_square=True, + ): + super().__init__(rig) + + assert rig.generator.stage == 'generate_bones' + + self.bones = rig.bones + self.id_name = id_name + + self.parent = parent + self.scale = scale or 1 + self.scale_mch = scale_mch or (self.scale * 0.7) + self.move_to = move_to + self.align_to = align_to + self.snap_to = snap_to + self.widget_axis = widget_axis + self.widget_cap = widget_cap + self.widget_square = widget_square + + name = name or make_derived_name(org_bone, 'ctrl', '_pivot') + + self.do_make_bones(org_bone, name, position, matrix) + + @property + def control(self): + return self.ctrl + + @property + def output(self): + return self.mch + + def do_make_bones(self, org, name, position, matrix): + self.bones.ctrl[self.id_name] = self.ctrl = self.copy_bone(org, name, parent=not self.parent, scale=self.scale) + self.bones.mch[self.id_name] = self.mch = self.copy_bone(org, make_derived_name(name, 'mch'), scale=self.scale_mch) + + if position or matrix: + put_bone(self.obj, self.ctrl, position, matrix=matrix) + put_bone(self.obj, self.mch, position, matrix=matrix) + + def parent_bones(self): + if self.snap_to: + bone = force_lazy(self.snap_to) + copy_bone_position(self.obj, bone, self.ctrl, scale=self.scale) + copy_bone_position(self.obj, bone, self.mch, scale=self.scale_mch) + + if self.move_to: + pos = self.get_bone(force_lazy(self.move_to)).head + put_bone(self.obj, self.ctrl, pos) + put_bone(self.obj, self.mch, pos) + + if self.align_to: + self.align_to = force_lazy(self.align_to) + align_bone_orientation(self.obj, self.ctrl, self.align_to) + align_bone_orientation(self.obj, self.mch, self.align_to) + + if self.parent: + self.set_bone_parent(self.ctrl, force_lazy(self.parent)) + + self.set_bone_parent(self.mch, self.ctrl) + + def rig_bones(self): + self.make_constraint(self.mch, 'COPY_LOCATION', self.ctrl, space='LOCAL', invert_xyz=(True,)*3) + + def generate_widgets(self): + create_pivot_widget(self.obj, self.ctrl, axis_size=self.widget_axis, cap_size=self.widget_cap, square=self.widget_square) diff --git a/rigify/utils/layers.py b/rigify/utils/layers.py index 7a1bcef8..0cbd41f8 100644 --- a/rigify/utils/layers.py +++ b/rigify/utils/layers.py @@ -71,7 +71,7 @@ class ControlLayersOption: self.toggle_option = self.name+'_layers_extra' self.layers_option = self.name+'_layers' - self.toggle_name = toggle_name if toggle_name else self.toggle_option + self.toggle_name = toggle_name if toggle_name else "Assign " + self.name.title() + " Layers" def get(self, params): if getattr(params, self.toggle_option): @@ -122,10 +122,15 @@ class ControlLayersOption: setattr(params, self.layers_option, prop_layers) def parameters_ui(self, layout, params): - r = layout.row() - r.prop(params, self.toggle_option) - r.active = getattr(params, self.toggle_option) + box = layout.box() + box.prop(params, self.toggle_option) + active = getattr(params, self.toggle_option) + + if not active: + return + + r = box.row() col = r.column(align=True) row = col.row(align=True) diff --git a/rigify/utils/misc.py b/rigify/utils/misc.py index 64367bb7..20fd6a08 100644 --- a/rigify/utils/misc.py +++ b/rigify/utils/misc.py @@ -156,6 +156,14 @@ def map_apply(func, *inputs): # Misc #============================================= + +def force_lazy(value): + if callable(value): + return value() + else: + return value + + def copy_attributes(a, b): keys = dir(a) for key in keys: diff --git a/rigify/utils/rig.py b/rigify/utils/rig.py index 8c646ab5..0c07cfe6 100644 --- a/rigify/utils/rig.py +++ b/rigify/utils/rig.py @@ -283,6 +283,7 @@ def write_metarig(obj, layers=False, func_name="create", groups=False): code.append(" bone.select = True") code.append(" bone.select_head = True") code.append(" bone.select_tail = True") + code.append(" bone.bbone_x = bone.bbone_z = bone.length * 0.05") code.append(" arm.edit_bones.active = bone") # Set appropriate layers visible diff --git a/rigify/utils/switch_parent.py b/rigify/utils/switch_parent.py index c26f5e74..61721266 100644 --- a/rigify/utils/switch_parent.py +++ b/rigify/utils/switch_parent.py @@ -8,7 +8,7 @@ import json from .errors import MetarigError from .naming import strip_prefix, make_derived_name from .mechanism import MechanismUtilityMixin -from .misc import map_list, map_apply +from .misc import map_list, map_apply, force_lazy from ..base_rig import * from ..base_generate import GeneratorPlugin @@ -16,11 +16,6 @@ from ..base_generate import GeneratorPlugin from collections import defaultdict from itertools import count, repeat, chain -def _auto_call(value): - if callable(value): - return value() - else: - return value def _rig_is_child(rig, parent): if parent is None: @@ -56,7 +51,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): ############################## # API - def register_parent(self, rig, bone, *, name=None, is_global=False, exclude_self=False): + def register_parent(self, rig, bone, *, name=None, is_global=False, exclude_self=False, inject_into=None, tags=None): """ Registers a bone of the specified rig as a possible parent. @@ -66,6 +61,8 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): name Name of the parent for mouse-over hint. is_global The parent is accessible to all rigs, instead of just children of owner. exclude_self The parent is invisible to the owner rig itself. + inject_into Make this parent available to children of the specified rig. + tags Set of tags to use for default parent selection. Lazy creation: The bone parameter may be a function creating the bone on demand and @@ -74,10 +71,19 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): assert not self.frozen assert isinstance(bone, str) or callable(bone) + assert callable(bone) or _rig_is_child(rig, self.generator.bone_owners[bone]) + assert _rig_is_child(rig, inject_into) + + real_rig = rig + + if inject_into and inject_into is not rig: + rig = inject_into + tags = (tags or set()) | {'injected'} entry = { - 'rig': rig, 'bone': bone, 'name': name, - 'is_global': is_global, 'exclude_self': exclude_self, 'used': False, + 'rig': rig, 'bone': bone, 'name': name, 'tags': tags, + 'is_global': is_global, 'exclude_self': exclude_self, + 'real_rig': real_rig, 'used': False, } if is_global: @@ -96,9 +102,13 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): extra_parents List of bone names or (name, user_name) pairs to use as additional parents. use_parent_mch Create an intermediate MCH bone for the constraints and parent the child to it. select_parent Select the specified bone instead of the last one. + select_tags List of parent tags to try for default selection. ignore_global Ignore the is_global flag of potential parents. exclude_self Ignore parents registered by the rig itself. - context_rig Rig to use for selecting parents. + allow_self Ignore the 'exclude_self' setting of the parent. + context_rig Rig to use for selecting parents; defaults to rig. + no_implicit Only use parents listed as extra_parents. + only_selected Like no_implicit, but allow the 'default' selected parent. prop_bone Name of the bone to add the property to. prop_id Actual name of the control property. @@ -160,7 +170,10 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): child_option_table = { 'extra_parents': None, 'prop_bone': None, 'prop_id': None, 'prop_name': None, 'controls': None, - 'select_parent': None, 'ignore_global': False, 'exclude_self': False, 'context_rig': None, + 'select_parent': None, 'ignore_global': False, + 'exclude_self': False, 'allow_self': False, + 'context_rig': None, 'select_tags': None, + 'no_implicit': False, 'only_selected': False, 'ctrl_bone': None, 'no_fix_location': False, 'no_fix_rotation': False, 'no_fix_scale': False, 'copy_location': None, 'copy_rotation': None, 'copy_scale': None, @@ -199,16 +212,23 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): parents = [] for parent in self.get_rig_parent_candidates(child_rig): + parent_rig = parent['rig'] + + # Exclude injected parents + if parent['real_rig'] is not parent_rig: + if _rig_is_child(parent_rig, child_rig): + continue + if parent['rig'] is child_rig: - if parent['exclude_self'] or child['exclude_self']: + if (parent['exclude_self'] and not child['allow_self']) or child['exclude_self']: continue elif parent['is_global'] and not child['ignore_global']: # Can't use parents from own children, even if global (cycle risk) - if _rig_is_child(parent['rig'], child_rig): + if _rig_is_child(parent_rig, child_rig): continue else: # Required to be a child of the parent's rig - if not _rig_is_child(child_rig, parent['rig']): + if not _rig_is_child(child_rig, parent_rig): continue parent['used'] = True @@ -219,7 +239,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): # Call lazy creation for parents for parent in self.parent_list: if parent['used']: - parent['bone'] = _auto_call(parent['bone']) + parent['bone'] = force_lazy(parent['bone']) def parent_bones(self): for child in self.child_list: @@ -248,34 +268,68 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): # Build the final list of parent bone names parent_map = dict() + parent_tags = defaultdict(set) for parent in child['parents']: if parent['bone'] not in parent_map: parent_map[parent['bone']] = parent['name'] + if parent['tags']: + parent_tags[parent['bone']] |= parent['tags'] last_main_parent_bone = child['parents'][-1]['bone'] - num_main_parents = len(parent_map.items()) + extra_parents = set() - for parent in _auto_call(child['extra_parents'] or []): + for parent in force_lazy(child['extra_parents'] or []): if not isinstance(parent, tuple): parent = (parent, None) + extra_parents.add(parent[0]) if parent[0] not in parent_map: parent_map[parent[0]] = parent[1] + for parent in parent_map: + if parent in self.child_map: + parent_tags[parent] |= {'child'} + parent_bones = list(parent_map.items()) - child['parent_bones'] = parent_bones # Find which bone to select - select_bone = _auto_call(child['select_parent']) or last_main_parent_bone - select_index = num_main_parents + select_bone = force_lazy(child['select_parent']) or last_main_parent_bone + select_tags = force_lazy(child['select_tags']) or [] + + if child['no_implicit']: + assert len(extra_parents) > 0 + parent_bones = [ item for item in parent_bones if item[0] in extra_parents ] + if last_main_parent_bone not in extra_parents: + last_main_parent_bone = parent_bones[-1][0] + + for tag in select_tags: + tag_set = tag if isinstance(tag, set) else {tag} + matching = [ + bone for (bone, _) in parent_bones + if not tag_set.isdisjoint(parent_tags[bone]) + ] + if len(matching) > 0: + select_bone = matching[-1] + break + + if select_bone not in parent_map: + print("RIGIFY ERROR: Can't find bone '%s' to select as default parent of '%s'\n" % (select_bone, bone)) + select_bone = last_main_parent_bone + + if child['only_selected']: + filter_set = { select_bone, *extra_parents } + parent_bones = [ item for item in parent_bones if item[0] in filter_set ] try: select_index = 1 + next(i for i, (bone, _) in enumerate(parent_bones) if bone == select_bone) except StopIteration: - print("RIGIFY ERROR: Can't find bone '%s' to select as default parent of '%s'\n" % (select_bone, bone)) + select_index = len(parent_bones) + print("RIGIFY ERROR: Invalid default parent '%s' of '%s'\n" % (select_bone, bone)) + + child['parent_bones'] = parent_bones # Create the controlling property - prop_bone = child['prop_bone'] = _auto_call(child['prop_bone']) or bone + prop_bone = child['prop_bone'] = force_lazy(child['prop_bone']) or bone prop_name = child['prop_name'] or child['prop_id'] or 'Parent Switch' prop_id = child['prop_id'] = child['prop_id'] or 'parent_switch' @@ -294,12 +348,12 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin): no_fix = [ child[n] for n in ['no_fix_location', 'no_fix_rotation', 'no_fix_scale'] ] - child['copy'] = [ _auto_call(child[n]) for n in ['copy_location', 'copy_rotation', 'copy_scale'] ] + child['copy'] = [ force_lazy(child[n]) for n in ['copy_location', 'copy_rotation', 'copy_scale'] ] locks = tuple(bool(nofix or copy) for nofix, copy in zip(no_fix, child['copy'])) # Create the script for the property - controls = _auto_call(child['controls']) or set([prop_bone, bone]) + controls = force_lazy(child['controls']) or set([prop_bone, bone]) script = self.generator.script panel = script.panel_with_selected_check(child['rig'], controls) @@ -377,9 +431,6 @@ class RigifySwitchParentBase: items=lambda s,c: RigifySwitchParentBase.parent_items ) - keyflags = None - keyflags_switch = None - def save_frame_state(self, context, obj): return get_transform_matrix(obj, self.bone, with_constraints=False) @@ -398,16 +449,6 @@ class RigifySwitchParentBase: no_loc=self.locks[0], no_rot=self.locks[1], no_scale=self.locks[2] ) - def get_bone_props(self): - props = set() - if not self.locks[0]: - props |= TRANSFORM_PROPS_LOCATION - if not self.locks[1]: - props |= TRANSFORM_PROPS_ROTATION - if not self.locks[2]: - props |= TRANSFORM_PROPS_SCALE - return props - def init_invoke(self, context): pose = context.active_object.pose @@ -440,11 +481,10 @@ class POSE_OT_rigify_switch_parent(RigifySwitchParentBase, RigifySingleUpdateMix class POSE_OT_rigify_switch_parent_bake(RigifySwitchParentBase, RigifyBakeKeyframesMixin, bpy.types.Operator): bl_idname = "pose.rigify_switch_parent_bake_" + rig_id bl_label = "Apply Switch Parent To Keyframes" - bl_options = {'UNDO', 'INTERNAL'} bl_description = "Switch parent over a frame range, adjusting keys to preserve the bone position and orientation" def execute_scan_curves(self, context, obj): - return self.bake_add_bone_frames(self.bone, self.get_bone_props()) + return self.bake_add_bone_frames(self.bone, transform_props_with_locks(*self.locks)) def execute_before_apply(self, context, obj, range, range_raw): self.bake_replace_custom_prop_keys_constant(self.prop_bone, self.prop_id, int(self.selected)) diff --git a/rigify/utils/widgets_basic.py b/rigify/utils/widgets_basic.py index 2848e5bf..8aab5d7b 100644 --- a/rigify/utils/widgets_basic.py +++ b/rigify/utils/widgets_basic.py @@ -129,7 +129,7 @@ def create_bone_widget(rig, bone_name, r1=0.1, l1=0.0, r2=0.04, l2=1.0, bone_tra mesh.update() -def create_pivot_widget(rig, bone_name, axis_size=1.0, cap_size=1.0, square=False, bone_transform_name=None): +def create_pivot_widget(rig, bone_name, axis_size=1.0, cap_size=1.0, square=True, bone_transform_name=None): """Creates a widget similar to Plain Axes empty, but with a cross or a square on the end of each axis line. """ |