11

With objects, there you can add Custom Properties to an object, though it only seems to let you specify numeric values.

Is there any way that I can add a color value as a custom property, such as through Blender's python API?

EDIT: To clarify what I am doing: I am making a set of character models for use in a web comic I am making. The character models will be "generic" ones for ordinary characters (ie: bystanders, pedestrians, etc.). What I want to do is put some color field properties onto the armature (which is the parent of all the model pieces and clothing), and then use drivers in the model pieces so that they can pull the color data for the clothing, eyes, and skin.

I wish to use this method because I want to use models in a linked fashion, where I import one or more generic models and set the colors in the scene they are used in after importing, so that I don't fill up my hard drive (or my cloud drive) with dozens of .blend files for every color variation I use.

EDIT 2: To clarify further, I wish for a solution that can be applied on a per-model basis, rather than needing to create an addon that adds the same set of properties to all models.

Zauberin Stardreamer
  • 1,578
  • 3
  • 18
  • 32
  • This should help: http://wiki.blender.org/index.php/Doc:2.6/Manual/Extensions/Python/Properties – Mike Pan Feb 12 '14 at 05:16
  • 1
    Does it need to appear in the Custom Properties panel? I would use a FloatVectorProperty() instead, which wouldn't show in tha panel, but can be added to any panel with a custom draw function. It would give you a color field, click to open color picker. – CodeManX Feb 12 '14 at 08:56
  • CoDEmanX: Yes, that's pretty much what I want. How do I set that up? – Zauberin Stardreamer Feb 12 '14 at 14:04

4 Answers4

11

Here is condensed heavily edited sample add-on an artist requested t use blender as the middleman to mass convert vertex colors data from custom data source, the latter being removed as its not related to the question.

The color value was selected using FloatVectorProperty, specifically with subtype COLOR. This also has the advantage that if exposed through the UI is visualised by the nice UI Color wheel/hex-widget.

The code is split into properties.py and ui.py as this is done for ease of maintainance and separation of concerns, ie storage and display. You can store the custom property anywhere you want I choose object as per the question, the same applies for where the ui appears.

You can also combine it into one script, just need to change registration from module to class and supply each class name.

I generally use a properties group when working with multiple properties, but you can just define a single custom property to attach. properties.py

import bpy
from bpy.props import FloatVectorProperty, StringProperty, PointerProperty

class ObjectProperties(bpy.types.PropertyGroup):
    @classmethod
    def register(cls):

        bpy.types.Object.custom = PointerProperty(
            name="Custom properties",
            description="Custom Properties for Objects",
            type=cls,
            )

        #Add in the properties you want      
        cls.hexwidget = FloatVectorProperty(name="Hex Value", 
                                        subtype='COLOR', 
                                        default=[0.0,0.0,0.0])

        cls.test_string = StringProperty(name="Test String",
                                        default="I am a string")

    @classmethod
    def unregister(cls):
        del bpy.types.Object.custom

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

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

This module has specific registration handling as we prefer to get rid of custom info if the addon is not install, design decision.

Here is the UI which will display the value stored in the defined property ui.py

import bpy

class UtilityPanel(bpy.types.Panel):
    bl_label = "Utilites Panel"
    bl_idname = "OBJECT_PT_utilities"

    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

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

        box = layout.box()
        row = box.row()
        row.prop(context.active_object.custom, "hexwidget")
        row = box.row()
        row.prop(context.active_object.custom, "test_string")

__init__.py for completeness

#--- ### Header
bl_info = {
    "name": "Custom Property: Color",
    "category": "Object",
}

import bpy
import bpy.props

from <folder_name> import ui, properties

def register():
    properties.register()
    bpy.utils.register_module(__name__)


def unregister():
    properties.unregister()
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

When enabled the add-on adds a custom propertygroup to each Object, which can be altered or expanded as you need.

Custom Panel Object Tab

