0
$\begingroup$
class TestFunction(bpy.types.Operator):
    """TestFunction"""
    bl_idname = "object.test_function"
    bl_label = "Test Function"
    bl_options = {'REGISTER', 'UNDO'}
    
    def merge_hierarchy(obj):
        """
        递归地合并层级结构中的所有子对象
        """
        # 如果对象没有子对象,直接返回
        if not obj.children:
            return
    
        # 找到所有非EMPTY的子对象
        objects_to_merge = [child for child in obj.children if child.type != 'EMPTY']
    
        # 如果有多个非EMPTY的子对象,合并它们
        if len(objects_to_merge) > 1:
            # 选择所有要合并的对象
            for child in objects_to_merge:
                child.select_set(True)
            # 设置第一个对象为活动对象
            bpy.context.view_layer.objects.active = objects_to_merge[0]
            # 执行合并操作
            bpy.ops.object.join()
            # 重新命名合并后的对象为父节点的名称
            merged_object = bpy.context.active_object
            merged_object.name = obj.name
            # 清除选择
            bpy.ops.object.select_all(action='DESELECT')
    
        # 递归处理每个子对象
        for child in obj.children:
            TestFunction.merge_hierarchy(child)
    
    def execute(self, context):
        
        """
        合并所有场景中的层级结构
        """
        # 获取所有顶层对象(没有父对象的对象)
        top_level_objects = [obj for obj in bpy.data.objects if obj.parent is None]
    
        for obj in top_level_objects:
            TestFunction.merge_hierarchy(obj)
        return {'FINISHED'}

Whenever I run the aforementioned code to process models in an engineering file, the software consistently crashes after a while. The scene contains about 6,000 models. I'm using Blender version 3.4.1, which should be paired with Python version 3.10.8. However, when I select multiple objects in Blender and right-click to merge them, the software completes the operation swiftly. Why does it crash when these actions are turned into code for batch execution? I monitored the CPU usage during code execution and noticed a peak utilization rate of 80%. The rate typically fluctuated between 20% and 45%, with significant variations. Despite this, the software remained stable. However, after continued operation, it unexpectedly crashed without prior indications.(The running computer CPU is i9-13900ks) enter image description here enter image description here There are many models under the empty object node I selected on the right. I want to merge all models under each hierarchical structure into a single one, ensuring only one object remains under each node.

$\endgroup$
3
  • 1
    $\begingroup$ Hello, what is the purpose of for child in obj.children: TestFunction.merge_hierarchy(child) ? $\endgroup$
    – Gorgious
    Commented Jul 31 at 9:16
  • $\begingroup$ Could you please explain what you expect this code to do? It would be helpful if you could share before and after screenshots to illustrate the intended outcome. Additionally, providing a simple setup in a .blend file would allow us to better understand and test the function effectively. And then we can re-open this question. $\endgroup$
    – Harry McKenzie
    Commented Jul 31 at 10:05
  • $\begingroup$ @HarryMcKenzie,I have updated my question, adding pictures and explanations to explain the effect I want to achieve. Please help me review this question again.@Gorgious $\endgroup$
    – MA__AM
    Commented Aug 1 at 1:00

1 Answer 1

1
$\begingroup$

I'm not sure, but though it seems functional, it could be made simpler, which on a large scale could mean saving a lot of computing power and time.

That being said, it seems that all the objects you need to merge are always child of an empty with a specific name pattern BuildNodes_, so perhaps you could greatly simplify the algorithm:

  1. create list of all objects matching this name pattern and with >1 children
  2. for each:
    1. deselect all
    2. select children
    3. set first child as active
    4. join.
import bpy

parents = [obj for obj in bpy.context.scene.objects if obj.name.startswith('BuildNodes_') and len(obj.children) > 1]

for parent in parents:
    bpy.ops.object.select_all(action='DESELECT')
    for child in parent.children:
        child.select_set(True)
    bpy.context.view_layer.objects.active = parent.children[0]
    bpy.ops.object.join()

To be tested on a large scale.

$\endgroup$
4
  • $\begingroup$ Hello, I found some problems after my test,This seems to have something to do with the number of objects in the scene and the model data to be processed. After I reduce the number of objects in the scene to 2404, both my code and the code you provide can be executed successfully. However, when the number of objects in the scene is 6293, the software will flash back when the two pieces of code are executed. Similarly, when I limit the number of models to be processed to about 2300 with some rules, the software will not flash back even when there are many objects in the scene executing the code. $\endgroup$
    – MA__AM
    Commented Aug 1 at 2:44
  • 1
    $\begingroup$ Not sure what you mean by "flash back". But perhaps a safer approach to this issue would be to make the script work only on a selection of objects. $\endgroup$
    – Lauloque
    Commented Aug 1 at 15:19
  • $\begingroup$ "flash back"It means that blender is suddenly closed without any symptoms during the execution of the code, without any prompt or automatic saving; Yes, I modified the code to only deal with the model under the object I selected. $\endgroup$
    – MA__AM
    Commented Aug 2 at 1:08
  • $\begingroup$ I seem to find the reason why Blender flashes back frequently during code execution. It may be that I associated the grids with the same model before, which led to repeated replication of grid data during batch model consolidation or Blender flash back caused by grid data errors. It has nothing to do with code (although blender is still slow in batch model processing). The root cause is still in the model. $\endgroup$
    – MA__AM
    Commented Aug 2 at 3:46

You must log in to answer this question.

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