Python Request

Hi All,
New-ish blender artist here - great program. I am looking to fix some material problems in my scene. I have 150+ materials so far to look through, so looking to automate this edit.

I dabbled in python to try to make this work, but not really sure what to do - new to python as well.
The script i tried did not work, and i would rather not spend 2 weeks trying to figure it out.
I would ask if a python expert could tell be what this code should be.

The basic idea:

  • scan through all the materials
  • do not delete or rename anything
  • if the material has any image node, reset the material node to just Principled BDSF >> Material Output nodes connected to each other (i will redo the image files later with Node Wrangler).
  • leave other materials with no image nodes unchanged
# --------------------------------------------------------------------------------
#  Finds materials with image textures, deletes all the nodes,
#  and resets to BDSF to Material Output node
# --------------------------------------------------------------------------------
# loop thru all materials and see ...
# if there are **any** image nodes, then ...
# 	1. delete all nodes
#      2. add BDSF and connected output node only
#      3. do not delete or rename anything
# repeat ...
# I made this to clean all images from the file, and redo those
# with better versions using Node Wranger - wanted to automate
# since i have 150+ materials

import bpy
for mat in bpy.data.materials:
	doit = 0
	nodes = mat.node_tree.nodes
	for node in nodes:
		if node.type == 'Image Texture':
			doit = -1
		if doit==-1:
			for node in nodes:
				nodes.remove(node)
			principled = mat.node_tree.nodes.new('Principled BDSF')
			principled.location = (0,0) # x,y
                        matlout = mat.node_tree.nodes.new('Material Output')
			matlout.location = (50,0) # x,y
			matlout.inputs[0] = principled.outputs[0]
			matlout.inputs[0] = principled.outputs[0]
# end script

You can paste code using the MarkDown ``` before and after your code.

here’s some code that you can use (not including any replacement function, as it depends from what you really want to do; for now it will just print the material name in the console):

import bpy

def doSomethingWithMaterial(mat):
    print(mat.name)

def loopOver():
    for m in bpy.data.materials:
        if m.use_nodes:
            imageNodes = [node for node in m.node_tree.nodes
                if node.type == 'TEX_IMAGE']
            if len(imageNodes)>0:
                 doSomethingWithMaterial(m)

loopOver()

Thanks! i added the code i wrote to the OP above for reference.
I will take what you have + what i have & try it again later today.

Anyone else can combine the two codes above to make a workable solution?

Thanks.

Here’s a mix of both codes (with small changes):

import bpy

def doSomethingWithMaterial(mat):
    nt = mat.node_tree

    # clear node_tree
    nt.links.clear()
    nt.nodes.clear()

    # create nodes and links
    mo = nt.nodes.new('ShaderNodeOutputMaterial')
    prc = nt.nodes.new('ShaderNodeBsdfPrincipled')
    nt.links.new(prc.outputs[0], mo.inputs[0])

    # reposition and deselect
    mo.location = (300,300)
    prc.location = (10, 300)
    mo.select = False           #corrected
    prc.select = False          #corrected

def loopOver():
    for m in bpy.data.materials:
        if m.use_nodes:
            imageNodes = [node for node in m.node_tree.nodes
                if node.type == 'TEX_IMAGE']
            if len(imageNodes)>0:
                 doSomethingWithMaterial(m)

loopOver()

Copied and saved your py file.
Ran it, got this error:
Python: Traceback (most recent call last):
File “C:\lightwave\BLENDER\lakehouse\blend\lakehouse_copy.blend\resetmatl.py”, line 35, in
File “C:\lightwave\BLENDER\lakehouse\blend\lakehouse_copy.blend\resetmatl.py”, line 33, in loopOver
File “C:\lightwave\BLENDER\lakehouse\blend\lakehouse_copy.blend\resetmatl.py”, line 24, in doSomethingWithMaterial
NameError: name ‘false’ is not defined. Did you mean: ‘False’?

Changed two lines to “False”, with a capitol “F”.
mo.select = False
prc.select = False

Worked great - ran it, purged the images and saved the file, reloaded, then started working on better texturing.

Thank you so much !! And i learned a bit from your example (like split into defined sub routines).

One question, how did you know what to use for #node names# in the nt.nodes.new(‘#node names#’) calls? List somewhere??

Internal shader node subclass names

ShaderNode(NodeInternal) — Blender Python API

1 Like

To complement @nezumi.blend’s answer, you can allways poke a node’s rna_type in the Python_Console and get its identifier (this is common when you’re using blender collections in python):

>>> node = D.materials[' XXX '].node_tree.nodes[' YYY ']
>>> node.rna_type.identifier
[output >> 'ShaderNode****']

BTW… my fault misspelling False… Glad that you figured that out! :wink: