import pymeshlab import trimesh import open3d as o3d def mesh_to_pymesh(vertices, faces): mesh = pymeshlab.Mesh(vertex_matrix=vertices, face_matrix=faces) ms = pymeshlab.MeshSet() ms.add_mesh(mesh) return ms def pymesh_to_trimesh(mesh): verts = mesh.vertex_matrix()#.tolist() faces = mesh.face_matrix()#.tolist() return trimesh.Trimesh(vertices=verts, faces=faces) #, vID, fID def simplify_mesh(mesh: trimesh.Trimesh, n_faces): if mesh.faces.shape[0] > n_faces: ms = mesh_to_pymesh(mesh.vertices, mesh.faces) ms.meshing_merge_close_vertices() ms.meshing_decimation_quadric_edge_collapse(targetfacenum = n_faces) return pymesh_to_trimesh(ms.current_mesh()) else: return mesh def repair_mesh_manifold(mesh_path): """Clean up non-manifold geometry (diso extraction / decimation can introduce it) so open3d's compute_uvatlas doesn't reject the mesh with UVAtlasPartition failed. pymeshlab can't write .glb directly, so route through trimesh for I/O like simplify_mesh does.""" mesh = trimesh.load(mesh_path, force="mesh") ms = mesh_to_pymesh(mesh.vertices, mesh.faces) ms.meshing_remove_duplicate_faces() ms.meshing_remove_duplicate_vertices() ms.meshing_remove_unreferenced_vertices() ms.meshing_repair_non_manifold_edges() ms.meshing_repair_non_manifold_vertices() pymesh_to_trimesh(ms.current_mesh()).export(mesh_path)