3

I would like to set some rules before loading a date object, into the current project. But I don't really know how to do it and if it is possible to do it.

So I give an example:

I would like to import (Then load) an object, only if it has a material in at least bpy.data.objects['object_name'].data.materials[:]

Unfortunately I realized that the bpy.data.libraries.load() method may not do what I have in mind.

Below, I report what I tried to do (which obviously does not work) but forste explains better what I would like to do:

with bpy.data.libraries.load(my_path, link=False) as (data_from, data_to):
    objs_to_load=[]
    for obj in data_from.objects:
        if obj.data.materials[:]: # <--Incorrect example on purpose
            objs_to_load.append(obj)
data_to.objects = objs_to_load

Clearly in the example above there is an error, I cannot read obj.data.materials, as it results in a string. The problem is that I don't want to import the object, as I don't want to fill the memory with useless objects for my purpose.

Anyone have any idea how to do it if it is possible?

Noob Cat
  • 1,222
  • 3
  • 20
  • 61
  • 1
    Unfortunately it seems blendfile.py is the only option (reading the binary file directly). https://blender.stackexchange.com/a/109704/86891 I hope you're ready to learn a new language :) – Gorgious May 30 '22 at 19:01
  • The module is interesting, but there seems to be no documentation about it. So it turns out unusable, without in-depth knowledge – Noob Cat Jun 01 '22 at 12:45
  • Yeah that's what I meant in the last sentence... – Gorgious Jun 01 '22 at 13:17
  • I think the best option would be to "ask blender to run its garbage collection now", but searching around I don't see an obvious way to do that, the defecto option is to save-loading the project :( https://blender.stackexchange.com/a/75608/3038 – ThorSummoner Jun 05 '22 at 23:37

1 Answers1

4

One obvious but inefficient way is to run a new Blender process in the background that opens the file and grabs whatever data you need. The data will need to be serialized by the background process, passed back to your script, then deserialized.

Afterwards you can use the data with libraries.load.

Here's a simple example:

import bpy
import subprocess

my_script = """ import bpy print("$ BEGIN") for ob in bpy.data.objects: if ob.material_slots: print("+", ob.name) print("$ END") """

my_path = "Test.blend"

result = subprocess.run( [ bpy.app.binary_path, "-b", my_path, "--python-exit-code", "1", "--python-expr", "exec(%s)" % repr(my_script), ], capture_output=True, check=True, text=True, )

Deserialize object names

lines = result.stdout.splitlines() lines = lines[lines.index("$ BEGIN") + 1:lines.index("$ END")] ob_names = [line.removeprefix("+ ") for line in lines]

print(ob_names)

scurest
  • 10,349
  • 13
  • 31
  • Interesting, does it work on all operating systems? – Noob Cat Jun 01 '22 at 20:03
  • 1
    I don't know why it wouldn't (maybe text encoding?), but you'd have to try it. Tested on Linux here. – scurest Jun 01 '22 at 20:18
  • 1
    I've tested it on Windows 10, Everything seems to be fine, and it works great. It only remains to be tested on the Macintosh Which unfortunately I don't have on hand – Noob Cat Jun 02 '22 at 18:18