3
$\begingroup$

So there is no built-in functionality to invert vertex color o.O

How can I invert vertex color on an active object?

$\endgroup$
2
$\begingroup$

This is all that is needed, and the way I prefer to access vertex colors. It works in any mode:

import bpy

obj = bpy.context.active_object

for ipoly in range(len(obj.data.polygons)):
    for idx, ivertex in enumerate(obj.data.polygons[ipoly].loop_indices):
        ivert = obj.data.polygons[ipoly].vertices[idx]
        col = obj.data.vertex_colors.active.data[ivertex].color
        obj.data.vertex_colors.active.data[ivertex].color = tuple(1-x for x in col)

If you want UI button add it with this micro addon (save as .py file into addon folder):

enter image description here

bl_info = {
    "name": "Invert Vertex Colors",
    "location": "3D viewport > Header > Paint menu in Vertex Paint mode",
    "version": (0,1,0),
    "blender": (2,7,6),
    "description": "Inverts vertex colors of active paint layer",
    "author": "Jerryno",
    "category": "Paint",
}

import bpy

class InvertVertexColors(bpy.types.Operator):
    bl_idname = "paint.invert_colors"
    bl_label = "Invert Vertex Colors"
    bl_description = "Invert vertex colors of active paint layer"

    @classmethod
    def poll(self, context):
        try:
            return context.active_object is not None
        except (AttributeError, KeyError, TypeError):
            return False

    def execute(self, context):
        active = context.active_object
        for ipoly in range(len(active.data.polygons)):
            for idx, ivertex in enumerate(active.data.polygons[ipoly].loop_indices):
                ivert = active.data.polygons[ipoly].vertices[idx]
                col = active.data.vertex_colors.active.data[ivertex].color
                active.data.vertex_colors.active.data[ivertex].color = tuple(1-x for x in col)
        return{'FINISHED'}

def menu_entry(self, context):
    self.layout.operator("paint.invert_colors", icon='IMAGE_ALPHA')

def register():
    bpy.utils.register_module(__name__)
    bpy.types.VIEW3D_MT_paint_vertex.append(menu_entry)

def unregister():
    bpy.utils.unregister_module(__name__)
    bpy.types.VIEW3D_MT_paint_vertex.remove(menu_entry)

if __name__ == "__main__":
    register()
$\endgroup$
  • 1
    $\begingroup$ aliasing can help speed up the dot lookups of active.data.polygons and active.data.vertex_colors.active_data. I suggest this, it's always less dense to read. gist.github.com/zeffii/8eede8ff41d6dac47448/revisions $\endgroup$ – zeffii Jan 13 '16 at 14:54
  • 1
    $\begingroup$ @zefii nice, also good it's a gist now, feel free to make it public.) $\endgroup$ – Jaroslav Jerryno Novotny Jan 13 '16 at 15:30
1
$\begingroup$

You can invert vertex colors with this script (which I found online and improved):

import bpy
import random

# get and store the object in object mode
obj = bpy.context.active_object
mesh = obj.data

# set active vertex paint layer
color_layer = mesh.vertex_colors.active

v = 0  # current vertex in loop

# iterate over the verices and invert their color
for poly in mesh.polygons:
    for idx in poly.loop_indices:
        col = [(1 - color_layer.data[v].color[i]) for i in range(3)]
        color_layer.data[v].color = col
        v += 1

# We have to refresh Vertex Paint mode to see the changes
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.mode_set(mode='VERTEX_PAINT')

Just select your object, set one of the vertex colors on your object to be active, switch to Vertex Pain mode and run the script.

It would be nice if someone improved it further and added UI button :)

$\endgroup$
1
$\begingroup$

or use foreach_set

import bpy

def invert_vcols(color_layer):

    # foreach_get requires us to pass it a container (list) with
    # the same amount of elements as " len(color_layer.data)*3 "
    # 3: because each vertex color has 3 components: [r,g,b]
    components = [1.0 for n in range(len(color_layer.data)*3)]

    # this writes the current [r,g,b,r,g,b,.....] of color_layer.data 
    # into the " components " variable
    color_layer.data.foreach_get("color", components)

    # this subtracts each component from 1 and overwrites " color_layer.data "
    color_layer.data.foreach_set("color", [1-c for c in components])

    bpy.ops.object.mode_set(mode='OBJECT')
    bpy.ops.object.mode_set(mode='VERTEX_PAINT')

obj = bpy.context.active_object
invert_vcols(obj.data.vertex_colors.active)

You can use foreach_set because each component of each vertex color gets inverted.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.