Vertex Group's weight to List of Values

Hi everybody,
in my add-on for many reasons I need to use Vertex Groups, but the only ways that I know so far requires a FOR loop and TRY.

weight = [0]*n_verts
for i in range(n_verts):
    try: weight[i] = ob.vertex_groups[0].weight(i)
    except: pass

Is that the most efficient way to do that? Is it possible to directly convert a vertex group to a list of values in one shot? For loops can be time consuming with Python.

It shouldn’t be necessary to specify the length of the list like you do. Python’s lists are dynamicly-sized.
I think what you want is object.vertex_groups. If you want to keep the association between the vertex index and the weight, you can use a dictionary:

dict = {}
for w in bpy.context.active_object.vertex_groups.active:
    dict[index] = w

I hope that helps. It should be faster since you’re looping through the weight group, not through the vertices.

I thought that assigning the value should have been a little bit faster than using append… Maybe I’m wrong.

Anyway, unfortunately your code doesn’t work:
TypeError: 'VertexGroup' object is not iterable

Yeah, actually I misread what that does. I thought I had done that before!

Here’s two ways of doing this, and I’ve set up code to measure how long they take and print it to the console. The second seems faster. You should clean up the ugly try/except block because it’s kind of a hack, but it works and it’s quick. It’s reliably ~half the time of the first.

import bpy
import time

start = time.time()

dict = {}
ob = bpy.context.active_object #any object will do
for v in range(len(ob.data.vertices)):
    try:
        dict[v] = ob.vertex_groups.active.weight(v)
    except RuntimeError:
        dict[v] = 0
    
timeElapsed = time.time() - start

print("Time elapsed:",timeElapsed)

start = time.time()

dict = {}
ob = bpy.context.active_object #any object will do
for v in ob.data.vertices:
    try:
        dict[v.index] = v.groups[0].weight
    except RuntimeError:
        dict[v.index] = 0
    except IndexError:
        dict[v.index] = 0
    
timeElapsed = time.time() - start

print("Time elapsed:",timeElapsed)

(edit, forgot to make it a code block. currently looking at this and seeing if I can find a better way)

1 Like

Thank Joseph for your help. I actually tried also that option, but there is a small thing that is not considered in the code. If you have more groups (let’s say 5), and a vertex is in only the last of them, then it will be indexed as 0, while the vertex group itself will be the index 4. Try creating many groups, but putting the vertices in only the last of them. If you type:

bpy.context.object.data.vertices[0].groups[0].group

You will find that the index is for example 4.

Starting from your code, it should be corrected as following:

import bpy
import time

vertexgroup_id = 1

start = time.time()

dict = {}
ob = bpy.context.active_object #any object will do
for v in range(len(ob.data.vertices)):
    try:
        dict[v] = ob.vertex_groups[vertexgroup_id].weight(v)
    except RuntimeError:
        dict[v] = 0

timeElapsed = time.time() - start

print('Time elapsed A:',timeElapsed)

start = time.time()

dict = {}
ob = bpy.context.active_object #any object will do
for v in ob.data.vertices:
    try:
        for g in v.groups:
            if g.group == vertexgroup_id:
                dict[v.index] = v.groups[0].weight
                break
    except RuntimeError:
        dict[v.index] = 0
    except IndexError:
        dict[v.index] = 0

timeElapsed = time.time() - start

print('Time elapsed B:',timeElapsed)

It is still a little bit faster, but not that much… This is why I asked for a function that returns all the values of one group as list of values. If a vertex is not in that group, than it will be a zero.

Actually, it would be great to have a function for read a Vertex Group all at once and a function for directly fill it with a list. In my Reaction-Diffusion simulation the bottleneck is reading and writing:


The link you posted is really cool.
Anyways, I think the data is actually stored in the MeshVertex itself. I had always assumed it was stored as a separate layer, hence my mistaken assumption earlier. I can’t even find a weight_group layer in Bmesh.

Have you tried doing it with vertex colors instead? I believe the data for vertex colors is saved as a bpy_prop_collection which might be better for you. On the other hand, the color layer is stored on face-corners, so you’d have a longer list to deal with.

I imagine it’s possible to do what you’re doing without having to store the data in weight groups directly. Perhaps there’s a way to leverage BMesh’s custom data layers? Or the ‘tag’ parameter (which is new in 2.8)? I haven’t had any luck playing around with them, though.

Another two ideas, both pretty far out there: use C for that portion of the code- you can use ctypes with a .dll that only searches mesh data for weight groups, and you’d get the mesh data from Blender with object.data.as_pointer() and pass that over to your .dll. I assume you can send a pointer with the weight-group list out of your .dll, read it into Python, then close the .dll and free the memory.
I’ve never used ctypes myself, and of course you’d have to have a solid understanding of the way the data is stored to do anything with it. But C is pretty reliably faster than Python because it is compiled.

Second: maybe you can use threading for the Python code? Threading is hard to do in Blender, but it’s possible as long as all of the threads close before the script terminates. This won’t necesarilly make it faster. But perhaps you could have sepearate threads each looping through a piece of the list. Take a look at this page from the API documentation: https://docs.blender.org/api/master/info_gotcha.html?highlight=thread

That being said… I’ve never done anything like that.

Joseph, thank you very much for your help!

Vertex Colors: I considered that, but what I need is a Vertex Group beacuse I want to use that for modifiers and other things.

Bmesh Layer: This is quite interesting option, but in this case I will loose the interactivity, and also the ability to use that for modifiers. Nice one though, I’ll consider for the future!

Using C: I’m really trying to avoid that, I’m not a programmer and I would like to keep it under Python for the moment.

Threading: I tried with the Threading module, but then I realised that I should use Multiprocessing in order to use more cores. So far it doesn’t work… I’ll try to understand better how it works, this can give me many advantages for Tissue’s Tessellation as well!

I think it might be possible to improve performance if you did the internal calculations as vertex colors or bmesh custom data and then copied them to weight paint just in time. That way, you’d only have to do the slow conversion when you need it, instead of every frame. You could keep the interactivity in vertex-paint mode, which would convert to weight paint (you would only have to convert once instead of twice, maybe). I’m not sure if this is possible or not for your case. But either way, here’s a stack exchange page with code for copying vertex colors to weight paint (look at the second answer for my code, which can do the exchange back-and-forth. I need to turn this into an addon at some point). https://blender.stackexchange.com/questions/15172/turn-weight-paintvertex-groups-into-vertex-paint

As for using C, maybe using Cython could make it easier? Cython is a Pyhon-to-C conversion language (more-or-less), but it relies on Python which can vary from system to system or from Blender version. So apparently that comes with difficulties in distribution. Take a look at this devtalk page, which also discusses threading some: Noob question - Does Cython brings similar performance to pure compiled C code?
It looks like the excellent performance that Animation Nodes provides is at least partially because of C code replacing pure Python, but this requires some trickery at the setup phase which I think is in the init.py of that addon (I looked a long time ago, out of curiosity).

I wish I could help more with a ‘conventional’ solution, but I don’t know if there is one.

For the conversion to Colors, actually Tissue (my add-on) do that, together with some tricks with vertex groups:


I would really prefer to keep only on vertex groups, because in that way you can run animations with modifiers working with that. As designer I’m more interested in that, but for rendering Vertex Colors could make sense. In the next releases I will consider it.

Regarding the performances, now the “math” runs really fast thanks to Numba (if you have it installed). Looking at some comparisons, the only thing that could go faster should be running with the GPU, if I’m not wrong.

1 Like