# How to color object based on roughness?

I'm very new to blender so apologies if this question doesn't make that much sense. Anyways I'm working with tumors and I'm trying to find a way to color them like a topographical map (the end result would look similar), with the blue being the smoother/flatter areas, and red being areas farther from the main surface. Does anyone have any ideas?

• Look into the Sharpness output of the Geometry node – Duarte Farrajota Ramos Aug 25 '18 at 14:16
• Could you give a closer definition of 'roughness', or 'protruding'? Possibly an example? – Robin Betts Aug 25 '18 at 15:02
• @RobinBetts I reworded it – Ana Ablove Aug 25 '18 at 18:06

One approach to this might be to use Dynamic Paint and Vertex Colors to create a proximity map between your surface, and a smoothed version of it. I imagine this will be for visualization and illustrative purposes, there's nothing calibrated about it. The method assumes quite high vertex density.

1. Derive a base surface, from which, heights will influence color

In this example, I used AltS to scale the original mesh down along its surface normals, and a Smooth Modifier. (The smoothed object you can see in the illustration is a copy; the one actually used is inside the original mesh. If you make your copy an instance using Alt D, the you'll be able to adjust it conveniently, while viewing its effect.)

1. Under the physics tab of the properties panel > Dynamic Paint, make the original mesh a Canvas, with settings as shown:

(.. you have to click the '+' next to the 'Paintmap Layer', to create a Vertex Color layer in the object)

1. Under the physics tab of the properties panel > Dynamic Paint, make the smoothed mesh a Brush, with settings as shown:

(You will have to tweak the 'Paint Distance' parameter, in particular, to get a good range of tones.)

1. Give the original mesh a material whose color is influenced by the tones in the Vertex Color layer, here left with its default name of 'dp_paintmap' (As you can see I haven't set the range of tones up perfectly, here)

and this is the sort of result:

Other options include combining this map with Sharpness as suggested by Duarte, or inverted normal Ambient Occlusion, to emphasise higher frequency (sharper) surface details, or thinner protrusions.

If you want to visualize something like surface roughness based on the mesh geometry I think there's no native way to do that in Blender.

Baking a displacement map of a high detail object to a smoothed version and exporting it, you could try image processing to calculate a representation of the local roughness. The resulting image can then be used as a texture in Blender.

As an example I used this “marshmallow” with regions of vertices randomized with different intensity.

The result ended up to look like this:

As a first step I created a rough UV map of the object followed by scaling it down and moving the UV islands a little bit apart as the baking will add some pixels of border around each island.

I duplicated the object and applied some iterations of smoothing – without reducing the poly count as I would like to reuse the UV map. The smoothed object is shown offset to the right in the screenshot, but would remain at the original position.

In Blender Render mode – which makes it easier to bake displacement maps – I create a new image with 2048×2048px, select the high detail object, shift click on the low detail version, go into edit mode and bake the displacement map in the render tab of the properties panel. Make sure to have “selected to active” checked and add a bit of margin.

I saved the image as grayscale and wrote a script for Python with numpy, scipy, matplotlib as well as scikit-image installed.

import numpy as np
import matplotlib.pyplot as plt
from skimage.morphology import disk
from scipy.ndimage import convolve

im[im==0] = np.nan

k = disk(10)  # kernel shape is circle of radius 10px
# should not be larger than margin of displacement_map

im = np.absolute(im - np.nanmean(im))
roughness = convolve(im, k, mode='nearest')
plt.imsave(fname='roughness_texture.png', arr=roughness)


The image roughness_texture.png that should be produced by the script can be added as a texture for the material of the object. By default, the colormap will be the purple to green viridis, but it can be changed to one of matplotlib's other color maps by requesting it in the imsave function. Alternatively, you can use a grayscale color map and use Blender's color ramp node to change the colors within Blender afterwards.

plt.imsave(fname='roughness_texture.png', arr=roughness, cmap=plt.cm.gray)

• I'm hooked.. could you describe what the contents of the disk is, that you've convolved over the height map? (I'm not familiar with skimage.morphology, though it looks as though I'll want to be.. ) – Robin Betts Aug 26 '18 at 16:22
• @RobinBetts disk is a (square) numpy array with a 1 everywhere closer than radius to the center and 0 everywhere else. Basically it generates a circular mask. By convolving an array with ones in it over the image, the result is an array with the values being the sum of the local (10px radius) neighborhoods of each original pixel. Normalizing the array, i.e. disk(10) / disk(10).sum() would result in a filter with the mean of the local neighborhood – which technically would be a little bit closer to the definition of the surface roughness, but I didn't look at the numbers anyway. – binweg Aug 26 '18 at 18:00
• It would be great to have a convolution node in Blender.. so you could filter procedural textures..I guess it would have to be part of the Texture system, which has always seemed a bit out of kilter to me, really belonging to the internal renderer? Which is going anyway? I don't know how it's going to evolve... – Robin Betts Aug 26 '18 at 18:31