process_from_sdf
Evaluate an SDF function and run the full pipeline
Import
from xeltofab import process_from_sdf
# or
from xeltofab.pipeline import process_from_sdfSignature
def process_from_sdf(
sdf_fn: SDFFunction,
bounds: Bounds3D,
resolution: int = 128,
adaptive: bool = False,
extraction_method: Literal["mc", "dc", "surfnets", "manifold"] = "dc",
chunk_size: int | None = None,
**pipeline_kwargs,
) -> PipelineStateParameters
| Parameter | Type | Default | Description |
|---|---|---|---|
sdf_fn | Callable[[ndarray], ndarray] | required | SDF function: [N, 3] float64 → [N] float64 signed distances |
bounds | tuple[float, ...] | required | (xmin, ymin, zmin, xmax, ymax, zmax) spatial region |
resolution | int | 128 | Cells along the longest bounding box axis; shorter axes proportional |
adaptive | bool | False | Use octree-accelerated evaluation — reduces evaluations from O(N³) to ~O(N²) by culling cells far from the surface |
extraction_method | str | "dc" | Extraction backend: mc, dc, surfnets, manifold |
chunk_size | int | None | None | Max points per sdf_fn call. None = entire Z-slab at once |
**pipeline_kwargs | Forwarded to PipelineParams (e.g., smoothing_method, decimate_ratio) |
Return value
Returns a PipelineState with extracted and post-processed mesh, identical to what process() returns.
What it does
process_from_sdf is the entry point for SDF functions (neural models, analytical formulas, or any callable). It:
- Validates the bounds (6 floats, each min < max)
- Evaluates the SDF function on a uniform grid (one Z-slab at a time for memory efficiency)
- Validates the first slab's output (shape, NaN/inf, dtype)
- Runs the full pipeline — extract → smooth → repair → remesh → decimate
The SDF function receives points as [N, 3] arrays in (x, y, z) order and must return [N] signed distances. Internally, the grid is stored as [Nz, Ny, Nx] to match the existing extraction pipeline.
Resolution semantics
resolution specifies cells along the longest bounding box axis. Shorter axes get proportionally fewer cells, preserving aspect ratio. For example, bounds=(0, 0, 0, 2, 1, 1) with resolution=128 produces a 128 x 64 x 64 grid.
Smart defaults
Since the input is an SDF function, process_from_sdf automatically sets field_type="sdf", which triggers the same smart defaults as grid-based SDF processing:
- Direct extraction (no preprocessing)
- Extraction level at 0.0 (zero level set)
- Dual Contouring as the default extraction method (which in turn triggers bilateral smoothing with reduced Taubin iterations)
Adaptive evaluation
When adaptive=True, the evaluator uses octree-accelerated coarse-to-fine refinement instead of evaluating every grid point:
- Evaluate SDF at a coarse grid (resolution / 8)
- Cull cells far from the zero level set using a Lipschitz bound
- Subdivide only near-surface cells and repeat for
log2(coarse_factor)levels - Evaluate remaining fine cells at the target resolution
This reduces evaluations from O(N³) to ~O(N²). Unevaluated regions far from the surface are filled with +1.0 (positive = outside). If the entire domain is inside or outside the surface (no zero crossing found), the fill value is determined by evaluating the SDF at the domain center — avoiding false surfaces.
Known limitations of adaptive mode
- Grid resolution may differ slightly from the requested
resolutiondue to rounding during coarse cell computation (e.g.,resolution=32may produce a 33³ grid). The returned coordinate arrays reflect the actual grid dimensions. - The output is an extraction cache, not a true SDF. Deep interior regions are filled with
+1.0regardless of the actual SDF sign. This is correct for mesh extraction (MC/DC ignore these regions) but meansoctree_evaluate()output should not be used as a general-purpose SDF field. - Mesh vertices are in grid-index coordinates, not world-space. This is consistent with all extraction methods in the pipeline (MC, DC, SurfNets, manifold3d).
For finer control, use octree_evaluate() directly from xeltofab.sdf_eval:
| Parameter | Type | Default | Description |
|---|---|---|---|
coarse_factor | int | 8 | Fine-to-coarse ratio. Must be a power of 2. |
lipschitz | float | 1.1 | Culling threshold. Cells kept when min(|SDF|) < lipschitz * cell_diagonal |
See the SDF Functions guide for details on when adaptive evaluation helps.
Examples
Analytical SDF
import numpy as np
from xeltofab import process_from_sdf, save_mesh
def sphere_sdf(points: np.ndarray) -> np.ndarray:
return np.linalg.norm(points, axis=1) - 1.0
result = process_from_sdf(sphere_sdf, bounds=(-2, -2, -2, 2, 2, 2), resolution=64)
save_mesh(result, "sphere.stl")PyTorch neural SDF
import numpy as np
import torch
from xeltofab import process_from_sdf, save_mesh
model = torch.load("nito_bridge.pt")
def bridge_sdf(points: np.ndarray) -> np.ndarray:
with torch.no_grad():
t = torch.from_numpy(points).float().cuda()
return model(t).squeeze(-1).cpu().numpy()
result = process_from_sdf(bridge_sdf, bounds=(-1, -1, -1, 1, 1, 1), resolution=256)
save_mesh(result, "bridge.stl")ONNX model (framework-free)
import numpy as np
import onnxruntime as ort
from xeltofab import process_from_sdf, save_mesh
session = ort.InferenceSession("model.onnx")
def onnx_sdf(points: np.ndarray) -> np.ndarray:
# flatten() ensures [N] output even if model returns [N, 1]
return session.run(None, {"points": points.astype(np.float32)})[0].flatten()
result = process_from_sdf(onnx_sdf, bounds=(-1, -1, -1, 1, 1, 1), resolution=256)
save_mesh(result, "output.stl")Custom pipeline parameters
result = process_from_sdf(
my_sdf,
bounds=(-1, -1, -1, 1, 1, 1),
resolution=128,
extraction_method="mc", # use Marching Cubes instead of DC
smoothing_method="taubin", # override bilateral default
decimate_ratio=0.3, # aggressive decimation
)Adaptive evaluation (octree)
# Large grid with expensive neural SDF — adaptive skips far-from-surface cells
result = process_from_sdf(
neural_sdf,
bounds=(-1, -1, -1, 1, 1, 1),
resolution=256,
adaptive=True,
chunk_size=50000,
)For advanced octree control (coarse_factor, lipschitz):
from xeltofab.sdf_eval import octree_evaluate
from xeltofab.pipeline import process
from xeltofab.state import PipelineParams, PipelineState
grid, x, y, z = octree_evaluate(
my_sdf,
bounds=(-1, -1, -1, 1, 1, 1),
resolution=256,
coarse_factor=16, # 4 refinement levels
lipschitz=1.5, # more conservative culling
)
params = PipelineParams(field_type="sdf")
state = PipelineState(field=grid, params=params)
result = process(state)