generated from GuangyanCai/nanobind_example
-
Notifications
You must be signed in to change notification settings - Fork 1
Examples
Guangyan Cai edited this page Jan 5, 2025
·
2 revisions
By default, isoext uses pytorch cuda tensors for most inputs and outputs. Read the API reference for more details.
This example demonstrates how to extract the isosurface of a complex shape using marching cubes and dual contouring.
import isoext
from isoext.sdf import *
# Create grid
grid = isoext.UniformGrid([256, 256, 256])
# Create composite SDF shape - a sphere with three orthogonal toroidal holes
torus_a = TorusSDF(R=0.75, r=0.15) # Base torus in xy plane
torus_b = RotationOp(sdf=torus_a, axis=[1, 0, 0], angle=90) # Rotated to xz plane
torus_c = RotationOp(sdf=torus_a, axis=[0, 1, 0], angle=90) # Rotated to yz plane
sphere_a = SphereSDF(radius=0.75)
sdf = IntersectionOp([sphere_a, NegationOp(UnionOp([torus_a, torus_b, torus_c]))])
# Evaluate SDF and extract isosurface
points = grid.get_points() # sample locations
sdf_v = sdf(points) # evaluate SDF at sample locations
grid.set_values(sdf_v) # store SDF values in grid
# Run marching cubes
print("Running marching cubes")
v, f = isoext.marching_cubes(grid)
print("Writing obj")
isoext.write_obj("mc.obj", v, f)
print("Done")
# Run dual contouring
print("Running dual contouring")
# Dual contouring requires a set of intersection points and normals to constrcut the QEF
its = isoext.get_intersection(grid)
points = its.get_points()
normals = get_sdf_normal(sdf, points)
its.set_normals(normals)
v, f = isoext.dual_contouring(grid, its)
print("Writing obj")
isoext.write_obj("dc.obj", v, f)
print("Done")Notes:
- You can specify the aabb bounds as follows:
grid = isoext.UniformGrid([256, 256, 256], aabb_min=[-1, -1, -1], aabb_max=[1, 1, 1])- You can use a neural network to generate the SDF values, or use a pre-computed SDF grid. If you have the grid of values already, you can skip the
grid.get_points()step and directly callgrid.set_values(). - Set the isolevel and method for marching cubes as follows:
isoext.marching_cubes(grid, level=0.0, method="nagae")- See Marching Cubes for more details.
- Dual contouring requires a set of intersection points and normals to constrcut the QEF. You can set the isolevel, regularization weight, and SVD tolerance (for QEF solver) for dual contouring as follows:
isoext.dual_contouring(grid, its, level=0.0, reg_weight=1e-2, svd_tol=1e-6)- See Dual Contouring for more details.
import isoext
from isoext.sdf import *
# Create grid
grid = isoext.SparseGrid([512, 512, 512])
# Create composite SDF shape - a sphere with three orthogonal toroidal holes
torus_a = TorusSDF(R=0.75, r=0.15) # Base torus in xy plane
torus_b = RotationOp(sdf=torus_a, axis=[1, 0, 0], angle=90) # Rotated to xz plane
torus_c = RotationOp(sdf=torus_a, axis=[0, 1, 0], angle=90) # Rotated to yz plane
sphere_a = SphereSDF(radius=0.75)
sdf = IntersectionOp([sphere_a, NegationOp(UnionOp([torus_a, torus_b, torus_c]))])
# Find active cells for sparse grid
max_chunk_size = 128**3
cell_indices_chunks = grid.get_potential_cell_indices(max_chunk_size)
active_cell_indices = []
for cell_indices in cell_indices_chunks:
points = grid.get_points_by_cell_indices(cell_indices)
values = sdf(points)
# Filter out inactive cells
filtered_cell_indices = grid.filter_cell_indices(cell_indices, values, level=0.0)
if filtered_cell_indices is not None:
active_cell_indices.append(filtered_cell_indices)
# Update grid with active cells
active_cell_indices = torch.cat(active_cell_indices)
grid.add_cells(active_cell_indices)
# Evaluate SDF and extract isosurface
sdf_v = sdf(grid.get_points())
grid.set_values(sdf_v)
# Run marching cubes
print("Running marching cubes")
v, f = isoext.marching_cubes(grid, level=0.0)
print("Writing obj")
isoext.write_obj("mc_sparse.obj", v, f)
print("Done")
# Run dual contouring
print("Running dual contouring")
its = isoext.get_intersection(grid)
points = its.get_points()
normals = get_sdf_normal(sdf, points)
its.set_normals(normals)
v, f = isoext.dual_contouring(grid, its, level=0.0)
print("Writing obj")
isoext.write_obj("dc_sparse.obj", v, f)
print("Done")