2
$\begingroup$

I'm using collection.objects to ask for the objects in a collection, and it gives me the whole object hierarchy. How do I get just the root of the hierarchy? So for example, I have a collection named "Models" and I import a model asset which has a transform hierarchy:

View Layer

In code I then want to go through my models and transform them say. But I obviously only want to transform the root objects (i.e. "Building"). If I ask for the objects in the "Models" collection I get all of the objects (building, Exterior, walls...).

Is there some way to ask for just the direct objects or to process all of the objects to get the root(s)? I can write the code to do this but it seems like there should be an easier way?

$\endgroup$

2 Answers 2

1
$\begingroup$

I went ahead and wrote the code to return the top-most objects from a collection.

def removeChildObjectFromList(objects):
    # This takes a list of Blender objects and removes any that have object(s) in the list above them in the hierarchy
    rootObjects = []
    voidParentObjects = set(objects)
    for objectNode in objects:
        isRootObject = True
        parentObject = objectNode.parent
        objectChain = set()
        while parentObject is not None:
            if parentObject in voidParentObjects:
                # Adding these to the voidParentObjects makes the method more efficient
                voidParentObjects.update(objectChain)
                isRootObject = False
                break
            objectChain.add(parentObject)
            parentObject = parentObject.parent
        if isRootObject:
            rootObjects.append(objectNode)
    return rootObjects

def getAssetRootObjectsFromCollection(assetCollection):
    return blenderUtils.removeChildObjectFromList(assetCollection.objects)

I still think it would be nice to have a way to ask a Collection for its direct objects; it obviously "knows" what they are as it's aware of the hierarchy when they're displayed in the View Layer.

$\endgroup$
0
$\begingroup$

As far as the collection is concerned, it isn't aware of the parent/child relationship between objects. You can however do something like this.

import bpy

col = bpy.data.collections["Model"]
for obj in col.objects:
    if obj.parent:
        continue
    do_something_on_parent(obj)

This might break if your topmost object in the collection has a parent relationship with an object that is outside of this collection, but it seems it isn't the case here.

See https://docs.blender.org/api/current/bpy.types.Object.html#bpy.types.Object.parent

And https://docs.blender.org/api/current/bpy.types.Collection.html#bpy.types.Collection

$\endgroup$
6
  • $\begingroup$ Hi Gorgious ;-) thanks for the reply. Yes that's the simplest way, but like you I was aware of the edge case, where the topmost object has a parent outside the collection. This might be the case if I decide that assets can be placed under other transforms maybe. So I wrote code to handle this too. I'll post in a reply in case anyone's interested. I still think it would be nice to have a way to ask a Collection for its direct objects; it obviously "knows" what they are as it's aware of the hierarchy when they're displayed in the View Layer. $\endgroup$
    – TomMelson
    Nov 16, 2022 at 17:40
  • $\begingroup$ I beg to differ :) A collection doesn't know if its objects are parented, it's the outliner editor that knows this, since it is responsible for displaying the data. In the outliner properties (sieve icon in the top right) you can uncheck "Object Children" and you'll see what the collection refers to as objects : a flattened collection of objects. $\endgroup$
    – Gorgious
    Nov 17, 2022 at 9:54
  • $\begingroup$ Yes I see your point. I still think it would be nice to have a built in way to get what's needed (and what's displayed in the View Layer when Object Children is on) but it's good to learn more about how it's structured, thanks. $\endgroup$
    – TomMelson
    Nov 17, 2022 at 12:05
  • $\begingroup$ It's possible I'm doing things in a non standard way I guess regarding asset importing etc. I've been looking at a video on Blender asset pipelines: youtube.com/watch?v=IBTEBhAouKc Interesting and we may adopt at a later point, but right now we're building Blender into our existing pipe, so model assets may come from outside of Blender (as Alembics) etc. $\endgroup$
    – TomMelson
    Nov 17, 2022 at 12:06
  • $\begingroup$ You can also unlink all children from the collections on import, so they don't appear in collection.objects $\endgroup$
    – Gorgious
    Nov 17, 2022 at 12:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .