Page MenuHome

get vertex group values from evaluated mesh object
Closed, ArchivedPublic

Description

System Information
Operating system: Darwin-17.7.0-x86_64-i386-64bit 64 Bits

Blender Version
Broken: version: 2.83.12, branch: master, commit date: 2021-01-26 15:41, hash: rBad0da4275159
Worked:

Short description of error
the task is, get vertex group value for each vertex in evaluated object so modifiers changing vertices and groups are applied in result

Exact steps for others to reproduce the error
open blend with test object with groups and modifiers, uncomment one of attempts and see result

one suggestion, please, can we have foreach_get and foreach_set for vertex groups? or at least something like VertexGroup.weight(index, default=None) like in bmesh BMDeformVert.get(key, default=None)

code here, maybe there is a rookie mistake you can spot on a first glance

import bpy
import bmesh
import numpy as np
import uuid

o = bpy.data.objects['Plane']


def get_ws0(o, ):
    me = o.data
    vg = o.vertex_groups.active
    l = len(me.vertices)
    a = np.arange(l).tolist()
    vg.add(a, 0.0, 'ADD', )
    ws = np.zeros(l, dtype=np.float32, )
    for v in me.vertices:
        i = v.index
        ws[i] = vg.weight(i)
    return ws

# ws = get_ws0(o, )
# print(ws)

# result:
# [0.9999534 0.        0.        1.       ]
# ok, got weights, but object has modifiers they need to be applied


