0
$\begingroup$

I'm creating a script in Blender and I need the mat_name = " " to be all the materials on the active object. To be more specific, this object has 2 node groups:

enter image description here

And I want to add an image texture in both of those materials in one click with python. How would I do that?

I also need the object name to be the active object, not a specific object. So if the object is named "Cube", I don't want it to just go to the object "Cube", I want it to go to any active object.

Here is my existing code:

import bpy

mat_name = "ActiveMaterial"
materials = bpy.data.materials


mat = materials.get(mat_name) or materials.new(mat_name)
mat.use_nodes = True
nodes = mat.node_tree.nodes

    
node = nodes.new('ShaderNodeTexImage')
node.location = (0,0)

(where it says "ActiveMaterial" I don't actually need it to make a new material called active material, that is just where I'm struggling adding the image texture on the active object's materials)

Thanks Daniel

$\endgroup$
2
  • $\begingroup$ Consider adding the code you have so far, to add some clarity,. $\endgroup$
    – batFINGER
    Commented Apr 13, 2021 at 15:08
  • $\begingroup$ Hi there, I just added the code. $\endgroup$
    – Daniel
    Commented Apr 13, 2021 at 15:21

1 Answer 1

1
$\begingroup$

I think you are getting too focused on the details and need to evaluate the overall goal. Sounds like you want to do:

Premise:

Given an object

if no material assigned create new material

For each material in material_slots

ensure use_nodes = True

Add shader node 'ShaderNodeTexImage'

Set node location (0,0)

import bpy

ob = bpy.context.object

def add_image_node(ob):
    if not ob.material_slots:
        ob.data.materials.append(bpy.data.materials.new(ob.name))
    for mat in ob.data.materials:
        mat.use_nodes = True
        my_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
        my_node.location = (0,0)

add_image_node(ob)

In which case he only name used is when creating a new material.

Edit added alternative code including linking example and some potential issues identified in comments to consider for your specific goals.

import bpy

ob = bpy.context.object

def link_texture(mat, nd_from, nd_to, ip_socket, op_socket):
    mat.node_tree.links.new(nd_to.inputs[ip_socket], nd_from.outputs[op_socket])

def add_texture_node(mat):
    tex_node = mat.node_tree.nodes.new('ShaderNodeTexImage')
    tex_node.location = (0,0)
    return tex_node

def add_mat_by_slot(ob):
    if not ob.material_slots:
        bpy.ops.object.material_slot_add()
    for slot in ob.material_slots:
        if not slot.material:
            new_mat = bpy.data.materials.new(ob.name)
            slot.material = new_mat
        slot.material.use_nodes = True
        # should there be a check before adding to prevent duplicates?
        if 'Image Texture' not in slot.material.node_tree.nodes:
            my_node = add_texture_node(slot.material)
        else:
            # reference existing node
            my_node = slot.material.node_tree.nodes['Image Texture']
        
        # potentially more than one bsdf which to connect to or all
        nds_to = [nd for nd in slot.material.node_tree.nodes if nd.type == 'BSDF_PRINCIPLED']
        
        # convenience variables to choose sockets by name
        ip_sock = "Base Color"
        op_sock = "Color"
        
        for nd in nds_to:
            # do you want to skip if link already exists to avoid over writing?
            if nd.inputs[ip_sock].links:
                continue
            link_texture(slot.material, my_node, nd, ip_sock, op_sock)

add_mat_by_slot(ob)
$\endgroup$
0

You must log in to answer this question.

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