# Is 2000 materials a lot? Is there a better way?

I'll have about 1000 cubes, with the color of each top face, and the color of the other five faces of each cube set by an algorithm in a script, basically two NumPy arrays. Right now I just create two diffuse materials in script attached to each cube, and continuously update the values with statements something like this_cube.data.materials[5].diffuse_color = (r, g, b)

My question is, is there an even more primitive way I can pass an RGB value directly to a face of each cube, or are dedicated materials the only (or recommended) gateway. I'm using cycles.

So far I haven't actually had a problem using materials, but I want to check if I'm missing a better method when I scale to larger problems.

The NumPy arrays can be pre-calculated and saved to disk if necessary. They change as the animation (simulation) progresses, but this is just one more dimension in the arrays top_color[nframe, nx, ny, 3] and other_color[nframe, nx, ny, 3].

• – gandalf3
Aug 17 '15 at 7:50
• I don't know about material generating, but vertex_colors assignment is very slow in blender api. I would guess your method might be orders of magnitude faster (or even more depending on the vertex_count of your models). If you implement this through vertex_colors though could you do some benchmarking and post the results? thx! Aug 17 '15 at 8:17
• Assigning vertex colors tends to be quite fast, even for objects with tens of thousands of faces. (100k faces not even a second) Aug 17 '15 at 8:33
• I'll set it up both ways and compare. In the mean time, I've learned something very new (to me) and useful.
– uhoh
Aug 17 '15 at 10:01
– uhoh
Aug 17 '15 at 10:09

Is 2000 materials a lot? It's a big number, but Blender can handle it. The real question is; is there a more manageable way. Maybe a way that lets you define one material, and use some property of the individual objects as a source for the color?

Yes there is. There's two parts to this answer.

### Step 1 : Vertex Colors (layer)

Using a obj.data.vertex_colors on the Object's Mesh to set the RGB of the faces. This is per vertex per face, the code is very simple.

import bpy

obj = bpy.data.objects['Cube']
mesh = obj.data
polygons = mesh.polygons
vcols = mesh.vertex_colors

if len(vcols) == 0:
vcols.new()

color_layer = vcols["Col"]

r, g, b = 0.3, 0.2, 0.9

for face in polygons:
for v_idx in polygons[face.index].loop_indices:
color_layer.data[v_idx].color = r, g, b


### Step 2 : Shader Tree 'Attribute Node'

This Node has a text field where you can specify the vertex_colors layer by name, by default it's 'Col', but you can name it what you like.

To see the effect of the vertex_color layer in the 3d viewport (without rendering) Swith to Vertex Paint mode

### Assigning one material to mutiple Objects

Once you have a material configured and want to share it over all objects in question, you can iterate over all these objects and do:

common_material = bpy.data.materials[some_named_material]
for obj in objects_in_question:
obj.active_material = common_material


### Things to consider

You raised another question about whether it might be easier to create the cubes as part of one object. That's totally doable if you keep track of the vertices and indices of the individual cubes ( at that point they are disjoint submeshes ) and when you know the face indices of each cube setting the vertex_color layer information is easy enough.

• Doing it all as one object means you will need only 1 vertex color layer, and 1 material. You could even use the foreach_set construct, it's perfect for meshes with uniform vertex-per-face counts (ie, all Tris, all Quads.. all N-gons)

 # flattened_list = [r,g,b,r,g,b,r,g,b,r,g,b,.....]
obj.data.vertex_colors[0].data.foreach_set("color", flattened_list)


https://gist.github.com/zeffii/1a7d6800559f9ee902f8 shows how to do it for an Icosphere

import bpy

# default 80 faces, all Tris
obj = bpy.data.objects['Icosphere']

# note the range is 80 * 3
flattened_list = []
[flattened_list.extend([0.5, 0.3, 0.7]) for i in range(80*3)]

obj.data.vertex_colors[0].data.foreach_set("color", flattened_list)
obj.data.update()

• Keeping the objects separate means you must use a vertex_color layer for each object, but you can share the common material.

• Using thousands of materials for thousands of objects is certainly OK too.

Which of these options is the best depends on your scenario.

• Code simplicity vs Efficiency
• Efficiency vs 'How important is Efficiency'

How important is Efficiency: Is a High real-time framerate a requirement or is it being rendered and is the efficiency of your method not a real concern.

• This will take a bit for me to try, but it definitely is the kind of thing I'm looking for. The name "vertex_colors" threw me off when I originally searched - I took it literally. Thanks to the nth!
– uhoh
Aug 17 '15 at 7:41
• yeah, during the loop over .loop_indices you can either set each vertex color unique, or share a color over each vertex of the face. A face_colors layer could be useful to some but a vertex_colors layer is more flexible because it allows transitions if that was needed. Aug 17 '15 at 7:49
• Yippee Yeehah! This works great! Wow, this is incredibly useful, I see what you mean, I can add transitions if I need. Oh, the possibilities...! Thank you sensei.
– uhoh
Aug 17 '15 at 9:55
• Thanks for adding the graphic and the info on viewing without rendering. It took me a minute to remember to make sure it was selected.
– uhoh
Aug 17 '15 at 10:05
• I'm trying this again, close but no cigar. Asked here.
– uhoh
Dec 22 '16 at 10:07