Using External SDF Libraries

While isoext includes basic SDF primitives for convenience, you can use any SDF library to generate your scalar fields. One excellent option is sdf by Michael Fogleman—a powerful Python library for constructing complex SDF.

It can be installed by

pip install git+https://github.com/fogleman/sdf
import sdf
import isoext
import torch
from _viz import show_mesh
Running cmake --build & --install in /home/gcnick/Documents/code/isoext/build/cp312-abi3-linux_x86_64

Example

This example recreates the weave demo from the sdf library.

# The following example is taken from https://github.com/fogleman/sdf/blob/main/examples/weave.py

f = sdf.rounded_box([3.2, 1, 0.25], 0.1).translate((1.5, 0, 0.0625))
f = f.bend_linear(sdf.X * 0.75, sdf.X * 2.25, sdf.Z * -0.1875, sdf.ease.in_out_quad)
f = f.circular_array(3, 0)

f = f.repeat((2.7, 5.4, 0), padding=1)
f |= f.translate((2.7 / 2, 2.7, 0))

f &= sdf.cylinder(10)
f |= (sdf.cylinder(12) - sdf.cylinder(10)) & sdf.slab(z0=-0.5, z1=0.5).k(0.25)

Sample the SDF on a grid. Since the sdf library operates on NumPy arrays, we convert between PyTorch and NumPy:

shape = [256, 256, 256]
aabb_min = [-13, -13, -13]
aabb_max = [13, 13, 13]
grid = isoext.UniformGrid(shape, aabb_min, aabb_max)
points = grid.get_points().cpu().numpy()
points = points.reshape(-1, 3)
values = f(points).reshape(shape)
values = torch.from_numpy(values).cuda()
grid.set_values(values)

Extract the mesh with marching cubes:

vertices, faces = isoext.marching_cubes(grid)

print(f"Vertices: {vertices.shape}")  # (N, 3) float32
print(f"Faces: {faces.shape}")        # (M, 3) uint32

show_mesh(vertices, faces)
Vertices: torch.Size([110818, 3])
Faces: torch.Size([222000, 3])
_images/688901cfaac9a30a804ee856b7febdad673d6f53983043278f55e9c580444303.png