5
$\begingroup$

I have multiple scenes in a blend file where each scene has multiple camera objects. Is there a way to read out every camera object for each scene? I can read every camera in the blend file, but I don't know which camera belongs to which scene. This is my code so far:

camList = []
with blendfile.open_blend(filepath) as blend:
    objs=blend.find_blocks_from_code(b'OB')
    for o in objs:
        if o[b'type'] == 11:
            camList.append(o[b'id',b'name'][2:])
  • I want to read the blend-file outside from blender (using the blendfile.py module)

  • As far as I understand each scene has multiple base structs that stores the objects, but base = scene.get_pointer(b'basact') gives None

  • bases are outdated, if I work with an older blend file (<2.8) it works fine, but not with newer (>=2.8) files

$\endgroup$
5
  • $\begingroup$ I would think the answer is to get Scenes from the blendfile and iterate to find any Camera type objects: blend.find_blocks_from_code(b'SC') ... for scene in scenes: for o in s.objects: if o.id_data.type == 'CAMERA': ? $\endgroup$
    – james_t
    Oct 27, 2021 at 17:53
  • $\begingroup$ as far as I know the scene struct doesn't contain the objects, $\endgroup$ Oct 27, 2021 at 18:31
  • $\begingroup$ Just fishing as I'm not a blendfile expert and only work with things like blender mfile.blend -P script.py, where I can do what I suggest. $\endgroup$
    – james_t
    Oct 27, 2021 at 20:03
  • $\begingroup$ yeah this would be a workaround but it would be nice if I could read a blend file out side blender $\endgroup$ Oct 28, 2021 at 14:17
  • $\begingroup$ Unfortunately, in devtalk, the devs have made it clear that they prefer that the blendfile format remain undocumented because it is intended to be used only by blender itself. $\endgroup$ Nov 1, 2021 at 17:21

2 Answers 2

2
$\begingroup$

The code belows reads all scenes from the provided .blend file and the cameras they have and prints them.

Result will look like <BlendFileBlock.Scene (SC), size=6912 at 0x1fdb5364088> [<BlendFileBlock.Object (OB), size=1488 at 0x1fdb520cf08>, <BlendFileBlock.Object (OB), size=1488 at 0x1fdb532ab08>]

If you want to get just names, you can wrap scenes/cameras objects in get_name() function provided at the beginning.

If you meant not the scene camera objects but the scene camera - it's way easier: camera = scene.get_pointer(b'camera').

PS Just in case if someone met this module for the first time, it's Blender Asset Tracer (used to be called blendfile/Blender Asset Manager). It's available on pip install blender-asset-tracer and official Blender repository. It allows you looking through data in .blend files without Blender itself and bpy module.

from pathlib import Path
BLEND_FILE_PATH = Path.home() / "bat.blend"
OB_CAMERA = 11

from blender_asset_tracer import blendfile
from blender_asset_tracer.blendfile import iterators

def get_name(id_datablock):
    return id_datablock.id_name[2:].decode('utf-8')

def get_collection_objects(collection):
    all_objects = set()
    collection_objects = collection.get_pointer((b'gobject', b'first'))
    # if ListBase is empty then it returns `None`
    if collection_objects is not None:
        for collection_obj in iterators.listbase(collection_objects):
            obj = collection_obj.get_pointer(b"ob")
            all_objects.add(obj)

    collection_children = collection.get_pointer((b'children', b'first'))
    if collection_children is not None:
        for collection_child in iterators.listbase(collection_children):
            collection = collection_child.get_pointer(b"collection")
            all_objects.update(get_collection_objects(collection))
    return all_objects

def get_scene_cameras(scene):
    collection = scene.get_pointer(b'master_collection')
    scene_objects = get_collection_objects(collection)
    return [obj for obj in scene_objects if obj[b'type'] == OB_CAMERA]

def print_scenes_cameras():
    with blendfile.open_cached(BLEND_FILE_PATH) as blend:
        scenes = blend.find_blocks_from_code(b'SC')
        for scene in scenes:
            cameras = get_scene_cameras(scene)
            # <BlendFileBlock.Scene (SC), size=6912 at 0x1fdb5364088>
            # [<BlendFileBlock.Object (OB), size=1488 at 0x1fdb520cf08>, <BlendFileBlock.Object (OB), size=1488 at 0x1fdb532ab08>]
            print(scene, cameras)

if __name__ == "__main__":
    print_scenes_cameras()
$\endgroup$
0
$\begingroup$

You did not provide a link to the blendfile.py module so I'm not sure how to import this. But there is a workaround solution to display all objects in each scene.

import bpy

filepath = "/path/to/blend/file"
scene_names = None

# Use the with statement to ensure the file is properly closed
with bpy.data.libraries.load(filepath) as (data_from, data_to):
    data_to.scenes = data_from.scenes
    scene_names = [name for name in data_from.scenes]

# Iterate over the scenes and their objects
scenes = data_to.scenes
for i, scene in zip(range(len(scenes)-1, -1, -1), reversed(scenes)):
    for obj in scene.objects:
        if obj.type == "CAMERA":
            print(f'{scene_names[i]} => {obj.name}')
    bpy.data.scenes.remove(bpy.data.scenes[scene.name])

bpy.ops.outliner.orphans_purge(do_recursive=True)
$\endgroup$

You must log in to answer this question.

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