Subscribe to our free newsletter

To make sure you won't miss any valuable content we share with our community.

How to Apply Boolean Union of Many Objects in Blender

This tutorial covers most (if not all) of the problems concerning the Boolean union of multiple objects in Blender. If you have worked with a Boolean modifier in Blender more than just a try, you must have faced the circumstances in which the result of union would have been a non-manifold mesh or you have wanted to Boolean union a great number of objects and you have ended up with a simple modifier that only does the Boolean union only for a couple of objects that you wouldn’t be sure if the result of the union would have non-manifold mesh or not. This article guides you with different ways to solve this issue.

Boolean Union of Multiple Objects in Blender

Suppose you have a lot of cubes that you want them all to merge into one object, if the number of cubes is n, you will have to apply the Boolean union modifier n-1 times, which takes a lot of time. You may use the Python Blender API and do this job in a loop. This solution is OK until you face with the non-manifold result caused by the Boolean modifier. That is when the issue begins.

To solve the above problem manually (without any scripting), you can get benefit from a useful hack in Blender and which is exporting the objects altogether. To do this, all you have to do is to select all the objects and export them (do not forget to check the Selection Only box). If you import the exported file, you will see that all of the objects have merged into one object.

There is also another way to do this in a more standard and sophisticated way and that is through scripting. The benefit of this method is that we can use it next to the rest of our code for more complex functionalities rather than just a Boolean union.

Now imagine that we want to create a button that Boolean union any number of cubes at once without any need to export or import anything. The following code will serve this purpose for us:

IMPORTANT NOTE:

Remember that the scripts we are using here are related to Blender version 2.83 and if you are working with any other versions, it is probable that the scripts might differ a little bit, but we will show you ways to find the proper functions if there are any differences at all.

Python Scripts

The below scripts will create a panel inside which you can Boolean union a large number of objects that have been imported in Blender or designed by the user. Notice that the main purpose of the below code is to make you familiar with the procedure and for other Boolean unions of another object with different names and numbers you should modify the code a bit. However, the utility functions remain the same.


import  bpy

####################################################################
#####                Utility Functions
####################################################################

def make_custom_context(*object_names, base_context=None, mode=None):
    if base_context is not None:
        ctx = base_context
    else:
        ctx = {}

    if mode is not None:
        assert mode in ('OBJECT', 'EDIT'), "Wrong mode used"
        ctx['mode'] = mode

    objs = [get_object_by_name(obj_name) for obj_name in object_names]
    ctx['active_object'] = ctx['object'] = objs[0]
    ctx['selected_editable_objects'] = ctx['selected_objects'] = objs
    ctx['editable_objects'] = ctx['selectable_objects'] = ctx['visible_objects'] = objs
    return ctx

def makeUnionOpt(*object_names):
    ctx = bpy.context.copy()
    if object_names:
        ctx = make_custom_context(*object_names, base_context=ctx, mode='OBJECT')
    bpy.ops.object.join(ctx)  # mostly the same as export/import combination

def get_object_by_name(obj_name):
    assert obj_name in bpy.data.objects, "Error getting object by name: {}".format(obj_name)
    obj = bpy.data.objects[obj_name]    
    return obj

def deselect_objects():
    bpy.ops.object.select_all(action='DESELECT')

####################################################################
########             Main Panel
####################################################################

class MainPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "VIEW_PT_MainPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Design Automation'
    
    def draw(self, context):
        layout = self.layout
        layout.scale_y = 1.2
        
        row = layout.row()
        row.label(text= "Design Automation", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("wm_function.myop", text= "Boolean Union of multiple cubes")           

####################################################################
####                  Main UI ّFunctions                  
####################################################################

class WM_Function_myOp(bpy.types.Operator):
    """Click to apply our customized function"""
    bl_label = "Our customized function"
    bl_idname = "wm_function.myop"
    
    n = bpy.props.IntProperty(name= "Enter the size of the Cube", default = 20)
  
    def execute(self, context):   
        n = self.n                    
        cubes = ["Cube" for i in range(n)]
        #cubes[0] = "Cube"      
        if(n >= 10 and n <= 99):
            for i in range (9):
                cubes[i+1] = "Cube.00%d"%(i+1)
          
            for i in range (n-10):
                cubes[i+10] = "Cube.0%d"%(i+10)
                
        elif(n < 10 and n >= 2):
            for i in range (9):
                cubes[i+1] = "Cube.00%d"%(i+1)
        
        cubes = tuple(cubes)      
        makeUnionOpt(cubes)

        return {'FINISHED'}
    
    def invoke(self, context, event):    
        return context.window_manager.invoke_props_dialog(self)  

####################################################################
#####                     Register and Unregister
####################################################################   
        
def register():
    bpy.utils.register_class(MainPanel)
    bpy.utils.register_class(WM_Function_myOp)
                                                  
def unregister():
    bpy.utils.unregister_class(MainPanel)
    bpy.utils.unregister_class(WM_Function_myOp)
                                                              
if __name__ == "__main__":
    register()
 

And as you can see, we have got one object at the end with the help of just a button.

Last Word

In this tutorial, we have managed to Boolean union a large number of objects using the Boolean union other than the one in the modifiers section. This type of union will join the objects and the good thing about this type of union is that the output will not have the non-manifold meshes especially when we have overlap between the objects. We have also provided a manual method so that you can avoid the scripts.

Download this Article in PDF format

web developement

Check Out Our Services

In Arashtad, we’re working on 3D games, metaverses, and other types of WebGL and 3D applications with our 3D web development team. However, our services are not limited to these. Back-end developments, front-end developments, 3d modeling, and animations are in our arsenal too.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
3D Development

A Quick Way to Automatically Remove Loose Parts in Blender

There are times that you face some unwanted extra objects all over your mesh such as when you get a raw 3d scan object that has been converted from point cloud to mesh. And, you want to quickly get rid of them all. In this tutorial, we are going to see how we can remove these loose parts in Blender and how we can create a button to quickly do that for us.

How to Remove Loose Parts in Blender

There are times that you face some unwanted extra objects all over your mesh such as when you get a raw 3d scan object that has been converted from point cloud to mesh and you want to quickly get rid of them all. In this tutorial, we are going to see how we can get away with these small useless specks of dust using Blender python and how we can create a button to quickly do that for us.

remove loose parts in Blender

IMPORTANT NOTE:

Remember that the scripts we are using here are related to Blender version 2.83 and if you are working with any other versions, it is probable that the scripts might differ a little bit, but we will show you ways to find the proper functions if there are any differences at all.

remove loose parts in Blender

Python Scripts

First of all, we write our utility functions and then apply them in the main panel.

import  bpy


####################################################################
#####                Utility Functions
####################################################################


def clean_from_loose_parts(obj):
    deselect_objects()

    # separate the mesh
    if obj.type == 'MESH':
        curr_obj_name = obj.name

        obj.select_set(True)
        bpy.ops.mesh.separate(type='LOOSE')

        # separated_objects = tuple(obj.name for obj in bpy.context.selected_objects))
        separated_objects_count = len(bpy.context.selected_objects)
        print("Mesh object {} separated in to {} object(s)".format(curr_obj_name, 									        
            separated_objects_count))

        if separated_objects_count > 1:
            # remove mesh objects which have less than max vertices
            obj_max_vertices = get_max_vertices_object_from_selection()
            obj_max_vertices.select_set(False)
            bpy.ops.object.delete()
            # restore input name of the object
            obj_max_vertices.name = curr_obj_name

        else:
            obj.select_set(False)



The above function will do the main job of removing small loose parts for us.

def get_max_vertices_object_from_selection():
    max_vert_count = 0
    obj_max_vertices = None
    for obj in bpy.context.selected_objects:
        vert_count = len(obj.data.vertices)
        if max_vert_count < vert_count:
            max_vert_count = vert_count
            obj_max_vertices = obj

    return obj_max_vertices            


The above function will count the vertices of the selected objects and return the one that has the maximum amount of vertices.

def get_object_by_name(obj_name):
    assert obj_name in bpy.data.objects, "Error getting object by name:{}".format(obj_name)
    obj = bpy.data.objects[obj_name]
    
    return obj


The above function will get the object by name and store it in a variable.

def deselect_objects():
    bpy.ops.object.select_all(action='DESELECT')


The above function will deselect the active object. Let’s write the code of our main panel.

####################################################################
########             Main Panel
####################################################################

class MainPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "VIEW_PT_MainPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Design Automation'
    
    def draw(self, context):
        layout = self.layout
        layout.scale_y = 1.2
        
        row = layout.row()
        row.label(text= "Design Automation", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("wm_function.myop", text= "Clean object from loose parts")           

####################################################################
####                  Main UI ّFunctions                  
####################################################################

class WM_Function_myOp(bpy.types.Operator):
    """Click to apply our customized function"""
    bl_label = "Our customized function"
    bl_idname = "wm_function.myop"
    

    def execute(self, context):
        
        obj = get_object_by_name('Sphere')
        clean_from_loose_parts(obj)

        return {'FINISHED'}
    
    def invoke(self, context, event):
        
        return context.window_manager.invoke_props_dialog(self)  

####################################################################
#####                     Register and Unregister
####################################################################

         
def register():
    bpy.utils.register_class(MainPanel)
    bpy.utils.register_class(WM_Function_myOp)
                                               
    
def unregister():
    bpy.utils.unregister_class(MainPanel)
    bpy.utils.unregister_class(WM_Function_myOp)
   
                                                       
    
if __name__ == "__main__":
    register()
    


In the above main panel script, we use the utility function clean_from_loose_parts(obj). The rest is related to the GUI of the panel.

Testing the Scripts

Now, it is finally time to run our code using CTRL + P or the run button at the top of the scripting window and we will see that a panel appears with a button using which we can remove extra loose parts.

Testing

And as you can see, the small loose parts are removed. Consequently, we can have a clean object from noises. You can apply this tool to any raw 3D scan and make the edition of it much faster.

Getting Rid of Loose Parts in Blender: Wrapping Up

In this tutorial, we have managed to create a panel that can remove the noises and loose parts from all the objects that have them in Blender. Most of the time we face the issue of having loose parts when we receive a raw 3D scan from a scanner device. Having such a tool is very useful and saves a lot of time for you.

Download this Article in PDF format

3d websites

Care to Know Us More?

In Arashtad, we have gathered a professional team of developers who are working in fields such as 3D websites, 3D games, metaverses, and other types of WebGL and 3D applications.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Fill in the Form
3D Development

How to Automate Your Tasks and Design in Blender

In this tutorial, you will see how Blender Python API could help you automate the tasks in Blender. So, You can skip many time-taking manual steps by scripting in the Blender Python. We are going to design a user interface to operate a certain number of tasks in a matter of seconds and at the same time make it easy for the user or designer to apply those tasks.

Introduction to Blender Python API

If you are familiar with the design processes in Blender, you must know that some design procedures can take hours or even days. So, you have to deal with some repeating tasks over and over again. That is when Blender Python API comes to our help. There are many times that you want to skip easily repeating but time-taking procedures and want them to boil down to only one button or some multiple buttons to make your life much easier and faster.

In this tutorial, we are going to see how we can manage these tasks and how we can find scripts related to the different modifiers that are going to be used consecutively.

Note: Remember that the scripts we are using here are related to Blender version 2.83 and if you are working with any other versions, it is probable that the scripts might differ a little bit, but we will show you ways to find the proper functions if there are any differences at all.

We start this tutorial with the most minimalistic functions and then try to build up our project to create a new valuable tool in Blender customized to hasten your designing procedures. Before we get started, we need to be familiar with some of the scripting tools provided in Blender. The first one is the scripting box which is created once you click on the scripting tab.

The second one is the Python console which helps you find the existing errors. And at last, one of the most important boxes that appears once you click the scripting tab is the one that shows the Python functions related to the modifiers that we apply manually or through the scripts on the bottom left window.

Designing the User Interface

Now, let’s get started with creating a button to automate our designing tasks in Blender:

First things first, we create a blank project. In other words, we create the front end of our customized function. Then write the backend of our project inside of our def execute the function. The following code is the simple front-end script that you need to start writing your API.

import  bpy

####################################################################
########             Main Panel
####################################################################

class MainPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "VIEW_PT_MainPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Design Automation'
    
    def draw(self, context):
        layout = self.layout
        layout.scale_y = 1.2    
        row = layout.row()
        row.label(text= "Design Automation", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("wm_function.myop", text= "Our Customized function")           



The above script is related to the front end of the button or buttons we are going to design. We create a class called MainPanel to design all of our buttons.

####################################################################
####                  Main UI Function               
####################################################################

class WM_Function_myOp(bpy.types.Operator):
    """Click to apply our customized function"""
    bl_label = "Our customized function"
    bl_idname = "wm_function.myop"
    
    size = bpy.props.FloatProperty(name= "Enter the required property", default = "2")

    def execute(self, context):        
        size = self.name
        return {'FINISHED'}
    
    def invoke(self, context, event):       
        return context.window_manager.invoke_props_dialog(self)  


In the above section of our script, we create a class for each button. Then we write our modifier functions inside of def execute (self, context). We also ask the users about the desired property for their design (like the size of an object). This job was done before executing the function by writing size = bpy.props.FloatProperty().


####################################################################
#####                     Register and Unregister
####################################################################  
         
def register():
    bpy.utils.register_class(MainPanel)
    bpy.utils.register_class(WM_Function_myOp)
                                                   
def unregister():
    bpy.utils.unregister_class(MainPanel)
    bpy.utils.unregister_class(WM_Function_myOp)


And finally, we should register and unregister all of the classes we have used inside of our script to be able to show them in the panel.

    
if __name__ == "__main__":
    register()


Also do not forget about the above if statement at the end of every project. Now if you run your code or press Ctrl + F, you will be able to see the panel and the corresponding button called Our Customized function.

Blender

Now that we are familiar with the base template of the code related to our own panel, it is time to write the scripts related to the consecutive tasks that we want to apply to an object or a number of objects. At first, you may not be familiar with the code related to every modifier. The way to find the code is to apply the modifier manually and then look at the bottom left window related to the Python script of the function. Then copy and paste the code in the def execute section of your code.

For example, we want to create a sphere and a cube and then resize them. First we add a cube and an sphere and resize our sphere by 1.4 in every direction:

Blender

Notice that it is really hard to resize our object exactly the number we want manually and if you want the precise numbers, you should script instead of manual design. Now, if we delete the objects and copy the codes related to creating and resizing the objects from the bottom left window and paste them into the execute function, run the code and click on the “Our Customized function” button, we will see the exact same result with the difference that this one is applied much faster and easier.

bpy.ops.mesh.primitive_uv_sphere_add(enter_editmode=False, align='WORLD', location=(0, 0, 0))
bpy.ops.transform.resize(value=(1.4, 1.4, 1.4))
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 0))


Notice that you can change the location of the object at the time of creating it, simply by changing the array of location attribute related to bpy.ops.mesh.primitive_uv_sphere_add or bpy.ops.mesh.primitive_cube_add.

You can do the above task for designing a large number of objects like designing a hundred cylinders or cubes or spheres. You can do this in a fraction of a second over and over again by using the above scripts and some Python for loops.

Final Word

In this tutorial, we have proposed an easier way to manage multi-tasking design processes. In other words, we managed to automate the tasks in Blender that take a much longer time if you want to apply them one by one. We have introduced Blender Python API as a tool to create a greater variety of tool boxes compared to the Blender modifiers.

Download this Article in PDF format

metaverse

Care to Know About Metaverse?

In Arashtad, we are providing custom services on 3d developments such as 3d websites, 3d models, metaverses and all 3d applications.

Arashtad Serivces
Drop us a message and tell us about your ideas.
Tell Us What You Need
Blockchain Development