|
import logging |
|
|
|
import numpy as np |
|
|
|
try: |
|
import pymeshlab |
|
|
|
PYMESHLAB_AVAILABLE = True |
|
except ImportError: |
|
logging.warning( |
|
"pymeshlab is not installed or could not be loaded. Please install it with `pip install pymeshlab`." |
|
) |
|
PYMESHLAB_AVAILABLE = False |
|
from typing import Any |
|
|
|
|
|
class pymeshlab: |
|
MeshSet = Any |
|
Mesh = Any |
|
|
|
|
|
def create_pymeshset(vertices: np.ndarray, faces: np.ndarray): |
|
""" |
|
Creates a MeshLab MeshSet given a list of vertices and faces. |
|
""" |
|
assert PYMESHLAB_AVAILABLE, "pymeshlab is not installed or could not be loaded." |
|
|
|
mesh_set = pymeshlab.MeshSet() |
|
input_mesh = pymeshlab.Mesh(vertex_matrix=vertices, face_matrix=faces) |
|
mesh_set.add_mesh(input_mesh, "input_mesh") |
|
logging.info("Mesh successfully added to pymeshlab MeshSet.") |
|
return mesh_set |
|
|
|
|
|
def cleanup(ms: pymeshlab.MeshSet): |
|
""" |
|
General cleanup for a given Mesh. Removes degenerate elements from the |
|
geometry. |
|
""" |
|
ms.meshing_remove_null_faces() |
|
ms.meshing_remove_folded_faces() |
|
ms.meshing_remove_duplicate_vertices() |
|
ms.meshing_remove_duplicate_faces() |
|
ms.meshing_remove_t_vertices() |
|
ms.meshing_remove_unreferenced_vertices() |
|
|
|
|
|
def remove_floaters(ms: pymeshlab.MeshSet, threshold: float = 0.005): |
|
""" |
|
Remove any floating artifacts that exist from our mesh generation. |
|
""" |
|
assert PYMESHLAB_AVAILABLE, "pymeshlab is not installed or could not be loaded." |
|
ms.meshing_remove_connected_component_by_diameter( |
|
mincomponentdiag=pymeshlab.PercentageValue(15), removeunref=True |
|
) |
|
|
|
|
|
def simplify_mesh(ms: pymeshlab.MeshSet, target_face_num: int): |
|
""" |
|
Simplify the mesh to the target number of faces. |
|
""" |
|
ms.meshing_decimation_quadric_edge_collapse( |
|
targetfacenum=target_face_num, |
|
qualitythr=0.4, |
|
preservenormal=True, |
|
autoclean=True, |
|
) |
|
|
|
|
|
def save_mesh(ms: pymeshlab.MeshSet, output_path: str): |
|
""" |
|
Save the mesh to a file. |
|
""" |
|
ms.save_current_mesh(output_path) |
|
logging.info(f"Mesh saved to {output_path}.") |
|
|
|
|
|
def postprocess_mesh(ms: pymeshlab.MeshSet, target_face_num: int, output_path: str): |
|
""" |
|
Postprocess the mesh to the target number of faces. |
|
""" |
|
cleanup(ms) |
|
remove_floaters(ms) |
|
simplify_mesh(ms, target_face_num) |
|
|