diff --git a/tsd/CMakeLists.txt b/tsd/CMakeLists.txt index e5f36d31..86ca16d5 100644 --- a/tsd/CMakeLists.txt +++ b/tsd/CMakeLists.txt @@ -59,6 +59,8 @@ option(TSD_USE_TORCH "Use PyTorch for importing neural geometries" OFF) option(TSD_USE_VTK "Use VTK for importing VTK file formats" OFF) option(TSD_USE_SILO "Use Silo for importing Silo file formats" OFF) option(TSD_USE_MPI "Enable MPI support" OFF) +option(TSD_NANOVDB_SKIP_INVALID_VOLUMES + "Skip NanoVDB volumes with zero active voxels" OFF) option(TSD_USE_NETWORKING "Enable networking support via boost.asio" OFF) if (APPLE) diff --git a/tsd/src/tsd/io/CMakeLists.txt b/tsd/src/tsd/io/CMakeLists.txt index 67ca9711..08865254 100644 --- a/tsd/src/tsd/io/CMakeLists.txt +++ b/tsd/src/tsd/io/CMakeLists.txt @@ -142,3 +142,9 @@ if (TSD_USE_SILO) else() project_compile_definitions(PRIVATE -DTSD_USE_SILO=0) endif() + +if (TSD_NANOVDB_SKIP_INVALID_VOLUMES) + project_compile_definitions(PRIVATE -DTSD_NANOVDB_SKIP_INVALID_VOLUMES=1) +else() + project_compile_definitions(PRIVATE -DTSD_NANOVDB_SKIP_INVALID_VOLUMES=0) +endif() diff --git a/tsd/src/tsd/io/importers/import_NVDB.cpp b/tsd/src/tsd/io/importers/import_NVDB.cpp index 78e2b5e6..e492a03f 100644 --- a/tsd/src/tsd/io/importers/import_NVDB.cpp +++ b/tsd/src/tsd/io/importers/import_NVDB.cpp @@ -50,6 +50,38 @@ SpatialFieldRef import_NVDB(Scene &scene, const char *filepath) try { auto grid = nanovdb::io::readGrid(filepath); auto metadata = grid.gridMetaData(); + + bool hasActiveVoxels = false; + switch (metadata->gridType()) { + case nanovdb::GridType::Fp4: + hasActiveVoxels = grid.grid()->activeVoxelCount() > 0; + break; + case nanovdb::GridType::Fp8: + hasActiveVoxels = grid.grid()->activeVoxelCount() > 0; + break; + case nanovdb::GridType::Fp16: + hasActiveVoxels = grid.grid()->activeVoxelCount() > 0; + break; + case nanovdb::GridType::FpN: + hasActiveVoxels = grid.grid()->activeVoxelCount() > 0; + break; + case nanovdb::GridType::Float: + hasActiveVoxels = grid.grid()->activeVoxelCount() > 0; + break; + default: + break; + } + + if (!hasActiveVoxels) { + logWarning("[import_NVDB] no active voxels in '%s'", filepath); + if (TSD_NANOVDB_SKIP_INVALID_VOLUMES) { + logStatus( + "[import_NVDB] skipping due to TSD_NANOVDB_SKIP_INVALID_VOLUMES"); + scene.removeObject(field.data()); + return {}; + } + } + if (!metadata->hasMinMax()) { switch (metadata->gridType()) { case nanovdb::GridType::Fp4: { diff --git a/tsd/src/tsd/io/importers/import_USD.cpp b/tsd/src/tsd/io/importers/import_USD.cpp index 2895a6a3..391c1b4c 100644 --- a/tsd/src/tsd/io/importers/import_USD.cpp +++ b/tsd/src/tsd/io/importers/import_USD.cpp @@ -910,7 +910,8 @@ static void import_usd_volume(Scene &scene, VolumeTransferFunction tf = get_volume_transfer_function(prim); ArrayRef colorArray; - math::float2 valueRange; + // Default to the field's value range to avoid undefined ranges. + math::float2 valueRange = field->computeValueRange(); // Create a volume node and assign the field, color map, and value range auto [inst, volume] = scene.insertNewChildObjectNode( @@ -922,7 +923,8 @@ static void import_usd_volume(Scene &scene, // Use transfer function from USD material colorArray = scene.createArray(ANARI_FLOAT32_VEC4, tf.colors.size()); colorArray->setData(tf.colors.data(), tf.colors.size()); - valueRange = tf.domain; + if (tf.domain.x < tf.domain.y) + valueRange = tf.domain; // Create opacity control points from USD transfer function std::vector opacityControlPoints;