3
$\begingroup$

I am writing a simple script that will help me automate exporting assets in Blender. One of the steps is combining objects based on their parent empty. My script works when there is only one parent and children, but once there are more parents, it crashes.

In the below example, I am getting all the objects in a collection and looping over the objects with a custom property "export" and combining all their children.

The line that is causing the crash is the last line "bpy.ops.object.join()".

"Grouped" objects

You can see in the image above how I have the objects setup. Each "group" has a parent empty. If I run the script with just one "group", it works, but not with multiple as shown.

Thanks for any help

for obj in collection.all_objects:
    
    if "export" in obj:
        parent_name = obj.name
        
        bpy.ops.object.select_all(action='DESELECT')
        
        bpy.data.objects[obj.name].select_set(True)
        bpy.context.view_layer.objects.active = bpy.data.objects[obj.name]
        
        bpy.ops.object.select_grouped(type='CHILDREN_RECURSIVE')
        group_children = bpy.context.selected_objects
            
        bpy.context.view_layer.objects.active = bpy.data.objects[group_children[0].name]

        bpy.ops.object.join()
$\endgroup$

1 Answer 1

3
$\begingroup$

My Blender (3.3.0) did not crash but I would not be surprised if it would because you're doing things that you should not do.

You join objects (=remove them) while you loop over them. It's like sawing off the branch you're sitting on.

Accessing data of invalid objects can crash Blender. Even when Blender does not crash the script will not work as you might expect:

obj is  <bpy_struct, Object invalid>
Error: Python: Traceback (most recent call last):
  File "untitled.blend\Text", line 12, in <module>
ReferenceError: StructRNA of type Object has been removed

How to fix it

Better save the object name in a Python list first. This list will not change when you join objects and remove them from the collection and blend file. This way you can check if the object still exists before you process it and access its data.

Script

Here is the script with the changes and a few prints so you can see in the System Console window what happens.

import bpy

collection = bpy.context.collection

print ("------- START -------")

# create a name list of all objects in the collection
object_names = [obj.name for obj in collection.all_objects]

for objname in object_names:
    print(f"objname is {objname}, retrieving the obj")
    obj = bpy.data.objects.get(objname)
    if obj:    
        print(f"- found obj, it's {obj.name}")
        if "export" in obj:
            print (f"- export flag found in {obj.name} - going to join some objects ...")
            parent_name = obj.name
            
            bpy.ops.object.select_all(action='DESELECT')
            
            bpy.data.objects[obj.name].select_set(True)
            bpy.context.view_layer.objects.active = bpy.data.objects[obj.name]
            
            bpy.ops.object.select_grouped(type='CHILDREN_RECURSIVE')
            group_children = bpy.context.selected_objects
                
            bpy.context.view_layer.objects.active = bpy.data.objects[group_children[0].name]

            bpy.ops.object.join()
            print (f"- some objects have been joined and are now gone!")
    else:
        print(f"- {objname} not found! (it got joined and no longer exists)")            
print ("------- END -------")

Example collection and objects

before the script runs

System Console output

------- START -------
objname is Big Cube, retrieving the obj
- found obj, it's Big Cube
objname is Empty (Group A), retrieving the obj
- found obj, it's Empty (Group A)
- export flag found in Empty (Group A) - going to join some objects ...
- some objects have been joined and are now gone!!
objname is Little Cube, retrieving the obj
- found obj, it's Little Cube
objname is Empty (Group B), retrieving the obj
- found obj, it's Empty (Group B)
- export flag found in Empty (Group B) - going to join some objects ...
- some objects have been joined and are now gone!!
objname is Sphere, retrieving the obj
- Sphere not found! (it got joined and no longer exists)
objname is Torus, retrieving the obj
- Torus not found! (it got joined and no longer exists)
------- END -------
$\endgroup$
1
  • $\begingroup$ thanks! I was messing with it more and I found it to have inconsistent results and trying to access data that isn't there anymore, like you said, makes total sense. $\endgroup$
    – Quentin
    Commented Dec 12, 2022 at 20:10

You must log in to answer this question.

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