How may I list Base Color of all Materials

I have a short code snippet which lists the Name; but I’m too much of a noobie to extend this to list the Base Color RGB info. It seems to be buried in the Node Tree/Shader NodeTree/Nodes/Principled BSDF/Color, where the RGB values reside. Here’s the code I’m starting with…

import bpy
#print(“hello”)
selected = bpy.context.selected_objects
for obj in selected:
materials = obj.data.materials
mat_dict = {mat.name: i for i, mat in enumerate(materials)}
for mat in materials:
print(obj.data.materials[mat_dict[mat.name]])
#color = mat.base color
#print(color[0], color[1], color[2], color[3])

The last two lines don’t work, obviously; how may I replace them to reference this Color property, please…?
I don’t need this to work for all objects ever, as I only deal with quite simple materials. I do not need any other info, such as Metallic; just the Base Color of the Principled BSDF.
Can any kind soul please add the lines needed for this…? Thanks in advance.
(I’m using Blender 4.3, if it helps…)

Thought you might have just very simple materials with just one PrincipledBSDF closure with no connections to any other node set, the biggest problem here is that material can be much more complicated…
They can be a mix of closures where each will have a base color, and the colors can even be generated by other nodes (which can lead to different colors for different parts of the object.

Anyway, to get the ‘base color’ from a very simple material with just one PrincipledBSDF and no other input to the ‘base color’ socket, you need to do something like this:

import bpy


selected = bpy.context.selected_objects

for obj in selected:
    materials = obj.data.materials
    mat_dict = {mat.name: i for i, mat in enumerate(materials)}

    for mat in materials:
        nt = mat.node_tree
        closure = nt.nodes["Principled BSDF"]
        base_color_socket = closure.inputs['Base Color']
        
        print(mat.name)
        if base_color_socket.is_linked:
            #skipping... unless we want to analyse all the other nodes
            print("Base Color comes from other nodes...")
        else:
            print("Base Color => ", base_color_socket.default_value[:])
1 Like

Thanks for that; I’ll try it this evening. I will, indeed, only be using the very simplest of Materials, with only one Principled BSDF linked to one Output. My final Blender model is to be exported as Gltf to be imported into a 3D train simulator, which only accepts very few Materials. I therefore want to take all the individual Material Colors and make a Photoshop palette file, with which I re-colour each Object UV. The result is only one Material (my Png file…), with up to 32 different colours. I add a Roughness file and an Emmisive file; the result is good enough for my model trains in the 3D programme. Up to now, I’ve been copying the colours one by one, by hand, but this becomes very tedious when converting an excellent, detailed model which uses many Base Colors. This script will save me hours (although I still have to pop them into my Photoshop palette, of course…).
I’ll report back with the result, later on this evening. Thanks again for the rapid reply.

Edit : I couldn’t wait until this evening; it works like a charm…! I’ll sort out the output layout easily enough, I hope, and work out how to convert the RGB values into one Hex value (easier for entering into Photoshop…), but that shouldn’t be the hardest part. Well done; problem solved (and I’ve even learned a little…!). Result…!

Almost, but not quite. The script works perfectly, for the very simple Materials that I’m addressing. The problem that it poses is the value returned. It’s the RGBA value used internally by Blender, but these values do not correspond to the RGBA values used elsewhere on Planet Earth. If I feed these into Photoshop, the colour obtained is skewed. Blender knows, however, about these other values; they are even displayed when I hover the mouse over the colour in the API Data Node, from where this script pulls its output. I presume that Blender has some internal calculation to convert from these internal values to the more mundane values used by Photoshop (and others…). I’ve tried working out the correlation between these values; there seems to be a sort of logarithmic factor involved, with a factor of 1 at one end and sharp rise to 16 at the other end. Having looked deeper, I can see nowhere in Blender the RGB values held, so I would like to know with what factor do I have to correct the values from the script to obtain the simple 0-255 values needed for Photoshop. Apologies if I’ve missed a step somewhere, and it’s so easy it’s staring me in the face, but I can’t see it. Is there a simple multiplier I should be using, or is this information held elsewhere…? So near, yet so far…

Why using Photoshop? Just pass the values to an image texture inside Blender…

import bpy

selected = bpy.context.selected_objects
mat_colors = {}

for obj in selected:
    materials = obj.data.materials
    mat_dict = {mat.name: i for i, mat in enumerate(materials)}

    for mat in materials:
        nt = mat.node_tree
        closure = nt.nodes["Principled BSDF"]
        base_color_socket = closure.inputs['Base Color']

        if not mat.name in mat_colors.keys():        
            mat_colors[mat.name] = base_color_socket.default_value[:]
            
# image setup   --> Change the resolution here (you need to delete the previous image, if there's one)   
img_name = "Mat_pallete"
x_res = 32 # or it could also be: len(mat_colors)
y_res = 1

image = None

if img_name in bpy.data.images:
    image = bpy.data.images[img_name]
else:
    image = bpy.data.images.new(img_name, x_res, y_res)

# move colors to image    
for ind, (mat, color) in enumerate(mat_colors.items()):
    pos = ind * 4
    image.pixels[pos:pos+4] = color
    print(f"{mat}'s color is being stored in pixel #{ind}")
    
# save image
path = "C:\\temp\\" + img_name + ".png"

image.save(filepath = path)
2 Likes

Response from Blender …

Python: Traceback (most recent call last):
File “F:\Blender_Divers\Scripts\Test_Cube_00.blend\Pale_Gene.py”, line 31, in
ValueError: too many values to unpack (expected 2)

Line concerned is…

30 # move colors to image
31 for ind, (mat, color) in enumerate(mat_colors):

An easy fix…?

Ohh… sorry, that was my fail…

that line should be:

for ind, (mat, color) in enumerate(mat_colors.items()):

I’m also correcting the post above

1 Like

All is well now. Thanks again for your patience. I’ll leave you in peace, and get back to modelling. Have a splendid day.