7
$\begingroup$

I'm implementing a Blender Python script to do batch conversions. It works like this:

for each model file found in a directory:

  • Import the model
  • Process it
  • Export in other format

The problem is, that after each iteration, the imported models, textures/materials and everything are still contained in the (scene?) blender instance.


How do i completely clear everything that is loaded in Blender in each iteration?

$\endgroup$
9
$\begingroup$

2.79 or newer

Note, to avoid having to remove this extra data, you can start a new file with blank scene, objects..., eg:

bpy.ops.wm.read_factory_settings(use_empty=True)

Or...

bpy.ops.wm.read_homefile(use_empty=True)

Old Answer (useful for partially clearing)

This can be done by running 'Reset Factory Settings' operator (then clear the data).

The advantage with doing this is we only need to clear the default Cube, Camera & Lamp. Since 'Reset Factory Settings' will clear everything else each time (images, packed data, curves.. etc).

import bpy

def reset_blend():
    bpy.ops.wm.read_factory_settings()

    for scene in bpy.data.scenes:
        for obj in scene.objects:
            scene.objects.unlink(obj)

    # only worry about data in the startup scene
    for bpy_data_iter in (
            bpy.data.objects,
            bpy.data.meshes,
            bpy.data.lamps,
            bpy.data.cameras,
    ):
        for id_data in bpy_data_iter:
            bpy_data_iter.remove(id_data)

reset_blend()

If you wanted to you could skip calling bpy.ops.wm.read_factory_settings(), but theres a possibility some other data was loaded (curves or lattice for eg) that you don't know about. The clearing function could be extended to test for all possible data, but loading factory settings is an easier way to ensure you didn't miss some.

$\endgroup$
  • $\begingroup$ When I bpy.ops.wm.read_homefile(use_empty=True), I get the warning DAG zero... not allowed to happen! Then later in my script, I get Operator bpy.ops.script.python_file_run.poll() failed, context is incorrect I know that's not the most detailed report, but any ideas how read_homefile() might leave things in a strange state? $\endgroup$ – Justin Helps Mar 19 at 19:39
  • $\begingroup$ for 2.78 reset_blend() is the only one that removed everything for me $\endgroup$ – j314erre Apr 5 at 3:17
  • $\begingroup$ @j314erre what data is kept w/ bpy.ops.wm.read_homefile ? $\endgroup$ – ideasman42 Apr 6 at 7:23
  • $\begingroup$ @ideasman42 I'm rendering 100's of images in a loop and the rendering time would shoot up from less than 1sec to over 1min per image. Using bpy.ops.wm.open_mainfile() helped the bpy.ops.wm.memory_statistics() not grow, but the rendering time keep going up steadily. Your reset_blend() function solved the problem for me, keeping rendering time fast for 1000's of images. $\endgroup$ – j314erre Apr 7 at 19:20
2
$\begingroup$

ideasman42's idea to reset everything to factory settings is pretty interesting. However, if you want to keep the current settings you can remove the unlinked data blocks, if you are willing to use Blender's Python API. This way you can make sure there will never be any memory leakage what so ever. You can execute the following code after you load each object or every couple of times (say every 10 objects).

First remove the meshes/objects with the following code:

for obj in bpy.context.scene.objects:
     if obj.type == 'MESH':
         obj.select = True
     else:
         obj.select = False
 bpy.ops.object.delete()

where you can check type against any of the following values according to [this documentation][1]:

[‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘ARMATURE’, ‘LATTICE’, ‘EMPTY’, ‘CAMERA’, ‘LAMP’, ‘SPEAKER’]

Then you can execute the following code snippet to remove all the unused blocks. This way you don't have to close/open Blender or save/open a .blend file:

for block in bpy.data.meshes:
    if block.users == 0:
        bpy.data.meshes.remove(block)

for block in bpy.data.materials:
    if block.users == 0:
        bpy.data.materials.remove(block)

for block in bpy.data.textures:
    if block.users == 0:
        bpy.data.textures.remove(block)

for block in bpy.data.images:
    if block.users == 0:
        bpy.data.images.remove(block)

IMPORTANT NOTE: It looks like that there is some dependencies between some data blocks such as mesh, texture, image and materials. If you do not remove the data blocks on the highest level of the hierarchy, you will not be able to remove other data blocks or you have to take the risk and remove data blocks with users more than 0. So make sure you use the code above in the following order to remove data blocks. This way you can remove all unlinked (users == 0) data blocks:

remove meshes --> remove materials --> remove textures --> remove images

The followings also have data blocks:

bpy.data.curves
bpy.data.lamps
bpy.data.cameras
$\endgroup$
  • $\begingroup$ This is also relevant to how you can prevent memory leakage in Blender $\endgroup$ – Amir Mar 6 '18 at 15:50
1
$\begingroup$

You can just reopen your blend file with open_mainfile:

bpy.ops.wm.open_mainfile(filepath=bpy.data.filepath)

That will clear-up all data created after file been saved.

$\endgroup$
  • $\begingroup$ This assumes you will be distributing a blend file with your batch processing tools, while it can work it seems an unnecessary step - especially when you only use for clearing contents. $\endgroup$ – ideasman42 Mar 26 '17 at 21:35
  • $\begingroup$ @ideasman42 question does not specify requirements for working conditions, and for a quick production solution my answer is still valid. $\endgroup$ – Mikhail Rachinskiy Mar 28 '17 at 4:45
  • $\begingroup$ Beware that this will clear your unsaved Python script upon execution. Just found out the hard way. :-) $\endgroup$ – Tomáš Hübelbauer Jan 28 at 22:28
0
$\begingroup$

Echo to @Amir's answer, and based on blender 2.8 update, selecting mesh should be done according to the API changes:

2.7x:

bpy.data.objects['Cube'].select = True

2.8x:

bpy.data.objects['Cube'].select_set(True)

This answer comes from:

Python: Selecting object by name in 2.8

$\endgroup$
  • $\begingroup$ While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review $\endgroup$ – Ray Mairlot Aug 22 at 16:26
  • $\begingroup$ @RayMairlot Thanks for the comment. Added. $\endgroup$ – X.Arthur Aug 22 at 22:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.