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:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .