Batch Delete Vertex Groups script

Here is a quick script I did to quickly delete a few vertex groups at once

very simple to use, just run the script.
a screen will appear listing all the vertex groups, select the ones you want to delete and press the delete button
thats it…


#!BPY
"""
Name: 'Delete Vertex Groups'
Blender: 248
Group: 'Mesh'
Tooltip: 'Batch Delete Vertex Groups'
"""

__author__ = "Brad Gonsalves AKA AVE"
__url__ = ["blenderartists.org", "www.blender.org"]
__version__ = "1.0 2009/06/09"

# -------------------------------------------------------------------------- 
# ***** 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
# 
# ***** END GPL LICENCE BLOCK ***** 
# --------------------------------------------------------------------------



import Blender
from Blender import Draw, BGL, Scene, Mesh, Window, sys, Object

import bpy




GroupList=[]
ToggleState=[]
VGListRunning=1
co=[0,0]
GEventNumBase=20
VGColumns=4
GError=False


scn = Scene.GetCurrent()
obj= scn.getActiveObject()

if obj.getType()!='Mesh':
    obj= None
    
sel= [ob for ob in Object.GetSelected() if ob.getType()=='Mesh' if ob != obj]
if not sel and not obj:
    Draw.PupMenu('Error, select a mesh as your active object')
    GError=True
else:
    me = obj.getData(mesh=1) 
    
    InEditMode = Window.EditMode()    
    
    co=Window.GetMouseCoords()

    Window.EditMode(0)
    Window.EditMode(1)


def ToggleButton(event, val):
    global ToggleState
    global VGListRunning
    Found=False
    for x in ToggleState:
        if x[0]==event:
            Found=True
            x[1]=val
    if Found==False:
        ToggleState.append([event,val])
    VGListRunning=1

def FindToggleState(event):
    Found=False
    for x in ToggleState:
        if x[0]==event:
            Found=True
            return(x[1])
    if Found==False:
        return(0)

def DeleteVGroups(event, val):
    global VGListRunning
    Window.EditMode(0)
    if event==1:
        EventNum=GEventNumBase
        for x in GroupList:
            Toggle=FindToggleState(EventNum)
            if Toggle:
                me.removeVertGroup(x)
            EventNum+=1
    VGListRunning=0

def buttons():
    global GroupList
    global co
    global VGListRunning
    global GEventNumBase
    
    ColHeight=20
    ColWidth=105
    
    GroupList=me.getVertGroupNames()
    
    EventNum=GEventNumBase
    if len(GroupList)<VGColumns:
        CenWidth=0
        CenHeight=0
    else:
        CenWidth=(VGColumns*ColWidth)/2
        CenHeight=((len(GroupList)/VGColumns)*ColHeight)/2
    
    BaseCoX=co[0]-CenWidth
    BaseCoY=co[1]+CenHeight
    coY=BaseCoY
    coX=BaseCoX
    
    
    
    for x in GroupList:
        Toggle=FindToggleState(EventNum)
        Draw.Toggle(x,EventNum,coX,coY,100,15,Toggle, "Delete: "+x,ToggleButton)
        coX+=ColWidth
        EventNum+=1
        if coX>=BaseCoX+(ColWidth*VGColumns):
            coX=BaseCoX
            coY-=ColHeight    
    if coX!=BaseCoX:        
        coY-=ColHeight
    Draw.PushButton("Delete", 1, BaseCoX, coY, 100, 15,"Delete all selected Vertex Groups", DeleteVGroups)
        
    VGListRunning=0


def main():
    
    if GError: return        
    while VGListRunning == 1:
        Draw.UIBlock(buttons, 0)
        
    Window.EditMode(1)
    Window.EditMode(0)
    
    if InEditMode:
        Window.EditMode(1)


if __name__ == '__main__':
    main()


(by the way if you want to change the number of columns that the vertex groups are displayed in, just change the item
VGColumns=4 right near the top of the script to what ever number you want)

Hey there, is it possible to port this to 2.7?
It’s a very useful script and I can’t find its counterpart for the latest versions.

EDIT: To be honest, I’m specifically looking for a script that will automatically remove all empty vertex groups from an object. Would anyone be willing to help, please?

bl_info = {
    "name": "Remove unused Vertex Groups",
    "author": "CoDEmanX",
    "version": (1, 0),
    "blender": (2, 70, 0),
    "location": "Properties Editor > Object data > Vertex Groups > Specials menu",
    "description": "Delete Vertex Groups with no assigned weight of active object",
    "warning": "",
    "wiki_url": "",
    "category": "Mesh"}


import bpy
from bpy.types import Operator


