color picker in custom sidebar in 3D view

I’m trying to figure out how to add a color picker box in a custom menu for a rig in the N panel of the 3D view. Just a little box like the color box under the material tab>Settings>viewport color. Or a small one like the color boxes in for instance the Diffuse BSDF node. The idea is that I link up that color and the viewport color to a color picker in a custom menu for a rig in the N panel of the 3D view.
Does anyone know how to achieve this?


import bpy


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'

    def draw(self, context):
        layout = self.layout

        theme = context.user_preferences.themes[0]
        gradients = theme.view_3d.space.gradients

        row = layout.row()
        row.prop(gradients, "high_gradient")

        obj = context.object
        mat = context.object.material_slots[obj.active_material_index].material

        row = layout.row()
        row.prop(mat, "diffuse_color")


def register():
    bpy.utils.register_class(HelloWorldPanel)


def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()



Define get/set methods for a custom property.

Thanks! Not quite what I had in mind, but I can start studying from here.
What I meant was not that I want the actual background color of the viewport to change, but how the color of the object with the material appears in the viewport. I want to change the color from a Diffuse BSDF node from a cycles material (which is the material the object is using. And to make it easier for the user to see that the color has changed in cycles when working in solid view, I also want the material’s viewport color to change so in solid view the object’s color changes as well as the diffuse BSDF which will show in rendered view mode.

So I want to change the color in 2 places:

  1. the color from a Diffuse BSDF node
  2. the viewport color of a material in the Material properties tab>Settings>Viewport Color

And I’d like to control those 2 color boxes from 1 single color box in the 3D view’s N panel.

You can use material shading with Cycles. If the material uses a more complex setup you will get in trouble.

I.e. if the first the node plugged into the output is a mix shader - which color do you want to show?

BTW:I already added the diffuse_color picker. Just left the background color picker for fun.

Thanks, really late here, will give it a go tomorrow. The cycles material has 3 shaders. A mis shader with a Diffuse shader in top slot, and glossy shader in the bottom slot. For this rig it doesn’t have to be more complex. I hope it’s doable if I were to use an image as well though. I want to try something later where the actual diffuse texture is black&white, and I add the color by mixing/multiplying it with a solid color. Pretty much the same thing I plan to do here, just a bit more complex shaders.
Anyway, thanks a bunch for the help, really appreciate it.

Yes, that works on an object, as long as the object is the object that is selected and the material only has a diffuse BSDF node right before the output. Still very happy with that because at least I can work around stuff for now.

I’ve been busy for a couple of hours trying to study what code I need, and right now my brain feels fried…

Two more questions, hope you don’t mind.p

  1. How do I set it up/code it so that I can select the armature object, and then the menu appears ONLY if you have the armature object selected, the color picker appears under that custom rig menu in the N panel. But while you have the armature selected, the color option in the menu will affect the color of another object, like the color of a simple character, or the iris area of an eye, for instance.

I have done this check before (only show the menu if the rig/armature is selected) by using old biped/rigify and red nelb ui script, still seems to work, but want to see if that is still the correct way or if there is a cleaner way to do this.

  1. Can I somehow drive the color of the diffuse BSDF node like you would drive a bone or bone constraint from that menu for example?
    Like you right click on a property/value you want to drive>Add driver> open graph editor and select driver window… If you do this for the color box of the BSDF node you get 4 channels: RGBA
    One channel for Red, one for Green, one for Blue and one for Alpha.
    Can I link each one of the channels up to the channel in the colorbox in the custom menu in he 3D view’s N panel?
    If so, how? Average value? Scripted expression?

So recap:

  1. How do I make the color box change the color of another object (in the script)

  2. How do I drive the (individual) color channels in the graph editor’s driver window?

here’s a sample of code that I’m using now for the rig:


# RUN THIS FOR CUSTOM SIDEBAR CONTROLS!

import bpy

class RigUI(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_label = "Character Properties"

    @classmethod
    def poll(self, context):
        try:
            ob = context.active_object
            mode = context.mode
            return (ob.name == "MTI_biped_rig" and mode == "POSE")
        except AttributeError:
            return 0

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        pose_bones = context.active_object.pose.bones
        try:
            selected_bones = [bone.name for bone in context.selected_pose_bones]
            selected_bones += [context.active_pose_bone.name]
        except (AttributeError, TypeError):
            return

        def is_selected(names):
            # Returns whether any of the named bones are selected.
            if type(names) == list:
                for name in names:
                    if name in selected_bones:
                        return True
            elif names in selected_bones:
                return True
            return False

#        ------------- blenderartist/red nelb method
#        def is_selected(context, names):
#            try:
#                for name in names:
#                    if context.active_pose_bone.name == name:
#                        return True
#                for bone in context.selected_pose_bones:
#                    for name in names:
#                        if bone.name == name:
#                            return True
#            except AttributeError:
#                pass
#            return False

#--------------------------------------------
# Required: per bone custom properties: 
# armIK.L, armIK.R
# legIK.L, legIK.R
# spineIK
#--------------------------------------------

        torso = ["waist-FK", "COG", "spine01-FK", "spine02-FK", "chest-FK", "stomach-IK", "chest-IK"]
        if is_selected(torso):
            col.prop(pose_bones["customprop"], '["spineIK"]', text="FK/IK Torso", slider=True)

        leg_L = ["hip-FK.L", "upperleg-FK.L", "lowerleg-FK.L", "foot-FK.L", "kneepole.L", "footroll.L", "toepivot.L", "foot.L""]
        if is_selected(leg_L):
            col.prop(pose_bones["customprop"], '["legIK.L"]', text="FK/IK Leg.L", slider=True)


        col.label(text="--- Visibility ---")
        riglayers = col.row()
        riglayers.label(text="Head:")
        riglayers.prop(context.active_object.data, "layers", index=0, toggle=True, text="Eye")
        riglayers.prop(context.active_object.data, "layers", index=1, toggle=True, text="Head")

        riglayers = col.row()
        riglayers.label(text="Body:")
        riglayers.prop(context.active_object.data, "layers", index=3, toggle=True, text="FK")
        riglayers.prop(context.active_object.data, "layers", index=4, toggle=True, text="IK")

        riglayers = col.row()
        riglayers.label(text="Arm.L:")
        riglayers.prop(context.active_object.data, "layers", index=6, toggle=True, text="FK")
        riglayers.prop(context.active_object.data, "layers", index=7, toggle=True, text="IK")

def register():
    bpy.utils.register_class(RigUI)

def unregister():
    bpy.utils.unregister_class(RigUI)

if __name__ == "__main__":
    register()
#-------------------------

I’m able to get this done in a more clumsy way: By adding 3 custom properties for Red, Green, Blue to the rig, add 3 more sliders to the rig menu, and then adding drivers to the color box of the diffuse BSDF and viewport settings color box… or any other color box for that matter. And then I drive these values with the data path from the custom properties Red, Green, Blue I just added to the rig. I might make another slider for the alpha or dark/light/whatever value.

How can I hook those 3 (or 4) sliders up to a color box, so I can just use 1 color box instead of 3 sliders?

bpy.types.Object.my_color = bpy.props.FloatVectorProperty(size=4, subtype=‘COLOR_GAMMA’, min=0, max=1) ?