Skip to content

Add narrow-band SDF reinitialize/retopologize ops#669

Merged
swahtz merged 4 commits into
openvdb:mainfrom
swahtz:retopologize_sdf
Jun 18, 2026
Merged

Add narrow-band SDF reinitialize/retopologize ops#669
swahtz merged 4 commits into
openvdb:mainfrom
swahtz:retopologize_sdf

Conversation

@swahtz

@swahtz swahtz commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Adds an SDF reinitialization operator and a narrow-band retopologization helper. The core is a VoxelBlockManager (VBM) eikonal solver ported from standalone code used in a NanoVDB meshing prototype.

Motivation

This is the first needed component of a port of the OpenVDB VolumeToMesh dual-contouring meshing tool to NanoVDB + VoxelBlockManager that I've been developing as a standalone example and I imagined is likely useful for other applications which use fvdb-core.

Changes

Core CUDA op — src/fvdb/detail/ops/ReinitializeSdf.{h,cu} (new)

reinitialize_sdf redistances a per-voxel signed field to |grad phi| = 1 on the same grid (topology unchanged):

  • TVD-RK Godunov upwind eikonal solve, order 1 (forward Euler), 2 (Heun), or 3 (Shu-Osher), with a frozen Peng smoothed sign.
  • Optional de-staircasing by mean-curvature or volume-preserving Taubin Laplacian smoothing (smooth passes), selected via SmoothingMode.
  • The field is clamped to [-band*vx, band*vx] each sweep; inactive face-neighbours read the +band*vx "outside" value.
  • Per-grid loop over the batch; per-grid value-indexed scratch buffers (slot 0 holds the background) are gathered from / scattered to the JaggedTensor.
  • float32 / float64; CUDA only (the VBM is a CUDA structure — CPU raises a clear TORCH_CHECK).

Python composition — fvdb/functional/_sdf.py (new)

retopologize_sdf composes reinitialize_sdf with existing ops, no new C++ plumbing:

  1. (optional, default pad=True) dilate by band via dilated_grid and carry the field onto the new voxels via inject, seeding them as exterior, so the output band is a full band voxels wide even when the input grid's active band was thinner;
  2. reinitialize_sdf; (optional, default prune=True) keep |phi| < band*vx*0.999 via the existing pruned_grid and select the field with JaggedTensor.rmask. The mask-based prune preserves canonical voxel order, so the field stays aligned with the pruned grid without a re-inject.

Public API

  • fvdb.functional.{reinitialize,retopologize}_sdf_{single,batch} (+ exports).
  • Grid.reinitialize_sdf / Grid.retopologize_sdf and the GridBatch equivalents
  • New SmoothingMode enum following fvdb's cross-boundary-enum convention

Dependency — src/cmake/get_nanovdb.cmake

  • Bumped the NanoVDB pin fec59777 → f9754140 for the VoxelBlockManager build/decode API (buildVoxelBlockManager, decodeInverseMaps, VoxelBlockManagerHandle).

Test plan

Built and tested in the fvdb conda env (PyTorch 2.11, CUDA 13, sm_120):

  • tests/unit/test_sdf.py: 10 passed — sphere-SDF preserved under redistancing (mean err ~0.09·vx), recovered from a crude sign step (~0.25·vx), band clamp, narrow-band prune, prune voxel-order alignment guard (grid.ijk[mask] == pruned.ijk), padding widens a thin band, batch-vs-single parity, and float64.
  • NanoVDB bump regression (run before adding the op): full rebuild on the new pin with no API drift; tests/unit/test_inject.py + test_io.py (234 passed) and test_dual.py + test_basic_ops_single.py (94 passed).
  • ReinitializeSdf.cu compiles clean under -Werror=all-warnings / -Xcompiler=-Wall,-Werror.

Notes / risks

  • retopologize_sdf(pad=True) seeding. New voxels created with padding are seeded as exterior (+band*vx), which is correct when the dilation extends outward — i.e. the grid's interior (phi < 0) is already represented (occupancy/TSDF/mesh-derived fields, the common case). For a hollow thin shell that doesn't fill its interior, pass pad=False with a pre-banded grid. Documented in the docstring.
  • Dtype. float32 / float64 only — float16 is intentionally rejected (the eikonal solve needs the precision).

