import bpy from ..core import common from bpy.types import Operator, Context, Mesh, Armature, EditBone, PoseBone from ..core.register import register_wrap from .translations import t @register_wrap class AvatarToolkit_RemoveZeroWeightBones(Operator): bl_idname = "avatar_toolkit.remove_zero_weight_bones" bl_label = t("Tools.remove_zero_weight_bones.label") bl_description = t("Tools.remove_zero_weight_bones.desc") bl_options = {'REGISTER', 'UNDO'} threshold: bpy.props.FloatProperty( default=0.01, name=t("Tools.remove_zero_weight_bones.threshold.label"), description=t("Tools.remove_zero_weight_bones.threshold.desc"), min=0.0000001, max=0.9999999) @classmethod def poll(cls, context: Context) -> bool: return common.get_selected_armature(context) is not None def execute(self, context: Context) -> set[str]: armature = common.get_selected_armature(context) if not common.is_valid_armature(armature): self.report({'ERROR'}, t("Tools.apply_transforms.invalid_armature")) return {'CANCELLED'} weighted_bones: list[str] = [] bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.select_all(action='DESELECT') armature.select_set(True) context.view_layer.objects.active = armature meshes = common.get_all_meshes(context) for mesh in meshes: mesh_data: Mesh = mesh.data for vertex in mesh_data.vertices: for group in vertex.groups: if group.weight > self.threshold: weighted_bones.append(mesh.vertex_groups[group.group].name) #add bone name to list of bones that are greater than the weight threshold bpy.ops.object.mode_set(mode='EDIT') amature_data: Armature = armature.data unweighted_bones: list[str] = [] #doing 2 loops to prevent modification of array during iteration for bone in amature_data.edit_bones: if bone.name not in weighted_bones: unweighted_bones.append(bone.name) #add bones that arent in the list of bones that have weight into the list of bones that don't for bone_name in unweighted_bones: for edit_bone in amature_data.edit_bones[bone_name].children: edit_bone.use_connect = False #to fix randomly moving bones edit_bone.parent = amature_data.edit_bones[bone_name].parent #to fix unparented bones. amature_data.edit_bones.remove(amature_data.edit_bones[bone_name]) #delete list of unweighted bones from the armature self.report({'INFO'}, t("Tools.remove_zero_weight_bones.success")) return {'FINISHED'}