2
$\begingroup$

The Situation: I'm creating a flying photo effect of hundreds of photos, using a particle system. I've created a custom group that includes lowering transparency based on camera distance, so as you fly through the photos they'll disappear the closer you get so you won't fly through an opaque one resulting in a one frame pop as you fly through it.

The Problem: I have hundreds of photo's that each have their own materials (imported with 'Images As Planes' add on). I need to insert this camera-distance-transparency group into every photo's material node set up (pictured below).

Question: Is there any easy way to do this rather than manually adding this group to hundreds of shaders one at a time? I'm relatively new to Blender so I can't figure out a workaround. I'd think there could be a way to create a 'for loop' script possibly, but I'm not knowledgable enough to be able to create that.

The circled group in this screenshot is what I'm trying to insert: enter image description here

Thanks for the help!

$\endgroup$
2
2
$\begingroup$

Look for Links.

Requested clarification, am making same assumption that you're after adding your group node between BSDF and Material Output.

Similarly to Look for Links method from this answer. The concept is to look for a certain link in all materials and, if it exists poke a group node inbetween.

Edit To reflect your Node Group

  • Name of Node Group (groupname)
  • Name or Index of Input Socket (in_socket)
  • Name or Index of Output Socket (out_socket)

If there is no node group with groupname as name, do nothing print message.

Look for all node materials links (links) between BSDF and into Material Outputs "Surface" socket. Looking at the node type avoids error if the node has been renamed.

If there are links then add a new group node and plug the bsdf out into designated in socket and out socket into material output surface socket. (Need a drink)

Shift the material output by 120% of group node width, and put groupnode where output node was.

Test script, as always back up first.

from bpy import data

# details of groupnode.
groupname = "NodeGroup"
# sockets to link by name or by index
in_socket = "Shader" 
out_socket = 0

# get the group node
group = data.node_groups.get(groupname)

if group:
    # find all the links to poke groupnode into
    links = [
            (mat.node_tree, link)
            for mat in data.materials
            if mat.use_nodes and not mat.is_grease_pencil
            for link in mat.node_tree.links
            if link.to_node.type.startswith('OUTPUT_MATERIAL')
            and link.to_socket.name.startswith("Surface")
            and link.from_node.type.startswith('BSDF_PRINCIPLED')
            ]
    while links:
        nt, link = links.pop()
        # make a groupnode assign it group.
        gn = nt.nodes.new('ShaderNodeGroup')
        gn.node_tree = group
        # put group node at location of output node
        # and move output to accomodate.
        gn.location = link.to_node.location
        link.to_node.location.x += 1.2 * gn.width

        # the sockets
        group_in = gn.inputs[in_socket]
        group_out = gn.outputs[out_socket]
        # make new links
        nt.links.new(link.from_socket, group_in)
        nt.links.new(group_out, link.to_socket)
else:
    print(f"No groupnode named {groupname}")
$\endgroup$
1
$\begingroup$

Assuming you want to add your node group between Material Output node and Principled BSDF node, here's the script.

Also if you want to learn more about nodes with python look here : https://blender.stackexchange.com/a/23446/115433

import bpy

#group = bpy.data.node_groups['your_node_group_name']
group = bpy.data.node_groups['1CameraBasedTransparency']

#get all non grease pencil materials
materials = [mat for mat in bpy.data.materials if mat.use_nodes and not mat.is_grease_pencil]
for mat in materials: #iterate over materials
    node_tree = mat.node_tree #get node-tree of material
    
    output_node = node_tree.nodes['Material Output'] #get output node of material
    principled_node = node_tree.nodes['Principled BSDF'] #get Principled node of material
    
    #add a group node in material
    group_node = node_tree.nodes.new('ShaderNodeGroup')
    group_node.node_tree = group

    #link it to Principled node
    node_tree.links.new(principled_node.outputs[0],group_node.inputs[0])
    #link it to output node
    node_tree.links.new(group_node.outputs[0],output_node.inputs[0])
$\endgroup$
3
  • 1
    $\begingroup$ That'll do it. Would also add mat.use_nodes test when making materials list. $\endgroup$
    – batFINGER
    Feb 21 '21 at 19:42
  • 1
    $\begingroup$ added mat.use_nodes $\endgroup$ Feb 21 '21 at 19:47
  • 1
    $\begingroup$ @PavanBhadaja that's amazing, thank you, that was fast and exactly what I was looking for! $\endgroup$
    – Lucas
    Feb 21 '21 at 22:41

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.