1
$\begingroup$

I have been struggling with trying to find a way to do this. It's related to my previous efforts here: How to get list of bm.verts that belong to a deform layer? When I do this

for vert in bm.verts:
        dvert = vert[layer_deform]

I get a dictionary of deform layer numbers (keys) and weights (values) per bm.vert. What I'd like to achieve is a list containing lists of verts, based on their deform layer (vertex group) number. So it should look something like this:

vertex_lists = [[<BMVert(0x000002A7818090B0), index=12>, <BMVert(0x000002A7818090E8), index=13>], [<BMVert(0x000002A7818090B0), index=15>, <BMVert(0x000002A7818090E8), index=20>], [<BMVert(0x000002A7818090B0), index=44>, <BMVert(0x000002A7818090E8), index=24>]]

I'd like to achieve this in order to automate further bmesh.ops. I am guessing I need to find a way to iterate over bm.verts and append them to a list based on their layer deform key (vertex group number). How do I group the verts into separate lists based on their respective layer_deform numbers?

$\endgroup$
0
$\begingroup$

Code below creates a dictionary of vertex, weight pairs for each vg. The defaultdict is great for this, as can set the default item to an empty list and append directly on key (in this case vg name)

import bpy
import bmesh
from collections import defaultdict
ob = bpy.context.edit_object
me = ob.data
names = tuple(vg.name for vg in ob.vertex_groups)
bm = bmesh.from_edit_mesh(me)
layer_deform = bm.verts.layers.deform.active
if layer_deform:
    vgs = defaultdict(list)
    for v in bm.verts:
        for vg_index, weight in v[layer_deform].items():
            name = names[vg_index]
            vgs[name].append((v, weight))

    for k, v in vgs.items():
        print(k, v)

sample output

Group [(<BMVert(0x7f99f0325010), index=0>, 1.0), (<BMVert(0x7f99f0325048), index=1>, 1.0), (<BMVert(0x7f99f0325080), index=2>, 1.0), (<BMVert(0x7f99f03250b8), index=3>, 1.0), (<BMVert(0x7f99f03250f0), index=4>, 1.0), (<BMVert(0x7f99f0325128), index=5>, 1.0), (<BMVert(0x7f99f0325160), index=6>, 1.0)]
Group.001 [(<BMVert(0x7f99f03250f0), index=4>, 1.0), (<BMVert(0x7f99f0325160), index=6>, 1.0)]
Group.002 [(<BMVert(0x7f99f0325128), index=5>, 1.0), (<BMVert(0x7f99f0325198), index=7>, 0.4263862371444702)]

can access with

for v, w in vgs[vg.name]:
    print("vertex", v.index, "has weight", w)

for a list of lists as requested in question, define array for length of vgs

vgs = [[]] * len(ob.vertex_groups) # create a list for each vg

then populate with

for vg_index in v[layer_deform].keys():
    vgs[vg_index].append(v)

Related: Accessing weights of a bmesh

$\endgroup$
  • $\begingroup$ The very last part seems to be appending any verts that belong to a vertex group to all the lists in vgs. I might be missing something. This has helped tremendously though, and I'm sure I'll figure it out from here on. If you can, please check the last two lines in a situation where there's two vert groups. One contains verts, the other one doesn't. In my case there is then two lists generated for vgs, and both will contain the vertices that only the first vertex group actually contains. $\endgroup$ – z01ks Mar 25 at 0:06
  • $\begingroup$ Achieved my goal by using the first codeblock you showed and only doing vgs[name].append(v). Would be interested in knowing if this is less efficient than the last lines you provided would be. I'm starting to look into optimizing the add-on that I've been working on, and I'm not familiar with the different performance aspects in python whatsoever. $\endgroup$ – z01ks Mar 25 at 0:30
  • $\begingroup$ Also, in order to create a list containing lists of verts, I did verts_in_groups = list(vgs.values()) $\endgroup$ – z01ks Mar 25 at 0:53
  • $\begingroup$ I like the defaultdict. Re comments above i) check your logic, ii) time the code, iii) will fail when there are empty vertex groups. $\endgroup$ – batFINGER Mar 25 at 6:17

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.