Collections with custom attributes

blender2-80

(Roy Nieterau) #1

I’m looking into managing some things with collections in Blender 2.8, to act as an “object set” (like in Maya) to act as a container for pipeline loaded content AND to keep a ‘stored selection’ (that saves with the scene) of output to publish with some specific settings.

Now I want to store custom attributes on these collections that the artist can easily access and potentially allow them to customize it. However, a collection is not a Blender “object” and lacks .data in Python nor can you view anything like that in the Object Data view.

I am not experienced enough with Blender to know whether I am approaching it wrong or am missing something. I hope the above gives enough details of what I’m looking for to get some tips on doing it with collections or other possible workflows. It not, I’d be happy to elaborate more.


(zeauro) #2

That is what overrides system was supposed to deliver.
Unfortunately, this target was postponed to release of 2.81.

I don’t know if devs are deliberately leaving an empty space in python API for them later and kept thinking about a rough workaround for 2.80 to later or simply did not have time.

But if you could develop what attributes, you would need to have custom per collection : that would help devs to precise priorities about this field.


(Roy Nieterau) #3

Thanks for the quick reply. Overrides kind of sound like “Collection specific scene overrides” like one would use for different renderlayers. Right? However for this purpose that’s not what I’d need to have.

I will try to describe my two use cases:

An output publish instance

  1. A collection of objects the Artist would like to output from the scene as an export, and publish it. In that regard it’s a group/object set that for example says: whatever is in this collection publish it as an Alembic. The collection would then have attributes the artist could set like the start frame, end frame, whether to write vertex colors or whether to include the parent hierarchy, etc. The use case is not related to rendering at all. By storing this in the scene we can produce consistent publishes from a single scene, without relying on any user selections.

It’s these attributes like start frame, end frame, etc is what I’d like to expose as custom data so an Artist could select the collection and set them through the blender interface.

Each loaded content package

  1. On the other hand I’d like to keep track of loaded content from the pipeline. Say I load a specific Alembic or other type of content I’d want to store in the scene the “loaded package they belong to”. I wanted to link these into their own collection on load so it would be managed like that. Than later, no matter the type of content loaded I can iterate these custom collections to figure out what was loaded (like an asset id, etc.) This collection is more of an internal pipeline usage than it being interacted with in the scene by the artist.

Again, these are my use cases. Please correct me if there are better ways to do this in Blender. We have implemented similar things in other packages like Maya, where translating the pipeline to Blender might make my brain miss better ways to do things in Blender.

So maybe other question would be: is there anything else like a set/group/collection of which a single object could be part of multiple ones?


(Ben H) #4

Objects can be in multiple Collections so you should be able to just use Collections. Collections are a subclass of ID and so should support custom properties if I remember correctly.


(Roy Nieterau) #5

To clarify, I am able to do this but note the difference between the collection and the cube. The comments should explain it.

# pseudocode, wrote this on my phone so could have typos

import bpy

# create collection
collection = bpy.data.collections.new("MyCollection")

# link to scene
bpy.context.scene.collection.children.link(collection)

# link an object, e.g. Cube
cube = bpy.data.objects.get("Cube")
collection.objects.link(cube)

# write into the collection itself (yet there is no .data?)
collection["startFrame"] = 1
collection["endFrame"] = 10

# Somehow the above works, it runs as code.
# So, the above 'data' seems to write but I cannot where it would be shown in the UI. Where could an Artist see this and potentially change the number?

# In comparison objects have .data
cube.data["myData"] = 1

# Now if I select the Cube and view its object data I am able to see this "myData" in Object Data in the UI. I am unable to find the same for collections.

(Ben H) #6

Okay so the issue isn’t that you can’t use Collections, it’s that you need a place in the UI to edit the properties of a collection. This should be doable with regular ui panels and layout, just the way it is for other objects. The only wrinkle is that you want to do this with something that cannot be selected in the 3D viewport.


(Roy Nieterau) #7

Yes, it would be nice if it could show up similar to the Properties panel > Object Data’s custom properties.

Also I’m fine with that you can only select them in the Outliner as opposed to the Viewport.

This should be doable with regular ui panels and layout

Would this be a UI I’d write with code or are you referring to the fact that blender should be able to have the custom properties on Collections plus allow to show/edit them in Blender out of the box without custom coding?


Note that I’ve been able to show this data:

collection["test"] = "Aa"

You can view (and edit) it in the Outliner > Data API > Collections, see:

Maybe it makes most sense to have Collections support .data custom properties and have something along the lines of Properties > Object > Custom Properties that an Artist can easily manage. (That UI is easier than the Data API overview.)


(Ben H) #8

The best approach is probably to use bpy.props to add additional properties to existing classes, and then write your own panel for manipulating those properties. You can get the currently active Collection with context.collection and layout widgets for your custom properties in a panel.


(sozap) #9

I’m not sure your really need the .data for collections.
You just need to create a custom panel that display the properties you’re adding to the collection.

To elaborate on what @brhumphe said, you can add some properties to collections type, so all collections get the properties with :

from bpy.props import BoolProperty
from bpy.types import Collection
Collection.my_bool = BoolProperty( name=“my bool”, default = False)

you can add a panel with something like this :

class BS_PT_Col(bpy.types.Panel) :
	bl_label       = "Collections bool"
	bl_space_type  = "PROPERTIES"
	bl_region_type = 'WINDOW'
	bl_context     = "scene"
	bl_options     = {'DEFAULT_CLOSED'}
	def draw(self, context):
		layout = self.layout
		row = layout.row()
		for col in bpy.data.collections:
			row.prop(col, "my_bool",text=col.name)
			row = layout.row()

(Roy Nieterau) #10

Thanks for the replies.

Maybe I will resort to a custom panel, yes. I was mostly looking for the way that would feel most natural for Blender artists using what’s present already. As I personally have no Blender experience I felt the route I was trying to take with Collections might be the wrong one for my use cases, but I couldn’t find another form of “object sets” (if I use Maya terminology). Seeing no other things than Collections being proposed it seems I might just be on the right track.

Anyway, I will look into adding my own properties for Collections. Note that I am not looking into all having these attributes, just these specific ones. But likely the concept with properties will remain similar. Any pointers on this? A quick search revealed this might not be that trivial?

Once I have some time again I will fiddle around some more and come back with updates. Again, thanks for the detailed answers.


(sozap) #11

You can have all collections having all the properties you need (in the way I pointed out) and if a collection isn’t intended to use them , they can have nothing in it , so you can do something like this :


Collection.start_frame = IntProperty( name="start frame”, default = 0)
Collection.end_frame = IntProperty( name="end frame”, default = 0)

colls =  bpy.data.collections
col_a = colls[0]
col_b = colls[1]
col_a.start_frame = 0
col_a.end_frame = 10
for col in colls : 
    if col.end_frame : 
         do_something(col)

or you can create properties on the fly as you did :

col_a["start_frame"] = 10 
if "start_frame" in col_a.keys() : 
    do_something(col_a) 

the best is generally to create a custom panel , or in some case append/prepend some buttons or properties to existing panels in the interface.
I don’t find quite convenient to look into the custom properties panel of objects, bones, scene ect…
But it really depends on how you want to design your tool !