3
$\begingroup$

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?

$\endgroup$

2 Answers 2

4
$\begingroup$

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

$\endgroup$
1
  • $\begingroup$ 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. $\endgroup$
    – eobet
    Commented Mar 10 at 14:48
5
$\begingroup$

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.

$\endgroup$
5
  • $\begingroup$ About the calc_loop_triangles not sure what I should change, I'm very inexperienced in those script types. $\endgroup$
    – jms2505
    Commented Feb 15, 2021 at 12:30
  • $\begingroup$ 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. $\endgroup$
    – scurest
    Commented Feb 15, 2021 at 12:34
  • $\begingroup$ Yeah I see, thanks! Will get it in mind. $\endgroup$
    – jms2505
    Commented Feb 15, 2021 at 12:40
  • $\begingroup$ bm.loops.layers.color[0] no longer seems to exist in Blender 4.0 $\endgroup$
    – eobet
    Commented Mar 18 at 18:13
  • 1
    $\begingroup$ @eobet Yes it does, but there are other places it can be now, depending on the domain and type. See blender.stackexchange.com/a/280720/88681. $\endgroup$
    – scurest
    Commented Mar 18 at 19:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .