3

I'm working on a custom exporter for an external software. I need to get a list of the vertex colors from a triangulated mesh.

To get the triangulated mesh I use this code:

bm = bmesh.new()
bm.from_mesh(SceneObj.to_mesh())
bmesh.ops.triangulate(bm, faces=bm.faces, quad_method='BEAUTY', ngon_method='BEAUTY')

With normal meshes I use this code:

#Get vertex color list without duplicates
VertexColList = []
if len(MeshObject.vertex_colors):
    if hasattr(MeshObject.vertex_colors.active, 'data'):
        for layer in MeshObject.vertex_colors:
            for vertex in layer.data:
                VertexColList.append(
                    (vertex.color[0] * .5, vertex.color[1] * .5, vertex.color[2] * .5, vertex.color[3])
                )
        VertexColList = list(dict.fromkeys(VertexColList))

But that piece of code not works in a bmesh, what should I change to make it works?

jms2505
  • 45
  • 4

2 Answers2

5

Each loop (= corner of a poly) has its own vertex color. You can print the vertex color for each corner with

# Get the first Vertex Color layer; can also use its name (eg. "Col")
layer = bm.loops.layers.color[0]

for face in bm.faces: for loop in face.loops: color = loop[layer] # gives a Vector((R, G, B, A)) print(color)

Btw, if possible you should get the triangulation with calc_loop_triangles instead, since it gives you the triangulation that Blender actually draws.

scurest
  • 10,349
  • 13
  • 31
  • About the calc_loop_triangles not sure what I should change, I'm very inexperienced in those script types. – jms2505 Feb 15 '21 at 12:30
  • For a bmesh, bm.calc_loop_triangles gives a list of tuples of loops, one tuple per tri. So you'd do for tri in bm.calc_loop_triangles(): for loop in tri:. A regular mesh has calc_loop_triangles too, but it's slightly different. – scurest Feb 15 '21 at 12:34
  • Yeah I see, thanks! Will get it in mind. – jms2505 Feb 15 '21 at 12:40
  • bm.loops.layers.color[0] no longer seems to exist in Blender 4.0 – eobet Mar 18 '24 at 18:13
  • 1
    @eobet Yes it does, but there are other places it can be now, depending on the domain and type. See https://blender.stackexchange.com/a/280720/88681. – scurest Mar 18 '24 at 19:41
4

Bmesh.from_object

Doh, @scurest Answered while I was putting the bins out, may as well post

import bpy
import bmesh

context = bpy.context ob = context.object dg = context.evaluated_depsgraph_get()

bm = bmesh.new() bm.from_object(ob, dg) print("Evaluated bmesh object", ob.name, "mesh:", ob.data.name) tris = bm.calc_loop_triangles() print( "faces", len(bm.faces), "edges", len(bm.edges), "verts", len(bm.verts), "tris", len(tris) )

for name, cl in bm.loops.layers.color.items(): print("Colour Layer", name)

for i, tri in enumerate(tris):
    print("Tri", i)
    for loop in tri:
        print(
            "loop", loop.index, 
            "face", loop.face.index,
            "edge", loop.edge.index,
            "vert", loop.vert.index, 
            "colour", loop[cl][:]
            )

Result on default plane, one vertex colour layer added, one subsurf modifier.

Evaluated bmesh object Plane mesh: Plane
faces 4 edges 12 verts 9 tris 8
Colour Layer Col
Tri 0
loop 0 face 0 edge 2 vert 0 colour (1.0, 1.0, 1.0, 1.0)
loop 1 face 0 edge 8 vert 5 colour (1.0, 1.0, 1.0, 1.0)
loop 2 face 0 edge 11 vert 8 colour (1.0, 1.0, 1.0, 1.0)
Tri 1
loop 0 face 0 edge 2 vert 0 colour (1.0, 1.0, 1.0, 1.0)
loop 2 face 0 edge 11 vert 8 colour (1.0, 1.0, 1.0, 1.0)
loop 3 face 0 edge 1 vert 4 colour (1.0, 1.0, 1.0, 1.0)
Tri 2
loop 4 face 1 edge 3 vert 5 colour (1.0, 1.0, 1.0, 1.0)
loop 5 face 1 edge 4 vert 1 colour (1.0, 1.0, 1.0, 1.0)
loop 6 face 1 edge 9 vert 6 colour (1.0, 1.0, 1.0, 1.0)
Tri 3
loop 4 face 1 edge 3 vert 5 colour (1.0, 1.0, 1.0, 1.0)
loop 6 face 1 edge 9 vert 6 colour (1.0, 1.0, 1.0, 1.0)
loop 7 face 1 edge 8 vert 8 colour (1.0, 1.0, 1.0, 1.0)
Tri 4
loop 8 face 2 edge 9 vert 8 colour (1.0, 1.0, 1.0, 1.0)
loop 9 face 2 edge 5 vert 6 colour (1.0, 1.0, 1.0, 1.0)
loop 10 face 2 edge 6 vert 3 colour (1.0, 1.0, 1.0, 1.0)
Tri 5
loop 8 face 2 edge 9 vert 8 colour (1.0, 1.0, 1.0, 1.0)
loop 10 face 2 edge 6 vert 3 colour (1.0, 1.0, 1.0, 1.0)
loop 11 face 2 edge 10 vert 7 colour (1.0, 1.0, 1.0, 1.0)
Tri 6
loop 12 face 3 edge 11 vert 4 colour (1.0, 1.0, 1.0, 1.0)
loop 13 face 3 edge 10 vert 8 colour (1.0, 1.0, 1.0, 1.0)
loop 14 face 3 edge 7 vert 7 colour (1.0, 1.0, 1.0, 1.0)
Tri 7
loop 12 face 3 edge 11 vert 4 colour (1.0, 1.0, 1.0, 1.0)
loop 14 face 3 edge 7 vert 7 colour (1.0, 1.0, 1.0, 1.0)
loop 15 face 3 edge 0 vert 2 colour (1.0, 1.0, 1.0, 1.0)

Applying per-vertex colors to new Bmesh

set a specified vertex color to black via python

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Has this changed in 2024 for Blender 4.0? When I run the above code, I get the output from the initial two print statements, but nothing from the for loop. Even though I have vertex colors baked into a color attribute entry, bm.loops.layers.color.items has 0 entries. – eobet Mar 10 '24 at 14:48