6
$\begingroup$

I feel like I'm close on this one. I am trying to print the material color of the active object.

Currently it is printing a value, but when I select a new active object, it prints the same value. I'm sure its a really simple thing that I'm missing but I also can't seem to find the correct method.

import bpy
obj = bpy.context.view_layer.objects.active
material = obj.active_material
color = material.diffuse_color
print(color[0], color[1], color[2], color[3])

What I am attempting to do is for each active object, report back the HSV value of the material attached to it. Ultimately I am trying to batch export each file with the file name containing the hex color of the object.

Getting the HSV values is just the first step.

enter image description here

$\endgroup$

2 Answers 2

6
$\begingroup$

The method for obtaining the diffuse color varies depending on what render engine you are using. For EEVEE and Cycles, diffuse_color isn't used and you need to find the color input of the shader node. For example, if you have the very simple setup of a Principled BSDF feeding the Material Output Surface Input, you need to find the Base Color input of the Principled Node. Here's a very simple material:

Simple material consisting of only a Principled BSDF shader

and here's a simple example replacing your last two lines but changing your last two

obj = bpy.context.view_layer.objects.active
material = obj.active_material
inputs = material.node_tree.nodes["Principled BSDF"].inputs
color = inputs["Base Color"].default_value
print(color[0], color[1], color[2], color[3])

Note that this only works in the simple case where

  • There is only one shader node
  • Its node name is Principled BSDF
  • It has no node connected to its Base Color input.

But the idea of a single diffuse color doesn't really apply except when you're using the workbench render engine, because even the Principled BSDF in this simple example will modify the color depending on the shape of the object its applied to, b applying the Fresnel Effect If any of this changes, you need to change the code to match. Since you mentioned you were using a diffuse BSDF in your comments, here's the code for that

obj = bpy.context.view_layer.objects.active
material = obj.active_material
inputs = material.node_tree.nodes["Diffuse BSDF"].inputs
color = inputs["Color"].default_value
print(color[0], color[1], color[2], color[3])
$\endgroup$
8
  • $\begingroup$ I am using eevee and diffuse color. Ultimately I am exporting these objects to gltf. What I'm aiming to do is export each object with the color of the object as the save file (hex). Each object has a mesh and its own basic material w/ diffuse color and no nodes. $\endgroup$
    – MrP
    Commented Nov 9, 2021 at 23:28
  • $\begingroup$ By 'diffuse color' do you mean you're using a Diffuse BSDF shader with no node connected to its Color input? $\endgroup$ Commented Nov 9, 2021 at 23:30
  • $\begingroup$ All I got is: Diffuse BSDF > Base Color on principled BSDF, BSDF > Surface $\endgroup$
    – MrP
    Commented Nov 9, 2021 at 23:32
  • $\begingroup$ @MrP delete the principled and hook the Diffuse directly to the Surface, and use the code I just added to my example. $\endgroup$ Commented Nov 9, 2021 at 23:40
  • $\begingroup$ It looks like it works even with principled bsdf. gunna do some testing quickly and if its right I'll mark yours as the correct answer. Thanks for the help. $\endgroup$
    – MrP
    Commented Nov 9, 2021 at 23:44
8
$\begingroup$

That's a common misunderstanding of the material system. Material.diffuse_color property is used for solid viewport shading (or renders created with the workbench engine) and does not affect the (final) rendering of all other engines, the main reason why you can find that property in the Viewport Display panel:

Due to the nature of node based materials (and almost endless possibilities of wiring things up), it's not that easy to get the diffuse/albedo color of a material as you might think.

If you're using e.g. just one Principled BSDF, you would have to get the material of the object, find the principled node in the node tree and read its 'Base Color' input property:

import bpy

# Get the object reference
obj = bpy.context.object

# Get the material via active slot 
mat = obj.active_material 
# or: bpy.data.materials.get("MaterialName")

if hasattr(mat, 'node_tree'):
    # Get the principled bsdf
    prince = mat.node_tree.nodes.get('Principled BSDF') 
    if prince:
        # Get the base color of the principled bsdf
        r, g, b, a = prince.inputs['Base Color'].default_value
        print(r, g, b, a)

Result

0.01615985296666622 0.04138465225696564 0.8000000715255737 1.0

Further reading


HSV, sRGB and Hex triplet

In case you'd like to get the HSV color and the Hex triplet as well, you'd have to implement the actual conversion using python since there is no API function to get them:

import bpy
import colorsys
import math

def lin_to_srgb(c):
    if c < 0.0031308:
        srgb = 0.0 if c < 0.0 else c * 12.92
    else:
        srgb = 1.055 * math.pow(c, 1.0 / 2.4) - 0.055
    return max(min(int(srgb * 255 + 0.5), 255), 0)

def hextriplet(c):
    return '#' + ''.join(f'{i:02X}' for i in c)


# Get the object reference
obj = bpy.context.object

# Get the material via active slot 
mat = obj.active_material 
# or: bpy.data.materials.get("MaterialName")

if hasattr(mat, 'node_tree'):
    # Get the principled bsdf
    prince = mat.node_tree.nodes.get('Principled BSDF') 
    if prince:
        # Get the base color of the principled bsdf
        r, g, b, a = prince.inputs['Base Color'].default_value
        # Convert rgb to hsv
        h, s, v = colorsys.rgb_to_hsv(r, g, b)
        # Convert to sRGB
        srgb = [lin_to_srgb(c) for c in (r, g, b)]

        # Print the values
        print("RGBA:", r, g, b, a)
        print("HSV:", h, s, v)
        print("sRGB:", ", ".join(map(str, srgb)))
        print("Hex:", hextriplet(srgb))

Result

RGBA: 0.04373500123620033 0.09530799835920334 0.7991030216217041 1.0
HSV: 0.655287445825263 0.9452698837911484 0.7991030216217041
sRGB: 59, 87, 231
Hex: #3B57E7
$\endgroup$
5
  • $\begingroup$ ultimately what I'm trying to do is access the color of each object, then convert it to hex and export the file with the name of the color associated with it using the batch export template. Each object is very simple. One object, one material, one hsv color. It is a diffuse color. $\endgroup$
    – MrP
    Commented Nov 9, 2021 at 23:25
  • $\begingroup$ @MrP Added how to get the hsv color as requested in the edit of your question. Unrelated IMHO, just FYI: If you'd like to export to gltf, you should use a principled bsdf according to the manual: docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html $\endgroup$
    – brockmann
    Commented Nov 10, 2021 at 5:05
  • $\begingroup$ Its funny actually, I just got to near the end of my project and I have a bunch of GLBs with no color data because its not principled. I think I discovered that as soon as you posted the message too. The other issue Im having now is that when I round the RGB values to format as hex, its not exactly accurate. Although that may have to be part of a new question. Sorry for posting HSV, my end goal is to have it in hex format. $\endgroup$
    – MrP
    Commented Nov 10, 2021 at 5:44
  • 1
    $\begingroup$ Sorry Brock, I thought I would be able to mark both of your answers correct because they both are technically correct. When I marked yours I had the other fellow complaining and based on the limitations of the platform, sadly I cant mark both correct :( $\endgroup$
    – MrP
    Commented Nov 10, 2021 at 20:41
  • $\begingroup$ Ez, your decision @MrP $\endgroup$
    – brockmann
    Commented Nov 10, 2021 at 20:51

You must log in to answer this question.

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