def get_ws1(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    me = eo.data
    
    l = len(me.vertices)
    vg = eo.vertex_groups.active
    # add zero to all to have all verts in group
    a = np.arange(l).tolist()
    vg.add(a, 0.0, 'ADD', )
    
    ws = np.zeros(l, dtype=np.float32, )
    for v in me.vertices:
        i = v.index
        ws[i] = vg.weight(i)
    
    return ws

# ws = get_ws1(o, )
# print(ws)

# result:
# [0. 0. 0. 0. 0. 0. 0. 0.]
# zeroed out?


def get_ws2(o, ):
    # so, lets try to add all verts first, and to all of them, maybe modifiers does something with that
    l = len(o.data.vertices)
    a = np.arange(l).tolist()
    for vg in o.vertex_groups:
        vg.add(a, 0.0, 'ADD', )
    
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    me = eo.data
    
    vg = eo.vertex_groups.active
    l = len(me.vertices)
    ws = np.zeros(l, dtype=np.float32, )
    for v in me.vertices:
        i = v.index
        ws[i] = vg.weight(i)
    
    return ws

# ws = get_ws2(o, )
# print(ws)

# result:
# RuntimeError: Error: Vertex not in group
# nope..


def get_ws3(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    me = eo.data
    
    l = len(me.vertices)
    vg = eo.vertex_groups.active
    vgi = vg.index
    ws = np.zeros(l, dtype=np.float32, )
    for v in me.vertices:
        i = v.index
        print(len(v.groups))
        for g in v.groups:
            if(g.group == vgi):
                ws[i] = g.weight
                break
    
    return ws

# ws = get_ws3(o, )
# print(ws)

# result:
# 0
# 0
# 0
# 0
# 0
# 0
# 0
# 0
# [0. 0. 0. 0. 0. 0. 0. 0.]
# each vertex groups property is empty?


def get_ws4(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    vg = eo.vertex_groups.active
    me = eo.data
    l = len(me.vertices)
    ws = np.zeros(l, dtype=np.float32, )
    for v in me.vertices:
        i = v.index
        # bad practice, but do this as an experiment
        try:
            ws[i] = vg.weight(i)
        except RuntimeError:
            print('error')
    
    return ws

# ws = get_ws4(o, )
# print(ws)

# result:
# error
# error
# error
# error
# error
# error
# error
# error
# [0. 0. 0. 0. 0. 0. 0. 0.]
# not even this works..


def get_ws5(o, ):
    vg = o.vertex_groups.active
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    bm = bmesh.new()
    bm.from_object(eo, depsgraph, deform=True, cage=False, face_normals=False, )
    bm.verts.ensure_lookup_table()
    layer = bm.verts.layers.deform.active
    gi = vg.index
    ws = np.zeros(len(bm.verts), dtype=np.float32, )
    for v in bm.verts:
        ws[v.index] = v[layer].get(gi, 0.0, )
    bm.free()
    return ws

# ws = get_ws5(o, )
# print(ws)

# result:
# [0.9999534  0.98888767 0.99569315 1.         0.9999534  0.98888767
#  0.99569315 1.        ]
# success, but what are the costs..


def get_ws6(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    eme = eo.to_mesh()
    
    vg = eo.vertex_groups.active
    l = len(eme.vertices)
    a = np.arange(l).tolist()
    vg.add(a, 0.0, 'ADD', )
    
    ws = np.zeros(l, dtype=np.float32, )
    for v in eme.vertices:
        i = v.index
        print(i)
        ws[i] = vg.weight(i)
    
    eo.to_mesh_clear()
    return ws

# ws = get_ws6(o, )
# print(ws)

# result:
# [0. 0. 0. 0. 0. 0. 0. 0.]
# nope..


def get_ws7(o, ):
    l = len(o.data.vertices)
    a = np.arange(l).tolist()
    for vg in o.vertex_groups:
        vg.add(a, 0.0, 'ADD', )
    
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    eme = eo.to_mesh()
    
    vg = eo.vertex_groups.active
    l = len(eme.vertices)
    ws = np.zeros(l, dtype=np.float32, )
    for v in eme.vertices:
        i = v.index
        ws[i] = vg.weight(i)
    
    eo.to_mesh_clear()
    return ws

# ws = get_ws7(o, )
# print(ws)

# result:
# RuntimeError: Error: Vertex not in group
# again..


def get_ws8(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    eme = eo.to_mesh()
    
    vg = eo.vertex_groups.active
    vgi = vg.index
    l = len(eme.vertices)
    ws = np.zeros(l, dtype=np.float32, )
    for v in eme.vertices:
        i = v.index
        print(len(v.groups))
        for g in v.groups:
            if(g.group == vgi):
                ws[i] = g.weight
                break
    
    eo.to_mesh_clear()
    return ws

# ws = get_ws8(o, )
# print(ws)

# result:
# 0
# 0
# 0
# 0
# 0
# 0
# 0
# 0
# [0. 0. 0. 0. 0. 0. 0. 0.]
# again..

Event Timeline

Philipp Oeser (lichtwerk) changed the task status from Needs Triage to Needs Information from User.Feb 10 2021, 6:23 PM

This one does it for me:
(use preserve_all_data_layers https://docs.blender.org/api/master/bpy.types.Object.html#bpy.types.Object.to_mesh)

def get_ws8(o, ):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    eo = o.evaluated_get(depsgraph)
    eme = eo.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
    
    vg = eo.vertex_groups.active
    vgi = vg.index
    l = len(eme.vertices)
    ws = np.zeros(l, dtype=np.float32, )
    for v in eme.vertices:
        i = v.index
        print(len(v.groups))
        for g in v.groups:
            if(g.group == vgi):
                ws[i] = g.weight
                break
    
    eo.to_mesh_clear()
    return ws

ws = get_ws8(o, )
print(ws)

Does this work for you?

Also wondering if T82831 could be relevant for you? (Group Add default weights with the VertexWeightEdit modifier)

@Philipp Oeser (lichtwerk) oh i am terribly sorry, i missed preserve_all_data_layers, thank you!
can i have a question? are going vertex groups, vertex colors etc. eventually replaced with attributes in future? would be nice to have unified access to all data

Philipp Oeser (lichtwerk) closed this task as Archived.Feb 27 2021, 6:51 PM

are going vertex groups, vertex colors etc. eventually replaced with attributes in future? would be nice to have unified access to all data

You'll probably be able to access them as attributes as well (geometry nodes already handles them like "regular" attributes), but the legacy access will stay as well (I dont think this will removed at all)

In regards to the original report, I think this can be closed then?
Feel free to comment again though if issues persist.