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

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.