@swahtz swahtz added this to the v0.5 milestone Jun 16, 2026
@swahtz swahtz requested a review from a team as a code owner June 16, 2026 02:49
@swahtz swahtz added the core library Core fVDB library. i.e. anything in the _Cpp module (C++) or fvdb python module label Jun 16, 2026
@swahtz swahtz requested review from harrism and matthewdcong June 16, 2026 02:49
Adds a signed-distance-field reinitialization operator and a narrow-band
retopologization helper for sparse grids, complementing the existing
marching-cubes / TSDF tooling.

**New ops**

* `reinitialize_sdf` (C++/CUDA): redistances a per-voxel signed field to
  |grad phi| = 1 with a TVD-RK Godunov upwind eikonal solve (order 1/2/3,
  frozen Peng sign), then optionally de-staircases it with mean-curvature or
  volume-preserving Taubin Laplacian smoothing. Grid topology is preserved.
  The 6-face stencil is fused into every sweep via the NanoVDB
  VoxelBlockManager, which is built once per grid and reused across all
  sweeps. Supports float32/f

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
@swahtz swahtz force-pushed the retopologize_sdf branch from 6725f6f to 014ecf1 Compare June 16, 2026 02:54
Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a CUDA-only narrow-band SDF reinitialization operator (Godunov upwind eikonal solve with optional Laplacian de-staircasing) plus a Python-level retopologize_sdf helper that composes padding/injection, reinitialization, and band pruning to produce a clean narrow-band SDF aligned with the output grid topology.

Changes:

  • Add reinitialize_sdf CUDA op backed by NanoVDB VoxelBlockManager and expose it through the C++/pybind layer.
  • Add Python functional + OO APIs for reinitialize_sdf and retopologize_sdf (single + batch), and introduce a cross-boundary SmoothingMode enum.
  • Add focused unit tests for correctness, pruning alignment, padding behavior, batch parity, and float64.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/fvdb/detail/ops/ReinitializeSdf.h Declares the new CUDA SDF reinitialization API + SmoothingMode.
src/fvdb/detail/ops/ReinitializeSdf.cu Implements the VBM-based narrow-band redistancing + optional smoothing.
src/python/GridBatchOps.cpp Binds SmoothingMode and reinitialize_sdf into _fvdb_cpp.
fvdb/functional/_sdf.py Adds Python functional wrappers and retopologize_sdf composition logic.
fvdb/functional/__init__.py Exports the new SDF functional APIs.
fvdb/enums.py Adds public SmoothingMode IntEnum.
fvdb/grid.py Adds Grid.reinitialize_sdf / Grid.retopologize_sdf.
fvdb/grid_batch.py Adds GridBatch.reinitialize_sdf / GridBatch.retopologize_sdf.
fvdb/_fvdb_cpp.pyi Adds type stubs for _fvdb_cpp.SmoothingMode and reinitialize_sdf.
fvdb/__init__.py Re-exports SmoothingMode at top-level.
tests/unit/test_sdf.py New unit tests for the SDF reinit/retopo behavior.
src/CMakeLists.txt Registers the new CUDA source file in the build.
src/cmake/get_nanovdb.cmake Updates NanoVDB pin for required VBM APIs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fvdb/functional/_sdf.py Outdated
Comment thread fvdb/grid.py
Comment thread fvdb/grid.py
Comment thread fvdb/grid_batch.py
Comment thread fvdb/grid_batch.py
The public `smoothing` parameter was annotated inconsistently across the SDF
entry points -- the `Grid` / `GridBatch` methods allowed `str` (which
`_to_cpp_smoothing` could not accept and would raise on), while the functional
wrappers allowed `int`. Neither matched the documented enum API.

Annotate `smoothing` as `SmoothingMode` everywhere, matching the existing
cross-boundary enum convention (`CameraModel` / `ProjectionMethod`), and
simplify `_to_cpp_smoothing` to a name-based lookup that accepts the public
enum (and passes a bound `_fvdb_cpp.SmoothingMode` through unchanged). Update
the smoothing test to select the mode with the enum.

Addresses review feedback on openvdb#669.

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

@harrism harrism left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just had one nit.

Comment thread fvdb/functional/_sdf.py
…more similar in their implementations.

Signed-off-by: Jonathan Swartz <jonathan@jswartz.info>
@swahtz swahtz enabled auto-merge (squash) June 18, 2026 09:11
@swahtz swahtz merged commit 5e2c749 into openvdb:main Jun 18, 2026
39 checks passed
@swahtz swahtz deleted the retopologize_sdf branch June 21, 2026 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core library Core fVDB library. i.e. anything in the _Cpp module (C++) or fvdb python module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants