I wonder what is the quickest way to remove vertex groups in which all vertices have zero weight.

Currently I got nearly 100 groups listed there after days of hard working, and I'm sure some of them are completely zero-weight groups and should definitely be removed, but it seems not so easy to quickly locate and remove them all.


4 Answers 4


This python snippet should work if you paste it into a Text Editor's new buffer and click Run Script.

import bpy

def survey(obj):
    maxWeight = {}
    for i in obj.vertex_groups:
        maxWeight[i.index] = 0

    for v in obj.data.vertices:
        for g in v.groups:
            gn = g.group
            w = obj.vertex_groups[g.group].weight(v.index)
            if (maxWeight.get(gn) is None or w>maxWeight[gn]):
                maxWeight[gn] = w
    return maxWeight

obj = bpy.context.active_object
maxWeight = survey(obj)
# fix bug pointed out by user2859
ka = []
ka.sort(key=lambda gn: -gn)
print (ka)
for gn in ka:
    if maxWeight[gn]<=0:
        print ("delete %d"%gn)
        obj.vertex_groups.remove(obj.vertex_groups[gn]) # actually remove the group
  • 1
    $\begingroup$ The last line contains a bug though. When it removes from vertex_groups the index changes, which might lead to an IndexErrors or even deleting the wrong groups. $\endgroup$
    – user2859
    Oct 7, 2014 at 23:27
  • $\begingroup$ Thanks. But like Mutant Bob said, it doesn't work very well. $\endgroup$ Oct 8, 2014 at 1:39
  • $\begingroup$ @LeonCheung Just curious, as I think I must be blind.. Where did Mutant Bob say that? $\endgroup$
    – gandalf3
    Oct 8, 2014 at 1:59
  • 1
    $\begingroup$ @gandalf3 Oops, I really mean user2859. :P $\endgroup$ Oct 8, 2014 at 2:06
  • 1
    $\begingroup$ @LeonCheung if the example isn't working, here is another variant $\endgroup$
    – user2859
    Oct 8, 2014 at 22:47

Just realized lately that we actually ignored one weight tool off the shelf - Clean.

You can simply click it then use the default Limit value 0.000. Done.

enter image description here

  • $\begingroup$ Note that it may not exactly solve the question, specifically, but might be useful for others who get smilar problem. $\endgroup$ Feb 2, 2016 at 5:51
  • 1
    $\begingroup$ If you are having trouble cleaning, set the limit to 1.0, it only worked for me when I did it like this. $\endgroup$
    – Renato
    May 19, 2018 at 21:05

This version is: Delete all empty vertex_groups for all selected objects

import bpy

def del_empty_vgroup(obj):
        vertex_groups = obj.vertex_groups
        groups = {r : None for r in range(len(vertex_groups))}

        for vert in obj.data.vertices:
            for vg in vert.groups:
                i = vg.group
                if i in groups:
                    del groups[i]

        lis = [k for k in groups]
        for i in lis:

for obj in bpy.context.selected_objects:
  • $\begingroup$ nice, slim, love it +1 $\endgroup$
    – quellenform
    Sep 7, 2022 at 21:04

This is a modification of CoDEmanX's code that doesn't delete mirror vertex groups, *.R vertex group has the info and *.L is empty, useful for objects with mirror modifier and armature deformation, use in the Text Editor https://github.com/sambler/myblendercontrib/blob/master/remove_unused_vertexGroups.py

import bpy
import re

ob = bpy.context.active_object

vgroup_used = {i: False for i, k in enumerate(ob.vertex_groups)}
vgroup_names = {i: k.name for i, k in enumerate(ob.vertex_groups)}

for v in ob.data.vertices:
    for g in v.groups:
        if g.weight > 0.0:
            vgroup_used[g.group] = True
            vgroup_name = vgroup_names[g.group]
            armatch = re.search('((.R|.L)(.(\d){1,}){0,1})(?!.)', vgroup_name)
            if armatch != None:
                tag = armatch.group()
                mirror_tag =  tag.replace(".R", ".L") if armatch.group(2) == ".R" else tag.replace(".L", ".R") 
                mirror_vgname = vgroup_name.replace(tag, mirror_tag)
                for i, name in sorted(vgroup_names.items(), reverse=True):
                    if mirror_vgname == name:
                        vgroup_used[i] = True
for i, used in sorted(vgroup_used.items(), reverse=True):
    if not used:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.