How to connect existing node group in a material in Python?

Hi, my code creates a node group and I needed it to be automatically assigned between the principled shader and the output node. It works if I try to connect any nodes, but not with my node group’s input and ouput. I’ve been trying for hours and I am clueless. I appreciate any possible help.

Here is the code, with one of the many failed attempts at linking the node at the bottom. I managed to make the code add the group to the materials, but it’s as far as I could go:

import bpy

#set here the path for the lightmaps
pathImg = "D:\\MaxToBlender\\Lightmaps\\"

selection_names = [] #declaring array
for obj in bpy.context.selected_objects: #loop through all the selected objects
  if obj.type == 'MESH':
    selection_names.append(obj) #add to array
    obj.select_set(False)
if selection_names != []:
    count = 00 #set the count
    for obj in selection_names: #loop through array
        count = count + 1
        bpy.context.view_layer.objects.active = obj
        imageNumber = (f"{(count):02d}")
        imageFile = (str(pathImg) + str(imageNumber) + "_c.exr")
        print(imageFile)
        
        # create a group for this object
        groupName = ("group" + str(imageNumber))
        bakeGroup = bpy.data.node_groups.new(groupName, 'ShaderNodeTree')
        # create group inputs
        group_inputs = bakeGroup.nodes.new('NodeGroupInput')
        group_inputs.location = (0,0)
        bakeGroup.inputs.new('NodeSocketShader','shaderIn')
        # create group outputs
        group_outputs = bakeGroup.nodes.new('NodeGroupOutput')
        group_outputs.location = (300,0)
        bakeGroup.outputs.new('NodeSocketShader','shaderOut')
        # create nodes in a group
        addShader = bakeGroup.nodes.new(type="ShaderNodeAddShader")
        addShader.location = 400,-200
        emissiveShader = bakeGroup.nodes.new(type="ShaderNodeEmission")
        emissiveShader.location = 300, -100
        lightImgNode = bakeGroup.nodes.new(type="ShaderNodeTexImage")
        lightImgNode.image = bpy.data.images.load(imageFile)
        lightImgNode.location = 200,-200
        # link nodes together
        bakeGroup.links.new(addShader.inputs[1], emissiveShader.outputs[0])
        bakeGroup.links.new(emissiveShader.inputs[0], lightImgNode.outputs[0])
        #link input and output of group
        bakeGroup.links.new(group_inputs.outputs['shaderIn'], addShader.inputs[0])
        bakeGroup.links.new(addShader.outputs[0], group_outputs.inputs['shaderOut'])
        
        
        
        for m in bpy.context.object.material_slots: #iterate through all materials on the object
            override = bpy.context.copy() #i don't know what it does. without it it says the context is wrong
            material = m.material.copy()#makes this material unique otherwise the shader will be created multiple times or same material in different objects will have the same lightmap
            m.link = 'OBJECT' #not necessary unless the objects are linked, but just in case...
            m.material = material #reassigns the material that goes away when the link is changed
 
            nodes = material.node_tree.nodes # get all material nodes
            material_output = nodes.get("Material Output") 
            mainShader = nodes.get("Principled BSDF") #get the principled hoping there's only one
            
            #add the group
            dummy_group_node = material.node_tree.nodes.new(type='ShaderNodeGroup')
            dummy_group_node.node_tree = bakeGroup
            
            #link input and output of group
            material.node_tree.links.new(bakeGroup.outputs['shaderIn'], mainShader.outputs[0])
            material.node_tree.links.new(material_output.inputs[0], bakeGroup.inputs['shaderOut'])

Hi, Do you mind to give more detail?

What is the intended thing to do that is not working?

Hi, what I wanted to do is to connect automatically the group the my script creates Capture

It’s doing everything as I want, and it adds the group you see in the image. All that I have to do left is to connect the output of the principled shader to the input of my group “shaderIn” and the output “shaderOut” to the material output.

Hope that cleares things up. Thanks

I think I found the problem

Just change the last two lines:

material.node_tree.links.new(bakeGroup.outputs['shaderIn'], mainShader.outputs[0])
material.node_tree.links.new(material_output.inputs[0], bakeGroup.inputs['shaderOut'])

To

material.node_tree.links.new(dummy_group_node.inputs["shaderIn"], mainShader.outputs[0])
material.node_tree.links.new(material_output.inputs[0], dummy_group_node.outputs['shaderOut'])

Now heres the explanation

You are using bakeGroup to link, the problem is here, bakeGroup is a NodeTree instead of node.

the Group node itself is the dummy_group_node when you created it above
So You just need to change bakeGroup to dummy_group_node

I hope this helps :slight_smile:

1 Like

Thank you so much! I knew the problem was something related to that. I searched so much and saw a lot of mentions of nodetree instead of node and so on but I couldn’t understand any of it.

I still can’t. But I guess it make sense since the dummy_group is what I spawned, even though it has the name of the nodegroup.

Anyway, I’m terrible with this kind of stuff but thanks a lot because that’s all I needed!