1
$\begingroup$

Here is my problem : i would like to store color data in my blender files and be able to switch between all colors for my object with a python script. So i tried to create custom properties for every color, with a "main property" which is linked to my materials. And then i would like to create a script to copy the RGB values of the stored colors and paste those values in my "Main Property".

The goal is to have a system that can be used for any type of object, no matter how much materials or colors it has : just change the "color" property and it will change every material using this color.

But is it possible ? And how can i write it in script ?

EDIT : In fact, I just want a way to change the base color of several materials with a python script. So if there is a simpler way to do so... XD


Thanks for your answers !

I finally successed to create a python script that works. The simplest way, maybe not the best. I created a "Main Color" property and a bunch of color properties and scripted it like this :

bpy.data.objects["MonObjet"]["MainColor"][0]=bpy.data.objects["MonObjet"]["9440"][0] bpy.data.objects["MonObjet"]["MainColor"][1]=bpy.data.objects["MonObjet"]["9440"][1] bpy.data.objects["MonObjet"]["MainColor"][2]=bpy.data.objects["MonObjet"]["9440"][2] bpy.data.objects["MonObjet"]["MainColor"][3]=bpy.data.objects["MonObjet"]["9440"][3] 

"9440" is the color reference, and MainColor is the driver pasted on all my materials. So my script just copy/paste the values of the stored color on the "MainColor" Property.

What do you think, is there a better way to do ?

$\endgroup$

1 Answer 1

4
$\begingroup$

You can use series of bool properties (as elements of a collection) which allows to have an active item and also trigger an event by using the update function of each BoolProperty.

Each BoolProperty can be displayed as an icon and the icon itself can be generated on the fly by adding a new preview collection and then assigning a pixel array to each new icon added: https://docs.blender.org/api/current/bpy.types.ImagePreview.html

enter image description here

Example of a custom color palette using BoolProperties. When a color is selected from the list, the color is assigned to base color of the principled shader and the diffuse color of all materials.

import bpy import bpy.utils.previews 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 = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "object" def draw(self, context): layout = self.layout scn = context.scene col = layout.column(align=True) row = col.row(align=True) active_item = None for idx, item in enumerate(scn.color_collection, start=1): row.prop(item, "active", icon_value=item.icon, icon_only=True) if item.active == True: active_item = item if idx % 11 == 0: row = col.row(align=True) if active_item: row = layout.row() r, g, b, a = active_item.color row.label(text=f"Active item: {r:.2f} {g:.2f} {b:.2f} {a:.2f}") def update_callback(self, context): if self.active: for i in self.id_data.color_collection: if i.name != self.name: i.active = False # set the diffuse and base color for all materials for slot in context.object.material_slots: material = slot.material material.diffuse_color = self.color if material.use_nodes: for node in material.node_tree.nodes: if node.type == 'BSDF_PRINCIPLED': node.inputs['Base Color'].default_value = self.color class ColorCollection(bpy.types.PropertyGroup): # name: bpy.props.StringProperty active: bpy.props.BoolProperty(default=False, update=update_callback) icon: bpy.props.IntProperty() color: bpy.props.FloatVectorProperty( name = "Color", subtype = "COLOR", default = (1.0,1.0,1.0,1.0), size = 4) # We can store multiple preview collections here, # however in this example we only store "main" preview_collections = {} color_palette = [ (0.46, 0.41, 0.62, 1), (0.67, 0.18, 0.34, 1), (0.64, 0.10, 0.91, 1), (0.66, 0.09, 0.01, 1), (0.86, 0.90, 0.90, 1), (0.95, 0.27, 0.83, 1), (0.53, 0.08, 0.78, 1), (0.47, 0.27, 0.61, 1)] def register(): # register the classes bpy.utils.register_class(HelloWorldPanel) bpy.utils.register_class(ColorCollection) bpy.types.Scene.color_collection = bpy.props.CollectionProperty(type=ColorCollection) # clear the collection if hasattr(bpy.context.scene, "color_collection"): bpy.context.scene.color_collection.clear() # generate colors and icons pcoll = bpy.utils.previews.new() size = 32, 32 for i, color in enumerate(color_palette): color_name = f"Color{i}" pixels = [*color] * size[0] * size[1] icon = pcoll.new(color_name) # name has to be unique! icon.icon_size = size icon.is_icon_custom = True icon.icon_pixels_float = pixels # add the item to the collection color_item = bpy.context.scene.color_collection.add() color_item.name = color_name color_item.color = color color_item.icon = pcoll[color_name].icon_id preview_collections["main"] = pcoll def unregister(): for pcoll in preview_collections.values(): bpy.utils.previews.remove(pcoll) preview_collections.clear() bpy.utils.unregister_class(ColorCollection) bpy.utils.unregister_class(HelloWorldPanel) del bpy.types.Scene.color_collection if __name__ == "__main__": register() 

If you prefer to use an operator instead of the update function, see one of my previous answers to: How to display a fixed list of RGB values in a panel and when a color is clicked call an operator

$\endgroup$
1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.