# How can we add to the rendered object name his material name?

Thanks to @FFeller, how helped me to automate a rendering of an object with the associated list of material. And Thanks to @Marty Fouts, how helped me with a script for renaming a rendered images with there associated materials. It works perfectly if the generated names are made by default. – link bellow – But I have many objects to render with the specific names, generated by a Compositing Output file, and the script looks for names like – 0000.png – and didn’t recognize names like – CUBE_ONE_0000.png – Knowing that I have a small knowledge of Python, can you please @Marty Fouts, help me to adjust the scripts. Images to illustrate my needs, hoping that I made it clear😊 Thanks a lot.

How can I render an object in a different material, each one in a separate image?

How can we render an object including his material name?

import bpy
from pathlib import Path

scene = bpy.context.scene
path = Path(scene.render.filepath)
suffix = ".png"

object = bpy.context.active_object
for index in range(len(object.material_slots)):
src_string = format(index, "04d") + suffix
src = path / src_string
dst_string = object.material_slots[index].material.name  + suffix
dst = path / dst_string
print(str(src), str(dst))
src.rename(dst)

• If you're asking for advice on a coding problem you should copy your code into the question, not just post a screenshot. That way other people can grab your code and test it on their own computer. Apr 20, 2022 at 14:43
• FYI you can use the backtick key >  to format your code in a post. Enclose the entire code block in three backticks on either side like  <your code here>  and it will be much more readable. Apr 20, 2022 at 15:11

## 2 Answers

import bpy
from pathlib import Path

scene = bpy.context.scene
path = Path(scene.render.filepath)
suffix = ".png"

def rename_object_render(object):
for index in range(len(object.material_slots)):
src_string = object.name + '_' + format(index+1, "04d") + suffix
src = path / src_string
dst_string = object.name + '_' + object.material_slots[index].material.name  + suffix
dst = path / dst_string
print(str(src), str(dst))
src.rename(dst)

for object in bpy.context.selected_objects:
rename_object_render(object)


I've made three important changes from the original script.

1. I've made the for loop into a function, since it will be invoked many times and it makes the code easier to read

2. I've added a loop to loop over all of the selected objects. If you want all objects instead, use bpy.data.objects in the for loop rather than bpy.context.selected_objects

3. I've changed src_string and dst_string assignments to prepend the object name.

I've also made one small change to fix a bug in the original script, replacing index by index+1 where relevant.

• It worked perfectly, just I had to select one by one the objects and run the script, so it modifies the name of the selected object only... Thanks @Marty Fouts Now I hope that I can handle it in my complex object file 😉 PS: I add a screenshot to illustrate the result Apr 20, 2022 at 15:26
• @Kalthoum great. You could have selected all of the objects and then ran the script. It would have iterated through the objects and done the one by one processing. Apr 20, 2022 at 15:31
• your script works perfectly, I render the 50 materials for the 20 component of my object, and I was able to add the material names for each render... it was like magic . thanks again. May 2, 2022 at 16:03

If you have two lists, one of every object with a unique material on it, and one with the image that needs to be renamed, I think using zip would be a better way to go about this. You already have the images rendered, so you don't need to get the scene render filepath, the images already have their filepath.

This isn't tested, you might need to work it a little bit but something like:

from pathlib import Path

objects = bpy.context.selectable_objects
frame_dir = Path('dir/to/rendered/png_images/')
# convert all a generator of all frames in the /render directory into a list
frames = list(frame_dir.iterdir())

# zip allows us to "zip" together two lists and iterate over them at the same # time.
# example:
# a = [1,2,3]
# b = [x,y,z]

# for num, letter in zip(a, b):
#    print(num, letter)
# >>> 1 x
# >>> 2 y
# >>> 3 z

# enumerate is a way to get the index for free while inside a for loop

# example:
## for i, num, letter in enumerate(zip(a, b)):
#    print(i, num, letter)
# >>> 0 1 x
# >>> 1 2 y
# >>> 2 3 z

# put it all together and this is what we got
for i, frame, obj in enumerate(zip(objects, frames)):
obj_name = obj.name
# this is the material name that you want correct?
material = obj.material_slots[0].name
# string utility function to make suffixes like '0001, 0002' etc
number = str(i).zfill(4)
# use an f-string to format the new name of the image
image_name = f"{material_name}_{number}.png"
# the frame is a Path object we can rename easily
frame.rename(image_name)

`

Again, you might need to check this for syntax errors or something, i didn't test it but I think it will do the trick for the most part.

• from the original question, the OP wants to replace "CUBE_ONE_nnnn.jpg" by "CUBE_ONE_M(nnnn-1).jpg' where M(nnnn-1) is CUBE_ONE's material_slot[nnnn-1].name Apr 20, 2022 at 15:29
• This entire script should work for that then, it's just a matter of changing the f-string to format it how you want Apr 20, 2022 at 20:50
• There are other changes you'd need; like you're using the material in slot 0 every time but you need the material that matches the slot that goes with the frame number. But sure, with a few changes, this script could be made to work. I even like that you're thinking of alternative approaches. Apr 20, 2022 at 23:30