Fixing Non-Manifold Meshes in Blender

Fixing Non-Manifold Meshes in Blender

One of the things that will make you fed up with Boolean modifiers in Blender is the non-manifold output. Unfortunately, there is no robust way to cover this issue. However, we can create a tool that can fix most (if not all) of the problematic meshes. This tool helps us fix non-manifold meshes in Blender.



Creating A Tool to fix Non-Manifold Meshes in Blender



In the photo below, you can see an example of a non-manifold result that appeared as a result of a Boolean difference of another cube from this one. If you apply another Boolean operation on this object, you will see that the object gets fully destroyed.

non-manifold meshes



Python Scripts

In the scripts below we will get benefit from the functions that will eventually create a standard mesh that is the result of remeshing from triangular meshes to voxel-based meshes and also removing the non-manifold meshes.

import bpy


import bmesh


import math

####################################################################


##### Utility Functions


####################################################################

def fixMesh(obj_name):


make_voxel_remesh(get_object_by_name(obj_name), 0.5)


if is_object_have_non_manifolds(get_object_by_name(obj_name)):


print(obj_name, "have non manifolds")


if remove_object_non_manifold_loops(obj_name, loops=2):


print("Filled:", fill_non_manifolds(obj_name))


obj = get_object_by_name(obj_name)


make_smooth_remesh(obj, 9, 0.9, 1, True, True)

The above function is the main function for fixing the meshes. At first, it remeshes the object from triangular to voxel-based. Then, it will check whether has non-manifold parts and if the answer is yes, it will remove those parts. In the end, it will smooth and remesh the object.

def is_object_have_non_manifolds(obj):


assert obj.type == 'MESH', "Unsupported object type"


bmo = bmesh.new()


bmo.from_mesh(obj.data)


have = False


for edge in bmo.edges:


if not edge.is_manifold:


have = True


break


if not have:


for vert in bmo.verts:


if not vert.is_manifold:


have = True


break


bmo.free() # free and prevent further access


return have

The above function checks whether the object has non-manifold parts or not.

def deselect_objects():


bpy.ops.object.select_all(action='DESELECT')

def select_object_by_name(obj_name):


get_object_by_name(obj_name).select_set(True) # Blender 2.8x

def activate_object_by_name(obj_name):


bpy.context.view_layer.objects.active = get_object_by_name(obj_name)

def is_object_contain_selected_vertices(obj):


if obj.mode == "EDIT":


bm = bmesh.from_edit_mesh(obj.data)


else:


bm = bmesh.new()


bm.from_mesh(obj.data)


selected = False


for v in bm.verts:


if v.select:


selected = True


break


bm.free()


return selected

def remove_object_non_manifold_loops(obj_name, loops=0):


deselect_objects()


select_object_by_name(obj_name)


activate_object_by_name(obj_name)


removed = False


bpy.ops.object.mode_set(mode='EDIT')


bpy.ops.mesh.select_mode(type="VERT")


bpy.ops.mesh.select_non_manifold(extend=False)


if is_object_contain_selected_vertices(get_object_by_name(obj_name)):


if loops:


for i in range(loops):


bpy.ops.mesh.select_more()


bpy.ops.mesh.delete(type='FACE')


else:


bpy.ops.mesh.delete(type='VERT')


removed = True


bpy.ops.mesh.select_all(action='DESELECT')


bpy.ops.object.mode_set(mode='OBJECT')


return removed

def fill_non_manifolds(obj_name):


deselect_objects()


select_object_by_name(obj_name)


filled = False


bpy.ops.object.mode_set(mode='EDIT')


bpy.ops.mesh.select_mode(type="VERT")


bpy.ops.mesh.select_non_manifold(extend=False)


if is_object_contain_selected_vertices(get_object_by_name(obj_name)):


bpy.ops.mesh.fill(use_beauty=True)


bpy.ops.mesh.normals_make_consistent(inside=False)


bpy.ops.mesh.faces_shade_smooth()


filled = True


bpy.ops.mesh.select_all(action='DESELECT')


bpy.ops.object.mode_set(mode='OBJECT')


return filled

The above function will fill the open meshes.

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


return obj

def make_voxel_remesh(obj, voxel_size, adaptivity=0, use_smooth_shade=True):


modifier = obj.modifiers.new(name='remesh', type='REMESH')


modifier.mode = 'VOXEL'


modifier.voxel_size = voxel_size


modifier.adaptivity = adaptivity


modifier.use_smooth_shade = use_smooth_shade


res = bpy.ops.object.modifier_apply({"object": obj}, apply_as='DATA', modifier=modifier.name)


assert "FINISHED" in res, "Error"

The above function will remesh the object to a voxel-based object.

def make_smooth_remesh(obj, octree_depth=9, scale=0.9, threshold=1, use_smooth_shade=True, use_remove_disconnected=True):


modifier = obj.modifiers.new(name='remesh', type='REMESH')


modifier.mode = 'SMOOTH'


modifier.use_smooth_shade = use_smooth_shade


modifier.octree_depth = octree_depth


modifier.scale = scale


modifier.use_remove_disconnected = use_remove_disconnected


modifier.threshold = threshold


res = bpy.ops.object.modifier_apply({"object": obj}, apply_as='DATA', modifier=modifier.name)


assert "FINISHED" in res, "Error"

####################################################################


######## 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= "Fix Mesh")

####################################################################


#### Main UI ّFunctions


####################################################################

class WM_Function_myOp(bpy.types.Operator):


"""Go to edit mode and determine the point then Click the button"""


bl_label = "Our customized function"


bl_idname = "wm_function.myop"

def execute(self, context):

fixMesh('Cube')

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()

Now if we run the code and click the Fix Mesh button in the panel, we will see that mesh of the cube has been fixed.

meshes in Blender



Fixing Non-Manifold Meshes: Done!

In this tutorial, we have managed to write the scripts of the utility functions that would help us remove or fix the non-manifold meshes in Blender. We have applied these utility functions in our main panel class and as a result, we have a fixed output.




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.




See Our Services

Arashtad Serivces

Drop us a message and tell us about your ideas.

Tell Us What You Need

3D Development
https://blog.arashtad.com/3d/blender/fix-non-manifold-meshes-in-blender/

Comments

Popular posts from this blog

Why Smart Contracts Are Revolutionary? (Smart Contracts Use Cases)

How to Improve SEO Rankings?

WordPress: The best CMS platform to create website