Can't figure out how Vertex Groups works


I need a little help understanding vertex groups in Blender 2.69.

As I understand vertex groups are an object-level data, you have each mesh-type object have it’s own list of vertex groups.

The problem is that multiple objects can share the same mesh data and each vertex on the mesh have it’s own list of groups they are part of, but it can’t understand how everything is related.

An example:

mesh_data is some mesh. We have OBJ_A and OBJ_B both pointing to this mesh.

OBJ_A have vertex groups VG1 and VG2. OBJ_B have vertex groups VG3 and VG4. I then go into edit mode using OBJ_A and assign some vertices to VG1 in OBJ_A (prior to that, none of the vertices are associated to groups). Then I go to OBJ_B into edit mode without assigning ANY vertices to ANY group and select the first group (VG3 in OBJ_B case) and hit “Select”. All my vertices assigned to VG1 get selected for no reason.

So to my understanding there are the following options

1 - This is a bug
2 - Vertex groups are assigned to the mesh data and the object is just a pointer to that data.

In case 1 I can open a bug report if one is not already open, but in case 2 I didn’t found any way to access vertex group data from the mesh in Python.

Can someone shed some light into this matter please?

Moved from “General Forums > Blender and CG Discussions” to “Coding > Python Support”

Interesting, this appears to be a bug. I would expect that each vertex group is completely independent of any other group.

IIRC, the situation with vertex groups is actually quite messy.

Each vertex group actually consists of 2 parts:

  1. Object->defbase = list of bDeformGroup’s – These are the object-level “labels” for vertex groups. This is where the names for each vertex group lives
  2. Mesh -> MDeformVert + MDeformWeight – These are the mesh-level data representations of vertex groups. Each MDeformVert corresponds to one vertex in the mesh. For each vertex, within MDeformVert there is an array of MDeformWeights. Each one of those MDeformWeights corresponds to that vertex belonging to some vertex group, which is identified using “MDeformWeight.def_nr” (which uses the 0-based index of the vertex group within the owning object’s vertex group list).

Now, getting back to your original question:
The above details are how Blender represents the data internally in C. However, for your purposes, the Python API will likely have some differences (mainly in terms of naming, though in some cases, nicer abstractions over the underlying data do also occur). You may want to consult my shape keys transfer script, which IIRC has a feature for transferring vertex groups too, for how to do this.

Thanks, I’m gonna look into it.

After messing with it a little more I noticed that in python each vertex is only interested in the index of the vertex group, so if I look into a vertex it will have a weight for VG at index 0, another at index 1 and so on.

So if a mesh is used by both OBJA and OBJB and OBJA have VGA and OBJ have VGB, each vertex in this mesh will only know that on the “first” group (index 0) it has weight 1.0. That’s why when I change weights for VGA in OBJA it will affect weights for VGB in OBJB as they’re both at index 0.

The same happens when I do the oposite. If I call bpy.objects[“OBJA”].vertex_groups[“VGA”].weight(0) (the weight of the first vertex) and do the same to “OBJB” they both will return the same weight even if I never assigned vertices to VGB, only to VGA.

I can get used to this behaviour but I still find it strange. Why not make vertex groups a mesh level only data then? Each object the mesh is linked to would show the vertex group data associated with that mesh.

Sure, you can have different labels in vertex groups be used to link those to different armatures, but what use is that if I still can only have one weight per group position for each vertex?

This design dates back at least 10+ years. AFAIK, the main rationale for it seems to be that we needed a way of having vertex groups for different types of objects (not just meshes), so that’s why the labels ended up on object level instead, so that they would be easier to access in a consistent manner.