2
$\begingroup$

I have a Python script that I am currently using to (excuse the confusing description) rename a given object's material's image-datablock-names to their actual filenames.

It works correctly, for a single selected object. When selecting multiple objects it only executes on the first object.

Is there a way I can modify this script to execute/iterate through each/every/all selected objects?

import bpy
import os

# Set the material_index to 0 ( the first material )
bpy.context.object.active_material_index = 0
# Go through list of materials assigned to selected object

for material in bpy.context.object.data.materials:
    material_index = bpy.context.object.active_material_index
    old_name = material.name
    try:
        # Get its first material slot
        material = bpy.context.active_object.material_slots[material_index].material
        # Get the nodes in the node tree
        nodes = material.node_tree.nodes
        # Get a principled node
        principled = next(n for n in nodes if n.type == 'BSDF_PRINCIPLED')
        # Get the slot for 'base color'
        base_color = principled.inputs['Base Color'] #Or principled.inputs[0]
        # Get the link
        link = base_color.links[0]
        link_node = link.from_node
        # Rename texture to image name
        link_node.image.name = os.path.split( link_node.image.filepath )[1]
        # Rename the material to the image name excluding the extension
        textName = os.path.split( link_node.image.filepath )[1]
        textName = os.path.splitext( textName )[0]
        # Print the results
        print( "Material Old Name:", old_name, )
        print( "Material New Name:", material.name )
        print( )
    except:
        print( 'not found' )
    # Add 1 to the material_index count ( move to the next material )
    bpy.context.object.active_material_index +=1

My meager misunderstood attempts at wrapping the entire script:

for obj in bpy.context.selected_objects:
    #pre-existing script, etc

perhaps obviously failed.

Thank you very much for any help, in advance.

$\endgroup$

2 Answers 2

2
$\begingroup$

Here's a suggestion using Pathlib and bpy.types.Object.material_slots.

Using bare try: except doesn't let you debug your code in case something goes wrong. You can either catch the right exception at every step or test if your variables contain the correct data beforehand. Ask for forgiveness vs Ask for permission.

import bpy
from pathlib import Path

def rename_materials_and_image_textures(obj):
    for material_slot in obj.material_slots:
        material = material_slot.material
        if material is None:
            continue
        principled = next((n for n in material.node_tree.nodes if n.type == 'BSDF_PRINCIPLED'), None)
        if principled is None:
            continue
        base_color_input = principled.inputs['Base Color']
        if not base_color_input.links:
            continue
        link = base_color_input.links[0]
        image_node = link.from_node
        if not hasattr(image_node, "image"):
            continue
        image_filepath = image_node.image.filepath
        if not image_filepath:
            continue
        image_stem = Path(image_filepath).stem
        image_node.image.name = image_stem
        material.name = image_stem

for obj in bpy.context.selected_objects:
    rename_materials_and_image_textures(obj)

You could use a cache system to avoid processing materials multiple times since one material can appear in multiple slots in one object, and it can also appear in multiple objects' material slots. Hopefully the script doesn't take too much time to compute so it shouldn't be a concern.

$\endgroup$
1
  • $\begingroup$ This works very well. Thank you very much for the help and information. I noticed you added back in the material renaming which I guess I had only removed part of in my initial example (didn't need for my use-case), but is simple to activate and deactivate as needed and could definitely come in handy. $\endgroup$
    – VictorC
    Mar 30 at 1:48
4
$\begingroup$
import bpy

def func(obj):
    # Set the material_index to 0 ( the first material )
    obj.active_material_index = 0
    # Go through list of materials assigned to selected object

    for material in obj.data.materials:
        material_index = obj.active_material_index
        old_name = material.name
        try:
            # Get its first material slot
            material = obj.material_slots[material_index].material
            # Get the nodes in the node tree
            nodes = material.node_tree.nodes
            # Get a principled node
            principled = next(n for n in nodes if n.type == 'BSDF_PRINCIPLED')
            # Get the slot for 'base color'
            base_color = principled.inputs['Base Color'] #Or principled.inputs[0]
            # Get the link
            link = base_color.links[0]
            link_node = link.from_node
            # Rename texture to image name
            link_node.image.name = os.path.split( link_node.image.filepath )[1]
            # Rename the material to the image name excluding the extension
            textName = os.path.split( link_node.image.filepath )[1]
            textName = os.path.splitext( textName )[0]
            # Print the results
            print( "Material Old Name:", old_name, )
            print( "Material New Name:", material.name )
            print( )
        except:
            print( 'not found' )
        # Add 1 to the material_index count ( move to the next material )
        obj.active_material_index +=1

for obj in bpy.context.selected_objects:
    func(obj)
$\endgroup$
2
  • $\begingroup$ You can directly iterate on material slots without having to change the material index, for mat_slot in obj.material_slots: material = mat_slot.material. see docs.blender.org/api/current/… also bare try: except are not a good idea, they will suppress any error in the block of code which is quite long, so it will be harder to debug. Also, this doesn't seem to rename the material ? $\endgroup$
    – Gorgious
    Mar 29 at 7:00
  • $\begingroup$ This, at least just directly copy/pasting in to my Blender 3x project, does not seem to function correctly. Could be an error on my part, though. Thank you very much for your reply and help, regardless. $\endgroup$
    – VictorC
    Mar 30 at 1:52

You must log in to answer this question.

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