1
$\begingroup$

I am trying to add colour to a mesh object where the colour varies based on the z location of each vertex (similar to a heat map). I am able to do so using the nodes editor (cycles render)

Uncoloured

into

Coloured

using the following nodes.

enter image description here

Could someone please tell me how to achieve the same (or similar) result using scripting in a very simple way? I have currently made this mesh in the following ways.

import bpy
from math import *

ob=bpy.data.objects['Grid']
for v in ob.data.vertices:
    v.co.z=-0.2*(((v.co.x)**2)-((v.co.y)**2))

I was hoping for a similar way to edit the colour of the mesh, where I select the vertices individually and then assign a colour to it based on the z location of the vertices. I am just not able to find the right python command to edit the vertex colour.

$\endgroup$
5
  • 1
    $\begingroup$ Does this answer your question? Control Cycles material nodes and material properties in Python $\endgroup$
    – brockmann
    May 21, 2020 at 16:10
  • 2
    $\begingroup$ Hi. Do you mean you would like to have a script which can generate those nodes or a script that can colour the mesh without the nodes? $\endgroup$ May 21, 2020 at 16:11
  • $\begingroup$ @RayMairlot I don't want to generate the corresponding nodes using python. I was hoping to be able to avoid nodes altogether, create the material in a simpler way, similar to the way I have made the mesh (code included in the edit). $\endgroup$ May 21, 2020 at 17:41
  • $\begingroup$ @brockmann I was hoping to avoid the nodes editor. Is it possible to edit the colour directly from the script? similar to how we can assign a material directly from the script with the command bpy.data.materials["Material.003"].diffuse_color=[1, 0, 0] $\endgroup$ May 21, 2020 at 17:49
  • 2
    $\begingroup$ Have a look into vertex colors: blender.stackexchange.com/a/911 $\endgroup$
    – brockmann
    May 21, 2020 at 18:17

2 Answers 2

3
$\begingroup$

Texture space

For this case I think node material is the easiest way to go. Added a link to bottom that similarly to @IsawU's answer (or at least I think so) writes a value to a UV map

enter image description here

AFAIK the generated texture space box around an object maps 0 to 1. ) Object Properties > Viewport Display > Texture Space We can plug this straight into a colorramp

enter image description here

After arbitrary resize and change yellow to blue

enter image description here

With vertex colours

Displacement generated in grid using question code. Vertex color layer named "Color" added and set on vertices to go from red (low) to blue (high) locally.

enter image description here

import bpy

context = bpy.context
ob = context.object
me = ob.data

for v in me.vertices:
    x, y = v.co.xy
    v.co.z = -0.2 * (x * x - y * y)

vc = me.vertex_colors.get("Color") or me.vertex_colors.new(name="Color")

z = [v.co.z for v in me.vertices]
zmin, zmax = min(z), max(z)
r = zmax - zmin
if r > 1e-5:
    cols = [((1 - (v.co.z - zmin)/ r), 0, ((v.co.z - zmin)/ r), 1) for v in me.vertices]
else:
    cols = ((1, 0, 0, 1),) * len(me.vertices)


for l in me.loops:
    vc.data[l.index].color = cols[l.vertex_index]   
me.update()

Result

enter image description here

Related

https://blender.stackexchange.com/a/161678/15543

Applying per-vertex colors to new Bmesh

set a specified vertex color to black via python

Setting per-vertex colors

How to get random color variation on a single mesh?

$\endgroup$
1
  • $\begingroup$ I was searching for a solution similar to the second method that you have provided. I tried it and it worked exactly as I needed it to. Thank you. $\endgroup$ May 22, 2020 at 20:06
3
$\begingroup$

I have devised a way to do this kind of hassle free.

I include my .

To set up your scene like me, you need:

  • a plane with 1 subdivision per 1 meter centered around world origin (limitations of math used)
  • a material 'Material.001' with Image Texture as the source for color

When you hit run script you should see coloured function result

The function runs from -32 to +32 on the X and Y axes to make the script a bit easier thanks to vertices with integer X and Y coordinates, but we would typically require a finer grid around 0 and so I use (kind of improperly named) zScale when displacing the vertices

v.co.z = -0.2 * (((v.co.x * zScale) ** 2) - ((v.co.y * zScale) ** 2))

Feel free to adjust zScale to quickly preview how the script behaves when the Z extremities are more extreme.

How does it work

  1. displace the vertices
  2. get the min and max Z coordinates for coloring purposes (in separate for loop for clarity, could be done in one loop)
  3. create a square image with the same amount of pixels, as there are vertices
  4. loop over vertices and color pixels at XY coords matching the XY coords of vertex (that's why they are integer) based on the Z coordinate, utilizing the min and max Z coordinates to go from green to red
  5. assign the texture

Edits I leave up to you

  • allow non-integer XY coordinates

  • you might want a fixed color scale, not an automatically adjusting as in my file

  • rotate the image (might be necessary for non-symmetrical functions, have not checked) seems to work correctly as is

  • always rewrite a single image file to reduce the clutter

  • add a script to set up the scene automatically for a drop-in capability

  • fixed resolution image for high density meshes (for speed reasons)

Alternative

The commented out section at the end of the code

I was playing with an idea to use the depth buffer to color the graph.

  1. Set up an ortographic camera above the graph, looking down at it
  2. render
  3. use Viewer node to use the depth buffer in script
  4. create image same size as the depth map
  5. loop over pixels in depth map, assign colors to the new image based on that

Works even if you displace the vertices on the Z axis by hand.

References

The how does it work section should allow for the code to be reconstructed at any time, I will drop here some answers for reference:

$\endgroup$
4
  • $\begingroup$ I have just noticed, you use pre 2.8 Blender. If you can't switch to 2.8 and later, you should still be able to use this as a reference. $\endgroup$
    – IsawU
    May 21, 2020 at 21:14
  • $\begingroup$ All this said, generating the node setup by code should be easier, yield faster results and work even if you displace the vertices by hand. $\endgroup$
    – IsawU
    May 21, 2020 at 21:17
  • $\begingroup$ I tried ur blender file and it seems to be working fine for me currently. But I will have difficulties in future when I need to colour an arbitrarily shaped mesh (instead of a square of a rectangular grid whose vertices are located at integral x and y) and also, instead of just the colour, will I be able to use this method to edit other material properties like emission, transparency, etc... And I have now downloaded blender 2.82. $\endgroup$ May 22, 2020 at 15:54
  • 1
    $\begingroup$ Yes, you should be able to use this method to change emission, transparency, etc. (You will need to add other textures to the node setup for these) If your mesh is going to be a square grid, or even rectangle grid, you should be able to do it with more math (for the non-integer coordiantes), other than that you could try affecting the UVs of the vertices, but that might get pretty difficult very soon. $\endgroup$
    – IsawU
    May 24, 2020 at 13:39

You must log in to answer this question.

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