Search code examples
pythonautomationcolorsblender

Assign different colors for instanced Blender objects automatically


I would like to be able to instance an object/objects and give it a random color (creating a unique name for materials seems to be necessary for some kind of blender internal reason).

When I do it by hand and copy the commands out of the Info Context Menu for one cube it seems to work. But as soon as I try to put a simple script together it does not. For the following code I am getting an AttributeError since apparently the attribute name does not exist.

import bpy
import random

#delete everything
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
  
bpy.ops.mesh.primitive_cube_add(size=2, align='WORLD', location=(0, 0, 0))
bpy.ops.material.new()
#create unique name for material
bpy.context.object.active_material.name = "test"

r,g,b = random.randint(0,255),random.randint(0,255),random.randint(0,255)
#change material
bpy.data.materials[name].node_tree.nodes["Principled BSDF"].inputs[0].default_value = (r, g, b, 1)

I had a look at Assign a material to an object in Blender using Python and Artistic Coding in Blender by David Mignot - YouTube.


Solution

  • I belive this does the desired action

    it was quite tricky as like described in here you need to set up input and output shaders and link it up correctly

    import bpy
    import random
    
    mat = bpy.data.materials.new(name="test")
    
    mat.use_nodes = True
    
    if mat.node_tree:
        mat.node_tree.links.clear()
        mat.node_tree.nodes.clear()
    
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    output = nodes.new(type='ShaderNodeOutputMaterial')
    
    #shader = nodes.new(type='ShaderNodeBsdfDiffuse')
    shader = nodes.new(type='ShaderNodeBsdfPrincipled')
    
    r,g,b = random.randint(0,255),random.randint(0,255),random.randint(0,255)
    nodes["Principled BSDF"].inputs[0].default_value = (r/255, g/255, b/255, 1)
    
    links.new(shader.outputs[0], output.inputs[0])
    
    bpy.ops.mesh.primitive_cube_add(size=2, align='WORLD', location=(0, 0, 0))
    bpy.context.active_object.data.materials.append(mat)