I hope to use different vertex coloring to create the effect of edge lines. Different vertex groups can achieve this effect by giving different colors. But currently I have a large number of meshes that need to be modified. How do I batch mesh vertex groups? Grouping, or how to modify the vertex color of the mesh in batches? thank you all enter image description here

enter image description here enter image description here


1 Answer 1


Script for Inset faces.

enter image description here Very basic test run on inset cube

Using same concept as How to get random color variation on a single mesh?

  • By looking at screen shot it appears the models all have inset faces.

  • Assuming this is the case then

    • For each unique mesh of selected objects

    • Get or create a color layer from setting for layer_color_name Blender uses the default of "Col"

    • Sort faces by area

    • Set loop verts colors to inset_color on "inset face" (largest)

    • Find all the faces connected by edge to this face and set to edge_color

    • Repeat until all faces processed

Test script, fill in the name of color layer, and the two colors.

import bpy
import bmesh

context = bpy.context

# parameters

color_layer_name = "Col"
inset_color = (1, 1, 1, 1)
edge_color = (0, 0, 0, 1)

meshes = set(o.data for o in context.selected_objects if o.type == 'MESH')
bm = bmesh.new()

for me in meshes:
    clayers = bm.loops.layers.color
    color_layer = clayers.get(color_layer_name) or clayers.new(color_layer_name)
    faces = sorted(bm.faces[:], key=lambda f: f.calc_area())
    while faces:
        # big face is an inset
        def color(face, color, material_index):
            face.material_index = material_index
            for l in face.loops:
                l[color_layer] = color
        face = faces.pop()
        color(face, inset_color, 0)
        insets = set(
            f for e in face.edges
            for f in e.link_faces
            ) - {face}
        for f in insets:
            color(f, edge_color, 1)
            if f in faces:
        me.update() # see result

To run the script.

Copy the script and paste into text editor. Click the run script "play" button. Didn't make much effort to optimize for speed, for all objects may take a minute or two. Wait for the button to return to unpressed state. While it is running blender will be unresponsive.

Result of running over all objects test file.

enter image description here

Many of the objects have no material assigned, but the vertex colors have been set. Some use material slot 1.

Here is a fix script to ensure all objects have two materials

import bpy

mat = bpy.data.materials[0]

for me in bpy.data.meshes:
    while len(me.materials) < 2:
    me.materials[1] = me.materials[0] = mat 

Have edited original code to assign material index 0 to insets, and 1 to edges. (These really could use same material since it is using vert color)

Now after having run this to ensure that each mesh has two materials

enter image description here

Some objects are not a result of all inset faces so may not have desired result. Other methods to look at would be looking for "skinny" faces.

Color Gradient.

To get a gradient on the "ridge"

  • Look for all verts that are only linked to edge faces. (Using the face material_index set in fix script above
  • Set every loop vert color of the corresponding vert to ridge_color

Run this after running scripts above at least once.

enter image description here

import bpy
import numpy as np
import bmesh

context = bpy.context

color_layer_name = "Col"
ridge_color = (0.5, 0.5, 0.5, 1)

meshes = set(o.data for o in context.selected_objects if o.type == 'MESH')
bm = bmesh.new()

for me in meshes:
    loops = len(me.loops)

    color_layer = (me.vertex_colors.get(color_layer_name)
                   or me.vertex_colors.new(name=color_layer_name)
    loop_colors = np.empty(4 * loops)
    loop_verts = np.ones(loops)
    loop_colors = loop_colors.reshape(-1, 4)       
    verts = [
            v.index for v in bm.verts 
            if all(f.material_index == 1 for f in v.link_faces)
    indices = np.where(np.in1d(loop_verts, verts))[0]

    loop_colors[indices] = ridge_color

  • $\begingroup$ First of all, thank you very much, but I am not very proficient in code and cannot operate successfully,I re-uploaded the file, thank you very much $\endgroup$
    – chun zhong
    Sep 6, 2021 at 10:27
  • $\begingroup$ Paste script into text editor. In OBJECT mode select any or all of the mesh objects to color, then click the run script "play" button. $\endgroup$
    – batFINGER
    Sep 6, 2021 at 10:32
  • $\begingroup$ Great. I succeeded, but currently only one mesh can be modified. How to generate it in batches? $\endgroup$
    – chun zhong
    Sep 6, 2021 at 10:38
  • $\begingroup$ Had to make a small edit since all meshes aren't the result of indiv inset faces. It will modify all the meshes of selected objects. Ran succesfully on all. BUT you have not assigned a material to many of them, and hence they have no visible result. btw have you looked at using freestyle to marking and rendering edge lines without adding geometry? $\endgroup$
    – batFINGER
    Sep 6, 2021 at 10:53
  • $\begingroup$ Added a fix it script to give each object at least 2 materials, and a GIF demo of usage. $\endgroup$
    – batFINGER
    Sep 6, 2021 at 11:27

You must log in to answer this question.

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