5
$\begingroup$

I have tried all the previous solutions but I can not change the colour of objects individually depending on a condition, the following code will produce 4 red cube instead of 2 red and 2 green:

template_object = bpy.data.objects.get('Cube')
matg = bpy.data.materials.new("Green")
matg.diffuse_color = (0,1,0,0.8)
matr = bpy.data.materials.new("Red")
matr.diffuse_color = (1,0,0,0.8)

manlist = [
{"color" :"red"},
{"color": "green"},
{"color": "green"},
{"color": "red"},
]
for man in manlist:
    ob = template_object.copy()
    if man['color'] == 'red':
        ob.active_material = matr
        print('red')
    if man['color'] == 'green':
        ob.active_material = matg
        print('green')
    bpy.context.collection.objects.link(ob)
$\endgroup$
3
  • $\begingroup$ You do know that the 'diffuse_color' is only used in viewport display and that you need to set the color in the principled shader to change it for render? $\endgroup$ Jan 22, 2022 at 18:35
  • $\begingroup$ Ah, your underlying problem is that your copies all have linked meshes, so you're actually getting them all set to whichever color you used last. $\endgroup$ Jan 22, 2022 at 18:42
  • $\begingroup$ I didn't mention it in my answer, but you could simplify your loop by having manlist simply be a list of materials, something like manlist = [ matr, matg, matg, matr] Then the if statements could be replaced by ob.active_material = man. It makes manlist less readable but the code much shorter. $\endgroup$ Jan 22, 2022 at 20:10

3 Answers 3

4
$\begingroup$

As Marty Fouts points out in the comments, your material slot is linked to a mesh, and all objects are linked to the same mesh. Probably the best way to resolve this is to link the material slot to the object:

import bpy

template_object = bpy.data.objects.get('Cube')
template_object.material_slots[0].link = 'OBJECT'
matg = bpy.data.materials.new("Green")
matg.diffuse_color = (0,1,0,0.8)
matr = bpy.data.materials.new("Red")
matr.diffuse_color = (1,0,0,0.8)

manlist = [
{"color" :"red"},
{"color": "green"},
{"color": "green"},
{"color": "red"},
]
for man in manlist:
    ob = template_object.copy()
    if man['color'] == 'red':
        ob.active_material = matr
        print('red')
    if man['color'] == 'green':
        ob.active_material = matg
        print('green')
    bpy.context.collection.objects.link(ob)
$\endgroup$
1
  • 1
    $\begingroup$ Hah! Beat you by 10 seconds. (or maybe you beat me by 10). $\endgroup$ Jan 22, 2022 at 19:02
5
$\begingroup$

You have two basic problems.

First, diffuse_color is only the display color used for an object in Solid Viewport shading. You need to actually create a material if you want the color in rendering. Here's green:

matg = bpy.data.materials.new("Green")
matg.use_nodes = True
tree = matg.node_tree
nodes = tree.nodes
bsdf = nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (0, 1, 0, 0.8)
matg.diffuse_color = (0, 1, 0, 0.8)

(Notice that while I was at it, I gave you a green color instead of a blue one for "Green")

Red would similar:

matr = bpy.data.materials.new("Red")
matg.use_nodes = True
tree = matg.node_tree
nodes = tree.nodes
bsdf = nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (1, 0, 0, 0.8)
matg.diffuse_color = (1, 0, 0, 0.8)

Second, your assignment loop is OK, except that the mesh copy() command is linking the mesh of the template object to each of the four new objects, so you only have one mesh. You're setting the color of that mesh by the last entry in your loop and that happens to be red.

There are several ways to duplicate the mesh without linking. It seems like using the duplicate operator would work, but I'll leave it to you to select an appropriate one. But here's how to do it with duplicate

for man in manlist:
    bpy.ops.object.duplicate()
    ob = bpy.context.active_object
    if man['color'] == 'red':
        ob.active_material = matr
        print('red')
    if man['color'] == 'green':
        ob.active_material = matg
        print('green')
    bpy.context.collection.objects.link(ob)
$\endgroup$
1
  • $\begingroup$ Thanks a lot Marty, it seems that using template_object.material_slots[0].link = 'OBJECT' I can render the color using diffuse color, maybe is just the alpha channel that is not working? $\endgroup$
    – G M
    Jan 24, 2022 at 15:44
1
$\begingroup$

Here is how I create color for an object using Goo package to create a cell object:

#====================== Colors =========================
# Green
matg = bpy.data.materials.new("Green")
matg.diffuse_color = (0,0.1,0,0.8)
# Red
matr = bpy.data.materials.new("red")
matr.diffuse_color = (0.1,0,0,0.8)

#================== Cell A Collection ==================
# Create a collection for cell A
cA_collection = bpy.data.collections.new("A_Cells")
# link the collection to the scene for visualization 
bpy.context.scene.collection.children.link(cA_collection)
# Define cell A1
cA1 = goo.Cell("cell_A1", loc = (2,2,0))
# Make a Blender mesh object for cell
goo.make_cell(cA1)
# The created cell is the active object
obj = bpy.context.active_object
# Set the object color
obj.active_material = matg
# Remove object from all collections not used in a scene 
object inside the collection
bpy.ops.collection.objects_remove_all()
# Add the active cell to our specific collection 
bpy.data.collections['A_Cells'].objects.link(obj)
$\endgroup$

You must log in to answer this question.

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