Add MeshToGrid: CUDA triangle mesh to NanoVDB UDF/IndexGrid converter#2178
Open
sifakis wants to merge 10 commits intoAcademySoftwareFoundation:masterfrom
Open
Add MeshToGrid: CUDA triangle mesh to NanoVDB UDF/IndexGrid converter#2178sifakis wants to merge 10 commits intoAcademySoftwareFoundation:masterfrom
sifakis wants to merge 10 commits intoAcademySoftwareFoundation:masterfrom
Conversation
Introduces nanovdb::tools::cuda::MeshToGrid<BuildT>, a GPU-accelerated
rasterizer that converts a triangle soup (vertex list + index list) into
a sparse NanoVDB grid on the device. Two output modes are implemented:
- getHandle() — produces a ValueOnIndex (topology-only) grid
- getHandleAndUDF() — produces the same grid plus a device sidecar
buffer of per-active-voxel unsigned distances
(world-space UDF, ordered by active voxel index)
SDF (signed distance field) output is planned future work.
The pipeline uses a hierarchical top-down subdivision approach:
1. transformTriangles() — vertices transformed to NanoVDB index space
via nanovdb::Map::applyInverseMap()
2. processRootTrianglePairs() — enumerates (root tile, triangle) pairs whose
padded AABBs overlap, via CUB prefix-sum +
scatter (no atomics)
3. processLeafTrianglePairs() — 3-level 8x subdivision (4096→512→64→8),
refining the pair list at each level using
triangle-AABB / SAT intersection tests
(evaluateAndCountSubBoxesKernel: 1 CTA per
pair, 512 threads, warp ballot + CUB reduce)
4. Topology assembly — unique leaf origins extracted, NanoVDB
ValueOnIndex tree built via TopologyBuilder,
empty leaves pruned via PruneGrid
5. UDF computation (optional) — ComputeUDFFunctor computes per-voxel
point-to-triangle distances via atomic-min,
finalized to world-space in a second pass
The example driver (ex_mesh_to_grid_cuda) reads an OBJ file, builds an
OpenVDB UDF as reference, and runs a thorough correctness validation:
- Active voxel set comparison (false negatives, false positive rate)
- Per-voxel UDF error histogram vs. OpenVDB reference (in voxel units)
- CPU brute-force ground-truth check on the worst-error voxels
New files:
nanovdb/nanovdb/tools/cuda/MeshToGrid.cuh
nanovdb/nanovdb/math/Proximity.h — point/triangle proximity utils
nanovdb/nanovdb/util/cuda/Rasterization.cuh — ComputeUDFFunctor and helpers
Modified files:
nanovdb/nanovdb/tools/cuda/TopologyBuilder.cuh — adds InitGridTreeRootFunctor
for constructing grids from scratch (no source grid to copy metadata from)
nanovdb/nanovdb/util/cuda/Util.h — adds operatorKernelInstance for launching
pre-constructed device functors carrying data members
nanovdb/nanovdb/examples/CMakeLists.txt — registers ex_mesh_to_grid_cuda
Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
Replace throws-on-zero with early returns throughout the pipeline so that getHandle() and getHandleAndUDF() return a valid empty grid when triangleCount == 0. Kernel launches over null sets are explicitly guarded before any buffer pointer is dereferenced. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
MeshToGrid_EmptyMesh: verifies that getHandle() returns a valid grid
with zero active voxels when the triangle list is empty.
MeshToGrid_UnitTetrahedron: constructs a unit tetrahedron (4 vertices,
4 faces) with voxel size 0.1. Tests both getHandle() (topology-only)
and getHandleAndUDF() (with sidecar). Checks:
- Topology: checksum from getHandle() equals that from getHandleAndUDF(),
confirming both paths produce identical grids.
- Per-voxel UDF: sidecar values match CPU brute-force (index-space
pointToTriangleDistSqr * voxelSize) within 1e-3 voxels.
- No false positives: every active voxel lies within the narrow band.
- No false negatives: every voxel with CPU UDF strictly inside the band
is active (checked via leaf-iteration active set).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
mesh_to_grid_cuda.cpp:
- Remove unused #include <openvdb/tools/Morphology.h>
- Fix cout label "openvdb_triangles" -> "triangles"
- Replace atof(argv[3]) with std::stof
- Remove spurious blank lines
mesh_to_grid_cuda_kernels.cu:
- Remove unused #include <array> (leftover from std::array<Vec3f,3> era)
- Collapse triple blank line after getHandleAndUDF() to single
- Replace the detailed per-voxel histogram, top-N worst-voxel heap,
and inline Ericson brute-force with a compact summary: active voxel
counts, false negative/positive counts, and a single UDF quality
line (max error + count exceeding 0.1 voxels vs OpenVDB reference)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
All mVerbose>=2 guarded timer restarts and printf diagnostics have been removed. Verbosity level 1 (function-scale start/stop timing) is retained. Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
…accessors - getHandle: parameter renamed from pool to buffer, matching the convention used throughout NanoVDB tools (PointsToGrid, DilateGrid, etc.) - getHandleAndUDF: parameters renamed from gridPool/sidecarPool to buffer/sidecarBuffer for the same reason - Local raw-buffer variables renamed to gridBuffer to avoid shadowing the (now renamed) buffer parameter - Remove getPairCount(), getDevicePairs(), getRootTileCount(), and getDeviceRootOrigins() — unused diagnostic-only accessors Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduces
nanovdb::tools::cuda::MeshToGrid<BuildT>, a GPU-accelerated rasterizer that converts a triangle soup (vertex list + index list) into a sparse NanoVDB grid on the device. Two output modes are implemented:getHandle()— produces aValueOnIndex(topology-only) IndexGridgetHandleAndUDF()— produces the same grid plus a device sidecar buffer of per-active-voxel unsigned distances (world-space UDF, ordered by active voxel index)SDF (signed distance field) output is planned future work.
Pipeline
transformTriangles()— vertices transformed to NanoVDB index spaceprocessRootTrianglePairs()— enumerates(root tile, triangle)pairs whose padded AABBs overlap, via CUB prefix-sum + scatter (no atomics)processLeafTrianglePairs()— 3-level 8× subdivision (4096→512→64→8), refining the pair list at each level using triangle-AABB / SAT intersection tests (1 CTA per pair, 512 threads, warp ballot + CUB block reduce)ValueOnIndextree built viaTopologyBuilder, empty leaves pruned viaPruneGridgetHandleAndUDFonly) —ComputeUDFFunctorcomputes per-voxel point-to-triangle distances via atomic-min, finalized to world-space in a second passFiles
New:
nanovdb/nanovdb/tools/cuda/MeshToGrid.cuh— main converternanovdb/nanovdb/math/Proximity.h— point/triangle proximity utilitiesnanovdb/nanovdb/util/cuda/Rasterization.cuh—ComputeUDFFunctorand helpersModified:
nanovdb/nanovdb/tools/cuda/TopologyBuilder.cuh— addsInitGridTreeRootFunctorfor constructing grids from scratch (no source grid to copy metadata from)nanovdb/nanovdb/util/cuda/Util.h— addsoperatorKernelInstancefor launching pre-constructed device functors carrying data membersnanovdb/nanovdb/examples/CMakeLists.txt— registersex_mesh_to_grid_cudaTests
Two unit tests added to
TestNanoVDB.cu:MeshToGrid_EmptyMesh— verifies an empty triangle list produces a valid zero-active-voxel gridMeshToGrid_UnitTetrahedron— verifies topology and UDF accuracy against a CPU brute-force reference on a unit tetrahedronKnown TODOs
TrianglePOD struct (currently inMeshToGrid.cuh) is a candidate for migration to a dedicated geometric-primitives header innanovdb/math/once such a header is introduced.