@@ -28,9 +28,10 @@ using namespace std::string_view_literals;
2828namespace tsd ::io {
2929
3030template <typename T>
31- void doExportStructuredRegularVolumeToNanoVDB (const T *data,
31+ void doExportStructuredVolumeToNanoVDB (const T *data,
3232 math::float3 origin,
3333 math::float3 spacing,
34+ math::float3 mapSpacing,
3435 math::int3 dims,
3536 std::string_view outputFilename,
3637 bool useUndefinedValue,
@@ -39,17 +40,17 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
3940 bool enableDithering)
4041{
4142 tsd::core::logStatus (
42- " [export_StructuredRegularVolumeToNanoVDB ] Volume dimensions: %u x %u x %u" ,
43+ " [export_StructuredVolumeToNanoVDB ] Volume dimensions: %u x %u x %u" ,
4344 dims.x ,
4445 dims.y ,
4546 dims.z );
4647 tsd::core::logStatus (
47- " [export_StructuredRegularVolumeToNanoVDB ] Origin: (%.3f, %.3f, %.3f)" ,
48+ " [export_StructuredVolumeToNanoVDB ] Origin: (%.3f, %.3f, %.3f)" ,
4849 origin.x ,
4950 origin.y ,
5051 origin.z );
5152 tsd::core::logStatus (
52- " [export_StructuredRegularVolumeToNanoVDB ] Spacing: (%.3f, %.3f, %.3f)" ,
53+ " [export_StructuredVolumeToNanoVDB ] Spacing: (%.3f, %.3f, %.3f)" ,
5354 spacing.x ,
5455 spacing.y ,
5556 spacing.z );
@@ -67,14 +68,14 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
6768 // mutable.
6869 constexpr size_t MatrixSize = 3 ;
6970 const std::array<std::array<double , MatrixSize>, MatrixSize> mat = {{
70- {{spacing .x , 0.0 , 0.0 }}, // row 0
71- {{0.0 , spacing .y , 0.0 }}, // row 1
72- {{0.0 , 0.0 , spacing .z }} // row 2
71+ {{mapSpacing .x , 0.0 , 0.0 }}, // row 0
72+ {{0.0 , mapSpacing .y , 0.0 }}, // row 1
73+ {{0.0 , 0.0 , mapSpacing .z }} // row 2
7374 }};
7475 const std::array<std::array<double , MatrixSize>, MatrixSize> invMat = {{
75- {{1.0 / spacing .x , 0.0 , 0.0 }}, // row 0
76- {{0.0 , 1.0 / spacing .y , 0.0 }}, // row 1
77- {{0.0 , 0.0 , 1.0 / spacing .z }} // row 2
76+ {{1.0 / mapSpacing .x , 0.0 , 0.0 }}, // row 0
77+ {{0.0 , 1.0 / mapSpacing .y , 0.0 }}, // row 1
78+ {{0.0 , 0.0 , 1.0 / mapSpacing .z }} // row 2
7879 }};
7980 const std::array<double , MatrixSize> trans = {origin.x , origin.y , origin.z };
8081 const_cast <nanovdb::Map &>(buildGrid->map ())
@@ -142,7 +143,7 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
142143 : 0 .0f ;
143144
144145 tsd::core::logStatus (
145- " [export_StructuredRegularVolumeToNanoVDB ] Active voxels: %zu/%zu (%.1f%% inactive cell compression)" ,
146+ " [export_StructuredVolumeToNanoVDB ] Active voxels: %zu/%zu (%.1f%% inactive cell compression)" ,
146147 activeVoxelsCount,
147148 totalVoxelsCount,
148149 inactiveCellCompression * 100 .0f );
@@ -152,11 +153,11 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
152153 // Validate quantization choice
153154 if (precision == VDBPrecision::Fp4 && valueRange > 30 .0f ) {
154155 tsd::core::logWarning (
155- " [export_StructuredRegularVolumeToNanoVDB ] Fp4 quantization with value range %.2f may introduce significant error (recommended < 30.0)" ,
156+ " [export_StructuredVolumeToNanoVDB ] Fp4 quantization with value range %.2f may introduce significant error (recommended < 30.0)" ,
156157 valueRange);
157158 } else if (precision == VDBPrecision::Fp8 && valueRange > 500 .0f ) {
158159 tsd::core::logWarning (
159- " [export_StructuredRegularVolumeToNanoVDB ] Fp8 quantization with value range %.2f may introduce significant error (recommended < 500.0)" ,
160+ " [export_StructuredVolumeToNanoVDB ] Fp8 quantization with value range %.2f may introduce significant error (recommended < 500.0)" ,
160161 valueRange);
161162 }
162163
@@ -203,7 +204,7 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
203204 break ;
204205 case VDBPrecision::Half:
205206 tsd::core::logWarning (
206- " [export_StructuredRegularVolumeToNanoVDB ] Half precision not supported in this NanoVDB build, using Fp16 instead" );
207+ " [export_StructuredVolumeToNanoVDB ] Half precision not supported in this NanoVDB build, using Fp16 instead" );
207208 handle = nanovdb::tools::createNanoGrid<nanovdb::tools::build::Grid<float >,
208209 nanovdb::Fp16>(*buildGrid,
209210 nanovdb::tools::StatsMode::All,
@@ -215,7 +216,7 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
215216
216217 if (!handle) {
217218 tsd::core::logError (
218- " [export_StructuredRegularVolumeToNanoVDB ] Failed to create NanoVDB grid." );
219+ " [export_StructuredVolumeToNanoVDB ] Failed to create NanoVDB grid." );
219220 return ;
220221 }
221222
@@ -229,12 +230,12 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
229230 : 0 .0f ;
230231
231232 tsd::core::logStatus (
232- " [export_StructuredRegularVolumeToNanoVDB ] Quantization compression: %.1f%% (%.2f MB -> %.2f MB)" ,
233+ " [export_StructuredVolumeToNanoVDB ] Quantization compression: %.1f%% (%.2f MB -> %.2f MB)" ,
233234 quantizationCompression * 100 .0f ,
234235 uncompressedActiveSize / (1024 .0f * 1024 .0f ),
235236 finalSize / (1024 .0f * 1024 .0f ));
236237 tsd::core::logStatus (
237- " [export_StructuredRegularVolumeToNanoVDB ] Total compression: %.1f%% (%.2f MB -> %.2f MB)" ,
238+ " [export_StructuredVolumeToNanoVDB ] Total compression: %.1f%% (%.2f MB -> %.2f MB)" ,
238239 totalCompression * 100 .0f ,
239240 uncompressedSize / (1024 .0f * 1024 .0f ),
240241 finalSize / (1024 .0f * 1024 .0f ));
@@ -244,16 +245,16 @@ void doExportStructuredRegularVolumeToNanoVDB(const T *data,
244245 nanovdb::io::writeGrid (
245246 std::string (outputFilename).c_str (), handle, nanovdb::io::Codec::NONE);
246247 tsd::core::logStatus (
247- " [export_StructuredRegularVolumeToNanoVDB ] Successfully wrote VDB file: %s" ,
248+ " [export_StructuredVolumeToNanoVDB ] Successfully wrote VDB file: %s" ,
248249 std::string (outputFilename).c_str ());
249250 } catch (const std::exception &e) {
250251 tsd::core::logError (
251- " [export_StructuredRegularVolumeToNanoVDB ] Failed to write VDB file: %s" ,
252+ " [export_StructuredVolumeToNanoVDB ] Failed to write VDB file: %s" ,
252253 e.what ());
253254 }
254255}
255256
256- void export_StructuredRegularVolumeToNanoVDB (const SpatialField *spatialField,
257+ void export_StructuredVolumeToNanoVDB (const SpatialField *spatialField,
257258 std::string_view outputFilename,
258259 bool useUndefinedValue,
259260 float undefinedValue,
@@ -268,7 +269,7 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
268269
269270 if (!isStructuredRegular && !isStructuredRectilinear) {
270271 tsd::core::logError (
271- " [export_StructuredRegularVolumeToNanoVDB ] Not a structured volume." );
272+ " [export_StructuredVolumeToNanoVDB ] Not a structured volume." );
272273 return ;
273274 }
274275
@@ -281,14 +282,13 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
281282 // Dumb heuristic here: everything but cell is node-centered
282283 const bool cellCentered = dataCentering == " cell" sv;
283284
284- tsd::core::logStatus (
285- " [export_StructuredRegularVolumeToNanoVDB] Data centering: %s" ,
285+ tsd::core::logStatus (" [export_StructuredVolumeToNanoVDB] Data centering: %s" ,
286286 dataCentering.c_str ());
287287
288288 const auto *volumeData = spatialField->parameterValueAsObject <Array>(" data" );
289289 if (!volumeData) {
290290 tsd::core::logError (
291- " [export_StructuredRegularVolumeToNanoVDB ] No volume data found." );
291+ " [export_StructuredVolumeToNanoVDB ] No volume data found." );
292292 return ;
293293 }
294294
@@ -297,6 +297,7 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
297297
298298 math::float3 origin{};
299299 math::float3 spacing{};
300+ math::float3 centeredSpacing{};
300301
301302 NanoVdbSidecar sidecar;
302303 sidecar.schemaVersion = 1 ;
@@ -321,7 +322,8 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
321322 math::float3 (0 .0f ));
322323 spacing = spatialField->parameterValueAs <math::float3>(" spacing" ).value_or (
323324 math::float3 (1 .0f ));
324- spacing = cellCentered ? spacing : spacing / dims * (dims - math::int3 (1 ));
325+ centeredSpacing =
326+ cellCentered ? spacing : spacing / dims * (dims - math::int3 (1 ));
325327
326328 sidecar.origin = origin;
327329 sidecar.spacing = spacing;
@@ -334,7 +336,7 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
334336
335337 if (!axisX || !axisY || !axisZ) {
336338 tsd::core::logError (
337- " [export_StructuredRegularVolumeToNanoVDB ] Missing rectilinear coordinates." );
339+ " [export_StructuredVolumeToNanoVDB ] Missing rectilinear coordinates." );
338340 return ;
339341 }
340342
@@ -359,13 +361,13 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
359361 if (!copyAxis (axisX, coordsX) || !copyAxis (axisY, coordsY)
360362 || !copyAxis (axisZ, coordsZ)) {
361363 tsd::core::logError (
362- " [export_StructuredRegularVolumeToNanoVDB ] Rectilinear coordinates must be float or double." );
364+ " [export_StructuredVolumeToNanoVDB ] Rectilinear coordinates must be float or double." );
363365 return ;
364366 }
365367
366368 if (coordsX.size () < 2 || coordsY.size () < 2 || coordsZ.size () < 2 ) {
367369 tsd::core::logError (
368- " [export_StructuredRegularVolumeToNanoVDB ] Rectilinear coordinates must have at least two entries per axis." );
370+ " [export_StructuredVolumeToNanoVDB ] Rectilinear coordinates must have at least two entries per axis." );
369371 return ;
370372 }
371373
@@ -378,16 +380,25 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
378380 static_cast <float >(coordsY.back () - coordsY.front ()),
379381 static_cast <float >(coordsZ.back () - coordsZ.front ()));
380382
383+ auto divisor = cellCentered ? dims : (dims - math::int3 (1 ));
384+ divisor.x = std::max (divisor.x , 1 );
385+ divisor.y = std::max (divisor.y , 1 );
386+ divisor.z = std::max (divisor.z , 1 );
387+
388+ centeredSpacing = extent / math::float3 (divisor);
389+ spacing = centeredSpacing;
390+
381391 // For rectilinear grids, only export coordinate arrays, not origin/spacing
382392 sidecar.coordsX = coordsX;
383393 sidecar.coordsY = coordsY;
384394 sidecar.coordsZ = coordsZ;
385395 }
386396
387397 auto dispatchExport = [&](auto ptr) {
388- doExportStructuredRegularVolumeToNanoVDB (ptr,
398+ doExportStructuredVolumeToNanoVDB (ptr,
389399 origin,
390400 spacing,
401+ centeredSpacing,
391402 dims,
392403 outputFilename,
393404 useUndefinedValue,
@@ -417,7 +428,7 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
417428 break ;
418429 default :
419430 tsd::core::logError (
420- " [export_StructuredRegularVolumeToNanoVDB ] Volume data is not of a supported float type." );
431+ " [export_StructuredVolumeToNanoVDB ] Volume data is not of a supported float type." );
421432 return ;
422433 }
423434
@@ -426,12 +437,11 @@ void export_StructuredRegularVolumeToNanoVDB(const SpatialField *spatialField,
426437 std::string sidecarError;
427438 if (!writeSidecar (sidecar, sidecarPath, sidecarError)) {
428439 tsd::core::logWarning (
429- " [export_StructuredRegularVolumeToNanoVDB ] Failed to write sidecar %s: %s" ,
440+ " [export_StructuredVolumeToNanoVDB ] Failed to write sidecar %s: %s" ,
430441 sidecarPath.string ().c_str (),
431442 sidecarError.c_str ());
432443 } else {
433- tsd::core::logStatus (
434- " [export_StructuredRegularVolumeToNanoVDB] Wrote sidecar: %s" ,
444+ tsd::core::logStatus (" [export_StructuredVolumeToNanoVDB] Wrote sidecar: %s" ,
435445 sidecarPath.string ().c_str ());
436446 }
437447}
0 commit comments