1

I have an object with vertex groups already set up and materials already added. I want to run through all of vertex groups in that object and randomly assign one of the materials to it. How do I do this? I can run through the vertex groups but I'm struggling to assign the material to it.

Thanks

1 Answers1

0

A vertex group, as the name says, is a group of vertices. A material is assigned to a face, not to a group. So how do you translate between the two? This will cause issues in a moment.

How to count the number of faces of each vertex group?

I think the most reasonable approach is the "select a face if all its vertices are selected" - it's also intuitive because that's how selection in Blender works. So I'm using the Bmesh - All Corners solution. First let's prepare Suzanne for make-up:

Whoops! You can't select lips without selecting the mouth as well. Again, this will cause a problem in a moment. Also, notice how the vertex groups and the material slots appear in the same order - this is needed, because the script will operate on indices rather than names - bmesh doesn't even store the names (neither does a mesh, only an object stores this information, to my knowledge).

import bpy, bmesh
from bpy import context as C, data as D
from collections import Counter

me = C.object.data bm = bmesh.from_edit_mesh(me)

layer = bm.verts.layers.deform.active for f in bm.faces: groups = (v[layer].keys() for v in f.verts) groups_set = set(next(groups)) for g in groups: groups_set.intersection_update(g) if groups_set: f.material_index = groups_set.pop() + 1 else: f.material_index = 0

Whoops! The entire mouth (the inside) has the lip color. Or at least for me this is the case, since I'm just popping from a set, I'm getting the first vertex group found for a given face - Lips is indexed before Mouth so it was found first, and is popped first. However, fixing this by swapping both vertex groups would be a mistake - while current CPython implementation is deterministic in this regard, there's no formal guarantee that this will always be so:

A set is an unordered collection

source

Instead, just explicitly prioritize the index of the Mouth vertex group:

import bpy, bmesh
from bpy import context as C, data as D
from collections import Counter

me = C.object.data bm = bmesh.from_edit_mesh(me)

layer = bm.verts.layers.deform.active for f in bm.faces: groups = (v[layer].keys() for v in f.verts) groups_set = set(next(groups)) for g in groups: groups_set.intersection_update(g) if 3 in groups_set: # prioritize Mouth f.material_index = 4 elif groups_set: f.material_index = groups_set.pop() + 1 else: f.material_index = 0

Markus von Broady
  • 36,563
  • 3
  • 30
  • 99