0
$\begingroup$

i am currently trying to batch-simplify all of my nodes from this:

enter image description here

to this:

enter image description here

so i can better export it as fbx and changing it to the second style dont change any visuals at all.

my code isnt really working somehow:

    import bpy

# Loop through all objects in the current scene
for obj in bpy.context.scene.objects:
    # Loop through all materials in the object
    for mat_slot in obj.material_slots:
        if mat_slot.material is not None:
            # Get the material node tree
            mat_tree = mat_slot.material.node_tree
            # Loop through all nodes in the tree
            for node in mat_tree.nodes:
                # Check if the node is a shader node
                if node.type == 'SHADER':
                    # Check if the node is not a standard shader
                    if node.bl_idname != 'ShaderNodeBsdfPrincipled':
                        # Create a new standard shader node
                        bsdf_node = mat_tree.nodes.new('ShaderNodeBsdfPrincipled')
                        # Copy the node's inputs to the new shader node
                        for input in node.inputs:
                            if input.is_linked:
                                for link in input.links:
                                    mat_tree.links.new(link.from_node.outputs[0], bsdf_node.inputs[input.name])
                            else:
                                bsdf_node.inputs[input.name].default_value = input.default_value
                        # Replace the old node with the new shader node
                        mat_tree.links.new(bsdf_node.outputs[0], node.inputs[0])
                        mat_tree.nodes.remove(node)

i dont get any errors, its just not working at all. any idea why?

$\endgroup$
2
  • 1
    $\begingroup$ That looks like a code you generated with chatGPT, right? $\endgroup$
    – L0Lock
    Mar 2, 2023 at 14:41
  • 1
    $\begingroup$ You don't need the first few for loops if you want to operate on all materials. You can just do : for mat in bpy.data.materials: if mat.use_nodes: ... $\endgroup$
    – Gorgious
    Mar 2, 2023 at 15:08

1 Answer 1

1
$\begingroup$

My answer is more about your way to work than giving you a functional script.


When I don't know the API I am working with, one of the things I like to do is to print everything I am using. It's absolutelly not necessary function-wise but it's a way to see what's happening and understand why it does or doesn't work.

For example:

import bpy

# Loop through all objects in the current scene
for obj in bpy.context.scene.objects:
    print(f"Looking object '{obj.name}'")
    # Loop through all materials in the object
    for mat_slot in obj.material_slots:
        print(f"  Looking mat_slot '{mat_slot.name}'")
        if mat_slot.material is not None:
            # Get the material node tree
            mat_tree = mat_slot.material.node_tree
            print(f"  Looking mat_tree '{mat_tree.name}'")
            # Loop through all nodes in the tree
            for node in mat_tree.nodes:
                print(f"    Looking node '{node.name}' of type '{node.type}'")
                # Check if the node is a shader node
                if node.type == 'SHADER':
                    print(f"      '{node.name}' is a shader node {node.bl_idname}")
                    # Check if the node is not a standard shader
                    if node.bl_idname != 'ShaderNodeBsdfPrincipled':
                        print(f"        '{node.name}' is not a Principled BSDF!")
                        # Create a new standard shader node
                        bsdf_node = mat_tree.nodes.new('ShaderNodeBsdfPrincipled')
                        print(f"        '{node.name}' replaing by a Principled BSDF...")
                        # Copy the node's inputs to the new shader node
                        for input in node.inputs:
                            if input.is_linked:
                                for link in input.links:
                                    mat_tree.links.new(link.from_node.outputs[0], bsdf_node.inputs[input.name])
                            else:
                                bsdf_node.inputs[input.name].default_value = input.default_value
                        # Replace the old node with the new shader node
                        mat_tree.links.new(bsdf_node.outputs[0], node.inputs[0])
                        mat_tree.nodes.remove(node)

Output:

Looking object 'Cube'
  Looking mat_slot 'Material'
  Looking mat_tree 'Shader Nodetree'
    Looking node 'Material Output' of type 'OUTPUT_MATERIAL'
    Looking node 'Diffuse BSDF' of type 'BSDF_DIFFUSE'
Looking object 'Light'
Looking object 'Camera'

Big issue here: your code expects that node.type will return 'Shader' on shader nodes, but it doesn't. So all what's written beyond if node.type == 'SHADER': just never happens because the condition isn't met.


But to be honest, I think your method is wrong to begin with.

Before asking ChatGPT to generate a script, establish precisely what you want to do. " Convert this from this" works for you because you have pictures and assumptions. Scripting have only texts.

Look at your first material: you have a mix shader, that combines a Transparent and a Diffuse. The Diffuse's color is fed by a mix color that combine what looks like two different textures with a bunch of color transformations in between.

  1. Are you sure all the materials you want to process follow the same pattern? If not, you need to really think beforehand of how to handle the different case scenarios.
  2. Are you sure all you have to do is discard all nodes except one texture and plug it in the base color of a Principled BSDF ? If you want to preseve your material result, it's probably more complicated than that.
    In fact, it's probably only plugging the last mix color into a Principled BSDF. But that's only for this material.
    In which case, what you might need to do is :
    1. Identify "a mix color node that is plugged into a diffuse shader"
    2. Create a Principled BSDF
    3. Plug that Mix color into the Principled's base color
    4. Plug that Principled into the material output
    5. Delete floating nodes
  3. If you don't care about preserving your material and just have one texture and one Principled:
    1. Determine which of the two texture nodes to preserve (maybe a pattern in the data name?)
    2. Delete everything but that texture and the material output
    3. Add a Principled
    4. Connect.

For example, with this material:

example material

A way to process it could be:

for each object:
    for each material slot:
        for each material:
            for each node:
                if node.type = 'TEX_IMAGE':
                    if not "DIFFUSE_" in node.image.name:
                        delete node
                elif node.type != 'OUTPUT_MATERIAL':
                    delete node
            connect the remains

Concerning the usage of ChatGPT, do understand that it takes effort and some degree of understanding of both Python and Blender's BPY. My experience so far with Blender is that I almost never got a functional script out of it, not without checking myself what he does, telling him the errors, the things he does wrong, and sometimes telling him to start over with a completelly new procedure.

Think of ChatGPT like a 10-year-old kid that does a bunch of google search for you in a split second and gives you back what "might be the answer you are looking for", all envelopped in a bunch of text that makes it look like it's an engeneer talking to you.

$\endgroup$

You must log in to answer this question.

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