Is there a way to use the terminal to check if a mesh is water tight? I want to do something like:
if my_mesh_obj.water_tight == True: print('It is water tight') else: print('It is not water tight')
In order to check if a mesh is watertight, we can test that the mesh is 2-manifold and no boundary edges exist .
The following definitions are loosely based on the quoted sources, some terminology and explanations were adjusted. This may not be up to standard for a scientific publication.
Definition: Watertight :
In layman terms, there shouldn't be any:
bpy.ops.mesh.select_non_manifold already performs these tests as batFINGER mentioned, except for the self-intersection check. This requires the use of a tree structure to efficiently determine intersections with itself, for instance a k-d tree, AABB tree, BVH tree or octree.
The script below selects only vertices that are non-manifold through
extend=False argument is important since the current vertex selection should be ignored. The
is_watertight function then iterates over the vertices and checks if any vertex is selected. Once it finds a selected vertex, it's clear that the mesh is non-manifold and therefore not watertight.
The self-intersection test is performed using a BVH tree. In case you don't need the test because you can guarantee that the mesh doesn't have self-intersections, you can disable it by setting the
check_self_intersection argument to
Please be aware that the BVH overlap computation in
mathutils doesn't allow to exclude the comparison between the exact same face when comparing the tree with itself. Therefore a small but non-zero epsilon is used during the intersection calculation to avoid false positives, where each face would be considered to be intersecting itself. However this non-zero epsilon also allows slight intersections below the threshold to pass as watertight. Therefore a proper implementation would exclude the comparison of faces with themselves. Given that the example is supposed to be self-contained, only use modules readily available in Blender and be reasonably efficient, I've used the
overlap function despite its shortcomings.
import bpy import bmesh import mathutils def is_watertight(object: bpy.types.Object, check_self_intersection=True) -> bool: """ Checks whether the given object is watertight or not :param object: Object the inspect :return: True if watertight, False otherwise """ old_active_object = bpy.context.view_layer.objects.active old_mode = old_active_object.mode bpy.context.view_layer.objects.active = object bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_non_manifold(extend=False) bm = bmesh.from_edit_mesh(object.data) is_watertight = True for v in bm.verts: if v.select: is_watertight = False break # Only check for self intersection if manifold if is_watertight and check_self_intersection: bvh_tree = mathutils.bvhtree.BVHTree.FromBMesh(bm, epsilon=0.000001) intersections = bvh_tree.overlap(bvh_tree) if intersections: is_watertight = False bpy.context.view_layer.objects.active = old_active_object bpy.ops.object.mode_set(mode=old_mode) return is_watertight if __name__ == "__main__": object = bpy.context.view_layer.objects.active if is_watertight(object): print("It's watertight.") else: print("It's not watertight.")
 David Stutz, A Formal Definition of Watertight Meshes, 2018. [Online]. Available: https://davidstutz.de/a-formal-definition-of-watertight-meshes/. [Accessed: 2019-12-05]
 C.-K. Shene, Mesh Basics, 2010. [Online]. Available: https://pages.mtu.edu/~shene/COURSES/cs3621/SLIDES/Mesh.pdf. [Accessed: 2019-12-05]