Fairly new to blender python, though have some experience with python outside of blender, I'm trying to work out why this bit of code is only ever working on the first color attribute and not the currently selected one.

def paint_map(self, mesh, map, color):
    i = 0
    for poly in mesh.polygons:
        for _ in poly.loop_indices:
            map[i].color = color
            i += 1

def paint_mesh(self, mesh, color):
    if len(mesh.vertex_colors) == 0:
    self.paint_map(mesh, mesh.vertex_colors.active.data, color)

def run(self, context):
    objs = context.selected_objects

    if len(objs) > 0:
        for obj in objs:
            if obj.sollum_type == SollumType.DRAWABLE_GEOMETRY:
                self.paint_mesh(obj.data, self.color)
                    f"{obj.name} was successfully painted.")
                    f"{obj.name} will be skipped because it is not a {SOLLUMZ_UI_NAMES[SollumType.DRAWABLE_GEOMETRY]} type.")
        self.message("No objects selected to paint.")
        return False

    return True

how this code currently behaves https://i.stack.imgur.com/oEix4.jpg

Whilst researching the online documentation I noticed that mesh.vertex_colors is depreciated and its best to use color_attributes moving forward. I've played around with it a bit and can't wrap my head around it.

I did notice if I do the following


within the python console it does indeed return the selected color attribute, I can't however work out how to rework the current codebase to use it however.

Python console tests https://i.stack.imgur.com/G9f1q.jpg

If someone could help me work out how to get and use the currently selected color attribute of the selected meshes I'd be very grateful! Thanks in advance! CuppaT


1 Answer 1


I can confirm this is a bug introduced in Blender 3.2. I'll file a bug report (edit: done).

In the meantime, if you want to continue using the vertex_colors API, you can get the active vertex color with mesh.vertex_colors.get(mesh.attributes.active_color.name). Warning: this may be None!

If you want to move over to the color_attributes API instead, read on...

Here's the main differences between the old and new APIs.

Vertex colors

  • Create with v = mesh.vertex_colors.new(name).
  • Always stores one color for each mesh corner (loop) ie. len(v.data) == len(mesh.loops).
  • Always stores colors as byte colors, with one byte for each of RGBA.
  • Accessing the color with v.data[i].color returns the color converted to float in sRGB space.

Color attributes

  • Create with v = mesh.color_attributes.new(name, type, domain).
  • domain can be either 'POINT' or 'CORNER', depending on whether you want to store a color at each vertex, or at each face corner.
  • type can be either 'FLOAT_COLOR' or 'BYTE_COLOR', depending on whether you want to store each RGBA component as a float or as a byte.
  • Classic vertex colors correspond to color_attributes.new(name, type='BYTE_COLOR', domain='CORNER'). In fact the mesh.vertex_colors endpoint now just exposes the subset of color attributes that are BYTE_COLOR + CORNER.
  • Accessing the color with v.data[i].color returns the color converted to float in linear space. In 3.4 they added v.data[i].color_srgb to access the color in sRGB space instead.

With that in mind, your code is really easy to update.

def paint_map(self, color_attr, color):
    for datum in color_attr.data:
        # Uses color_srgb to match the behavior of the old
        # vertex_colors code. Requires 3.4+.
        datum.color_srgb = color
    # (You could also use foreach_set here instead.)

def paint_mesh(self, mesh, color):
    if not mesh.color_attributes:
        mesh.color_attributes.new("Color", 'BYTE_COLOR', 'CORNER')
    self.paint_map(mesh.attributes.active_color, color)

(Note that due to a bug it's actually possible to have color attributes but no active_color right now.)

  • $\begingroup$ This works perfectly! thank you so much for you help <3 $\endgroup$ Feb 16, 2023 at 15:05

You must log in to answer this question.

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