neomonkeus
  • 782
  • 1
  • 5
  • 16
  • Okay, going to try this out. Will ask if I have any trouble. – Zauberin Stardreamer Feb 12 '14 at 18:58
  • Okay, I have all three scripts copied into the text editor and registered. How do I hook them up to an object, though? – Zauberin Stardreamer Feb 12 '14 at 19:03
  • This is the bare bones of an addon. Create a new folder in your addon directory and enable the new add-on. – neomonkeus Feb 12 '14 at 19:11
  • Okay, and after that, how do I use it? Also, I am going to edit the original question to put my use case down so that it fits into the context. – Zauberin Stardreamer Feb 12 '14 at 19:12
  • You need to edit the <folder_name> of init to whatever you called the folder you created. Some slight corrections, works and displays in the Properties -> Object tab. See screenshot – neomonkeus Feb 12 '14 at 20:10
  • Okay, it appears to be working now. One last question: what do I set bl_context to if I want it to appear in the toolbox instead of the object tab? – Zauberin Stardreamer Feb 12 '14 at 22:43
  • Normally I would suggest API documentation but in this case all you get it is "The context in which the panel belongs to. (TODO: explain the possible combinations bl_context/bl_region_type/bl_space_type)". Next solution for finding out stuff is open the tab in question; Left click -> Edit Source find the bl_context.

    As for the expanded version of question it might be best to start a new question, referring back tho this as the basis as its turning into a tutorial at this stage.

    – neomonkeus Feb 13 '14 at 09:19
  • I think I'll just revise my original question. Now that I've tried this solution, it doesn't really fit with what I want, since I would have the same set of properties for all of my models, whereas I would want to add them as-needed to specific models. – Zauberin Stardreamer Feb 13 '14 at 14:47
  • I wound up utilizing this solution, or rather, a heavily-modified version. I modded it to all go into a single script, and will be embedding that script as-needed into the .blend files. Though, I may adapt it further to make it more dynamic (ie: using a list value in Custom Properties to define the colors needed) – Zauberin Stardreamer Feb 13 '14 at 20:14
  • Well this is only to show you how to create a single custom property, you can expand as needed. You can also do the other part where you could tie the an update function for the values into the material color or via drivers. – neomonkeus Feb 22 '14 at 19:21
  • You want to add min=0.0 and max=1.0 to the FloatVectorProperty or the color picker will spazz out trying to pick colors. Also, setting size to 4 allows choosing alpha values. – Ray Nov 22 '23 at 20:45
5

I'm not sure if this is a recent feature (tested on blender 3.1) or not (otherwise I don't see why nobody mentioned it before), but you can add a color property without using any sort of python, with or without alpha by simply using the type Float Array, set dimension to 3 (4 if you want alpha), and the Subtype should be Linear Color or Gamma Corrected Colors:

enter image description here

enter image description here

tobiasBora
  • 1,149
  • 12
  • 26
  • This is actually the correct answer to the original question. Thank you! That Subtype field only shows up when using 'Float Array'-- totally eluded me. I wish it was higher up in the list of parameters. – j-conrad Apr 27 '22 at 21:52
4

I don't know whether this would be the intended way, but at least it works:

You could add a string representation of other datatypes than integer from the edit dialog, there you could paste a color value Ctrl-V copied from e.g. material settings, this would add a list with 4 floats.

enter image description here

To access your custom properties attached to your object e.g.

o=bpy.data.objects["Cube"]
c = Color( o["customColor"][:3] )
print( c )
>>> <Color (r=0.8000, g=0.2236, b=0.2440)>

To set a color programmatically:

c = Color((1,2,3))
o["customColor"]=c

c2=o["customColor"]
print(c2)
>>> <bpy id property array [3]>

print(Color(c2))
>>> <Color (r=1.0000, g=2.0000, b=3.0000)>

See also:

stacker
  • 38,549
  • 31
  • 141
  • 243
4

Just want do add:

Similar to python properties, the properties from bpy.props basically provide setter/getter methods for custom properties which actually are items of an ID dictionary.

Creating such a property

bpy.types.Object.test = bpy.props.IntProperty()

has no effect on an object until you assign a value to its test attribute

obj.test = 4
#calls the default setter if not specified which sets the custom property
obj["test"] = 4

The getter method returns the default value if nothing has been set for this attribute

obj.test
#calls the default setter if not specified which either returns the custom property,
#if it exists, or the default value
if "test" in obj:
    return obj["test"]
else:
    return default_value

Custom properties will be saved to the .blend file.

Correct me if i am wrong.

In this case:

#addon bl_info to be inserted here - see Templates -> Addon Add Object
import bpy

def hndl_draw(self, context):
    row = self.layout.row()
    #if "myColor" in context.object.data:
    row.prop(context.object.data, "myColor")

def register():   
    bpy.types.Armature.myColor = bpy.props.FloatVectorProperty(
                                     name = "myColor",
                                     subtype = "COLOR",
                                     size = 4,
                                     min = 0.0,
                                     max = 1.0,
                                     default = (0.75,0.0,0.8,1.0)
                                     )
    bpy.types.DATA_PT_display.append(hndl_draw)

def unregister():
    bpy.types.DATA_PT_display.remove(hndl_draw)
    del bpy.types.Armature.myColor

if __name__ == "__main__":
    register()

For all armatures the specified default color will be displayed in Properties Area -> Armature -> Display
ColorPicker

If you don't change the color no data will be added to the armature.

You can hide this color picker for objects without the custom property "myColor" by uncommenting the if-line. However you will have to set obj.data["myColor"] = (0.0,0.0,0.0,1.0) manually then (via console, script or UI).

pink vertex
  • 9,896
  • 1
  • 25
  • 44