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