OpenVDB 13.1.0
Loading...
Searching...
No Matches
CreateNanoGrid.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5 \file nanovdb/tools/CreateNanoGrid.h
6
7 \author Ken Museth
8
9 \date June 26, 2020
10
11 \note In the examples below we assume that @c srcGrid is a exiting grid of type
12 SrcGridT = @c openvdb::FloatGrid, @c openvdb::FloatGrid or @c nanovdb::tools::build::FloatGrid.
13
14 \brief Convert any grid to a nanovdb grid of the same type, e.g. float->float
15 \code
16 auto handle = nanovdb::tools::createNanoGrid(srcGrid);
17 auto *dstGrid = handle.grid<float>();
18 \endcode
19
20 \brief Convert a grid to a nanovdb grid of a different type, e.g. float->half
21 \code
22 auto handle = nanovdb::tools::createNanoGrid<SrcGridT,nanovdb::Fp16>(srcGrid);
23 auto *dstGrid = handle.grid<nanovdb::Fp16>();
24 \endcode
25
26 \brief Convert a grid to a nanovdb grid of the same type but using a CUDA buffer
27 \code
28 auto handle = nanovdb::tools::createNanoGrid<SrcGridT, float, nanovdb::CudaDeviceBuffer>(srcGrid);
29 auto *dstGrid = handle.grid<float>();
30 \endcode
31
32 \brief Create a nanovdb grid that indices values in an existing source grid of any type.
33 If DstBuildT = nanovdb::ValueIndex both active and in-active values are indexed
34 and if DstBuildT = nanovdb::ValueOnIndex only active values are indexed.
35 \code
36 using DstBuildT = nanovdb::ValueIndex;// index both active an inactive values
37 auto handle = nanovdb::tools::createNanoGridSrcGridT,DstBuildT>(srcGrid,0,false,false);//no blind data, tile values or stats
38 auto *dstGrid = handle.grid<DstBuildT>();
39 \endcode
40
41 \brief Create a NanoVDB grid from scratch
42 \code
43#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
44 using SrcGridT = openvdb::FloatGrid;
45#else
46 using SrcGridT = nanovdb::tools::build::FloatGrid;
47#endif
48 SrcGridT srcGrid(0.0f);// create an empty source grid
49 auto srcAcc = srcGrid.getAccessor();// create an accessor
50 srcAcc.setValue(nanovdb::Coord(1,2,3), 1.0f);// set a voxel value
51
52 auto handle = nanovdb::tools::createNanoGrid(srcGrid);// convert source grid to a grid handle
53 auto dstGrid = handle.grid<float>();// get a pointer to the destination grid
54 \endcode
55
56 \brief Convert a base-pointer to an openvdb grid, denoted srcGrid, to a nanovdb
57 grid of the same type, e.g. float -> float or openvdb::Vec3f -> nanovdb::Vec3f
58 \code
59 auto handle = nanovdb::openToNanoVDB(*srcGrid);// convert source grid to a grid handle
60 auto dstGrid = handle.grid<float>();// get a pointer to the destination grid
61 \endcode
62
63 \brief Converts any existing grid to a NanoVDB grid, for example:
64 nanovdb::tools::build::Grid<SrcBuildT> -> nanovdb::Grid<DstBuildT>
65 nanovdb::Grid<SrcBuildT> -> nanovdb::Grid<DstBuildT>
66 nanovdb::Grid<SrcBuildT> -> nanovdb::Grid<ValueIndex or ValueOnIndex>
67 openvdb::Grid<SrcBuildT> -> nanovdb::Grid<DstBuildT>
68 openvdb::Grid<PointIndex> -> nanovdb::Grid<PointIndex>
69 openvdb::Grid<PointData> -> nanovdb::Grid<PointData>
70 openvdb::Grid<SrcBuildT> -> nanovdb::Grid<ValueIndex or ValueOnIndex>
71
72 \note This files replaces GridBuilder.h, IndexGridBuilder.h and OpenToNanoVDB.h
73*/
74
75#ifndef NANOVDB_TOOLS_CREATENANOGRID_H_HAS_BEEN_INCLUDED
76#define NANOVDB_TOOLS_CREATENANOGRID_H_HAS_BEEN_INCLUDED
77
78#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
79#include <openvdb/openvdb.h>
82#endif
83
84#include <nanovdb/NodeManager.h>
85#include <nanovdb/GridHandle.h>
89#include <nanovdb/util/Range.h>
90#include <nanovdb/util/Invoke.h>
92#include <nanovdb/util/Reduce.h>
94#include <nanovdb/math/DitherLUT.h>// for nanovdb::math::DitherLUT
95
96#include <limits>
97#include <vector>
98#include <set>
99#include <cstring> // for strncpy
100#include <type_traits>
101
102namespace nanovdb {// ============================================================================
103
104namespace tools {// ==============================================================================
105
106// Forward declarations (defined below)
107template <typename> class CreateNanoGrid;
108class AbsDiff;
109template <typename> struct MapToNano;
110
111//================================================================================================
112
113#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
114/// @brief Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHandle
115/// @tparam BufferT Type of the buffer used to allocate the destination grid
116/// @param base Shared pointer to a base openvdb grid to be converted
117/// @param sMode Mode for computing statistics of the destination grid
118/// @param cMode Mode for computing checksums of the destination grid
119/// @param verbose Mode of verbosity
120/// @return Handle to the destination NanoGrid
121template<typename BufferT = HostBuffer>
123openToNanoVDB(const openvdb::GridBase::Ptr& base,
126 int verbose = 0);
127
128/// @brief Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHandle with an IndexGrid
129/// @tparam DstBuildT Should be either nanovdb::ValueIndex or nanovdb::ValueOnIndex
130/// @tparam BufferT Type of the buffer used to allocate the destination grid
131/// @param base Shared pointer to a base openvdb grid to be converted
132/// @param channels Number of sidecar channels with the values (active or all) in the source grid
133/// @param includeStats If true stats are also indexed
134/// @param includeTiles If true tile values (active or all) are also indexed
135/// @param verbose Mode of verbosity
136/// @return Handle to the destination NanoGrid of type IndexGrid or OnIndexGrid
137template<typename DstBuildT = nanovdb::ValueOnIndex, typename BufferT = HostBuffer>
139openToIndexVDB(const openvdb::GridBase::Ptr& base,
140 uint32_t channels = 1u,
141 bool includeStats = true,
142 bool includeTiles = true,
143 int verbose = 0);
144#endif
145
146//================================================================================================
147
148/// @brief Freestanding function that creates a NanoGrid<T> from any source grid
149/// @tparam SrcGridT Type of in input (source) grid, e.g. openvdb::Grid or nanovdb::Grid
150/// @tparam DstBuildT Type of values in the output (destination) nanovdb Grid, e.g. float or nanovdb::Fp16
151/// @tparam BufferT Type of the buffer used ti allocate the destination grid
152/// @param srcGrid Input (source) grid to be converted
153/// @param sMode Mode for computing statistics of the destination grid
154/// @param cMode Mode for computing checksums of the destination grid
155/// @param verbose Mode of verbosity
156/// @param buffer Instance of a buffer used for allocation
157/// @return Handle to the destination NanoGrid
158template<typename SrcGridT,
159 typename DstBuildT = typename MapToNano<typename SrcGridT::BuildType>::type,
160 typename BufferT = HostBuffer>
162createNanoGrid(const SrcGridT &srcGrid,
165 int verbose = 0,
166 const BufferT &buffer = BufferT());
167
168//================================================================================================
169
170/// @brief Freestanding function that creates a NanoGrid<ValueIndex> or NanoGrid<ValueOnIndex> from any source grid
171/// @tparam SrcGridT Type of in input (source) grid, e.g. openvdb::Grid or nanovdb::Grid
172/// @tparam DstBuildT If ValueIndex all (active and inactive) values are indexed and if
173/// it is ValueOnIndex only active values are indexed.
174/// @tparam BufferT BufferT Type of the buffer used ti allocate the destination grid
175/// @param srcGrid Input (source) grid to be converted
176/// @param channels If non-zero the values (active or all) in @c srcGrid are encoded as blind
177/// data in the output index grid. @c channels indicates the number of copies
178/// of these blind data
179/// @param includeStats If true all tree nodes will includes indices for stats, i.e. min/max/avg/std-div
180/// @param includeTiles If false on values in leaf nodes are indexed
181/// @param verbose Mode of verbosity
182/// @param buffer Instance of a buffer used for allocation
183/// @return Handle to the destination NanoGrid<T> where T = ValueIndex or ValueOnIndex
184template<typename SrcGridT,
185 typename DstBuildT = typename MapToNano<typename SrcGridT::BuildType>::type,
186 typename BufferT = HostBuffer>
188createNanoGrid(const SrcGridT &srcGrid,
189 uint32_t channels = 0u,
190 bool includeStats = true,
191 bool includeTiles = true,
192 int verbose = 0,
193 const BufferT &buffer = BufferT());
194
195//================================================================================================
196
197/// @brief Freestanding function to create a NanoGrid<FpN> from any source grid
198/// @tparam SrcGridT Type of in input (source) grid, e.g. openvdb::Grid or nanovdb::Grid
199/// @tparam DstBuildT = FpN, i.e. variable bit-width of the output grid
200/// @tparam OracleT Type of the oracle used to determine the local bit-width, i.e. N in FpN
201/// @tparam BufferT Type of the buffer used to allocate the destination grid
202/// @param srcGrid Input (source) grid to be converted
203/// @param ditherOn switch to enable or disable dithering of quantization error
204/// @param sMode Mode for computing statistics of the destination grid
205/// @param cMode Mode for computing checksums of the destination grid
206/// @param verbose Mode of verbosity
207/// @param oracle Instance of a oracle used to determine the local bit-width, i.e. N in FpN
208/// @param buffer Instance of a buffer used for allocation
209/// @return Handle to the destination NanoGrid
210template<typename SrcGridT,
211 typename DstBuildT = typename MapToNano<typename SrcGridT::BuildType>::type,
212 typename OracleT = AbsDiff,
213 typename BufferT = HostBuffer>
215createNanoGrid(const SrcGridT &srcGrid,
218 bool ditherOn = false,
219 int verbose = 0,
220 const OracleT &oracle = OracleT(),
221 const BufferT &buffer = BufferT());
222
223//================================================================================================
224
225/// @brief Freestanding function to create a NanoGrid<FpX> from any source grid, X=4,8,16
226/// @tparam SrcGridT Type of in input (source) grid, e.g. openvdb::Grid or nanovdb::Grid
227/// @tparam DstBuildT = Fp4, Fp8 or Fp16, i.e. quantization bit-width of the output grid
228/// @tparam BufferT Type of the buffer used to allocate the destination grid
229/// @param srcGrid Input (source) grid to be converted
230/// @param ditherOn switch to enable or disable dithering of quantization error
231/// @param sMode Mode for computing statistics of the destination grid
232/// @param cMode Mode for computing checksums of the destination grid
233/// @param verbose Mode of verbosity
234/// @param buffer Instance of a buffer used for allocation
235/// @return Handle to the destination NanoGrid
236template<typename SrcGridT,
237 typename DstBuildT = typename MapToNano<typename SrcGridT::BuildType>::type,
238 typename BufferT = HostBuffer>
240createNanoGrid(const SrcGridT &srcGrid,
243 bool ditherOn = false,
244 int verbose = 0,
245 const BufferT &buffer = BufferT());
246
247//================================================================================================
248
249/// @brief Compression oracle based on absolute difference
251{
252 float mTolerance;// absolute error tolerance
253public:
254 /// @note The default value of -1 means it's un-initialized!
255 AbsDiff(float tolerance = -1.0f) : mTolerance(tolerance) {}
256 AbsDiff(const AbsDiff&) = default;
257 ~AbsDiff() = default;
258 operator bool() const {return mTolerance>=0.0f;}
259 void init(nanovdb::GridClass gClass, float background) {
260 if (gClass == GridClass::LevelSet) {
261 static const float halfWidth = 3.0f;
262 mTolerance = 0.1f * background / halfWidth;// range of ls: [-3dx; 3dx]
263 } else if (gClass == GridClass::FogVolume) {
264 mTolerance = 0.01f;// range of FOG volumes: [0;1]
265 } else {
266 mTolerance = 0.0f;
267 }
268 }
269 void setTolerance(float tolerance) { mTolerance = tolerance; }
270 float getTolerance() const { return mTolerance; }
271 /// @brief Return true if the approximate value is within the accepted
272 /// absolute error bounds of the exact value.
273 ///
274 /// @details Required member method
275 bool operator()(float exact, float approx) const
276 {
277 return math::Abs(exact - approx) <= mTolerance;
278 }
279};// AbsDiff
280
281//================================================================================================
282
283/// @brief Compression oracle based on relative difference
285{
286 float mTolerance;// relative error tolerance
287public:
288 /// @note The default value of -1 means it's un-initialized!
289 RelDiff(float tolerance = -1.0f) : mTolerance(tolerance) {}
290 RelDiff(const RelDiff&) = default;
291 ~RelDiff() = default;
292 operator bool() const {return mTolerance>=0.0f;}
293 void setTolerance(float tolerance) { mTolerance = tolerance; }
294 float getTolerance() const { return mTolerance; }
295 /// @brief Return true if the approximate value is within the accepted
296 /// relative error bounds of the exact value.
297 ///
298 /// @details Required member method
299 bool operator()(float exact, float approx) const
300 {
301 return math::Abs(exact - approx)/math::Max(math::Abs(exact), math::Abs(approx)) <= mTolerance;
302 }
303};// RelDiff
304
305//================================================================================================
306
307/// @brief The NodeAccessor provides a uniform API for accessing nodes in NanoVDB, OpenVDB and build Grids
308///
309/// @note General implementation that works with nanovdb::tools::build::Grid
310template <typename GridT>
312{
313public:
314 static constexpr bool IS_OPENVDB = false;
315 static constexpr bool IS_NANOVDB = false;
316 using BuildType = typename GridT::BuildType;
317 using ValueType = typename GridT::ValueType;
318 using GridType = GridT;
319 using TreeType = typename GridT::TreeType;
320 using RootType = typename TreeType::RootNodeType;
321 template<int LEVEL>
323 NodeAccessor(const GridT &grid) : mMgr(const_cast<GridT&>(grid)) {}
324 const GridType& grid() const {return mMgr.grid();}
325 const TreeType& tree() const {return mMgr.tree();}
326 const RootType& root() const {return mMgr.root();}
327 uint64_t nodeCount(int level) const { return mMgr.nodeCount(level); }
328 template <int LEVEL>
329 const NodeType<LEVEL>& node(uint32_t i) const {return mMgr.template node<LEVEL>(i); }
330 const std::string& getName() const {return this->grid().getName();};
331 bool hasLongGridName() const {return this->grid().getName().length() >= GridData::MaxNameSize;}
332 const nanovdb::Map& map() const {return this->grid().map();}
333 GridClass gridClass() const {return this->grid().gridClass();}
334private:
336};// NodeAccessor<GridT>
337
338//================================================================================================
339
340/// @brief Template specialization for nanovdb::Grid which is special since its NodeManage
341/// uses a handle in order to support node access on the GPU!
342template <typename BuildT>
343class NodeAccessor< NanoGrid<BuildT> >
344{
345public:
346 static constexpr bool IS_OPENVDB = false;
347 static constexpr bool IS_NANOVDB = true;
348 using BuildType = BuildT;
352 using TreeType = typename GridType::TreeType;
353 using RootType = typename TreeType::RootType;
354 template<int LEVEL>
357 : mHandle(createNodeManager<BuildT, BufferType>(grid))
358 , mMgr(*(mHandle.template mgr<BuildT>())) {}
359 const GridType& grid() const {return mMgr.grid();}
360 const TreeType& tree() const {return mMgr.tree();}
361 const RootType& root() const {return mMgr.root();}
362 uint64_t nodeCount(int level) const { return mMgr.nodeCount(level); }
363 template <int LEVEL>
364 const NodeType<LEVEL>& node(uint32_t i) const {return mMgr.template node<LEVEL>(i); }
365 std::string getName() const {return std::string(this->grid().gridName());};
366 bool hasLongGridName() const {return this->grid().hasLongGridName();}
367 const nanovdb::Map& map() const {return this->grid().map();}
368 GridClass gridClass() const {return this->grid().gridClass();}
369private:
371 const NodeManager<BuildT> &mMgr;
372};// NodeAccessor<nanovdb::Grid>
373
374//================================================================================================
375
376/// @brief Trait that maps any type to the corresponding nanovdb type
377/// @tparam T Type to be mapped
378template<typename T>
379struct MapToNano { using type = T; };
380
381#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
382
383template<>
385template<typename T>
386struct MapToNano<openvdb::math::Vec3<T>>{using type = nanovdb::math::Vec3<T>;};
387template<typename T>
388struct MapToNano<openvdb::math::Vec4<T>>{using type = nanovdb::math::Vec4<T>;};
389template<>
390struct MapToNano<openvdb::PointIndex32> {using type = uint32_t;};
391template<>
392struct MapToNano<openvdb::PointDataIndex32> {using type = uint32_t;};
393
394/// Templated Grid with default 32->16->8 configuration
395template <typename BuildT>
396using OpenLeaf = openvdb::tree::LeafNode<BuildT,3>;
397template <typename BuildT>
398using OpenLower = openvdb::tree::InternalNode<OpenLeaf<BuildT>,4>;
399template <typename BuildT>
400using OpenUpper = openvdb::tree::InternalNode<OpenLower<BuildT>,5>;
401template <typename BuildT>
402using OpenRoot = openvdb::tree::RootNode<OpenUpper<BuildT>>;
403template <typename BuildT>
404using OpenTree = openvdb::tree::Tree<OpenRoot<BuildT>>;
405template <typename BuildT>
406using OpenGrid = openvdb::Grid<OpenTree<BuildT>>;
407
408//================================================================================================
409
410/// @brief Template specialization for openvdb::Grid
411template <typename BuildT>
412class NodeAccessor<OpenGrid<BuildT>>
413{
414public:
415 static constexpr bool IS_OPENVDB = true;
416 static constexpr bool IS_NANOVDB = false;
417 using BuildType = BuildT;
418 using GridType = OpenGrid<BuildT>;
419 using ValueType = typename GridType::ValueType;
420 using TreeType = OpenTree<BuildT>;
421 using RootType = OpenRoot<BuildT>;
422 template<int LEVEL>
423 using NodeType = typename NodeTrait<const TreeType, LEVEL>::type;
424 NodeAccessor(const GridType &grid) : mMgr(const_cast<GridType&>(grid)) {
425 const auto mat4 = this->grid().transform().baseMap()->getAffineMap()->getMat4();
426 mMap.set(mat4, mat4.inverse());
427 }
428 const GridType& grid() const {return mMgr.grid();}
429 const TreeType& tree() const {return mMgr.tree();}
430 const RootType& root() const {return mMgr.root();}
431 uint64_t nodeCount(int level) const { return mMgr.nodeCount(level); }
432 template <int LEVEL>
433 const NodeType<LEVEL>& node(uint32_t i) const {return mMgr.template node<LEVEL>(i); }
434 std::string getName() const { return this->grid().getName(); };
435 bool hasLongGridName() const {return this->grid().getName().length() >= GridData::MaxNameSize;}
436 const nanovdb::Map& map() const {return mMap;}
437 GridClass gridClass() const {
438 switch (this->grid().getGridClass()) {
440 if (!util::is_floating_point<BuildT>::value) OPENVDB_THROW(openvdb::ValueError, "processGrid: Level sets are expected to be floating point types");
441 return GridClass::LevelSet;
446 default:
447 return GridClass::Unknown;
448 }
449 }
450private:
451 build::NodeManager<GridType> mMgr;
452 nanovdb::Map mMap;
453};// NodeAccessor<openvdb::Grid<T>>
454
455//================================================================================================
456
457/// @brief Template specialization for openvdb::tools::PointIndexGrid
458template <>
459class NodeAccessor<openvdb::tools::PointIndexGrid>
460{
461public:
462 static constexpr bool IS_OPENVDB = true;
463 static constexpr bool IS_NANOVDB = false;
465 using GridType = openvdb::tools::PointIndexGrid;
466 using TreeType = openvdb::tools::PointIndexTree;
467 using RootType = typename TreeType::RootNodeType;
468 using ValueType = typename GridType::ValueType;
469 template<int LEVEL>
470 using NodeType = typename NodeTrait<const TreeType, LEVEL>::type;
471 NodeAccessor(const GridType &grid) : mMgr(const_cast<GridType&>(grid)) {
472 const auto mat4 = this->grid().transform().baseMap()->getAffineMap()->getMat4();
473 mMap.set(mat4, mat4.inverse());
474 }
475 const GridType& grid() const {return mMgr.grid();}
476 const TreeType& tree() const {return mMgr.tree();}
477 const RootType& root() const {return mMgr.root();}
478 uint64_t nodeCount(int level) const { return mMgr.nodeCount(level); }
479 template <int LEVEL>
480 const NodeType<LEVEL>& node(uint32_t i) const {return mMgr.template node<LEVEL>(i); }
481 std::string getName() const { return this->grid().getName(); };
482 bool hasLongGridName() const {return this->grid().getName().length() >= GridData::MaxNameSize;}
483 const nanovdb::Map& map() const {return mMap;}
485private:
486 build::NodeManager<GridType> mMgr;
487 nanovdb::Map mMap;
488};// NodeAccessor<openvdb::tools::PointIndexGrid>
489
490//================================================================================================
491
492// @brief Template specialization for openvdb::points::PointDataGrid
493template <>
494class NodeAccessor<openvdb::points::PointDataGrid>
495{
496public:
497 static constexpr bool IS_OPENVDB = true;
498 static constexpr bool IS_NANOVDB = false;
500 using GridType = openvdb::points::PointDataGrid;
501 using TreeType = openvdb::points::PointDataTree;
502 using RootType = typename TreeType::RootNodeType;
503 using ValueType = typename GridType::ValueType;
504 template<int LEVEL>
505 using NodeType = typename NodeTrait<const TreeType, LEVEL>::type;
506 NodeAccessor(const GridType &grid) : mMgr(const_cast<GridType&>(grid)) {
507 const auto mat4 = this->grid().transform().baseMap()->getAffineMap()->getMat4();
508 mMap.set(mat4, mat4.inverse());
509 }
510 const GridType& grid() const {return mMgr.grid();}
511 const TreeType& tree() const {return mMgr.tree();}
512 const RootType& root() const {return mMgr.root();}
513 uint64_t nodeCount(int level) const { return mMgr.nodeCount(level); }
514 template <int LEVEL>
515 const NodeType<LEVEL>& node(uint32_t i) const {return mMgr.template node<LEVEL>(i); }
516 std::string getName() const { return this->grid().getName(); };
517 bool hasLongGridName() const {return this->grid().getName().length() >= GridData::MaxNameSize;}
518 const nanovdb::Map& map() const {return mMap;}
520private:
521 build::NodeManager<GridType> mMgr;
522 nanovdb::Map mMap;
523};// NodeAccessor<openvdb::points::PointDataGrid>
524
525#endif
526
527//================================================================================================
528
529/// @brief Creates any nanovdb Grid from any source grid (certain combinations are obviously not allowed)
530template <typename SrcGridT>
532{
533public:
534 // SrcGridT can be either openvdb::Grid, nanovdb::Grid or nanovdb::tools::build::Grid
540 template <int LEVEL>
542
543 /// @brief Constructor from a source grid
544 /// @param srcGrid Source grid of type SrcGridT
545 CreateNanoGrid(const SrcGridT &srcGrid);
546
547 /// @brief Constructor from a source node accessor (defined above)
548 /// @param srcNodeAcc Source node accessor of type SrcNodeAccT
549 CreateNanoGrid(const SrcNodeAccT &srcNodeAcc);
550
551 /// @brief Set the level of verbosity
552 /// @param mode level of verbosity, mode=0 means quiet
553 void setVerbose(int mode = 1) { mVerbose = mode; }
554
555 /// @brief Enable or disable dithering, i.e. randomization of the quantization error.
556 /// @param on enable or disable dithering
557 /// @warning Dithering only has an affect when DstBuildT = {Fp4, Fp8, Fp16, FpN}
558 void enableDithering(bool on = true) { mDitherOn = on; }
559
560 /// @brief Set the mode used for computing statistics of the destination grid
561 /// @param mode specify the mode of statistics
562 void setStats(StatsMode mode = StatsMode::Default) { mStats = mode; }
563
564 /// @brief Set the mode used for computing checksums of the destination grid
565 /// @param mode specify the mode of checksum
566 void setChecksum(CheckMode mode = CheckMode::Default) { mChecksum = mode; }
567
568 /// @brief Converts the source grid into a nanovdb grid with the specified destination build type
569 /// @tparam DstBuildT build type of the destination, output, grid
570 /// @tparam BufferT Type of the buffer used for allocating the destination grid
571 /// @param buffer instance of the buffer use for allocation
572 /// @return Return an instance of a GridHandle (invoking move semantics)
573 /// @note This version is when DstBuildT != {FpN, ValueIndex, ValueOnIndex}
574 template<typename DstBuildT = typename MapToNano<SrcBuildT>::type, typename BufferT = HostBuffer>
577 getHandle(const BufferT &buffer = BufferT());
578
579 /// @brief Converts the source grid into a nanovdb grid with variable bit quantization
580 /// @tparam DstBuildT FpN, i.e. the destination grid uses variable bit quantization
581 /// @tparam OracleT Type of oracle used to determine the N in FpN
582 /// @tparam BufferT Type of the buffer used for allocating the destination grid
583 /// @param oracle Instance of the oracle used to determine the N in FpN
584 /// @param buffer instance of the buffer use for allocation
585 /// @return Return an instance of a GridHandle (invoking move semantics)
586 /// @note This version assumes DstBuildT == FpN
587 template<typename DstBuildT = typename MapToNano<SrcBuildT>::type, typename OracleT = AbsDiff, typename BufferT = HostBuffer>
589 getHandle(const OracleT &oracle = OracleT(),
590 const BufferT &buffer = BufferT());
591
592 /// @brief Converts the source grid into a nanovdb grid with indices to external arrays of values
593 /// @tparam DstBuildT ValueIndex or ValueOnIndex, i.e. index all or just active values
594 /// @tparam BufferT Type of the buffer used for allocating the destination grid
595 /// @param channels Number of copies of values encoded as blind data in the destination grid
596 /// @param includeStats Specify if statics should be indexed
597 /// @param includeTiles Specify if tile values, i.e. non-leaf-node-values, should be indexed
598 /// @param buffer instance of the buffer use for allocation
599 /// @return Return an instance of a GridHandle (invoking move semantics)
600 template<typename DstBuildT = typename MapToNano<SrcBuildT>::type, typename BufferT = HostBuffer>
602 getHandle(uint32_t channels = 0u,
603 bool includeStats = true,
604 bool includeTiles = true,
605 const BufferT &buffer = BufferT());
606
607 /// @brief Add blind data to the destination grid
608 /// @param name String name of the blind data
609 /// @param dataSemantic Semantics of the blind data
610 /// @param dataClass Class of the blind data
611 /// @param dataType Type of the blind data
612 /// @param count Element count of the blind data
613 /// @param size Size of each element of the blind data
614 /// @return Return the index used to access the blind data
615 uint64_t addBlindData(const std::string& name,
616 GridBlindDataSemantic dataSemantic,
617 GridBlindDataClass dataClass,
618 GridType dataType,
619 size_t count, size_t size)
620 {
621 const size_t order = mBlindMetaData.size();
622 mBlindMetaData.emplace(name, dataSemantic, dataClass, dataType, order, count, size);
623 return order;
624 }
625
626 /// @brief This method only has affect when getHandle was called with DstBuildT = ValueIndex or ValueOnIndex
627 /// @return Return the number of indexed values. If called before getHandle was called with
628 /// DstBuildT = ValueIndex or ValueOnIndex the return value is zero. Else it is a value larger than zero.
629 uint64_t valueCount() const {return mValIdx[0].empty() ? 0u : mValIdx[0].back();}
630
631 /// @brief Copy values from the source grid into a provided buffer
632 /// @tparam DstBuildT Must be ValueIndex or ValueOnIndex, i.e. a index grid
633 /// @param buffer point in which to write values
634 template <typename DstBuildT>
636 copyValues(SrcValueT *buffer);
637
638private:
639
640 // =========================================================
641
642 template <typename T, int LEVEL>
643 typename util::enable_if<!(util::is_same<T,FpN>::value&&LEVEL==0), typename NodeTrait<NanoRoot<T>, LEVEL>::type*>::type
644 dstNode(uint64_t i) const {
645 static_assert(LEVEL==0 || LEVEL==1 || LEVEL==2, "Expected LEVEL== {0,1,2}");
646 using NodeT = typename NodeTrait<NanoRoot<T>, LEVEL>::type;
647 return util::PtrAdd<NodeT>(mBufferPtr, mOffset[5-LEVEL]) + i;
648 }
649 template <typename T, int LEVEL>
651 dstNode(uint64_t i) const {return util::PtrAdd<NanoLeaf<FpN>>(mBufferPtr, mCodec[i].offset);}
652
653 template <typename T> NanoRoot<T>* dstRoot() const {return util::PtrAdd<NanoRoot<T>>(mBufferPtr, mOffset.root);}
654 template <typename T> NanoTree<T>* dstTree() const {return util::PtrAdd<NanoTree<T>>(mBufferPtr, mOffset.tree);}
655 template <typename T> NanoGrid<T>* dstGrid() const {return util::PtrAdd<NanoGrid<T>>(mBufferPtr, mOffset.grid);}
656 GridBlindMetaData* dstMeta(uint32_t i) const { return util::PtrAdd<GridBlindMetaData>(mBufferPtr, mOffset.meta) + i;};
657
658 // =========================================================
659
660 template <typename DstBuildT>
661 typename util::disable_if<util::is_same<FpN,DstBuildT>::value || BuildTraits<DstBuildT>::is_index>::type
662 preProcess();
663
664 template <typename DstBuildT>
665 typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
666 preProcess(uint32_t channels);
667
668 template <typename DstBuildT, typename OracleT>
669 typename util::enable_if<util::is_same<FpN, DstBuildT>::value>::type
670 preProcess(OracleT oracle);
671
672 // =========================================================
673
674 // Below are private methods use to serialize nodes into NanoVDB
675 template<typename DstBuildT, typename BufferT>
676 GridHandle<BufferT> initHandle(const BufferT& buffer);
677
678 // =========================================================
679
680 template <typename DstBuildT>
681 inline typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
682 postProcess(uint32_t channels);
683
684 template <typename DstBuildT>
685 inline typename util::disable_if<BuildTraits<DstBuildT>::is_index>::type
686 postProcess();
687
688 // ========================================================
689
690 template<typename DstBuildT>
691 typename util::disable_if<BuildTraits<DstBuildT>::is_special>::type
692 processLeafs();
693
694 template<typename DstBuildT>
695 typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
696 processLeafs();
697
698 template<typename DstBuildT>
699 typename util::enable_if<BuildTraits<DstBuildT>::is_FpX>::type
700 processLeafs();
701
702 template<typename DstBuildT>
703 typename util::enable_if<util::is_same<FpN, DstBuildT>::value>::type
704 processLeafs();
705
706 template<typename DstBuildT>
707 typename util::enable_if<util::is_same<bool, DstBuildT>::value>::type
708 processLeafs();
709
710 template<typename DstBuildT>
711 typename util::enable_if<util::is_same<ValueMask, DstBuildT>::value>::type
712 processLeafs();
713
714 // =========================================================
715
716 template<typename DstBuildT, int LEVEL>
717 typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
718 processInternalNodes();
719
720 template<typename DstBuildT, int LEVEL>
721 typename util::enable_if<!BuildTraits<DstBuildT>::is_index>::type
722 processInternalNodes();
723
724 // =========================================================
725
726 template <typename DstBuildT>
727 typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
728 processRoot();
729
730 template <typename DstBuildT>
731 typename util::enable_if<!BuildTraits<DstBuildT>::is_index>::type
732 processRoot();
733
734 // =========================================================
735
736 template<typename DstBuildT>
737 void processTree();
738
739 template<typename DstBuildT>
740 void processGrid();
741
742 template <typename DstBuildT, int LEVEL>
743 typename util::enable_if<BuildTraits<DstBuildT>::is_index, uint64_t>::type
744 countTileValues(uint64_t valueCount);
745
746 template <typename DstBuildT>
747 typename util::enable_if<BuildTraits<DstBuildT>::is_index, uint64_t>::type
748 countValues();
749
750#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
751 template<typename T = SrcGridT>
752 typename util::disable_if<util::is_same<T, openvdb::tools::PointIndexGrid>::value ||
754 countPoints() const;
755
756 template<typename T = SrcGridT>
757 typename util::enable_if<util::is_same<T, openvdb::tools::PointIndexGrid>::value ||
759 countPoints() const;
760
761 template<typename DstBuildT, typename AttT, typename CodecT = openvdb::points::UnknownCodec, typename T = SrcGridT>
762 typename util::enable_if<util::is_same<openvdb::points::PointDataGrid, T>::value>::type
763 copyPointAttribute(size_t attIdx, AttT *attPtr);
764#else
765 uint64_t countPoints() const {return 0u;}
766#endif
767
768 void* mBufferPtr;// pointer to the beginning of the destination nanovdb grid buffer
769 struct BufferOffsets {
770 uint64_t grid, tree, root, upper, lower, leaf, meta, blind, size;
771 uint64_t operator[](int i) const { return *(reinterpret_cast<const uint64_t*>(this)+i); }
772 } mOffset;
773 int mVerbose;
774 uint64_t mLeafNodeSize;// non-trivial when DstBuiltT = FpN
775
776 std::unique_ptr<SrcNodeAccT> mSrcNodeAccPtr;// placeholder for potential local instance
777 const SrcNodeAccT &mSrcNodeAcc;
778 struct OrderedBlindMetaData; // forward declaration
779 std::set<OrderedBlindMetaData> mBlindMetaData; // sorted set of GridBlindMetaData
780 struct Codec { float min, max; uint64_t offset; uint8_t log2; };// used for adaptive bit-rate quantization
781 std::unique_ptr<Codec[]> mCodec;// defines a codec per leaf node when DstBuildT = FpN
782 StatsMode mStats;
783 CheckMode mChecksum;
784 bool mDitherOn, mIncludeStats, mIncludeTiles;
785 std::vector<uint64_t> mValIdx[3];// store id of first value in node
786}; // CreateNanoGrid
787
788//================================================================================================
789
790template <typename SrcGridT>
792 : mVerbose(0)
793 , mSrcNodeAccPtr(new SrcNodeAccT(srcGrid))
794 , mSrcNodeAcc(*mSrcNodeAccPtr)
795 , mStats(StatsMode::Default)
796 , mChecksum(CheckMode::Default)
797 , mDitherOn(false)
798 , mIncludeStats(true)
799 , mIncludeTiles(true)
800{
801}
802
803//================================================================================================
804
805template <typename SrcGridT>
807 : mVerbose(0)
808 , mSrcNodeAccPtr(nullptr)
809 , mSrcNodeAcc(srcNodeAcc)
810 , mStats(StatsMode::Default)
811 , mChecksum(CheckMode::Default)
812 , mDitherOn(false)
813 , mIncludeStats(true)
814 , mIncludeTiles(true)
815{
816}
817
818//================================================================================================
819
820template <typename SrcGridT>
822{
823 OrderedBlindMetaData(const std::string& name,// name, also used to derive GridBlindDataSemantic
824 const std::string& type,// used to derive GridType of blind data
825 GridBlindDataClass dataClass,
826 size_t i, size_t valueCount, size_t valueSize)
827 : metaData(new GridBlindMetaData(0, valueCount, valueSize, this->mapToSemantics(name), dataClass, this->mapToType(type)))
828 , order(i)// sorted id of meta data
829 {
830 if (!metaData->setName(name.c_str())) throw std::runtime_error("blind data name exceeds character limit");
831 NANOVDB_ASSERT(metaData->isValid());
832 }
833 OrderedBlindMetaData(const std::string& name,// only used to name blind data
834 GridBlindDataSemantic dataSemantic,
835 GridBlindDataClass dataClass,
836 GridType dataType,
837 size_t i, size_t valueCount, size_t valueSize)
838 : metaData(new GridBlindMetaData(0, valueCount, valueSize, dataSemantic, dataClass, dataType))
839 , order(i)// sorted id of meta data
840 {
841 if (!metaData->setName(name.c_str())) throw std::runtime_error("blind data name exceeds character limit");
842 NANOVDB_ASSERT(metaData->isValid());
843 }
845 bool operator<(const OrderedBlindMetaData& other) const { return order < other.order; } // required by std::set
846 static GridType mapToType(const std::string& name)
847 {
849 if ("uint32_t" == name) {
850 type = GridType::UInt32;
851 } else if ("float" == name) {
852 type = GridType::Float;
853 } else if ("vec3s"== name) {
854 type = GridType::Vec3f;
855 } else if ("int32" == name) {
856 type = GridType::Int32;
857 } else if ("int64" == name) {
858 type = GridType::Int64;
859 }
860 return type;
861 }
862 /// @brief Maps from string names of point attributes in openvdb to GridBlindDataSemantic
863 /// @param name Attribute name, typically used for point attributes in OpenVDB
864 /// @return GridBlindDataSemantic
865 static GridBlindDataSemantic mapToSemantics(const std::string& name)
866 {
868 if ("P" == name) {
870 } else if ("V" == name) {
872 } else if ("Cd" == name) {
874 } else if ("N" == name) {
876 } else if ("id" == name) {
878 }
879 return semantic;
880 }
881 size_t memUsage() const {return metaData->blindDataSize();}
882 GridBlindMetaData *metaData;// a pointer is preferred since it avoids deep copy during sorting
883 const size_t order;// index used for sorting of the blind meta data
884}; // CreateNanoGrid::OrderedBlindMetaData
885
886//================================================================================================
887
888template <typename SrcGridT>
889template<typename DstBuildT, typename BufferT>
893{
894 this->template preProcess<DstBuildT>();
895 auto handle = this->template initHandle<DstBuildT>(pool);
896 this->template postProcess<DstBuildT>();
897 return handle;
898} // CreateNanoGrid::getHandle<T>
899
900//================================================================================================
901
902template <typename SrcGridT>
903template<typename DstBuildT, typename OracleT, typename BufferT>
905CreateNanoGrid<SrcGridT>::getHandle(const OracleT& oracle, const BufferT& pool)
906{
907 this->template preProcess<DstBuildT, OracleT>(oracle);
908 auto handle = this->template initHandle<DstBuildT>(pool);
909 this->template postProcess<DstBuildT>();
910 return handle;
911} // CreateNanoGrid::getHandle<FpN>
912
913//================================================================================================
914
915template <typename SrcGridT>
916template<typename DstBuildT, typename BufferT>
919 bool includeStats,
920 bool includeTiles,
921 const BufferT &pool)
922{
923 mIncludeStats = includeStats;
924 mIncludeTiles = includeTiles;
925 this->template preProcess<DstBuildT>(channels);
926 auto handle = this->template initHandle<DstBuildT>(pool);
927 this->template postProcess<DstBuildT>(channels);
928 return handle;
929}// CreateNanoGrid::getHandle<ValueIndex or ValueOnIndex>
930
931//================================================================================================
932
933template <typename SrcGridT>
934template <typename DstBuildT, typename BufferT>
935GridHandle<BufferT> CreateNanoGrid<SrcGridT>::initHandle(const BufferT& pool)
936{
937 mOffset.grid = 0;// grid is always stored at the start of the buffer!
938 mOffset.tree = NanoGrid<DstBuildT>::memUsage(); // grid ends and tree begins
939 mOffset.root = mOffset.tree + NanoTree<DstBuildT>::memUsage(); // tree ends and root node begins
940 mOffset.upper = mOffset.root + NanoRoot<DstBuildT>::memUsage(mSrcNodeAcc.root().getTableSize()); // root node ends and upper internal nodes begin
941 mOffset.lower = mOffset.upper + NanoUpper<DstBuildT>::memUsage()*mSrcNodeAcc.nodeCount(2); // upper internal nodes ends and lower internal nodes begin
942 mOffset.leaf = mOffset.lower + NanoLower<DstBuildT>::memUsage()*mSrcNodeAcc.nodeCount(1); // lower internal nodes ends and leaf nodes begin
943 mOffset.meta = mOffset.leaf + mLeafNodeSize;// leaf nodes end and blind meta data begins
944 mOffset.blind = mOffset.meta + sizeof(GridBlindMetaData)*mBlindMetaData.size(); // meta data ends and blind data begins
945 mOffset.size = mOffset.blind;// end of buffer
946 for (const auto& b : mBlindMetaData) mOffset.size += b.memUsage(); // accumulate all the blind data
947
948 auto buffer = BufferT::create(mOffset.size, &pool);
949 mBufferPtr = buffer.data();
950
951 // Concurrent processing of all tree levels!
952 util::invoke( [&](){this->template processLeafs<DstBuildT>();},
953 [&](){this->template processInternalNodes<DstBuildT, 1>();},
954 [&](){this->template processInternalNodes<DstBuildT, 2>();},
955 [&](){this->template processRoot<DstBuildT>();},
956 [&](){this->template processTree<DstBuildT>();},
957 [&](){this->template processGrid<DstBuildT>();} );
958
959 return GridHandle<BufferT>(std::move(buffer));
960} // CreateNanoGrid::initHandle
961
962//================================================================================================
963
964template <typename SrcGridT>
965template <typename DstBuildT>
966inline typename util::disable_if<util::is_same<FpN, DstBuildT>::value || BuildTraits<DstBuildT>::is_index>::type
967CreateNanoGrid<SrcGridT>::preProcess()
968{
969 if (const uint64_t pointCount = this->countPoints()) {
970#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
972 if (!mBlindMetaData.empty()) throw std::runtime_error("expected no blind meta data");
973 this->addBlindData("index",
977 pointCount,
978 sizeof(uint32_t));
980 if (!mBlindMetaData.empty()) throw std::runtime_error("expected no blind meta data");
981 auto &srcLeaf = mSrcNodeAcc.template node<0>(0);
982 const auto& attributeSet = srcLeaf.attributeSet();
983 const auto& descriptor = attributeSet.descriptor();
984 const auto& nameMap = descriptor.map();
985 for (auto it = nameMap.begin(); it != nameMap.end(); ++it) {
986 const size_t index = it->second;
987 auto& attArray = srcLeaf.constAttributeArray(index);
988 mBlindMetaData.emplace(it->first, // name used to derive semantics
989 descriptor.valueType(index), // type
991 index, // order
992 pointCount, // element count
993 attArray.valueTypeSize()); // element size
994 }
995 }
996#endif
997 }
998 if (mSrcNodeAcc.hasLongGridName()) {
999 this->addBlindData("grid name",
1003 mSrcNodeAcc.getName().length() + 1, 1);
1004 }
1005 mLeafNodeSize = mSrcNodeAcc.nodeCount(0)*NanoLeaf<DstBuildT>::DataType::memUsage();
1006}// CreateNanoGrid::preProcess<T>
1007
1008//================================================================================================
1009
1010template <typename SrcGridT>
1011template <typename DstBuildT, typename OracleT>
1012inline typename util::enable_if<util::is_same<FpN, DstBuildT>::value>::type
1013CreateNanoGrid<SrcGridT>::preProcess(OracleT oracle)
1014{
1015 static_assert(util::is_same<float, SrcValueT>::value, "preProcess<FpN>: expected SrcValueT == float");
1016
1017 const size_t leafCount = mSrcNodeAcc.nodeCount(0);
1018 if (leafCount==0) {
1019 mLeafNodeSize = 0u;
1020 return;
1021 }
1022 mCodec.reset(new Codec[leafCount]);
1023
1025 if (!oracle) oracle.init(mSrcNodeAcc.gridClass(), mSrcNodeAcc.root().background());
1026 }
1027
1028 math::DitherLUT lut(mDitherOn);
1029 util::forEach(0, leafCount, 4, [&](const util::Range1D &r) {
1030 for (auto i=r.begin(); i!=r.end(); ++i) {
1031 const auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1032 float &min = mCodec[i].min = std::numeric_limits<float>::max();
1033 float &max = mCodec[i].max = -min;
1034 for (int j=0; j<512; ++j) {
1035 float v = srcLeaf.getValue(j);
1036 if (v<min) min = v;
1037 if (v>max) max = v;
1038 }
1039 const float range = max - min;
1040 uint8_t &logBitWidth = mCodec[i].log2 = 0;// 0,1,2,3,4 => 1,2,4,8,16 bits
1041 while (range > 0.0f && logBitWidth < 4u) {
1042 const uint32_t mask = (uint32_t(1) << (uint32_t(1) << logBitWidth)) - 1u;
1043 const float encode = mask/range;
1044 const float decode = range/mask;
1045 int j = 0;
1046 do {
1047 const float exact = srcLeaf.getValue(j);//data[j];// exact value
1048 const uint32_t code = uint32_t(encode*(exact - min) + lut(j));
1049 const float approx = code * decode + min;// approximate value
1050 j += oracle(exact, approx) ? 1 : 513;
1051 } while(j < 512);
1052 if (j == 512) break;
1053 ++logBitWidth;
1054 }
1055 }
1056 });
1057
1058 auto getOffset = [&](size_t i){
1059 --i;
1060 return mCodec[i].offset + NanoLeaf<DstBuildT>::DataType::memUsage(1u << mCodec[i].log2);
1061 };
1062 mCodec[0].offset = NanoGrid<FpN>::memUsage() +
1064 NanoRoot<FpN>::memUsage(mSrcNodeAcc.root().getTableSize()) +
1065 NanoUpper<FpN>::memUsage()*mSrcNodeAcc.nodeCount(2) +
1066 NanoLower<FpN>::memUsage()*mSrcNodeAcc.nodeCount(1);
1067 for (size_t i=1; i<leafCount; ++i) mCodec[i].offset = getOffset(i);
1068 mLeafNodeSize = getOffset(leafCount);
1069
1070 if (mVerbose) {
1071 uint32_t counters[5+1] = {0};
1072 ++counters[mCodec[0].log2];
1073 for (size_t i=1; i<leafCount; ++i) ++counters[mCodec[i].log2];
1074 std::cout << "\n" << oracle << std::endl;
1075 std::cout << "Dithering: " << (mDitherOn ? "enabled" : "disabled") << std::endl;
1076 float avg = 0.0f;
1077 for (uint32_t i=0; i<=5; ++i) {
1078 if (uint32_t n = counters[i]) {
1079 avg += n * float(1 << i);
1080 printf("%2i bits: %6u leaf nodes, i.e. %4.1f%%\n",1<<i, n, 100.0f*n/float(leafCount));
1081 }
1082 }
1083 printf("%4.1f bits per value on average\n", avg/float(leafCount));
1084 }
1085
1086 if (mSrcNodeAcc.hasLongGridName()) {
1087 this->addBlindData("grid name",
1091 mSrcNodeAcc.getName().length() + 1, 1);
1092 }
1093}// CreateNanoGrid::preProcess<FpN>
1094
1095//================================================================================================
1096
1097template <typename SrcGridT>
1098template <typename DstBuildT, int LEVEL>
1099inline typename util::enable_if<BuildTraits<DstBuildT>::is_index, uint64_t>::type
1100CreateNanoGrid<SrcGridT>::countTileValues(uint64_t valueCount)
1101{
1102 const uint64_t stats = mIncludeStats ? 4u : 0u;// minimum, maximum, average, and deviation
1103 mValIdx[LEVEL].clear();
1104 mValIdx[LEVEL].resize(mSrcNodeAcc.nodeCount(LEVEL) + 1, stats);// minimum 1 entry
1105 util::forEach(1, mValIdx[LEVEL].size(), 8, [&](const util::Range1D& r){
1106 for (auto i = r.begin(); i!=r.end(); ++i) {
1107 auto &srcNode = mSrcNodeAcc.template node<LEVEL>(i-1);
1108 if constexpr(BuildTraits<DstBuildT>::is_onindex) {// resolved at compile time
1109 mValIdx[LEVEL][i] += srcNode.getValueMask().countOn();
1110 } else {
1111 static const uint64_t maxTileCount = uint64_t(1u) << 3*srcNode.LOG2DIM;
1112 mValIdx[LEVEL][i] += maxTileCount - srcNode.getChildMask().countOn();
1113 }
1114 }
1115 });
1116 mValIdx[LEVEL][0] = valueCount;
1117 for (size_t i=1; i<mValIdx[LEVEL].size(); ++i) mValIdx[LEVEL][i] += mValIdx[LEVEL][i-1];// pre-fixed sum
1118 return mValIdx[LEVEL].back();
1119}// CreateNanoGrid::countTileValues<ValueIndex or ValueOnIndex>
1120
1121//================================================================================================
1122
1123template <typename SrcGridT>
1124template <typename DstBuildT>
1125inline typename util::enable_if<BuildTraits<DstBuildT>::is_index, uint64_t>::type
1126CreateNanoGrid<SrcGridT>::countValues()
1127{
1128 const uint64_t stats = mIncludeStats ? 4u : 0u;// minimum, maximum, average, and deviation
1129 uint64_t valueCount = 1u;// offset 0 corresponds to the background value
1130 if (mIncludeTiles) {
1132 for (auto it = mSrcNodeAcc.root().cbeginValueOn(); it; ++it) ++valueCount;
1133 } else {
1134 for (auto it = mSrcNodeAcc.root().cbeginValueAll(); it; ++it) ++valueCount;
1135 }
1136 valueCount += stats;// optionally append stats for the root node
1137 valueCount = countTileValues<DstBuildT, 2>(valueCount);
1138 valueCount = countTileValues<DstBuildT, 1>(valueCount);
1139 }
1140 mValIdx[0].clear();
1141 mValIdx[0].resize(mSrcNodeAcc.nodeCount(0) + 1, 512u + stats);// minimum 1 entry
1143 util::forEach(1, mValIdx[0].size(), 8, [&](const util::Range1D& r) {
1144 for (auto i = r.begin(); i != r.end(); ++i) {
1145 mValIdx[0][i] = stats;
1146 mValIdx[0][i] += mSrcNodeAcc.template node<0>(i-1).getValueMask().countOn();
1147 }
1148 });
1149 }
1150 mValIdx[0][0] = valueCount;
1151 util::prefixSum(mValIdx[0], true);// inclusive prefix sum
1152 return mValIdx[0].back();
1153}// CreateNanoGrid::countValues<ValueIndex or ValueOnIndex>()
1154
1155//================================================================================================
1156
1157template <typename SrcGridT>
1158template <typename DstBuildT>
1159inline typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
1160CreateNanoGrid<SrcGridT>::preProcess(uint32_t channels)
1161{
1162 const uint64_t valueCount = this->template countValues<DstBuildT>();
1163 mLeafNodeSize = mSrcNodeAcc.nodeCount(0)*NanoLeaf<DstBuildT>::DataType::memUsage();
1164
1165 uint32_t order = mBlindMetaData.size();
1166 char str[16];
1167 for (uint32_t i=0; i<channels; ++i) {
1168 mBlindMetaData.emplace("channel_" + std::to_string(i),
1171 order++,
1172 valueCount,
1173 sizeof(SrcValueT));
1174 }
1175 if (mSrcNodeAcc.hasLongGridName()) {
1176 this->addBlindData("grid name",
1180 mSrcNodeAcc.getName().length() + 1, 1);
1181 }
1182}// preProcess<ValueIndex or ValueOnIndex>
1183
1184//================================================================================================
1185
1186template <typename SrcGridT>
1187template <typename DstBuildT>
1188inline typename util::disable_if<BuildTraits<DstBuildT>::is_special>::type
1189CreateNanoGrid<SrcGridT>::processLeafs()
1190{
1191 using DstDataT = typename NanoLeaf<DstBuildT>::DataType;
1192 using DstValueT = typename DstDataT::ValueType;
1193 static_assert(DstDataT::FIXED_SIZE, "Expected destination LeafNode<T> to have fixed size");
1194 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1195 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1196 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1197 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1198 if (DstDataT::padding()>0u) {
1199 util::memzero(dstLeaf, DstDataT::memUsage());
1200 } else {
1201 dstLeaf->mBBoxDif[0] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[2] = 0u;
1202 dstLeaf->mFlags = 0u;// enable rendering, no bbox, no stats
1203 dstLeaf->mMinimum = dstLeaf->mMaximum = typename DstDataT::ValueType();
1204 dstLeaf->mAverage = dstLeaf->mStdDevi = 0;
1205 }
1206 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1207 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1208 DstValueT *dst = dstLeaf->mValues;
1209 if constexpr(util::is_same<DstValueT, SrcValueT>::value && SrcNodeAccT::IS_OPENVDB) {
1210 const SrcValueT *src = srcLeaf.buffer().data();
1211 for (auto *end = dst + 512u; dst != end; dst += 4, src += 4) {
1212 dst[0] = src[0]; // copy *all* voxel values in sets of four, i.e. loop-unrolling
1213 dst[1] = src[1];
1214 dst[2] = src[2];
1215 dst[3] = src[3];
1216 }
1217 } else {
1218 for (uint32_t j=0; j<512u; ++j) *dst++ = static_cast<DstValueT>(srcLeaf.getValue(j));
1219 }
1220 }
1221 });
1222} // CreateNanoGrid::processLeafs<T>
1223
1224//================================================================================================
1225
1226template <typename SrcGridT>
1227template <typename DstBuildT>
1229CreateNanoGrid<SrcGridT>::processLeafs()
1230{
1231 using DstDataT = typename NanoLeaf<DstBuildT>::DataType;
1232 static_assert(DstDataT::FIXED_SIZE, "Expected destination LeafNode<ValueIndex> to have fixed size");
1233 static_assert(DstDataT::padding()==0u, "Expected leaf nodes to have no padding");
1234
1235 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1236 const uint8_t flags = mIncludeStats ? 16u : 0u;// 4th bit indicates stats
1237 DstDataT *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());// fixed size
1238 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1239 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1240 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1241 dstLeaf->mBBoxDif[0] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[2] = 0u;
1242 dstLeaf->mFlags = flags;
1243 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1244 dstLeaf->mOffset = mValIdx[0][i];
1245 if constexpr(BuildTraits<DstBuildT>::is_onindex) {
1246 const uint64_t *w = dstLeaf->mValueMask.words();
1247#ifdef USE_OLD_VALUE_ON_INDEX
1248 int32_t sum = CountOn(*w++);
1249 uint8_t *p = reinterpret_cast<uint8_t*>(&dstLeaf->mPrefixSum), *q = p + 7;
1250 for (int j=0; j<7; ++j) {
1251 *p++ = sum & 255u;
1252 *q |= (sum >> 8) << j;
1253 sum += CountOn(*w++);
1254 }
1255#else
1256 uint64_t &prefixSum = dstLeaf->mPrefixSum, sum = util::countOn(*w++);
1257 prefixSum = sum;
1258 for (int n = 9; n < 55; n += 9) {// n=i*9 where i=1,2,..6
1259 sum += util::countOn(*w++);
1260 prefixSum |= sum << n;// each pre-fixed sum is encoded in 9 bits
1261 }
1262#endif
1263 } else {
1264 dstLeaf->mPrefixSum = 0u;
1265 }
1266 }
1267 });
1268} // CreateNanoGrid::processLeafs<ValueIndex or ValueOnIndex>
1269
1270//================================================================================================
1271
1272template <typename SrcGridT>
1273template <typename DstBuildT>
1274inline typename util::enable_if<util::is_same<ValueMask, DstBuildT>::value>::type
1275CreateNanoGrid<SrcGridT>::processLeafs()
1276{
1277 using DstDataT = typename NanoLeaf<ValueMask>::DataType;
1278 static_assert(DstDataT::FIXED_SIZE, "Expected destination LeafNode<ValueMask> to have fixed size");
1279 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1280 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1281 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1282 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1283 if (DstDataT::padding()>0u) {
1284 util::memzero(dstLeaf, DstDataT::memUsage());
1285 } else {
1286 dstLeaf->mBBoxDif[0] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[2] = 0u;
1287 dstLeaf->mFlags = 0u;// enable rendering, no bbox, no stats
1288 dstLeaf->mPadding[0] = dstLeaf->mPadding[1] = 0u;
1289 }
1290 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1291 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1292 }
1293 });
1294} // CreateNanoGrid::processLeafs<ValueMask>
1295
1296//================================================================================================
1297
1298template <typename SrcGridT>
1299template <typename DstBuildT>
1300inline typename util::enable_if<util::is_same<bool, DstBuildT>::value>::type
1301CreateNanoGrid<SrcGridT>::processLeafs()
1302{
1303 using DstDataT = typename NanoLeaf<bool>::DataType;
1304 static_assert(DstDataT::FIXED_SIZE, "Expected destination LeafNode<bool> to have fixed size");
1305 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1306 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1307 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1308 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1309 if (DstDataT::padding()>0u) {
1310 util::memzero(dstLeaf, DstDataT::memUsage());
1311 } else {
1312 dstLeaf->mBBoxDif[0] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[2] = 0u;
1313 dstLeaf->mFlags = 0u;// enable rendering, no bbox, no stats
1314 }
1315 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1316 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1317 if constexpr(!util::is_same<bool, SrcBuildT>::value) {
1318 for (int j=0; j<512; ++j) dstLeaf->mValues.set(j, static_cast<bool>(srcLeaf.getValue(j)));
1319 } else if constexpr(SrcNodeAccT::IS_OPENVDB) {
1320 dstLeaf->mValues = *reinterpret_cast<const Mask<3>*>(srcLeaf.buffer().data());
1321 } else if constexpr(SrcNodeAccT::IS_NANOVDB) {
1322 dstLeaf->mValues = srcLeaf.data()->mValues;
1323 } else {// tools::Leaf
1324 dstLeaf->mValues = srcLeaf.mValues; // copy value mask
1325 }
1326 }
1327 });
1328} // CreateNanoGrid::processLeafs<bool>
1329
1330//================================================================================================
1331
1332template <typename SrcGridT>
1333template <typename DstBuildT>
1334inline typename util::enable_if<BuildTraits<DstBuildT>::is_FpX>::type
1335CreateNanoGrid<SrcGridT>::processLeafs()
1336{
1337 using DstDataT = typename NanoLeaf<DstBuildT>::DataType;
1338 static_assert(DstDataT::FIXED_SIZE, "Expected destination LeafNode<Fp4|Fp8|Fp16> to have fixed size");
1339 using ArrayT = typename DstDataT::ArrayType;
1340 static_assert(util::is_same<float, SrcValueT>::value, "Expected ValueT == float");
1341 using FloatT = typename std::conditional<DstDataT::bitWidth()>=16, double, float>::type;// 16 compression and higher requires double
1342 static constexpr FloatT UNITS = FloatT((1 << DstDataT::bitWidth()) - 1);// # of unique non-zero values
1343 math::DitherLUT lut(mDitherOn);
1344
1345 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1346 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1347 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1348 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1349 if (DstDataT::padding()>0u) {
1350 util::memzero(dstLeaf, DstDataT::memUsage());
1351 } else {
1352 dstLeaf->mFlags = dstLeaf->mBBoxDif[2] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[0] = 0u;
1353 dstLeaf->mDev = dstLeaf->mAvg = dstLeaf->mMax = dstLeaf->mMin = 0u;
1354 }
1355 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1356 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1357 // compute extrema values
1358 float min = std::numeric_limits<float>::max(), max = -min;
1359 for (uint32_t j=0; j<512u; ++j) {
1360 const float v = srcLeaf.getValue(j);
1361 if (v < min) min = v;
1362 if (v > max) max = v;
1363 }
1364 dstLeaf->init(min, max, DstDataT::bitWidth());
1365 // perform quantization relative to the values in the current leaf node
1366 const FloatT encode = UNITS/(max-min);
1367 uint32_t offset = 0;
1368 auto quantize = [&]()->ArrayT{
1369 const ArrayT tmp = static_cast<ArrayT>(encode * (srcLeaf.getValue(offset) - min) + lut(offset));
1370 ++offset;
1371 return tmp;
1372 };
1373 auto *code = reinterpret_cast<ArrayT*>(dstLeaf->mCode);
1374 if (util::is_same<Fp4, DstBuildT>::value) {// resolved at compile-time
1375 for (uint32_t j=0; j<128u; ++j) {
1376 auto tmp = quantize();
1377 *code++ = quantize() << 4 | tmp;
1378 tmp = quantize();
1379 *code++ = quantize() << 4 | tmp;
1380 }
1381 } else {
1382 for (uint32_t j=0; j<128u; ++j) {
1383 *code++ = quantize();
1384 *code++ = quantize();
1385 *code++ = quantize();
1386 *code++ = quantize();
1387 }
1388 }
1389 }
1390 });
1391} // CreateNanoGrid::processLeafs<Fp4, Fp8, Fp16>
1392
1393//================================================================================================
1394
1395template <typename SrcGridT>
1396template <typename DstBuildT>
1397inline typename util::enable_if<util::is_same<FpN, DstBuildT>::value>::type
1398CreateNanoGrid<SrcGridT>::processLeafs()
1399{
1400 static_assert(util::is_same<float, SrcValueT>::value, "Expected SrcValueT == float");
1401 math::DitherLUT lut(mDitherOn);
1402 util::forEach(0, mSrcNodeAcc.nodeCount(0), 8, [&](const util::Range1D& r) {
1403 for (auto i = r.begin(); i != r.end(); ++i) {
1404 auto &srcLeaf = mSrcNodeAcc.template node<0>(i);
1405 auto *dstLeaf = this->template dstNode<DstBuildT,0>(i);
1406 dstLeaf->mBBoxMin = srcLeaf.origin(); // copy origin of node
1407 dstLeaf->mBBoxDif[0] = dstLeaf->mBBoxDif[1] = dstLeaf->mBBoxDif[2] = 0u;
1408 const uint8_t logBitWidth = mCodec[i].log2;
1409 dstLeaf->mFlags = logBitWidth << 5;// pack logBitWidth into 3 MSB of mFlag
1410 dstLeaf->mValueMask = srcLeaf.getValueMask(); // copy value mask
1411 const float min = mCodec[i].min, max = mCodec[i].max;
1412 dstLeaf->init(min, max, uint8_t(1) << logBitWidth);
1413 // perform quantization relative to the values in the current leaf node
1414 uint32_t offset = 0;
1415 float encode = 0.0f;
1416 auto quantize = [&]()->uint8_t{
1417 const uint8_t tmp = static_cast<uint8_t>(encode * (srcLeaf.getValue(offset) - min) + lut(offset));
1418 ++offset;
1419 return tmp;
1420 };
1421 auto *dst = reinterpret_cast<uint8_t*>(dstLeaf+1);
1422 switch (logBitWidth) {
1423 case 0u: {// 1 bit
1424 encode = 1.0f/(max - min);
1425 for (int j=0; j<64; ++j) {
1426 uint8_t a = 0;
1427 for (int k=0; k<8; ++k) a |= quantize() << k;
1428 *dst++ = a;
1429 }
1430 }
1431 break;
1432 case 1u: {// 2 bits
1433 encode = 3.0f/(max - min);
1434 for (int j=0; j<128; ++j) {
1435 auto a = quantize();
1436 a |= quantize() << 2;
1437 a |= quantize() << 4;
1438 *dst++ = quantize() << 6 | a;
1439 }
1440 }
1441 break;
1442 case 2u: {// 4 bits
1443 encode = 15.0f/(max - min);
1444 for (int j=0; j<128; ++j) {
1445 auto a = quantize();
1446 *dst++ = quantize() << 4 | a;
1447 a = quantize();
1448 *dst++ = quantize() << 4 | a;
1449 }
1450 }
1451 break;
1452 case 3u: {// 8 bits
1453 encode = 255.0f/(max - min);
1454 for (int j=0; j<128; ++j) {
1455 *dst++ = quantize();
1456 *dst++ = quantize();
1457 *dst++ = quantize();
1458 *dst++ = quantize();
1459 }
1460 }
1461 break;
1462 default: {// 16 bits - special implementation using higher bit-precision
1463 auto *dst = reinterpret_cast<uint16_t*>(dstLeaf+1);
1464 const double encode = 65535.0/(max - min);// note that double is required!
1465 for (int j=0; j<128; ++j) {
1466 *dst++ = uint16_t(encode * (srcLeaf.getValue(offset) - min) + lut(offset)); ++offset;
1467 *dst++ = uint16_t(encode * (srcLeaf.getValue(offset) - min) + lut(offset)); ++offset;
1468 *dst++ = uint16_t(encode * (srcLeaf.getValue(offset) - min) + lut(offset)); ++offset;
1469 *dst++ = uint16_t(encode * (srcLeaf.getValue(offset) - min) + lut(offset)); ++offset;
1470 }
1471 }
1472 }// end switch
1473 }
1474 });// kernel
1475} // CreateNanoGrid::processLeafs<FpN>
1476
1477//================================================================================================
1478
1479template <typename SrcGridT>
1480template <typename DstBuildT, int LEVEL>
1481inline typename util::enable_if<!BuildTraits<DstBuildT>::is_index>::type
1482CreateNanoGrid<SrcGridT>::processInternalNodes()
1483{
1484 using DstNodeT = typename NanoNode<DstBuildT, LEVEL>::type;
1485 using DstValueT = typename DstNodeT::ValueType;
1486 using DstChildT = typename NanoNode<DstBuildT, LEVEL-1>::type;
1487 static_assert(LEVEL == 1 || LEVEL == 2, "Expected internal node");
1488
1489 const uint64_t nodeCount = mSrcNodeAcc.nodeCount(LEVEL);
1490 if (nodeCount > 0) {// compute and temporarily encode IDs of child nodes
1491 uint64_t childCount = 0;
1492 auto *dstNode = this->template dstNode<DstBuildT,LEVEL>(0);
1493 for (uint64_t i=0; i<nodeCount; ++i) {
1494 dstNode[i].mFlags = childCount;
1495 childCount += mSrcNodeAcc.template node<LEVEL>(static_cast<uint32_t>(i)).getChildMask().countOn();
1496 }
1497 }
1498
1499 util::forEach(0, nodeCount, 4, [&](const util::Range1D& r) {
1500 auto *dstNode = this->template dstNode<DstBuildT,LEVEL>(r.begin());
1501 for (auto i = r.begin(); i != r.end(); ++i, ++dstNode) {
1502 auto &srcNode = mSrcNodeAcc.template node<LEVEL>(i);
1503 uint64_t childID = dstNode->mFlags;
1504 if (DstNodeT::DataType::padding()>0u) {
1505 util::memzero(dstNode, DstNodeT::memUsage());
1506 } else {
1507 dstNode->mFlags = 0;// enable rendering, no bbox, no stats
1508 dstNode->mMinimum = dstNode->mMaximum = typename DstNodeT::ValueType();
1509 dstNode->mAverage = dstNode->mStdDevi = 0;
1510 }
1511 dstNode->mBBox[0] = srcNode.origin(); // copy origin of node
1512 dstNode->mValueMask = srcNode.getValueMask(); // copy value mask
1513 dstNode->mChildMask = srcNode.getChildMask(); // copy child mask
1514 for (auto it = srcNode.cbeginChildAll(); it; ++it) {
1515 SrcValueT value{}; // default initialization
1516 if (it.probeChild(value)) {
1517 DstChildT *dstChild = this->template dstNode<DstBuildT,LEVEL-1>(childID++);// might be Leaf<FpN>
1518 dstNode->setChild(it.pos(), dstChild);
1519 } else {
1520 dstNode->setValue(it.pos(), static_cast<DstValueT>(value));
1521 }
1522 }
1523 }
1524 });
1525} // CreateNanoGrid::processInternalNodes<T>
1526
1527//================================================================================================
1528
1529template <typename SrcGridT>
1530template <typename DstBuildT, int LEVEL>
1531inline typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
1532CreateNanoGrid<SrcGridT>::processInternalNodes()
1533{
1534 using DstNodeT = typename NanoNode<DstBuildT, LEVEL>::type;
1535 using DstChildT = typename NanoNode<DstBuildT, LEVEL-1>::type;
1536 static_assert(LEVEL == 1 || LEVEL == 2, "Expected internal node");
1537 static_assert(DstNodeT::DataType::padding()==0u, "Expected internal nodes to have no padding");
1538
1539 const uint64_t nodeCount = mSrcNodeAcc.nodeCount(LEVEL);
1540 if (nodeCount > 0) {// compute and temporarily encode IDs of child nodes
1541 uint64_t childCount = 0;
1542 auto *dstNode = this->template dstNode<DstBuildT,LEVEL>(0);
1543 for (uint64_t i=0; i<nodeCount; ++i) {
1544 dstNode[i].mFlags = childCount;
1545 childCount += mSrcNodeAcc.template node<LEVEL>(i).getChildMask().countOn();
1546 }
1547 }
1548
1549 util::forEach(0, nodeCount, 4, [&](const util::Range1D& r) {
1550 auto *dstNode = this->template dstNode<DstBuildT,LEVEL>(r.begin());
1551 for (auto i = r.begin(); i != r.end(); ++i, ++dstNode) {
1552 auto &srcNode = mSrcNodeAcc.template node<LEVEL>(i);
1553 uint64_t childID = dstNode->mFlags;
1554 dstNode->mFlags = 0u;
1555 dstNode->mBBox[0] = srcNode.origin(); // copy origin of node
1556 dstNode->mValueMask = srcNode.getValueMask(); // copy value mask
1557 dstNode->mChildMask = srcNode.getChildMask(); // copy child mask
1558 uint64_t n = mIncludeTiles ? mValIdx[LEVEL][i] : 0u;
1559 for (auto it = srcNode.cbeginChildAll(); it; ++it) {
1560 SrcValueT value;
1561 if (it.probeChild(value)) {
1562 DstChildT *dstChild = this->template dstNode<DstBuildT,LEVEL-1>(childID++);// might be Leaf<FpN>
1563 dstNode->setChild(it.pos(), dstChild);
1564 } else {
1565 uint64_t m = 0u;
1566 if (mIncludeTiles && !((BuildTraits<DstBuildT>::is_onindex) && dstNode->mValueMask.isOff(it.pos()))) m = n++;
1567 dstNode->setValue(it.pos(), m);
1568 }
1569 }
1570 if (mIncludeTiles && mIncludeStats) {// stats are always placed after the tile values
1571 dstNode->mMinimum = n++;
1572 dstNode->mMaximum = n++;
1573 dstNode->mAverage = n++;
1574 dstNode->mStdDevi = n++;
1575 } else {// if not tiles or stats set stats to the background offset
1576 dstNode->mMinimum = 0u;
1577 dstNode->mMaximum = 0u;
1578 dstNode->mAverage = 0u;
1579 dstNode->mStdDevi = 0u;
1580 }
1581 }
1582 });
1583} // CreateNanoGrid::processInternalNodes<ValueIndex or ValueOnIndex>
1584
1585//================================================================================================
1586
1587template <typename SrcGridT>
1588template <typename DstBuildT>
1589inline typename util::enable_if<!BuildTraits<DstBuildT>::is_index>::type
1590CreateNanoGrid<SrcGridT>::processRoot()
1591{
1592 using DstRootT = NanoRoot<DstBuildT>;
1593 using DstValueT = typename DstRootT::ValueType;
1594 auto &srcRoot = mSrcNodeAcc.root();
1595 auto *dstRoot = this->template dstRoot<DstBuildT>();
1596 const uint32_t tableSize = srcRoot.getTableSize();
1597 if (DstRootT::DataType::padding()>0) util::memzero(dstRoot, DstRootT::memUsage(tableSize));
1598 dstRoot->mTableSize = tableSize;
1599 dstRoot->mMinimum = dstRoot->mMaximum = dstRoot->mBackground = srcRoot.background();
1600 dstRoot->mBBox = CoordBBox(); // // set to an empty bounding box
1601 if (tableSize==0) return;
1602 auto *dstChild = this->template dstNode<DstBuildT, 2>(0);// fixed size and linear in memory
1603 auto *dstTile = dstRoot->tile(0);// fixed size and linear in memory
1604 for (auto it = srcRoot.cbeginChildAll(); it; ++it, ++dstTile) {
1605 SrcValueT value;
1606 if (it.probeChild(value)) {
1607 dstTile->setChild(it.getCoord(), dstChild++, dstRoot);
1608 } else {
1609 dstTile->setValue(it.getCoord(), it.isValueOn(), static_cast<DstValueT>(value));
1610 }
1611 }
1612} // CreateNanoGrid::processRoot<T>
1613
1614//================================================================================================
1615
1616template <typename SrcGridT>
1617template <typename DstBuildT>
1618inline typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
1619CreateNanoGrid<SrcGridT>::processRoot()
1620{
1621 using DstRootT = NanoRoot<DstBuildT>;
1622 auto &srcRoot = mSrcNodeAcc.root();
1623 auto *dstRoot = this->template dstRoot<DstBuildT>();
1624 const uint32_t tableSize = srcRoot.getTableSize();
1625 if (DstRootT::DataType::padding()>0) util::memzero(dstRoot, DstRootT::memUsage(tableSize));
1626 dstRoot->mTableSize = tableSize;
1627 dstRoot->mBackground = 0u;
1628 uint64_t valueCount = 0u;// the first entry is always the background value
1629 dstRoot->mBBox = CoordBBox(); // set to an empty/invalid bounding box
1630
1631 if (tableSize>0) {
1632 auto *dstChild = this->template dstNode<DstBuildT, 2>(0);// fixed size and linear in memory
1633 auto *dstTile = dstRoot->tile(0);// fixed size and linear in memory
1634 for (auto it = srcRoot.cbeginChildAll(); it; ++it, ++dstTile) {
1635 SrcValueT tmp;
1636 if (it.probeChild(tmp)) {
1637 dstTile->setChild(it.getCoord(), dstChild++, dstRoot);
1638 } else {
1639 dstTile->setValue(it.getCoord(), it.isValueOn(), 0u);
1640 if (mIncludeTiles && !((BuildTraits<DstBuildT>::is_onindex) && !dstTile->state)) dstTile->value = ++valueCount;
1641 }
1642 }
1643 }
1644 if (mIncludeTiles && mIncludeStats) {// stats are always placed after the tile values
1645 dstRoot->mMinimum = ++valueCount;
1646 dstRoot->mMaximum = ++valueCount;
1647 dstRoot->mAverage = ++valueCount;
1648 dstRoot->mStdDevi = ++valueCount;
1649 } else if (dstRoot->padding()==0) {
1650 dstRoot->mMinimum = 0u;
1651 dstRoot->mMaximum = 0u;
1652 dstRoot->mAverage = 0u;
1653 dstRoot->mStdDevi = 0u;
1654 }
1655} // CreateNanoGrid::processRoot<ValueIndex or ValueOnIndex>
1656
1657//================================================================================================
1658
1659template <typename SrcGridT>
1660template <typename DstBuildT>
1661void CreateNanoGrid<SrcGridT>::processTree()
1662{
1663 const uint64_t nodeCount[3] = {mSrcNodeAcc.nodeCount(0), mSrcNodeAcc.nodeCount(1), mSrcNodeAcc.nodeCount(2)};
1664 auto *dstTree = this->template dstTree<DstBuildT>();
1665 dstTree->setRoot( this->template dstRoot<DstBuildT>() );
1666 dstTree->setFirstNode(nodeCount[2] ? this->template dstNode<DstBuildT, 2>(0) : nullptr);
1667 dstTree->setFirstNode(nodeCount[1] ? this->template dstNode<DstBuildT, 1>(0) : nullptr);
1668 dstTree->setFirstNode(nodeCount[0] ? this->template dstNode<DstBuildT, 0>(0) : nullptr);
1669
1670 dstTree->mNodeCount[0] = static_cast<uint32_t>(nodeCount[0]);
1671 dstTree->mNodeCount[1] = static_cast<uint32_t>(nodeCount[1]);
1672 dstTree->mNodeCount[2] = static_cast<uint32_t>(nodeCount[2]);
1673
1674 // Count number of active leaf level tiles
1675 dstTree->mTileCount[0] = util::reduce(util::Range1D(0,nodeCount[1]), uint32_t(0), [&](const util::Range1D &r, uint32_t sum){
1676 for (auto i=r.begin(); i!=r.end(); ++i) sum += mSrcNodeAcc.template node<1>(i).getValueMask().countOn();
1677 return sum;}, std::plus<uint32_t>());
1678
1679 // Count number of active lower internal node tiles
1680 dstTree->mTileCount[1] = util::reduce(util::Range1D(0,nodeCount[2]), uint32_t(0), [&](const util::Range1D &r, uint32_t sum){
1681 for (auto i=r.begin(); i!=r.end(); ++i) sum += mSrcNodeAcc.template node<2>(i).getValueMask().countOn();
1682 return sum;}, std::plus<uint32_t>());
1683
1684 // Count number of active upper internal node tiles
1685 dstTree->mTileCount[2] = 0;
1686 for (auto it = mSrcNodeAcc.root().cbeginValueOn(); it; ++it) dstTree->mTileCount[2] += 1;
1687
1688 // Count number of active voxels
1689 dstTree->mVoxelCount = util::reduce(util::Range1D(0, nodeCount[0]), uint64_t(0), [&](const util::Range1D &r, uint64_t sum){
1690 for (auto i=r.begin(); i!=r.end(); ++i) sum += mSrcNodeAcc.template node<0>(i).getValueMask().countOn();
1691 return sum;}, std::plus<uint64_t>());
1692
1693 dstTree->mVoxelCount += uint64_t(dstTree->mTileCount[0]) << 9;// = 3 * 3
1694 dstTree->mVoxelCount += uint64_t(dstTree->mTileCount[1]) << 21;// = 3 * (3+4)
1695 dstTree->mVoxelCount += uint64_t(dstTree->mTileCount[2]) << 36;// = 3 * (3+4+5)
1696
1697} // CreateNanoGrid::processTree
1698
1699//================================================================================================
1700
1701template <typename SrcGridT>
1702template <typename DstBuildT>
1703void CreateNanoGrid<SrcGridT>::processGrid()
1704{
1705 auto* dstGrid = this->template dstGrid<DstBuildT>();
1706 dstGrid->init({GridFlags::IsBreadthFirst}, mOffset.size, mSrcNodeAcc.map(),
1707 toGridType<DstBuildT>(), toGridClass<DstBuildT>(mSrcNodeAcc.gridClass()));
1708 dstGrid->mBlindMetadataCount = static_cast<uint32_t>(mBlindMetaData.size());
1709 dstGrid->mData1 = this->valueCount();
1710
1711 util::memzero(dstGrid->mGridName, GridData::MaxNameSize);// initialize mGridName to zero
1712 strncpy(dstGrid->mGridName, mSrcNodeAcc.getName().c_str(), GridData::MaxNameSize-1);
1713 if (mSrcNodeAcc.hasLongGridName()) dstGrid->setLongGridNameOn();// grid name is long so store it as blind data
1714
1715 // Partially process blind meta data - they will be complete in postProcess
1716 if (mBlindMetaData.size()>0) {
1717 auto *metaData = this->dstMeta(0);
1718 dstGrid->mBlindMetadataOffset = util::PtrDiff(metaData, dstGrid);
1719 dstGrid->mBlindMetadataCount = static_cast<uint32_t>(mBlindMetaData.size());
1720 char *blindData = util::PtrAdd<char>(mBufferPtr, mOffset.blind);
1721 for (const auto &b : mBlindMetaData) {
1722 *metaData = *b.metaData;
1723 metaData->setBlindData(blindData);// sets metaData.mOffset
1724 if (metaData->mDataClass == GridBlindDataClass::GridName) strcpy(blindData, mSrcNodeAcc.getName().c_str());
1725 ++metaData;
1726 blindData += b.memUsage();
1727 }
1728 mBlindMetaData.clear();
1729 }
1730} // CreateNanoGrid::processGrid
1731
1732//================================================================================================
1733
1734template <typename SrcGridT>
1735template <typename DstBuildT>
1736inline typename util::disable_if<BuildTraits<DstBuildT>::is_index>::type
1737CreateNanoGrid<SrcGridT>::postProcess()
1738{
1739 if constexpr(util::is_same<FpN, DstBuildT>::value) mCodec.reset();
1740 auto *dstGrid = this->template dstGrid<DstBuildT>();
1741 updateGridStats(dstGrid, mStats);
1742#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
1743 auto *metaData = this->dstMeta(0);
1744 if constexpr(util::is_same<openvdb::tools::PointIndexGrid, SrcGridT>::value ||
1745 util::is_same<openvdb::points::PointDataGrid, SrcGridT>::value) {
1746 static_assert(util::is_same<DstBuildT, uint32_t>::value, "expected DstBuildT==uint32_t");
1747 auto *dstData0 = this->template dstNode<DstBuildT,0>(0)->data();
1748 dstData0->mMinimum = 0; // start of prefix sum
1749 dstData0->mMaximum = dstData0->mValues[511u];
1750 for (uint64_t i=1, n=mSrcNodeAcc.nodeCount(0); i<n; ++i) {
1751 auto *dstData1 = dstData0 + 1;
1752 dstData1->mMinimum = dstData0->mMinimum + dstData0->mMaximum;
1753 dstData1->mMaximum = dstData1->mValues[511u];
1754 dstData0 = dstData1;
1755 }
1756 for (size_t i = 0, n = dstGrid->blindDataCount(); i < n; ++i, ++metaData) {
1757 if constexpr(util::is_same<openvdb::tools::PointIndexGrid, SrcGridT>::value) {
1758 if (metaData->mDataClass != GridBlindDataClass::IndexArray) continue;
1759 if (metaData->mDataType == GridType::UInt32) {
1760 uint32_t *blindData = const_cast<uint32_t*>(metaData->template getBlindData<uint32_t>());
1761 util::forEach(0, mSrcNodeAcc.nodeCount(0), 16, [&](const auto& r) {
1762 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1763 for (auto j = r.begin(); j != r.end(); ++j, ++dstLeaf) {
1764 uint32_t* p = blindData + dstLeaf->mMinimum;
1765 for (uint32_t idx : mSrcNodeAcc.template node<0>(j).indices()) *p++ = idx;
1766 }
1767 });
1768 }
1769 } else {// if constexpr(util::is_same<openvdb::points::PointDataGrid, SrcGridT>::value)
1770 if (metaData->mDataClass != GridBlindDataClass::AttributeArray) continue;
1771 if (auto *blindData = dstGrid->template getBlindData<float>(i)) {
1772 this->template copyPointAttribute<DstBuildT>(i, blindData);
1773 } else if (auto *blindData = dstGrid->template getBlindData<nanovdb::Vec3f>(i)) {
1774 this->template copyPointAttribute<DstBuildT>(i, reinterpret_cast<openvdb::Vec3f*>(blindData));
1775 } else if (auto *blindData = dstGrid->template getBlindData<int32_t>(i)) {
1776 this->template copyPointAttribute<DstBuildT>(i, blindData);
1777 } else if (auto *blindData = dstGrid->template getBlindData<int64_t>(i)) {
1778 this->template copyPointAttribute<DstBuildT>(i, blindData);
1779 } else {
1780 char str[16];
1781 std::cerr << "unsupported point attribute \"" << toStr(str, metaData->mDataType) << "\"\n";
1782 }
1783 }// if
1784 }// loop
1785 } else { // if
1786 (void)metaData;
1787 }
1788#endif
1789 updateChecksum(dstGrid, mChecksum);
1790}// CreateNanoGrid::postProcess<T>
1791
1792//================================================================================================
1793
1794template <typename SrcGridT>
1795template <typename DstBuildT>
1796inline typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
1797CreateNanoGrid<SrcGridT>::postProcess(uint32_t channels)
1798{
1799 char str[16];
1800 const std::string typeName = toStr(str, toGridType<SrcValueT>());
1801 const uint64_t valueCount = this->valueCount();
1802 auto *dstGrid = this->template dstGrid<DstBuildT>();
1803 for (uint32_t i=0; i<channels; ++i) {
1804 const std::string name = "channel_"+std::to_string(i);
1805 int j = dstGrid->findBlindData(name.c_str());
1806 if (j<0) throw std::runtime_error("CreateNanoGrid::postProcess: missing " + name);
1807 auto *metaData = this->dstMeta(j);// partially set in processGrid
1808 metaData->mDataClass = GridBlindDataClass::ChannelArray;
1809 metaData->mDataType = toGridType<SrcValueT>();
1810 if (metaData->mSemantic == GridBlindDataSemantic::Unknown) {// try to derive it from the source grid
1811 metaData->mSemantic = toSemantic( mSrcNodeAcc.gridClass());
1812 }
1813 SrcValueT *blindData = const_cast<SrcValueT*>(metaData->template getBlindData<SrcValueT>());
1814 if (i>0) {// concurrent copy from previous channel
1815 util::forEach(0,valueCount,1024,[&](const util::Range1D &r){
1816 SrcValueT *dst=blindData+r.begin(), *end=dst+r.size(), *src=dst-valueCount;
1817 while(dst!=end) *dst++ = *src++;
1818 });
1819 } else {
1820 this->template copyValues<DstBuildT>(blindData);
1821 }
1822 }// loop over channels
1823 updateGridStats(this->template dstGrid<DstBuildT>(), std::min(StatsMode::BBox, mStats));
1824 updateChecksum(dstGrid, mChecksum);
1825}// CreateNanoGrid::postProcess<ValueIndex or ValueOnIndex>
1826
1827//================================================================================================
1828
1829template <typename SrcGridT>
1830template <typename DstBuildT>
1831typename util::enable_if<BuildTraits<DstBuildT>::is_index>::type
1833{// copy values from the source grid into the provided buffer
1834 assert(mBufferPtr && buffer);
1835 using StatsT = typename FloatTraits<SrcValueT>::FloatType;
1836
1837 if (this->valueCount()==0) this->template countValues<DstBuildT>();
1838
1839 auto copyNodeValues = [&](const auto &node, SrcValueT *v) {
1841 for (auto it = node.cbeginValueOn(); it; ++it) *v++ = *it;
1842 } else {
1843 for (auto it = node.cbeginValueAll(); it; ++it) *v++ = *it;
1844 }
1845 if (mIncludeStats) {
1846 if constexpr(SrcNodeAccT::IS_NANOVDB) {// resolved at compile time
1847 *v++ = node.minimum();
1848 *v++ = node.maximum();
1850 *v++ = node.average();
1851 *v++ = node.stdDeviation();
1852 } else {// eg when SrcValueT=Vec3f and StatsT=float
1853 *v++ = SrcValueT(node.average());
1854 *v++ = SrcValueT(node.stdDeviation());
1855 }
1856 } else {// openvdb and nanovdb::tools::build::Grid have no stats
1857 *v++ = buffer[0];// background
1858 *v++ = buffer[0];// background
1859 *v++ = buffer[0];// background
1860 *v++ = buffer[0];// background
1861 }
1862 }
1863 };// copyNodeValues
1864
1865 const SrcRootT &root = mSrcNodeAcc.root();
1866 buffer[0] = root.background();// Value array always starts with the background value
1867 if (mIncludeTiles) {
1868 copyNodeValues(root, buffer + 1u);
1869 util::forEach(0, mSrcNodeAcc.nodeCount(2), 1, [&](const util::Range1D& r) {
1870 for (auto i = r.begin(); i!=r.end(); ++i) {
1871 copyNodeValues(mSrcNodeAcc.template node<2>(i), buffer + mValIdx[2][i]);
1872 }
1873 });
1874 util::forEach(0, mSrcNodeAcc.nodeCount(1), 1, [&](const util::Range1D& r) {
1875 for (auto i = r.begin(); i!=r.end(); ++i) {
1876 copyNodeValues(mSrcNodeAcc.template node<1>(i), buffer + mValIdx[1][i]);
1877 }
1878 });
1879 }
1880 util::forEach(0, mSrcNodeAcc.nodeCount(0), 4, [&](const util::Range1D& r) {
1881 for (auto i = r.begin(); i!=r.end(); ++i) {
1882 copyNodeValues(mSrcNodeAcc.template node<0>(i), buffer + mValIdx[0][i]);
1883 }
1884 });
1885}// CreateNanoGrid::copyValues<ValueIndex or ValueOnIndex>
1886
1887
1888//================================================================================================
1889
1890#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
1891
1892template <typename SrcGridT>
1893template<typename T>
1894typename util::disable_if<util::is_same<T, openvdb::tools::PointIndexGrid>::value ||
1895 util::is_same<T, openvdb::points::PointDataGrid>::value, uint64_t>::type
1896CreateNanoGrid<SrcGridT>::countPoints() const
1897{
1898 static_assert(util::is_same<T, SrcGridT>::value, "expected default template parameter");
1899 return 0u;
1900}// CreateNanoGrid::countPoints<T>
1901
1902template <typename SrcGridT>
1903template<typename T>
1904typename util::enable_if<util::is_same<T, openvdb::tools::PointIndexGrid>::value ||
1905 util::is_same<T, openvdb::points::PointDataGrid>::value, uint64_t>::type
1906CreateNanoGrid<SrcGridT>::countPoints() const
1907{
1908 static_assert(util::is_same<T, SrcGridT>::value, "expected default template parameter");
1909 return util::reduce(0, mSrcNodeAcc.nodeCount(0), 8, uint64_t(0), [&](auto &r, uint64_t sum) {
1910 for (auto i=r.begin(); i!=r.end(); ++i) sum += mSrcNodeAcc.template node<0>(i).getLastValue();
1911 return sum;}, std::plus<uint64_t>());
1912}// CreateNanoGrid::countPoints<PointIndexGrid or PointDataGrid>
1913
1914template <typename SrcGridT>
1915template<typename DstBuildT, typename AttT, typename CodecT, typename T>
1916typename util::enable_if<util::is_same<openvdb::points::PointDataGrid, T>::value>::type
1917CreateNanoGrid<SrcGridT>::copyPointAttribute(size_t attIdx, AttT *attPtr)
1918{
1919 static_assert(util::is_same<SrcGridT, T>::value, "Expected default parameter");
1920 using HandleT = openvdb::points::AttributeHandle<AttT, CodecT>;
1921 util::forEach(0, mSrcNodeAcc.nodeCount(0), 16, [&](const auto& r) {
1922 auto *dstLeaf = this->template dstNode<DstBuildT,0>(r.begin());
1923 for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
1924 auto& srcLeaf = mSrcNodeAcc.template node<0>(i);
1925 HandleT handle(srcLeaf.constAttributeArray(attIdx));
1926 AttT *p = attPtr + dstLeaf->mMinimum;
1927 for (auto iter = srcLeaf.beginIndexOn(); iter; ++iter) *p++ = handle.get(*iter);
1928 }
1929 });
1930}// CreateNanoGrid::copyPointAttribute
1931
1932#endif
1933
1934//================================================================================================
1935
1936template<typename SrcGridT, typename DstBuildT, typename BufferT>
1937typename util::disable_if<BuildTraits<DstBuildT>::is_index || BuildTraits<DstBuildT>::is_Fp, GridHandle<BufferT>>::type
1938createNanoGrid(const SrcGridT &srcGrid,
1939 StatsMode sMode,
1940 CheckMode cMode,
1941 int verbose,
1942 const BufferT &buffer)
1943{
1944 CreateNanoGrid<SrcGridT> converter(srcGrid);
1945 converter.setStats(sMode);
1946 converter.setChecksum(cMode);
1947 converter.setVerbose(verbose);
1948 return converter.template getHandle<DstBuildT, BufferT>(buffer);
1949}// createNanoGrid<T>
1950
1951//================================================================================================
1952
1953template<typename SrcGridT, typename DstBuildT, typename BufferT>
1955createNanoGrid(const SrcGridT &srcGrid,
1956 uint32_t channels,
1957 bool includeStats,
1958 bool includeTiles,
1959 int verbose,
1960 const BufferT &buffer)
1961{
1962 CreateNanoGrid<SrcGridT> converter(srcGrid);
1963 converter.setVerbose(verbose);
1964 return converter.template getHandle<DstBuildT, BufferT>(channels, includeStats, includeTiles, buffer);
1965}
1966
1967//================================================================================================
1968
1969template<typename SrcGridT, typename DstBuildT, typename OracleT, typename BufferT>
1971createNanoGrid(const SrcGridT &srcGrid,
1972 StatsMode sMode,
1973 CheckMode cMode,
1974 bool ditherOn,
1975 int verbose,
1976 const OracleT &oracle,
1977 const BufferT &buffer)
1978{
1979 CreateNanoGrid<SrcGridT> converter(srcGrid);
1980 converter.setStats(sMode);
1981 converter.setChecksum(cMode);
1982 converter.enableDithering(ditherOn);
1983 converter.setVerbose(verbose);
1984 return converter.template getHandle<DstBuildT, OracleT, BufferT>(oracle, buffer);
1985}// createNanoGrid<FpN>
1986
1987//================================================================================================
1988
1989template<typename SrcGridT, typename DstBuildT, typename BufferT>
1991createNanoGrid(const SrcGridT &srcGrid,
1992 StatsMode sMode,
1993 CheckMode cMode,
1994 bool ditherOn,
1995 int verbose,
1996 const BufferT &buffer)
1997{
1998 CreateNanoGrid<SrcGridT> converter(srcGrid);
1999 converter.setStats(sMode);
2000 converter.setChecksum(cMode);
2001 converter.enableDithering(ditherOn);
2002 converter.setVerbose(verbose);
2003 return converter.template getHandle<DstBuildT, BufferT>(buffer);
2004}// createNanoGrid<Fp4,8,16>
2005
2006//================================================================================================
2007
2008#if defined(NANOVDB_USE_OPENVDB) && !defined(__CUDACC__)
2009template<typename BufferT>
2011openToNanoVDB(const openvdb::GridBase::Ptr& base,
2012 StatsMode sMode,
2013 CheckMode cMode,
2014 int verbose)
2015{
2016 // We need to define these types because they are not defined in OpenVDB
2017 using openvdb_Vec4fTree = typename openvdb::tree::Tree4<openvdb::Vec4f, 5, 4, 3>::Type;
2018 using openvdb_Vec4dTree = typename openvdb::tree::Tree4<openvdb::Vec4d, 5, 4, 3>::Type;
2019 using openvdb_Vec4fGrid = openvdb::Grid<openvdb_Vec4fTree>;
2020 using openvdb_Vec4dGrid = openvdb::Grid<openvdb_Vec4dTree>;
2021 using openvdb_UInt32Grid = openvdb::Grid<openvdb::UInt32Tree>;
2022
2023 if (auto grid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
2024 return createNanoGrid<openvdb::FloatGrid, float, BufferT>(*grid, sMode, cMode, verbose);
2025 } else if (auto grid = openvdb::GridBase::grid<openvdb::DoubleGrid>(base)) {
2026 return createNanoGrid<openvdb::DoubleGrid, double, BufferT>(*grid, sMode, cMode, verbose);
2027 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int32Grid>(base)) {
2028 return createNanoGrid<openvdb::Int32Grid, int32_t,BufferT>(*grid, sMode, cMode, verbose);
2029 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int64Grid>(base)) {
2030 return createNanoGrid<openvdb::Int64Grid, int64_t, BufferT>(*grid, sMode, cMode, verbose);
2031 } else if (auto grid = openvdb::GridBase::grid<openvdb_UInt32Grid>(base)) {
2032 return createNanoGrid<openvdb_UInt32Grid, uint32_t, BufferT>(*grid, sMode, cMode, verbose);
2033 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3fGrid>(base)) {
2034 return createNanoGrid<openvdb::Vec3fGrid, nanovdb::Vec3f, BufferT>(*grid, sMode, cMode, verbose);
2035 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3dGrid>(base)) {
2036 return createNanoGrid<openvdb::Vec3dGrid, nanovdb::Vec3d, BufferT>(*grid, sMode, cMode, verbose);
2037 } else if (auto grid = openvdb::GridBase::grid<openvdb::tools::PointIndexGrid>(base)) {
2038 return createNanoGrid<openvdb::tools::PointIndexGrid, uint32_t, BufferT>(*grid, sMode, cMode, verbose);
2039 } else if (auto grid = openvdb::GridBase::grid<openvdb::points::PointDataGrid>(base)) {
2040 return createNanoGrid<openvdb::points::PointDataGrid, uint32_t, BufferT>(*grid, sMode, cMode, verbose);
2041 } else if (auto grid = openvdb::GridBase::grid<openvdb::MaskGrid>(base)) {
2042 return createNanoGrid<openvdb::MaskGrid, nanovdb::ValueMask, BufferT>(*grid, sMode, cMode, verbose);
2043 } else if (auto grid = openvdb::GridBase::grid<openvdb::BoolGrid>(base)) {
2044 return createNanoGrid<openvdb::BoolGrid, bool, BufferT>(*grid, sMode, cMode, verbose);
2045 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4fGrid>(base)) {
2046 return createNanoGrid<openvdb_Vec4fGrid, nanovdb::Vec4f, BufferT>(*grid, sMode, cMode, verbose);
2047 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4dGrid>(base)) {
2048 return createNanoGrid<openvdb_Vec4dGrid, nanovdb::Vec4d, BufferT>(*grid, sMode, cMode, verbose);
2049 } else {
2050 OPENVDB_THROW(openvdb::RuntimeError, "Unrecognized OpenVDB grid type");
2051 }
2052}// openToNanoVDB
2053
2054template<typename DstBuildT, typename BufferT>
2055typename util::enable_if<BuildTraits<DstBuildT>::is_index, GridHandle<BufferT>>::type
2056openToIndexVDB(const openvdb::GridBase::Ptr& base,
2057 uint32_t channels,
2058 bool includeStats,
2059 bool includeTiles,
2060 int verbose)
2061{
2062 // We need to define these types because they are not defined in OpenVDB
2063 using openvdb_Vec4fTree = typename openvdb::tree::Tree4<openvdb::Vec4f, 5, 4, 3>::Type;
2064 using openvdb_Vec4dTree = typename openvdb::tree::Tree4<openvdb::Vec4d, 5, 4, 3>::Type;
2065 using openvdb_Vec4fGrid = openvdb::Grid<openvdb_Vec4fTree>;
2066 using openvdb_Vec4dGrid = openvdb::Grid<openvdb_Vec4dTree>;
2067 using openvdb_UInt32Grid = openvdb::Grid<openvdb::UInt32Tree>;
2068
2069 if (auto grid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
2070 return createNanoGrid<openvdb::FloatGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2071 } else if (auto grid = openvdb::GridBase::grid<openvdb::DoubleGrid>(base)) {
2072 return createNanoGrid<openvdb::DoubleGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2073 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int32Grid>(base)) {
2074 return createNanoGrid<openvdb::Int32Grid, DstBuildT,BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2075 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int64Grid>(base)) {
2076 return createNanoGrid<openvdb::Int64Grid, DstBuildT, BufferT>(*grid, includeStats, includeTiles, verbose);
2077 } else if (auto grid = openvdb::GridBase::grid<openvdb_UInt32Grid>(base)) {
2078 return createNanoGrid<openvdb_UInt32Grid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2079 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3fGrid>(base)) {
2080 return createNanoGrid<openvdb::Vec3fGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2081 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3dGrid>(base)) {
2082 return createNanoGrid<openvdb::Vec3dGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2083 } else if (auto grid = openvdb::GridBase::grid<openvdb::tools::PointIndexGrid>(base)) {
2084 return createNanoGrid<openvdb::tools::PointIndexGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2085 } else if (auto grid = openvdb::GridBase::grid<openvdb::points::PointDataGrid>(base)) {
2086 return createNanoGrid<openvdb::points::PointDataGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2087 } else if (auto grid = openvdb::GridBase::grid<openvdb::MaskGrid>(base)) {
2088 return createNanoGrid<openvdb::MaskGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2089 } else if (auto grid = openvdb::GridBase::grid<openvdb::BoolGrid>(base)) {
2090 return createNanoGrid<openvdb::BoolGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2091 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4fGrid>(base)) {
2092 return createNanoGrid<openvdb_Vec4fGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2093 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4dGrid>(base)) {
2094 return createNanoGrid<openvdb_Vec4dGrid, DstBuildT, BufferT>(*grid, channels, includeStats, includeTiles, verbose);
2095 } else {
2096 OPENVDB_THROW(openvdb::RuntimeError, "Unrecognized OpenVDB grid type");
2097 }
2098}// openToIndexVDB
2099#endif
2100
2101}// namespace tools ===============================================================================
2102
2103} // namespace nanovdb
2104
2105inline std::ostream& operator<<(std::ostream& os, const nanovdb::tools::AbsDiff& diff)
2106{
2107 os << "Absolute tolerance: " << diff.getTolerance();
2108 return os;
2109}
2110
2111inline std::ostream& operator<<(std::ostream& os, const nanovdb::tools::RelDiff& diff)
2112{
2113 os << "Relative tolerance: " << diff.getTolerance();
2114 return os;
2115}
2116
2117#endif // NANOVDB_TOOLS_CREATENANOGRID_H_HAS_BEEN_INCLUDED
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
Defines GridHandle, which manages a memory buffer containing one or more NanoVDB grids: host-resident...
A unified wrapper for tbb::parallel_invoke and a naive std::thread analog.
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Multi-threaded implementations of inclusive prefix sum.
Custom Range class that is compatible with the tbb::blocked_range classes.
A unified wrapper for tbb::parallel_reduce and a naive std::future analog.
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition GridHandle.h:109
const NanoGrid< ValueT > * grid(uint32_t n=0) const
Returns a const host pointer to the n'th NanoVDB grid encoded in this GridHandle.
Definition GridHandle.h:546
typename NanoTree< BuildT >::ValueType ValueType
Definition NanoVDB.h:2191
NanoTree< BuildT > TreeType
Definition NanoVDB.h:2184
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition HostBuffer.h:181
void reset()
Clears all existing buffers that are registered against the memory pool and resets the pool so it can...
Definition HostBuffer.h:636
static size_t memUsage()
Definition NanoVDB.h:3545
LeafData< BuildT, Coord, Mask, Log2Dim > DataType
Definition NanoVDB.h:4337
uint64_t memUsage() const
Definition NanoVDB.h:4543
NodeManagerHandle manages the memory of a NodeManager.
Definition NodeManager.h:55
NodeManager allows for sequential access to nodes.
Definition NodeManager.h:203
uint64_t memUsage() const
Definition NanoVDB.h:3114
static uint64_t memUsage()
Definition NanoVDB.h:2515
Dummy type for a voxel whose value equals its binary active state.
Definition NanoVDB.h:183
A simple vector class with three components, similar to openvdb::math::Vec3.
Definition Math.h:1362
A simple vector class with four components, similar to openvdb::math::Vec4.
Definition Math.h:1560
Compression oracle based on absolute difference.
Definition CreateNanoGrid.h:251
bool operator()(float exact, float approx) const
Return true if the approximate value is within the accepted absolute error bounds of the exact value.
Definition CreateNanoGrid.h:275
float getTolerance() const
Definition CreateNanoGrid.h:270
AbsDiff(float tolerance=-1.0f)
Definition CreateNanoGrid.h:255
void init(nanovdb::GridClass gClass, float background)
Definition CreateNanoGrid.h:259
AbsDiff(const AbsDiff &)=default
void setTolerance(float tolerance)
Definition CreateNanoGrid.h:269
Creates any nanovdb Grid from any source grid (certain combinations are obviously not allowed)
Definition CreateNanoGrid.h:532
uint64_t addBlindData(const std::string &name, GridBlindDataSemantic dataSemantic, GridBlindDataClass dataClass, GridType dataType, size_t count, size_t size)
Add blind data to the destination grid.
Definition CreateNanoGrid.h:615
typename SrcNodeAccT::BuildType SrcBuildT
Definition CreateNanoGrid.h:536
void setStats(StatsMode mode=StatsMode::Default)
Set the mode used for computing statistics of the destination grid.
Definition CreateNanoGrid.h:562
typename SrcNodeAccT::TreeType SrcTreeT
Definition CreateNanoGrid.h:538
util::disable_if< util::is_same< DstBuildT, FpN >::value||BuildTraits< DstBuildT >::is_index, GridHandle< BufferT > >::type getHandle(const BufferT &buffer=BufferT())
Converts the source grid into a nanovdb grid with the specified destination build type.
Definition CreateNanoGrid.h:892
typename SrcNodeAccT::RootType SrcRootT
Definition CreateNanoGrid.h:539
void enableDithering(bool on=true)
Enable or disable dithering, i.e. randomization of the quantization error.
Definition CreateNanoGrid.h:558
typename NodeTrait< SrcRootT, LEVEL >::type SrcNodeT
Definition CreateNanoGrid.h:541
void setVerbose(int mode=1)
Set the level of verbosity.
Definition CreateNanoGrid.h:553
CreateNanoGrid(const SrcGridT &srcGrid)
Constructor from a source grid.
Definition CreateNanoGrid.h:791
util::enable_if< BuildTraits< DstBuildT >::is_index >::type copyValues(SrcValueT *buffer)
Copy values from the source grid into a provided buffer.
Definition CreateNanoGrid.h:1832
void setChecksum(CheckMode mode=CheckMode::Default)
Set the mode used for computing checksums of the destination grid.
Definition CreateNanoGrid.h:566
NodeAccessor< SrcGridT > SrcNodeAccT
Definition CreateNanoGrid.h:535
uint64_t valueCount() const
This method only has affect when getHandle was called with DstBuildT = ValueIndex or ValueOnIndex.
Definition CreateNanoGrid.h:629
typename SrcNodeAccT::ValueType SrcValueT
Definition CreateNanoGrid.h:537
const TreeType & tree() const
Definition CreateNanoGrid.h:360
static constexpr bool IS_NANOVDB
Definition CreateNanoGrid.h:347
uint64_t nodeCount(int level) const
Definition CreateNanoGrid.h:362
const NodeType< LEVEL > & node(uint32_t i) const
Definition CreateNanoGrid.h:364
NodeAccessor(const GridType &grid)
Definition CreateNanoGrid.h:356
NanoGrid< BuildT > GridType
Definition CreateNanoGrid.h:350
static constexpr bool IS_OPENVDB
Definition CreateNanoGrid.h:346
typename NodeTrait< TreeType, LEVEL >::type NodeType
Definition CreateNanoGrid.h:355
typename GridType::ValueType ValueType
Definition CreateNanoGrid.h:351
typename GridType::TreeType TreeType
Definition CreateNanoGrid.h:352
std::string getName() const
Definition CreateNanoGrid.h:365
typename TreeType::RootType RootType
Definition CreateNanoGrid.h:353
const RootType & root() const
Definition CreateNanoGrid.h:361
bool hasLongGridName() const
Definition CreateNanoGrid.h:366
const GridType & grid() const
Definition CreateNanoGrid.h:359
GridClass gridClass() const
Definition CreateNanoGrid.h:368
HostBuffer BufferType
Definition CreateNanoGrid.h:349
BuildT BuildType
Definition CreateNanoGrid.h:348
const nanovdb::Map & map() const
Definition CreateNanoGrid.h:367
The NodeAccessor provides a uniform API for accessing nodes in NanoVDB, OpenVDB and build Grids.
Definition CreateNanoGrid.h:312
const TreeType & tree() const
Definition CreateNanoGrid.h:325
static constexpr bool IS_NANOVDB
Definition CreateNanoGrid.h:315
uint64_t nodeCount(int level) const
Definition CreateNanoGrid.h:327
const NodeType< LEVEL > & node(uint32_t i) const
Definition CreateNanoGrid.h:329
const std::string & getName() const
Definition CreateNanoGrid.h:330
static constexpr bool IS_OPENVDB
Definition CreateNanoGrid.h:314
typename TreeType::RootNodeType RootType
Definition CreateNanoGrid.h:320
typename GridT::BuildType BuildType
Definition CreateNanoGrid.h:316
typename NodeTrait< const TreeType, LEVEL >::type NodeType
Definition CreateNanoGrid.h:322
const RootType & root() const
Definition CreateNanoGrid.h:326
typename GridT::TreeType TreeType
Definition CreateNanoGrid.h:319
typename GridT::ValueType ValueType
Definition CreateNanoGrid.h:317
bool hasLongGridName() const
Definition CreateNanoGrid.h:331
const GridType & grid() const
Definition CreateNanoGrid.h:324
NodeAccessor(const GridT &grid)
Definition CreateNanoGrid.h:323
GridClass gridClass() const
Definition CreateNanoGrid.h:333
GridT GridType
Definition CreateNanoGrid.h:318
const nanovdb::Map & map() const
Definition CreateNanoGrid.h:332
Compression oracle based on relative difference.
Definition CreateNanoGrid.h:285
RelDiff(float tolerance=-1.0f)
Definition CreateNanoGrid.h:289
bool operator()(float exact, float approx) const
Return true if the approximate value is within the accepted relative error bounds of the exact value.
Definition CreateNanoGrid.h:299
RelDiff(const RelDiff &)=default
float getTolerance() const
Definition CreateNanoGrid.h:294
void setTolerance(float tolerance)
Definition CreateNanoGrid.h:293
Definition GridBuilder.h:2055
Container class that associates a tree with a transform and metadata.
Definition Grid.h:571
Definition Exceptions.h:63
Defines look up table to do dithering of 8^3 leaf nodes.
__hostdev__ T Abs(T x)
Definition Math.h:229
__hostdev__ Type Max(Type a, Type b)
Definition Math.h:154
typename openvdb::tree::Tree4< trait::MapToOpenT< T >, 5, 4, 3 >::Type OpenTree
Definition NanoToOpenVDB.h:46
openvdb::Grid< OpenTree< T > > OpenGrid
Definition NanoToOpenVDB.h:49
Definition CreateNanoGrid.h:104
void updateChecksum(GridData *gridData, CheckMode mode)
Updates the checksum of a grid.
Definition GridChecksum.h:71
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition GridStats.h:40
@ Default
Definition GridStats.h:45
util::disable_if< BuildTraits< DstBuildT >::is_index||BuildTraits< DstBuildT >::is_Fp, GridHandle< BufferT > >::type createNanoGrid(const SrcGridT &srcGrid, StatsMode sMode=StatsMode::Default, CheckMode cMode=CheckMode::Default, int verbose=0, const BufferT &buffer=BufferT())
Freestanding function that creates a NanoGrid<T> from any source grid.
Definition CreateNanoGrid.h:1938
void updateGridStats(NanoGrid< BuildT > *grid, StatsMode mode=StatsMode::Default)
Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid.
Definition GridStats.h:735
char * strncpy(char *dst, const char *src, size_t max)
Copies the first num characters of src to dst. If the end of the source C string (which is signaled b...
Definition Util.h:197
static DstT * PtrAdd(void *p, int64_t offset)
Adds a byte offset to a non-const pointer to produce another non-const pointer.
Definition Util.h:524
char * strcpy(char *dst, const char *src)
Copy characters from src to dst.
Definition Util.h:178
int invoke(const Func &taskFunc1, Rest... taskFuncN)
Definition Invoke.h:66
T prefixSum(std::vector< T > &vec, bool threaded=true, OpT op=OpT())
Computes inclusive prefix sum of a vector.
Definition PrefixSum.h:74
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition ForEach.h:42
Range< 1, size_t > Range1D
Definition Range.h:33
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition NanoVDB.h:851
Grid< NanoTree< BuildT > > NanoGrid
Definition NanoVDB.h:4742
GridBlindDataSemantic toSemantic(GridClass gridClass, GridBlindDataSemantic defaultSemantic=GridBlindDataSemantic::Unknown)
Maps from GridClass to GridBlindDataSemantic.
Definition NanoVDB.h:482
GridClass
Classes (superset of OpenVDB) that are currently supported by NanoVDB.
Definition NanoVDB.h:288
@ FogVolume
Definition NanoVDB.h:290
@ Unknown
Definition NanoVDB.h:288
@ PointIndex
Definition NanoVDB.h:292
@ PointData
Definition NanoVDB.h:293
@ Staggered
Definition NanoVDB.h:291
@ LevelSet
Definition NanoVDB.h:289
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:219
@ Float
Definition NanoVDB.h:220
@ Unknown
Definition NanoVDB.h:219
@ Int32
Definition NanoVDB.h:223
@ UInt32
Definition NanoVDB.h:229
@ Vec3f
Definition NanoVDB.h:225
@ Int64
Definition NanoVDB.h:224
CheckMode
List of different modes for computing for a checksum.
Definition NanoVDB.h:1846
@ Default
Definition NanoVDB.h:1850
RootNode< NanoUpper< BuildT > > NanoRoot
Definition NanoVDB.h:4738
Tree< NanoRoot< BuildT > > NanoTree
Definition NanoVDB.h:4740
LeafNode< BuildT, Coord, Mask, 3 > NanoLeaf
Template specializations to the default configuration used in OpenVDB: Root -> 32^3 -> 16^3 -> 8^3.
Definition NanoVDB.h:4732
GridBlindDataClass
Blind-data Classes that are currently supported by NanoVDB.
Definition NanoVDB.h:410
@ IndexArray
Definition NanoVDB.h:411
@ AttributeArray
Definition NanoVDB.h:412
@ GridName
Definition NanoVDB.h:413
char * toStr(char *dst, GridType gridType)
Maps a GridType to a c-string.
Definition NanoVDB.h:253
math::BBox< Coord > CoordBBox
Definition Math.h:2241
GridBlindDataSemantic
Blind-data Semantics that are currently understood by NanoVDB.
Definition NanoVDB.h:418
@ PointPosition
Definition NanoVDB.h:419
@ PointColor
Definition NanoVDB.h:420
@ PointVelocity
Definition NanoVDB.h:423
@ Unknown
Definition NanoVDB.h:418
@ PointNormal
Definition NanoVDB.h:421
@ PointId
Definition NanoVDB.h:424
NodeManagerHandle< BufferT > createNodeManager(const NanoGrid< BuildT > &grid, const BufferT &buffer=BufferT())
brief Construct a NodeManager and return its handle
Definition NodeManager.h:307
uint32_t getGridClass(std::ios_base &)
Return the class (GRID_LEVEL_SET, GRID_UNKNOWN, etc.) of the grid currently being read from or writte...
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition Composite.h:110
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition Composite.h:106
math::Vec3< float > Vec3f
Definition Types.h:55
@ GRID_FOG_VOLUME
Definition Types.h:527
@ GRID_STAGGERED
Definition Types.h:528
@ GRID_LEVEL_SET
Definition Types.h:526
PointIndex< Index32, 0 > PointIndex32
Definition Types.h:159
PointIndex< Index32, 1 > PointDataIndex32
Definition Types.h:162
Definition Exceptions.h:13
This class allows for sequential access to nodes in a NanoVDB tree on both the host and device.
#define NANOVDB_ASSERT(x)
Definition Util.h:53
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
static constexpr bool is_onindex
Definition NanoVDB.h:509
static constexpr bool is_index
Definition NanoVDB.h:508
static constexpr bool is_Fp
Definition NanoVDB.h:514
float FloatType
Definition NanoVDB.h:808
Definition NanoVDB.h:1588
static uint64_t memUsage()
Definition NanoVDB.h:2145
static const int MaxNameSize
Definition NanoVDB.h:1978
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation.
Definition NanoVDB.h:1415
Struct to derive node type from its level in a given grid, tree or root while preserving constness.
Definition NanoVDB.h:1723
size_t memUsage() const
Definition CreateNanoGrid.h:881
const size_t order
Definition CreateNanoGrid.h:883
static GridBlindDataSemantic mapToSemantics(const std::string &name)
Maps from string names of point attributes in openvdb to GridBlindDataSemantic.
Definition CreateNanoGrid.h:865
OrderedBlindMetaData(const std::string &name, const std::string &type, GridBlindDataClass dataClass, size_t i, size_t valueCount, size_t valueSize)
Definition CreateNanoGrid.h:823
OrderedBlindMetaData(const std::string &name, GridBlindDataSemantic dataSemantic, GridBlindDataClass dataClass, GridType dataType, size_t i, size_t valueCount, size_t valueSize)
Definition CreateNanoGrid.h:833
GridBlindMetaData * metaData
Definition CreateNanoGrid.h:882
static GridType mapToType(const std::string &name)
Definition CreateNanoGrid.h:846
~OrderedBlindMetaData()
Definition CreateNanoGrid.h:844
bool operator<(const OrderedBlindMetaData &other) const
Definition CreateNanoGrid.h:845
Trait that maps any type to the corresponding nanovdb type.
Definition CreateNanoGrid.h:379
T type
Definition CreateNanoGrid.h:379
Definition Util.h:364
C++11 implementation of std::enable_if.
Definition Util.h:353
static constexpr bool value
Definition Util.h:344
static constexpr bool value
Definition Util.h:328
std::ostream & operator<<(std::ostream &os, const nanovdb::tools::AbsDiff &diff)
Definition CreateNanoGrid.h:2105
This file defines a minimum set of tree nodes and tools that can be used (instead of OpenVDB) to buil...
Computes a pair of uint32_t checksums, of a Grid, by means of 32 bit Cyclic Redundancy Check (CRC32)
Re-computes min/max/avg/var/bbox information for each node in a pre-existing NanoVDB grid.