Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions cumesh/remeshing.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ def remesh_narrow_band_dc(
band: float = 1,
project_back: float = 0,
verbose: bool = False,
bvh = None
bvh = None,
preserve_sharp_edges: bool = False,
sharp_angle_threshold: float = 30.0,
) -> Tuple[torch.Tensor, torch.Tensor]:
"""
Remesh the mesh using the narrow band UDF and dual contouring.

This function implements a narrow-band Isosurface extraction.
It first builds a sparse voxel grid around the surface using an octree-like approach,
then computes Dual Contouring vertices using the C++ extension,
Expand All @@ -49,6 +51,8 @@ def remesh_narrow_band_dc(
band: width of the narrow band in voxel units.
project_back: float ratio to project the vertices back to the original mesh
verbose: print progress.
preserve_sharp_edges: if True, detect and preserve edges sharper than threshold.
sharp_angle_threshold: angle in degrees above which edges are considered sharp.

Returns:
(V_new, F_new): Tuple of vertices and faces of the new mesh.
Expand Down Expand Up @@ -172,17 +176,27 @@ def remesh_narrow_band_dc(
# -------------------------------------------------------------------------
if verbose:
print("Running Dual Contouring...")

if preserve_sharp_edges:
print(f" Sharp edge preservation enabled (threshold: {sharp_angle_threshold}°)")

# Insert Grid Vertices into a new hashmap so DC kernel can look up values by coord
hashmap_vert = _init_hashmap(resolution + 1, 2 * Nvert, device)
# The hashmap maps (x,y,z) -> index in grid_verts/distances_vert
_C.hashmap_insert_3d_idx_as_val_cuda(*hashmap_vert, torch.cat([torch.zeros_like(grid_verts[:, :1]), grid_verts], dim=1), resolution + 1, resolution + 1, resolution + 1)
# Compute dual vertices positions (Relaxation / Mean of intersections) and intersections

# Compute dual vertices positions and intersections
# Returns (Nvox, 3) float tensor and (Nvox, 3) int tensor
dual_verts, intersected = _C.simple_dual_contour(
*hashmap_vert, coords, distances_vert, resolution + 1, resolution + 1, resolution + 1
)
if preserve_sharp_edges:
# Use sharp edge preserving kernel with gradient-based normal clustering
dual_verts, intersected = _C.simple_dual_contour_sharp(
*hashmap_vert, coords, distances_vert, resolution + 1, resolution + 1, resolution + 1,
sharp_angle_threshold
)
else:
# Original behavior: mean of intersections
dual_verts, intersected = _C.simple_dual_contour(
*hashmap_vert, coords, distances_vert, resolution + 1, resolution + 1, resolution + 1
)

# -------------------------------------------------------------------------
# 6. Topology Generation (Connectivity)
Expand Down
1 change: 1 addition & 0 deletions src/ext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
// Remeshing functions
m.def("get_sparse_voxel_grid_active_vertices", &cumesh::get_sparse_voxel_grid_active_vertices);
m.def("simple_dual_contour", &cumesh::simple_dual_contour);
m.def("simple_dual_contour_sharp", &cumesh::simple_dual_contour_sharp);
}
27 changes: 27 additions & 0 deletions src/remesh/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,31 @@ std::tuple<torch::Tensor, torch::Tensor> simple_dual_contour(
);


/**
* Isosurfacing with sharp edge preservation using gradient-based normal clustering.
*
* @param hashmap_keys [Nvert] uint32/uint64 hashmap of the vertices keys
* @param hashmap_vals [Nvert] uint32 tensor containing the hashmap values as vertex indices
* @param coords [Mvox, 3] int32 tensor containing the coordinates of the active voxels
* @param udf [Mvert] float tensor containing the UDF/SDF values at the vertices
* @param W the number of width dimensions
* @param H the number of height dimensions
* @param D the number of depth dimensions
* @param sharp_angle_threshold angle in degrees above which edges are considered sharp
*
* @return [L, 3] float tensor containing the active vertices (Dual Vertices)
* [L, 3] int32 tensor containing the intersected edges
*/
std::tuple<torch::Tensor, torch::Tensor> simple_dual_contour_sharp(
const torch::Tensor& hashmap_keys,
const torch::Tensor& hashmap_vals,
const torch::Tensor& coords,
const torch::Tensor& udf,
int W,
int H,
int D,
float sharp_angle_threshold
);


} // namespace cumesh
Loading