1
$\begingroup$

My users would like to be able to adjust the transparency of their mesh objects with a single slider in the panel of an addon, where the transparency ranges from invisible to opaque. The desired functionality is exactly like the functionality of the alpha channel of the diffuse color in Solid display mode:

mat = bpy.context.object.active_material
row.prop(mat, "diffuse_color", text="color+alpha")

However, we also have image textures in our scenes, which are only visible in the Material Preview or Rendered display modes. Is there a way to reproduce this one single slider functionality for a transparency that is visible in the Material Preview/Rendered display modes?

More details:
I have been using a Principled BSDF node, but there are many different settings for the transparency, and none of them range from invisible to opaque. If Blend Mode = "Alpha Blend", then the object is never opaque, but if Blend Mode = "Opaque" then there is no transparency. The alpha channel of the Base Color is more helpful than the Alpha input of the BSDF node, but neither of them range from invisible to opaque. And there are several other color settings, but none of their alphas help to achieve what I need. I'm hoping that I've been searching down the wrong path, and there is actually a simpler way to deal with transparencies that is visible in the Material Preview/Rendered display modes.

Thanks for your help!


Following Gorgious' solution, I am now trying to link the full diffuse color as well, using the same method. However, the resulting color isn't correct, I think the problem might be with deleting the variable and creating a new one for all three color channels, but I'm having trouble determining the data structure:

def attach_color_driver(mat, rgb_ind):
    color_input = mat.node_tree.nodes["Principled BSDF"].inputs["Base Color"]
    driver = color_input.driver_add("default_value")[rgb_ind].driver
    [driver.variables.remove(value) for value in reversed(driver.variables.values())]
    var = driver.variables.new()
    target = var.targets[0]
    target.id_type = 'MATERIAL'
    target.id = mat
    target.data_path = "diffuse_color[" + str(rgb_ind) + "]"
    driver.expression = "var"

attach_color_driver(mat, 0)
attach_color_driver(mat, 1)
attach_color_driver(mat, 2)

This displays green as green, blue as cyan, and red as green.

$\endgroup$
2
$\begingroup$

If you don't mind not being able to directly tweak the shader's alpha in the shader editor, you can set a driver between the viewport display alpha and the shader alpha. Note that you can also set it the other way around, drive the viewport alpha with the shader alpha.

import bpy

obj = bpy.context.object

mat = obj.active_material 
# Make sure the material has a principled BSDF (replace with appropriate node name)
if mat and mat.use_nodes and mat.node_tree.nodes["Principled BSDF"]: 
    alpha_input = mat.node_tree.nodes["Principled BSDF"].inputs["Alpha"]  # Store access to the alpha input
    driver = alpha_input.driver_add("default_value").driver  # Create a new driver and store it
    [driver.variables.remove(value) for value in reversed(driver.variables.values())]  # Clear the driver
    var = driver.variables.new()  # Add a new variable
    
    target = var.targets[0]  # Access the first driver variable and set appropriate paths...
    target.id_type = 'MATERIAL'
    target.id = mat
    target.data_path = "diffuse_color[3]"
    driver.expression = "var"

Result :

enter image description here

As an addendum, if you want to drive the principled BSDF's color with the viewport display color, you have to add a driver to each of the color property's dimensions. Here's how to do it. Add these lines at the end of the previous code :

color_input = mat.node_tree.nodes["Principled BSDF"].inputs["Base Color"]
for channel in range(3):
    driver = color_input.driver_add("default_value", channel).driver
    [driver.variables.remove(value) for value in reversed(driver.variables.values())]
    var = driver.variables.new()

    target = var.targets[0]
    target.id_type = 'MATERIAL'
    target.id = mat
    target.data_path = f"diffuse_color[{channel}]"
    driver.expression = "var"

Result:

enter image description here

As a side note, you don't have to clear the driver variables, but it does not automatically get removed when accessing this particular field's driver (I think), and if you try adding new variables to a driver without checking first if it already has some, it will simply add more and more. That could lead to some serious bloat if you accidentally run this operation multiple times.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you Gorgious, this is excellent! I am now trying to link the full diffuse color as well using the same method, but the resulting color isn't correct. I will ask this as a followup solution in order to provide code. $\endgroup$ – Animik Jul 3 at 18:10
  • 1
    $\begingroup$ Thanks again for the very helpful updated solution! $\endgroup$ – Animik Jul 8 at 10:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.