- Added 3DGS - Solved the problem of auto_grad fail using with torch.inference_mode(False): since torch in ComfyUI is set to inference mode by default - Testing Example workflows & Updated the documents
148 lines
4.0 KiB
Python
148 lines
4.0 KiB
Python
import numpy as np
|
|
import pymeshlab as pml
|
|
|
|
|
|
def poisson_mesh_reconstruction(points, normals=None):
|
|
# points/normals: [N, 3] np.ndarray
|
|
|
|
import open3d as o3d
|
|
|
|
pcd = o3d.geometry.PointCloud()
|
|
pcd.points = o3d.utility.Vector3dVector(points)
|
|
|
|
# outlier removal
|
|
pcd, ind = pcd.remove_statistical_outlier(nb_neighbors=20, std_ratio=10)
|
|
|
|
# normals
|
|
if normals is None:
|
|
pcd.estimate_normals()
|
|
else:
|
|
pcd.normals = o3d.utility.Vector3dVector(normals[ind])
|
|
|
|
# visualize
|
|
o3d.visualization.draw_geometries([pcd], point_show_normal=False)
|
|
|
|
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
|
|
pcd, depth=9
|
|
)
|
|
vertices_to_remove = densities < np.quantile(densities, 0.1)
|
|
mesh.remove_vertices_by_mask(vertices_to_remove)
|
|
|
|
# visualize
|
|
o3d.visualization.draw_geometries([mesh])
|
|
|
|
vertices = np.asarray(mesh.vertices)
|
|
triangles = np.asarray(mesh.triangles)
|
|
|
|
print(
|
|
f"[INFO] poisson mesh reconstruction: {points.shape} --> {vertices.shape} / {triangles.shape}"
|
|
)
|
|
|
|
return vertices, triangles
|
|
|
|
|
|
def decimate_mesh(
|
|
verts, faces, target, backend="pymeshlab", remesh=False, optimalplacement=True
|
|
):
|
|
# optimalplacement: default is True, but for flat mesh must turn False to prevent spike artifect.
|
|
|
|
_ori_vert_shape = verts.shape
|
|
_ori_face_shape = faces.shape
|
|
|
|
if backend == "pyfqmr":
|
|
import pyfqmr
|
|
|
|
solver = pyfqmr.Simplify()
|
|
solver.setMesh(verts, faces)
|
|
solver.simplify_mesh(target_count=target, preserve_border=False, verbose=False)
|
|
verts, faces, normals = solver.getMesh()
|
|
else:
|
|
m = pml.Mesh(verts, faces)
|
|
ms = pml.MeshSet()
|
|
ms.add_mesh(m, "mesh") # will copy!
|
|
|
|
# filters
|
|
# ms.meshing_decimation_clustering(threshold=pml.Percentage(1))
|
|
ms.meshing_decimation_quadric_edge_collapse(
|
|
targetfacenum=int(target), optimalplacement=optimalplacement
|
|
)
|
|
|
|
if remesh:
|
|
# ms.apply_coord_taubin_smoothing()
|
|
ms.meshing_isotropic_explicit_remeshing(
|
|
iterations=3, targetlen=pml.Percentage(1)
|
|
)
|
|
|
|
# extract mesh
|
|
m = ms.current_mesh()
|
|
verts = m.vertex_matrix()
|
|
faces = m.face_matrix()
|
|
|
|
print(
|
|
f"[INFO] mesh decimation: {_ori_vert_shape} --> {verts.shape}, {_ori_face_shape} --> {faces.shape}"
|
|
)
|
|
|
|
return verts, faces
|
|
|
|
|
|
def clean_mesh(
|
|
verts,
|
|
faces,
|
|
v_pct=1,
|
|
min_f=64,
|
|
min_d=20,
|
|
repair=True,
|
|
remesh=True,
|
|
remesh_size=0.01,
|
|
):
|
|
# verts: [N, 3]
|
|
# faces: [N, 3]
|
|
|
|
_ori_vert_shape = verts.shape
|
|
_ori_face_shape = faces.shape
|
|
|
|
m = pml.Mesh(verts, faces)
|
|
ms = pml.MeshSet()
|
|
ms.add_mesh(m, "mesh") # will copy!
|
|
|
|
# filters
|
|
ms.meshing_remove_unreferenced_vertices() # verts not refed by any faces
|
|
|
|
if v_pct > 0:
|
|
ms.meshing_merge_close_vertices(
|
|
threshold=pml.Percentage(v_pct)
|
|
) # 1/10000 of bounding box diagonal
|
|
|
|
ms.meshing_remove_duplicate_faces() # faces defined by the same verts
|
|
ms.meshing_remove_null_faces() # faces with area == 0
|
|
|
|
if min_d > 0:
|
|
ms.meshing_remove_connected_component_by_diameter(
|
|
mincomponentdiag=pml.Percentage(min_d)
|
|
)
|
|
|
|
if min_f > 0:
|
|
ms.meshing_remove_connected_component_by_face_number(mincomponentsize=min_f)
|
|
|
|
if repair:
|
|
# ms.meshing_remove_t_vertices(method=0, threshold=40, repeat=True)
|
|
ms.meshing_repair_non_manifold_edges(method=0)
|
|
ms.meshing_repair_non_manifold_vertices(vertdispratio=0)
|
|
|
|
if remesh:
|
|
# ms.apply_coord_taubin_smoothing()
|
|
ms.meshing_isotropic_explicit_remeshing(
|
|
iterations=3, targetlen=pml.AbsoluteValue(remesh_size)
|
|
)
|
|
|
|
# extract mesh
|
|
m = ms.current_mesh()
|
|
verts = m.vertex_matrix()
|
|
faces = m.face_matrix()
|
|
|
|
print(
|
|
f"[INFO] mesh cleaning: {_ori_vert_shape} --> {verts.shape}, {_ori_face_shape} --> {faces.shape}"
|
|
)
|
|
|
|
return verts, faces
|