2
$\begingroup$

Ron Jensen's comment was the solution! Thank you!

My goal is to cycle through a bunch of different materials that have image textures, and link the alpha output of the image texture to a Principled BSDF node that is also in the material. What I have at the moment doesn't work, and while I do know a little bit of python, I don't think I have a deep enough understanding of blender's libraries to figure this out on my own.

This is patched together from this highlighted youtube comment and BlenderBoi2018's post here:

https://www.youtube.com/watch?v=BSfX4ZqP92A&lc=Ugw90Cf07jL79-IQtQZ4AaABAg

https://blenderartists.org/t/how-to-connect-existing-node-group-in-a-material-in-python/1295671/4#post_4

import bpy
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper

# Run through all materials of the current blend file

for mat in bpy.data.materials:

    # If the material has a node tree

    if mat.node_tree:
        
        # Link alpha from image texture to alpha on principled bsdf

        mat.node_tree.links.new(PrincipledBSDFWrapper.inputs["Alpha"], image_tex.outputs["Alpha])

My (potentially very wrong) understanding of the last line is material name.the material's node tree.links between nodes.new link(target node.input slot[name], node to link from.output slot[name]). Somebody please explain it if I have that wrong. The use of PrincipledBSDFWrapper comes from here:

https://blenderartists.org/t/how-to-change-shader-type/1202722/3#post_3

But it doesn't seem to be intended for use in that way.

I couldn't find a bl_idname for the Pricipled BSDF, which I think would have worked in this context, but I don't know that for sure. If I have all my information correct my holdup here is figuring out how to specify which node is which.

$\endgroup$
1
  • 2
    $\begingroup$ Assuming the material has exactly one Principled BSDF and exactly one Image Texture, you could do: mat.node_tree.links.new( mat.node_tree.nodes['Principled BSDF'].inputs['Alpha'], mat.node_tree.nodes['Image Texture'].outputs['Alpha'] ) however, this may be brittle due to name mangling internal to Blender. $\endgroup$
    – Ron Jensen
    Commented Oct 4, 2021 at 20:12

1 Answer 1

1
$\begingroup$

You don't need to use the wrapper class, but as Ron Jensen commented yesterday, the obvious way to do this is very fragile. Here is a long script that tries to do as much error handling as possible, and uses node types rather than naming conventions. But even this is fragile in the face of multiple image textures or multiple principled shaders, as it only picks one at random and doesn't retry with the others if that fails.

import bpy
        
def find_nodes_by_type(material, node_type):
    """ Return a list of all of the nodes in the material
        that match the node type.
        Return an empty list if the material doesn't use
        nodes or doesn't have a tree.
    """
    node_list = []
    if material.use_nodes and material.node_tree:
            for n in material.node_tree.nodes:
                if n.type == node_type:
                    node_list.append(n)
    return node_list

def link_alpha(material):
    """ Find at least one image texture in the material
        and at least one Principled shader.
        If they both exist and neither have a link to
        the relevant alpha socket, connect them.
        There are many ways this can fail.
        if there's no image; if there's no principled
        shader; if the selected image/principled sockets
        are already in use.
        Returns false on any detected error.
        Does not try alternatives if there are multiple
        images or multiple principled shaders.
    """
    print(f'processing material {material.name}')
    it_list = find_nodes_by_type(material, 'TEX_IMAGE')
    if len(it_list) == 0:
        print(f'{material.name}: no image texture nodes.')
        return False
    if len(it_list) > 1:
        print(f'{material.name}: too many image textures. Trying the first one')
    s_list = find_nodes_by_type(material, 'BSDF_PRINCIPLED')
    if len(s_list) == 0:
        print(f'{material.name}: no principled shader.')
        return False
    if len(s_list) != 1:
        print(f'{material.name}: too many principled shaders. Trying the first one')
    image_node = it_list[0]
    shader_node = s_list[0]
    print(f'{material.name}: Attempting to connect {image_node.name} alpha to {shader_node.name}')
    image_socket = image_node.outputs['Alpha']
    if not image_socket:
        print(f'{material.name}: Image texture does not have an alpha node.  Something is seriously broken.')
        return False
    if image_socket.is_linked:
        print(f'{material.name}: Image texture alpha output already in use.')
        return False
    shader_socket = shader_node.inputs['Alpha']
    if not shader_socket:
        print(f'{material.name}: Principled BSDF does not have an alpha node. Version of Blender too old?')
        return False
    if shader_socket.is_linked:
        print(f'{material.name}: Principled BSDF alpha input already in use.')
        return False
    material.node_tree.links.new(shader_socket, image_socket)
    return True

#if __name__ == '__main__'
    for m in bpy.data.materials:
        if not m.use_nodes:
            continue
        b = link_alpha(m)
        print(f'alpha link of {m.name} returned {b}')
$\endgroup$

You must log in to answer this question.

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