Note: This is an archived version of the Blender Developer Wiki (archived 2024). The current developer documentation is available on developer.blender.org/docs.

User:Sybren/SfA/SceneBuilding

Scripting for Artists: Scene Building

  • About constructing a scene with Python.
    • JSON file with scene description.
    • Link assets from blend files.
    • Put them into the scene in the right collection.

Linking assets from Python

Start with the linking, because that's the biggest unknown. We have managed collections before (https://cloud.blender.org/p/scripting-for-artists/5e7c941c5afb8fa58fad6718). Parsing a JSON file is also an unknown for now, but only once we know how we link things to a blend file will we know what we want to put into that JSON file.

Start with docs.

Simple script to explore

import bpy
from pprint import pprint

filepath = "//../envs/desert_plants.blend"

with bpy.data.libraries.load(filepath, link=True) as (data_from, data_to):
    pprint(data_from.collections)

Note that in the outliner, Libraries, the blend file is listed. Also in bpy.data.libraries.

Filter collections by name

import bpy
from pprint import pprint

filepath = "//../envs/desert_plants.blend"

prefix = 'EN-cactus_fork.'

with bpy.data.libraries.load(filepath, link=True) as (data_from, data_to):
    pprint(data_from.collections)
    for name in data_from.collections:
        if not name.startswith(prefix):
            continue
    
        print(name)
        data_to.collections.append(name)

Now in the outliner you can see the linked collections. Saving & reloading the file still removes them, because they are not yet used.

Instancing into the scene

First do this by hand, to explore what happens.

An instance is just a carefully crafted Empty.

  • Create the Empty with the name of the collection.
  • Set it to instance that collection (.instance_type = "COLLECTION", .instance_collection = coll)
  • Link it to the desired scene collection.
# Create top collection
scene = bpy.context.scene
coll_name = 'Environment'
try:
    top_coll = scene.collection.children[coll_name]
except KeyError:
    top_coll = bpy.data.collections.new(coll_name)
    scene.collection.children.link(top_coll)

# Instance into the scene
location_x = 0
step_x = 1.0
for coll in data_to.collections:
    empty = bpy.data.objects.new(coll.name, None)
    empty.instance_type = 'COLLECTION'
    empty.instance_collection = coll
    link_to.objects.link(empty)

    empty.location.x = location_x
    empty.location.y = location_y
    location_x += x_step

Parsing JSON file

  • JSON is not the most human-friendly, but quite simple, and support is built into Python.
  • Meaning of {} and [] pretty much the same as in Python (dict vs. list).
{
    "version": 1,
    "collections": {
        "Rocks": {
            "link": [
                {
                    "file": "//../envs/rocks.blend",
                    "prefix": "EN-rock_s_"
                },
                {
                    "file": "//../envs/rocks.blend",
                    "prefix": "EN-rock_smooth_"
                }
            ]
        },
        "Plants": {
            "link": [
                {
                    "file": "//../envs/desert_plants.blend",
                    "prefix": "EN-cactus_fork."
                },
                {
                    "file": "//../envs/desert_plants.blend",
                    "prefix": "EN-cactus_elements."
                },
                {
                    "file": "//../envs/desert_plants.blend",
                    "prefix": "EN-cactus_ball."
                }
            ]
        }
    }
}