Cleanup and Structure

A scene with a hundred objects is not a problem. A scene with a hundred objects called Cube.001 to Cube.100 is. Structure is what lets you come back in three weeks, or hand the file to somebody else, without explaining anything. In Blender the tool for that is the collection.

Collections are the scene’s table of contents

  • bpy.data.collections.new("Pyramid") creates a collection. It lives in the file, but it is not in the scene until it is linked: scene.collection.children.link(pyramid).
  • pyramid.children.link(col) nests one collection inside another. That is how you get a tree instead of a flat list of names.
  • to_collection() is the part worth understanding. A new object always lands in whatever collection is active, so the helper unlinks it from every collection it is in and links it into the one we want. Without that step, blocks sit in the scene root and the collections stay empty.
  • Names are built from the loop counter: Level_%02d for the collection, Step_%02d_%02d_%02d for a block. Zero padding keeps them sorted in the Outliner.
  • The script also clears old collections before it starts, the same way it clears old objects. A tidy build has to be repeatable.

structure_scene.py

# A tidy scene: one collection per level, so the structure is readable
import bpy

# start from nothing, collections included
for col in list(bpy.data.collections):
    bpy.data.collections.remove(col)
for obj in list(bpy.data.objects):
    bpy.data.objects.remove(obj, do_unlink=True)

SIZE = 0.16        # m, block size
GAP = 0.02         # m, air between blocks
LEVELS = 5         # steps of the pyramid
LEVEL_COLOURS = (  # one colour per level, bottom to top
    (0.35, 0.75, 0.95),
    (0.35, 0.90, 0.55),
    (0.95, 0.85, 0.35),
    (0.95, 0.55, 0.30),
    (0.90, 0.35, 0.40),
)

# one parent collection for the whole building
pyramid = bpy.data.collections.new("Pyramid")
bpy.context.scene.collection.children.link(pyramid)


def to_collection(obj, col):
    """Take an object out of whatever collection it landed in and put it in ours."""
    for other in list(obj.users_collection):
        other.objects.unlink(obj)
    col.objects.link(obj)


for level in range(LEVELS):
    side = LEVELS - level                   # each level is one block shorter
    width = side * SIZE + (side - 1) * GAP  # real width of this level
    z = SIZE / 2 + level * SIZE             # it sits on the level below

    # every level gets its own collection, inside the Pyramid collection
    col = bpy.data.collections.new("Level_%02d" % (level + 1))
    pyramid.children.link(col)
    rgb = LEVEL_COLOURS[level % len(LEVEL_COLOURS)]

    for row in range(side):
        for ci in range(side):
            x = -width / 2 + SIZE / 2 + ci * (SIZE + GAP)
            y = -width / 2 + SIZE / 2 + row * (SIZE + GAP)

            bpy.ops.mesh.primitive_cube_add(size=SIZE, location=(x, y, z))
            step = bpy.context.view_layer.objects.active
            step.name = "Step_%02d_%02d_%02d" % (level + 1, row + 1, ci + 1)
            step.color = (rgb[0], rgb[1], rgb[2], 1.0)
            to_collection(step, col)

print("collections:", [c.name for c in pyramid.children])
print("blocks per level:", [len(c.objects) for c in pyramid.children])
print("total blocks:", len(bpy.data.objects))
The structure script and the pyramid it organised
One collection per level, nested under one Pyramid collection: 55 blocks you can still read.
Text Editor close-up of the collection code
The script up close: each level creates its collection, then moves its blocks into it.
Outliner close-up of the collection tree
The Outliner up close: Pyramid, then Level_01 to Level_05, each holding its own blocks.

Why this pays off later

Collections are not decoration, they are switches. A collection can be hidden, hidden in renders only, or excluded from the view layer entirely, and doing that to a collection is one click instead of selecting forty objects. The cutters from the boolean lesson are the perfect example: they live in their own Cutters collection, so they can be hidden while the part is shown, and shown again when the hole size needs changing.

  • Hidden, not deleted: keep the tools that made the part in a collection of their own.
  • One collection per repeated unit: module, level, product or client.
  • A collection per export: select a collection, export it, and the file names stay meaningful.
  • Colours per collection make the structure visible at a glance, which is what the screenshot above is doing with one colour per level.
The pyramid with one colour per level
One colour per level. The same structure the Outliner shows, visible in the model.
Console counting levels and blocks
The Python Console up close: five levels, and the block count of each one.

The habit worth taking away

Build the structure while you build the geometry, not afterwards. A loop that creates objects is the natural place to decide where they belong, and at that point you still know why. Renaming and sorting a finished scene is work you do twice, and the second time you are guessing what you meant.

Next, and last: putting the whole course together in one script, and the checklist to run before you call a build finished.

← Back to the lessons list