is it possible to assign a new Material(principled shader) to each mesh (or a selection of meshes) in my scene using python? The script should use the individual mesh name to name the material, and delete the existing material if there was a material before. How can i approach this problem?

  • $\begingroup$ I opened a new Blender session and created a new principled Material called "Material.001" then I created a new principled Material called "Material.002" the following code allowed me to set the material I wanted to the cube and should give you a jumping off point. bpy.data.objects["Cube"].material_slots[0].material = bpy.data.materials["Material.002"] $\endgroup$ – rob Sep 26 '18 at 10:23

Run this with your objects selected:

import bpy

# I separated the creation of nodes to a function so it's easier 
# to edit later if needed
def create_nodes(mat): 
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    for every_node in nodes: # this removes all existing nodes

    # creating Principled node and moving it:
    node = nodes.new('ShaderNodeBsdfPrincipled')
    node.location = (-190,100)

    # creating Output node and moving it:
    output_node = nodes.new('ShaderNodeOutputMaterial')
    output_node.location = (40,100)

    # creating the link between the two nodes:
    links = mat.node_tree.links
    link = links.new(node.outputs[0], output_node.inputs[0])

# this saves the currently active object so it can be restored later
active = bpy.context.object 

# let's loop through all selected objects
for every_object in bpy.context.selected_objects: 
    # I only want to work with objects capable of having a material
    if every_object.type in {'MESH','CURVE', 'SURFACE','META', 'FONT'}: 
        if every_object.name not in bpy.data.materials:
        # if there is no material named after the object yet let's make one
            mat = bpy.data.materials.new(every_object.name)
            # and let's create the nodes for it
            # if the material already exists let's just use it
            mat = bpy.data.materials.get(every_object.name)
        if len(every_object.material_slots) == 0: # if there are no material slots
            # let's make the current object active and create a material slot
            bpy.context.scene.objects.active = every_object
            # let's leave the active object as it was
            bpy.context.scene.objects.active = active

        # The only thing left now is to assign the material to 
        # all material slots. We probably do not want to loose the info
        # about how the object is divided into separate materials
        for every_slot in every_object.material_slots:
            every_slot.material = mat  
  • $\begingroup$ Thanks Martin, this does exactly what i was asking for! great! $\endgroup$ – user62799 Sep 26 '18 at 13:47
  • $\begingroup$ Would you mind explaining the steps- so i can learn from it :) ? $\endgroup$ – user62799 Sep 26 '18 at 13:48
  • $\begingroup$ I tried to add comments. If you have any questions, let me know. $\endgroup$ – Martin Z Sep 26 '18 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.