I've recently started dabbling in Blender to do some scientific visualization, like ParaView but 1000x prettier :)

At the moment I'm trying to tackle adding a color ramp to a 3D surface. As of now, I've been able to figure out how to use the surface's vertex geometry as the input for coloring. My current node setup looks something like this:


This separates the z-values from the geometry and uses them as input for the color map (after normalizing them in the map range node).

I want to do this exact same process, but instead of using the z-values, I want to use arbitrary values.

If I have a surface with n points, I will have an array with n values. These may represent temperature, salinity, velocity etc.

How could I go about doing this? Both GUI and python based solutions welcome! Would like to learn it first by GUI but will eventually be coded.

  • 2
    $\begingroup$ Hi! Seems like your question titles are pretty much the same for all of your latest questions. Please make them specific, thanks. Consider that this is not a regular forum, please read: blender.stackexchange.com/help/how-to-ask $\endgroup$
    – brockmann
    Apr 18, 2020 at 7:22
  • $\begingroup$ there are several questions that are related but are distinct questions, I ask them individually otherwise I get penalized for putting too much in one... trying to do one thing with multiple steps...any idea how to do this? $\endgroup$
    – Derek Eden
    Apr 18, 2020 at 16:56
  • 1
    $\begingroup$ Your edit doesn't really help. Again, please take the time, read the link of my first comment and make your question useful for all of us by trying to find a specific title. $\endgroup$
    – brockmann
    Apr 18, 2020 at 17:03
  • 1
    $\begingroup$ I feel like I'm somewhat responsible for this. It did seem to me that @DerekEden had two related, yet nevertheless distinct questions in a previous post. If reaching two goals requires two (potentially) distinct approaches, should there not be a separate question associated with each? $\endgroup$ Apr 18, 2020 at 18:23
  • 1
    $\begingroup$ Related blender.stackexchange.com/questions/161664/… Can also use UV layer u, v data. $\endgroup$
    – batFINGER
    Apr 19, 2020 at 10:06

1 Answer 1


You can loop over every vertex after initializing different arrays for each of your vertex color layers. You can parse the init data from a file (eg .csv) with python but this is not covered in this answer.

import bpy
import bmesh

obj = bpy.context.selected_objects[0]  # Get the currently selected object

vertex_colors = obj.data.vertex_colors
while vertex_colors:
    vertex_colors.remove(vertex_colors[0])  # Remove all vertex color layers form the mesh data

bm = bmesh.new()  # Create new bmesh object
bm.from_mesh(obj.data)  # Init the bmesh with the current mesh

verts_count = len(bm.verts)  # Get the number of vertices in the mesh 
# Not obligatory, I just use this to populate the vertex color layers)

# This dictionary will map each vertex color layer name to the data for each vertex
data_layers = {
    'Temperature':  # vertex color layer name 1
        (1, 0, 0, 1),  # Color of vertex index 0
        (0, 1, 0, 1),  # Color of vertex index 1
        (0, 0, 1, 1),  # Color of vertex index 2
        (1, 1, 1, 1),  # Color of vertex index 3...
    'Velocity':  # vertex color layer name 2
        [(i / verts_count, i / verts_count, i / verts_count, 1) for i in range(verts_count)],
    'Salinity':  # vertex color layer name 3
        [(i / verts_count, 1 - (i / verts_count), 0.5, 1) for i in range(verts_count)],        

color_layers = {}
for layer_name in data_layers:
    # Create the vertex color layers and store them in a dictionary for easy access by name
    color_layers[layer_name] = bm.loops.layers.color.new(layer_name)

for layer_name, layer in color_layers.items():
    # Loop over each vertex color layer
    for v in bm.verts:
        # Loop over every vertex
        for loop in v.link_loops:
            # Loop over every loop of this vertex (the corners of the faces in which this vertex exists)  
                loop[layer] = data_layers[layer_name][v.index]
                # Get the value from the init dictionary
            except IndexError:
                loop[layer] = (1, 0, 1, 1)
                # Set a placeholder (magenta) value if the mapping array is not long enough

bm.to_mesh(obj.data)  # Give the data back to the actual mesh

Then to acces the vertex colors in your material, use the vertex color node :

enter image description here

Note that the "Temperature" layer was initialized with only 4 values, so only a few vertices in the right eye got colored and the rest of the vertices got mapped to a magenta color.

Also note that you can store 4 values in each of the 4 channels of your color. Example with the 'Velocity' vertex color layer used before :

enter image description here

  • 1
    $\begingroup$ looks insane...going to attempt this after dinner, will get back to you..thanks for input $\endgroup$
    – Derek Eden
    Apr 19, 2020 at 0:14
  • 1
    $\begingroup$ seriously thank you, this worked like a charm. $\endgroup$
    – Derek Eden
    Apr 19, 2020 at 1:23
  • $\begingroup$ @DerekEden I'm glad it helped you ! I have added a tip to add more information in each color's channel if you are intersted $\endgroup$
    – Gorgious
    Apr 19, 2020 at 8:43
  • $\begingroup$ @Gorgious This is a very nice answer. Do you know off-hand if the same can be done without using bmesh? I don't see any list like link_loops within an object's data property. $\endgroup$ Apr 20, 2020 at 22:52
  • $\begingroup$ @JeremyHilgar Mesh has a loops attribute and then you can check the current loop's vertex_index attribute for mapping. But I'd rather use bmesh, any reason why you can't use this ? If it's an edit-mode problem, you can create a from-edit-meshbmesh $\endgroup$
    – Gorgious
    Apr 21, 2020 at 7:23

You must log in to answer this question.

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