class OBJECT_OT_vertex_group_remove_unused(Operator):
    bl_idname = "object.vertex_group_remove_unused"
    bl_label = "Remove unused Vertex Groups"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return (context.object is not None and
                context.object.type == 'MESH')

    def execute(self, context):

        ob = context.object
        ob.update_from_editmode()
        
        vgroup_used = {i: False 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
        
        for i, used in sorted(vgroup_used.items(), reverse=True):
            if not used:
                ob.vertex_groups.remove(ob.vertex_groups[i])
                
        return {'FINISHED'}


def draw_func(self, context):
    self.layout.operator(
        OBJECT_OT_vertex_group_remove_unused.bl_idname,
        icon='X'
    )


def register():
    bpy.utils.register_module(__name__)
    bpy.types.MESH_MT_vertex_group_specials.prepend(draw_func)


def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.MESH_MT_vertex_group_specials.remove(draw_func)

if __name__ == "__main__":
    register()


It adds an entry to the VGroup specials menu

Worked like a charm, muchas gracias.

If you want to delete all vertex groups of an object, pythonically,
for ob in bpy.data.objects[‘OBJECTNAME’].vertex_groups:
print(ob)
bpy.data.objects[‘OBJECTNAME’].vertex_groups.remove(ob)

7quads, don’t forget to indent!


for ob in bpy.data.objects['OBJECTNAME'].vertex_groups:
    print(ob)
    bpy.data.objects['OBJECTNAME'].vertex_groups.remove(ob)


for ob in bpy.data.objects['OBJECTNAME'].vertex_groups:
    
    bpy.data.objects['OBJECTNAME'].vertex_groups.remove(ob)

How would you apply this to all selected objects? I am trying to remove all vertex groups on multiple objects and I really hope I don’t have to do them one at a time.

It’s as simple as:

for ob in bpy.context.selected_editable_objects:
    for vgroup in ob.vertex_groups:
        ob.vertex_groups.remove(vgroup)
1 Like

Thank you CoDEmanX.

coDEmanX, this is awesome. Tested it in Blender 2.76 and it works like a charm. This is going to save me a LOT of tedious list scrolling.

Much luv, 3D brother.

Sorry, I’m pretty damn new here, but how do you save and run scripts on Blender? I tried copy-pasting into console, don’t think it works…

This works great in 2.77 but it also deletes empty mirror groups, like having only the L groups weighted for an armature and the R groups are just placeholders so the deformation get’s actually mirrored.
I forgot that the empty mirror groups were neccessary and was wondering why my armature went weird suddenly and tracked it down to this having removed the empty R groups.

So could a check be added along “if groupname ends in .R or .L check the opposite for used == True” ?

I’d do it myself by I don’t know (nor like) python nor blender’s api yet, so maybe someone else who does know both can figure it out faster.

Edit: ok seems like I managed to fix this myself

bl_info = {
    "name": "Remove unused Vertex Groups",
    "author": "CoDEmanX",
    "version": (1, 0),
    "blender": (2, 70, 0),
    "location": "Properties Editor > Object data > Vertex Groups > Specials menu",
    "description": "Delete Vertex Groups with no assigned weight of active object",
    "warning": "",
    "wiki_url": "",
    "category": "Mesh"
}


import bpy
from bpy.types import Operator


class OBJECT_OT_vertex_group_remove_unused(Operator):
    bl_idname = "object.vertex_group_remove_unused"
    bl_label = "Remove unused Vertex Groups"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        return (context.object is not None and
                context.object.type == 'MESH')

    def execute(self, context):

        ob = context.object
        ob.update_from_editmode()
        
        vgs = ob.vertex_groups
        vgroup_used = {i: False 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
                    g_name = vgs[g.group].name
                    if g_name.endswith(".L"):
                        vgroup_used[vgs.find(g_name[0:-1] + "R")] = True
                    if g_name.endswith(".R"):
                        vgroup_used[vgs.find(g_name[0:-1] + "L")] = True
        
        for i, used in sorted(vgroup_used.items(), reverse=True):
            if not used:
                ob.vertex_groups.remove(ob.vertex_groups[i])
                
        return {'FINISHED'}


def draw_func(self, context):
    self.layout.operator(
        OBJECT_OT_vertex_group_remove_unused.bl_idname,
        icon='X'
    )


def register():
    bpy.utils.register_module(__name__)
    bpy.types.MESH_MT_vertex_group_specials.prepend(draw_func)


def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.MESH_MT_vertex_group_specials.remove(draw_func)

if __name__ == "__main__":
    register()

Probably fails for groups ending with non capital L/R but meh, works for me.

Hello,

this doesn’t work for me, I get a syntax error (how can I copy script errors?).

It says “Syntax Error: Invalid Syntax” in line 38.

That would be this one:

if g.weight > 0.0:

Awesome add-on. I had been using it everyday, till Blender 2.8 came out. Can you please upgrade it for Blender 2.8.

Updated to 2.8: https://gumroad.com/l/Gxkbp

what are u talking about? just type 0$ and u can download it for free. I’ve upload it on gumroad for convenience because it’s easy to share it that way.

Ah, I stand corrected, didn’t realise you could actually enter 0. Sorry. In that case I’ll kill my message, since it’s probably quite useless now :).

Hey, radenoff! Just to let you know that the gumroad download seems to be corrupted. The rar file doesnt include the 2.8 folder and throws an error when attempting to extract. Any chance you can upload again?

Also, as a suggestion, wouldn’t the script be even easier to share if it was a github repo? That way people would get access to previous versions, and could even contribute with their fixes, in a more structured way than a forum thread. Just a suggestion.

Gumroad forces you to enter an email address, and if you feel like being honest, it doesn’t tell you that they’re giving out your actual email address to the uploader (I just use random words like [email protected]).
The only convenience I see is offering people a more intertwined “option” to donate money (since BA allow file uploads).

But that aside, I came here to say I tweaked CodemanX’s code a while ago but neglected to add that in my notes, and then thought I made it :rofl:


If anyone wants to use CoDEmanX’s code or BloodyRain2k’s, you have to replace [>] with [>].
I believe that’s a glitch from the new forum’s system migration.


Here is the version that I tweaked:
remove_unused_vertex_groups.py (2.9 KB)

The functional difference from CoDEmanX’s is you can run it on multiple objects (alt+click), and it keeps vertex groups used by shape keys and modifiers. Not constraints, as those can be set from bones and other objects and I don’t even use them, so I just didn’t bother ¯\_(ツ)_/¯.

Actually there is another convenience. You will get updates email for the downloaded add-on if you use an accesible email address.