OpenVDB  9.0.1
OpenToNanoVDB.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5  \file OpenToNanoVDB.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief This class will serialize an OpenVDB grid into a NanoVDB grid.
12 */
13 
14 #include <openvdb/openvdb.h>
16 #include <openvdb/util/CpuTimer.h>
17 
18 #include "GridHandle.h" // manages and streams the raw memory buffer of a NanoVDB grid.
19 #include "GridChecksum.h" // for nanovdb::checksum
20 #include "GridStats.h" // for nanovdb::Extrema
21 #include "GridBuilder.h" // for nanovdb::AbsDiff
22 #include "ForEach.h"// for nanovdb::forEach
23 #include "Reduce.h"// for nanovdb::reduce
24 #include "Invoke.h"// for nanovdb::invoke
25 #include "DitherLUT.h"// for nanovdb::DitherLUT
26 
27 #include <type_traits>
28 
29 #ifndef NANOVDB_OPENTONANOVDB_H_HAS_BEEN_INCLUDED
30 #define NANOVDB_OPENTONANOVDB_H_HAS_BEEN_INCLUDED
31 
32 namespace nanovdb {
33 
34 /// @brief Converts OpenVDB types to NanoVDB types, e.g. openvdb::Vec3f to nanovdb::Vec3f
35 /// Template specializations are defined below.
36 template<typename T>
37 struct OpenToNanoType { using Type = T; };
38 
39 //================================================================================================
40 
41 /// @brief Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHandle
42 template<typename BufferT = HostBuffer>
47  int verbose = 0);
48 
49 //================================================================================================
50 
51 /// @brief Forward declaration of free-standing function that converts a typed OpenVDB Grid into a NanoVDB GridHandle
52 ///
53 /// @details Unlike the function above that takes a base openvdb grid, this method is strongly typed and allows
54 /// for compression, e.g. openToNanoVDB<HostBuffer, openvdb::FloatTree, nanovdb::Fp16>
55 template<typename BufferT = HostBuffer,
56  typename OpenTreeT = openvdb::FloatTree,//dummy default type - it will be resolved from the grid argument
57  typename NanoBuildT = typename OpenToNanoType<typename OpenTreeT::BuildType>::Type>
62  int verbose = 0);
63 
64 //================================================================================================
65 
66 /// @brief Template specialization for openvdb::Coord
67 template<>
69 {
71  static_assert(sizeof(Type) == sizeof(openvdb::Coord), "Mismatching sizeof");
72 };
73 
74 /// @brief Template specialization for openvdb::CoordBBox
75 template<>
77 {
79  static_assert(sizeof(Type) == sizeof(openvdb::CoordBBox), "Mismatching sizeof");
80 };
81 
82 /// @brief Template specialization for openvdb::math::BBox
83 template<typename T>
85 {
87  static_assert(sizeof(Type) == sizeof(openvdb::math::BBox<T>), "Mismatching sizeof");
88 };
89 
90 /// @brief Template specialization for openvdb::math::Vec3
91 template<typename T>
92 struct OpenToNanoType<openvdb::math::Vec3<T>>
93 {
95  static_assert(sizeof(Type) == sizeof(openvdb::math::Vec3<T>), "Mismatching sizeof");
96 };
97 
98 /// @brief Template specialization for openvdb::math::Vec4
99 template<typename T>
100 struct OpenToNanoType<openvdb::math::Vec4<T>>
101 {
103  static_assert(sizeof(Type) == sizeof(openvdb::math::Vec4<T>), "Mismatching sizeof");
104 };
105 
106 /// @brief Template specialization for openvdb::ValueMask
107 template<>
109 {
111 };
112 
113 //================================================================================================
114 
115 /// @brief Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids
116 template <typename BuildT>
118 {
120  using TreeT = typename GridT::TreeType;
121  using RootT = typename TreeT::RootNodeType;
122  using UpperT = typename RootT::ChildNodeType;
123  using LowerT = typename UpperT::ChildNodeType;
124  using LeafT = typename LowerT::ChildNodeType;
125  using ValueT = typename LeafT::ValueType;
126 };
127 
128 /// @brief Template specialization for the PointIndexGrid
129 template <>
131 {
133  using TreeT = typename GridT::TreeType;
134  using RootT = typename TreeT::RootNodeType;
135  using UpperT = typename RootT::ChildNodeType;
136  using LowerT = typename UpperT::ChildNodeType;
137  using LeafT = typename LowerT::ChildNodeType;
138  using ValueT = typename LeafT::ValueType;
139 };
140 
141 /// @brief Template specialization for the PointDataGrid
142 template <>
144 {
146  using TreeT = typename GridT::TreeType;
147  using RootT = typename TreeT::RootNodeType;
148  using UpperT = typename RootT::ChildNodeType;
149  using LowerT = typename UpperT::ChildNodeType;
150  using LeafT = typename LowerT::ChildNodeType;
151  using ValueT = typename LeafT::ValueType;
152 };
153 
154 //================================================================================================
155 
156 /// @brief This class will convert an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
157 ///
158 /// @note Note that this converter assumes a 5,4,3 tree configuration of BOTH the OpenVDB and NanoVDB
159 /// grids. This is a consequence of the fact that the OpenVDB tree is defined in OpenGridType and
160 /// that all NanoVDB trees are by design always 5,4,3!
161 ///
162 /// @details While NanoVDB allows root, internal and leaf nodes to reside anywhere in the memory buffer
163 /// this conversion tool uses the following memory layout:
164 ///
165 ///
166 /// Grid | Tree Root... Node2... Node1... Leaf... BlindMetaData... BlindData...
167 /// where "..." means size may vary and "|" means "no gap"
168 
169 template<typename OpenBuildT,
170  typename NanoBuildT,
171  typename OracleT = AbsDiff,
172  typename BufferT = HostBuffer>
174 {
175  struct BlindMetaData; // forward declerations
176  template <typename NodeT> struct NodePair;
177  struct Codec {float min, max; uint16_t log2, size;};// used for adaptive bit-rate quantization
178 
179  using OpenGridT = typename OpenGridType<OpenBuildT>::GridT;// OpenVDB grid
180  using OpenTreeT = typename OpenGridType<OpenBuildT>::TreeT;// OpenVDB tree
181  using OpenRootT = typename OpenGridType<OpenBuildT>::RootT;// OpenVDB root node
182  using OpenUpperT= typename OpenGridType<OpenBuildT>::UpperT;// OpenVDB upper internal node
183  using OpenLowerT= typename OpenGridType<OpenBuildT>::LowerT;// OpenVDB lower internal node
184  using OpenLeafT = typename OpenGridType<OpenBuildT>::LeafT;// OpenVDB leaf node
185  using OpenValueT= typename OpenGridType<OpenBuildT>::ValueT;
186 
187  using NanoValueT= typename BuildToValueMap<NanoBuildT>::Type;// e.g. maps from Fp16 to float
194 
195  static_assert(sizeof(NanoValueT) == sizeof(OpenValueT), "Mismatching sizeof");
196  static_assert(is_same<NanoValueT, typename OpenToNanoType<OpenValueT>::Type>::value, "Mismatching ValueT");
197 
198  NanoValueT mDelta; // skip node if: node.max < -mDelta || node.min > mDelta
199  uint8_t* mBufferPtr;// pointer to the beginning of the buffer
200  uint64_t mBufferOffsets[9];//grid, tree, root, upper. lower, leafs, meta data, blind data, buffer size
201  int mVerbose;
202  std::set<BlindMetaData> mBlindMetaData; // sorted according to index
203  std::vector<NodePair<OpenLeafT >> mArray0; // leaf nodes
204  std::vector<NodePair<OpenLowerT>> mArray1; // lower internal nodes
205  std::vector<NodePair<OpenUpperT>> mArray2; // upper internal nodes
206  std::unique_ptr<Codec[]> mCodec;// defines a codec per leaf node
207  StatsMode mStats;
208  ChecksumMode mChecksum;
209  bool mDitherOn;
210  OracleT mOracle;// used for adaptive bit-rate quantization
211 
212 public:
213  /// @brief Default c-tor
214  OpenToNanoVDB();
215 
216  /// @brief return a reference to the compression oracle
217  ///
218  /// @note Note, the oracle is only used when NanoBuildT = nanovdb::FpN!
219  OracleT& oracle() { return mOracle; }
220 
221  void setVerbose(int mode = 1) { mVerbose = mode; }
222 
223  void enableDithering(bool on = true) { mDitherOn = on; }
224 
225  void setStats(StatsMode mode = StatsMode::Default) { mStats = mode; }
226 
227  void setChecksum(ChecksumMode mode = ChecksumMode::Default) { mChecksum = mode; }
228 
229  /// @brief Return a shared pointer to a NanoVDB grid handle constructed from the specified OpenVDB grid
230  GridHandle<BufferT> operator()(const OpenGridT& grid,
231  const BufferT& allocator = BufferT());
232 
233  GridHandle<BufferT> operator()(const OpenGridT& grid,
234  StatsMode sMode,
235  ChecksumMode cMode,
236  int verbose,
237  const BufferT& allocator = BufferT());
238 
239 private:
240 
241  /// @brief Allocates and return a handle for the buffer
242  GridHandle<BufferT> initHandle(const OpenGridT& openGrid, const BufferT& allocator);
243 
244  template <typename T>
245  inline typename std::enable_if<!std::is_same<T, FpN>::value>::type
246  compression(const OpenGridT&, uint64_t&) {}// no-op
247 
248  template <typename T>
249  inline typename std::enable_if<std::is_same<T, FpN>::value>::type
250  compression(const OpenGridT& openGrid, uint64_t &offset);
251 
252  /// @brief Private method to process the grid
253  NanoGridT* processGrid(const OpenGridT& openGrid);
254 
255  // @brief Private method to process the tree
256  NanoTreeT* processTree(const OpenTreeT& openTree);
257 
258  /// @brief Private method to process the root node
259  NanoRootT* processRoot(const OpenRootT& openRoot);
260 
261  template <typename T>
262  void processNodes(std::vector<NodePair<T>> &nodes);
263 
264  //////////////////////
265 
266  template<typename T>
267  typename std::enable_if<!std::is_same<typename OpenGridType<openvdb::ValueMask>::LeafT, typename T::OpenNodeT>::value &&
268  !std::is_same<typename OpenGridType<bool>::LeafT, typename T::OpenNodeT>::value &&
273  processLeafs(std::vector<T> &leafs);
274 
275  template<typename T>
279  processLeafs(std::vector<T> &leafs);
280 
281  template<typename T>
283  processLeafs(std::vector<T> &leafs);
284 
285  template<typename T>
286  typename std::enable_if<std::is_same<T, typename OpenGridType<openvdb::ValueMask>::LeafT>::value>::type
287  processLeafs(std::vector<NodePair<T>> &leafs);
288 
289  template<typename T>
290  typename std::enable_if<std::is_same<T, typename OpenGridType<bool>::LeafT>::value>::type
291  processLeafs(std::vector<NodePair<T>> &leafs);
292 
293  //////////////////////
294 
295  /// @brief Private methods to pre-process the bind metadata
296  template <typename T>
299  preProcessMetadata(const T& openGrid);
300 
301  template <typename T>
303  preProcessMetadata(const T& openGrid);
304 
305  template <typename T>
307  preProcessMetadata(const T& openGrid);
308 
309  //////////////////////
310 
311  /// @brief Private methods to process the blind metadata
312  template<typename T>
315  processMetadata(const T& openGrid);
316 
317  template<typename T>
319  processMetadata(const T& openGrid);
320 
321  template<typename T>
323  processMetadata(const T& openGrid);
324 
325  //////////////////////
326 
327  uint64_t pointCount();
328 
329  template<typename AttT, typename CodecT = openvdb::points::UnknownCodec>
330  void copyPointAttribute(size_t attIdx, AttT *attPtr);
331 
332  /// @brief Performs: nanoNode.origin = openNode.origin
333  /// openNode.origin = nanoNode offset
334  template <typename OpenNodeT, typename NanoNodeT>
335  void encode(const OpenNodeT *openNode, NanoNodeT *nanoNode);
336 
337  /// @brief Performs: nanoNode offset = openNode.origin
338  /// openNode.origin = nanoNode.origin
339  /// return nanoNode offset
340  template <typename OpenNodeT>
341  typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type* decode(const OpenNodeT *openNode);
342 
343 }; // OpenToNanoVDB class
344 
345 //================================================================================================
346 
347 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
349  : mVerbose(0)
350  , mStats(StatsMode::Default)
351  , mChecksum(ChecksumMode::Default)
352  , mDitherOn(false)
353  , mOracle()
354 {
355 }
356 
357 //================================================================================================
358 
359 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
360 inline GridHandle<BufferT>
362  operator()(const OpenGridT& openGrid,
363  StatsMode sMode,
364  ChecksumMode cMode,
365  int verbose,
366  const BufferT& allocator)
367 {
368  this->setStats(sMode);
369  this->setChecksum(cMode);
370  this->setVerbose(verbose);
371  return (*this)(openGrid, allocator);
372 }
373 
374 //================================================================================================
375 
376 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
377 inline GridHandle<BufferT>
379  operator()(const OpenGridT& openGrid,
380  const BufferT& allocator)
381 {
382  std::unique_ptr<openvdb::util::CpuTimer> timer(mVerbose > 1 ? new openvdb::util::CpuTimer() : nullptr);
383 
384  if (timer) timer->start("Allocating memory for the NanoVDB buffer");
385  auto handle = this->initHandle(openGrid, allocator);
386  if (timer) timer->stop();
387 
388  if (timer) timer->start("Processing leaf nodes");
389  this->processLeafs(mArray0);
390  if (timer) timer->stop();
391 
392  if (timer) timer->start("Processing lower internal nodes");
393  this->processNodes(mArray1);
394  if (timer) timer->stop();
395 
396  if (timer) timer->start("Processing upper internal nodes");
397  this->processNodes(mArray2);
398  if (timer) timer->stop();
399 
400  if (timer) timer->start("Processing grid, tree and root node");
401  NanoGridT *nanoGrid = this->processGrid(openGrid);
402  if (timer) timer->stop();
403 
404  // Point grids already make use of min/max so they shouldn't be re-computed
407  if (mStats > StatsMode::BBox) mStats = StatsMode::BBox;
408  }
409 
410  if (timer) timer->start("GridStats");
411  gridStats(*nanoGrid, mStats);
412  if (timer) timer->stop();
413 
414  if (timer) timer->start("Checksum");
415  updateChecksum(*nanoGrid, mChecksum);
416  if (timer) timer->stop();
417 
418  return handle; // invokes move constructor
419 } // OpenToNanoVDB::operator()
420 
421 //================================================================================================
422 
423 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
424 template <typename T>
425 inline typename std::enable_if<std::is_same<T, FpN>::value>::type
427  compression(const OpenGridT& openGrid, uint64_t &offset)
428 {
429  static_assert(is_same<float, OpenBuildT>::value, "compression: expected OpenBuildT == float");
430  static_assert(is_same<FpN, NanoBuildT>::value, "compression: expected NanoBuildT == FpN");
431  if (is_same<AbsDiff, OracleT>::value && mOracle.getTolerance() < 0.0f) {// default tolerance for level set and fog volumes
432  if (openGrid.getGridClass() == openvdb::GRID_LEVEL_SET) {
433  mOracle.setTolerance(0.1f * openGrid.voxelSize()[0]);// range of ls: [-3dx; 3dx]
434  } else if (openGrid.getGridClass() == openvdb::GRID_FOG_VOLUME) {
435  mOracle.setTolerance(0.01f);// range of FOG volumes: [0;1]
436  } else {
437  mOracle.setTolerance(0.0f);
438  }
439  }
440 
441  const size_t size = mArray0.size();
442  mCodec.reset(new Codec[size]);
443 
444  DitherLUT lut(mDitherOn);
445  auto kernel = [&](const auto &r) {
446  const OracleT oracle = mOracle;
447  for (auto i=r.begin(); i!=r.end(); ++i) {
448  const float *data = mArray0[i].node->buffer().data();
450  for (int j=0; j<512; ++j) {
451  float v = data[j];
452  if (v<min) min=v;
453  if (v>max) max=v;
454  }
455  mCodec[i].min = min;
456  mCodec[i].max = max;
457  const float range = max - min;
458  uint16_t logBitWidth = 0;// 0,1,2,3,4 => 1,2,4,8,16 bits
459  while (range > 0.0f && logBitWidth < 4u) {
460  const uint32_t mask = (uint32_t(1) << (uint32_t(1) << logBitWidth)) - 1u;
461  const float encode = mask/range;
462  const float decode = range/mask;
463  int j = 0;
464  do {
465  const float exact = data[j];// exact value
466  const uint32_t code = uint32_t(encode*(exact - min) + lut(j));
467  const float approx = code * decode + min;// approximate value
468  j += mOracle(exact, approx) ? 1 : 513;
469  } while(j < 512);
470  if (j == 512) break;
471  ++logBitWidth;
472  }
473  mCodec[i].log2 = logBitWidth;
474  mCodec[i].size = NanoLeafT::DataType::memUsage(1u<<logBitWidth);
475  }
476  };// kernel
477  forEach(0, size, 4, kernel);
478 
479  if (mVerbose) {
480  uint32_t counters[5+1] = {0};
481  ++counters[mCodec[0].log2];
482  for (size_t i=1; i<size; ++i) {
483  ++counters[mCodec[i].log2];
484  mArray0[i].offset = mArray0[i-1].offset + mCodec[i-1].size;
485  }
486  std::cout << "\n" << mOracle << std::endl;
487  std::cout << "Dithering: " << (mDitherOn ? "enabled" : "disabled") << std::endl;
488  float avg = 0.0f;
489  for (uint32_t i=0; i<=5; ++i) {
490  if (uint32_t n = counters[i]) {
491  avg += n * float(1 << i);
492  printf("%2i bits: %6u leaf nodes, i.e. %4.1f%%\n",1<<i, n, 100.0f*n/float(size));
493  }
494  }
495  printf("%4.1f bits per value on average\n", avg/float(size));
496  } else {
497  for (size_t i=1; i<size; ++i) {
498  mArray0[i].offset = mArray0[i-1].offset + mCodec[i-1].size;
499  }
500  }
501  offset = mArray0[size-1].offset + mCodec[size-1].size;
502 }// OpenToNanoVDB::compression
503 
504 //================================================================================================
505 
506 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
508  initHandle(const OpenGridT& openGrid, const BufferT& buffer)
509 {
510  auto &openTree = openGrid.tree();
511  auto &openRoot = openTree.root();
512 
513  mArray0.clear();
514  mArray1.clear();
515  mArray2.clear();
516 #if OPENVDB_ABI_VERSION_NUMBER >= 7
517  std::vector<uint32_t> nodeCount = openTree.nodeCount();
518 #else
519  std::vector<uint32_t> nodeCount(openTree.treeDepth());
520  for (auto it = openTree.cbeginNode(); it; ++it) {
521  ++(nodeCount[it.getDepth()]);
522  }
523 #endif
524  mArray0.reserve(nodeCount[0]);
525  mArray1.reserve(nodeCount[1]);
526  mArray2.reserve(nodeCount[2]);
527 
528  uint64_t offset[3] = {0};
529  for (auto it2 = openRoot.cbeginChildOn(); it2; ++it2) {
530  mArray2.emplace_back(&(*it2), offset[2]);
531  offset[2] += NanoUpperT::memUsage();
532  for (auto it1 = it2->cbeginChildOn(); it1; ++it1) {
533  mArray1.emplace_back(&(*it1), offset[1]);
534  offset[1] += NanoLowerT::memUsage();
535  for (auto it0 = it1->cbeginChildOn(); it0; ++it0) {
536  mArray0.emplace_back(&(*it0), offset[0]);
537  offset[0] += sizeof(NanoLeafT);
538  }
539  }
540  }
541 
542  this->template compression<NanoBuildT>(openGrid, offset[0]);
543 
544  this->preProcessMetadata(openGrid);
545 
546  mBufferOffsets[0] = 0;// grid is always plated at the beginning of the buffer!
547  mBufferOffsets[1] = NanoGridT::memUsage(); // grid ends and tree begins
548  mBufferOffsets[2] = NanoTreeT::memUsage(); // tree ends and root begins
549  mBufferOffsets[3] = NanoRootT::memUsage(openTree.root().getTableSize()); // root ends and upper internal nodes begins
550  mBufferOffsets[4] = offset[2];// upper ends and lower internal nodes
551  mBufferOffsets[5] = offset[1];// lower ends and leaf nodes begins
552  mBufferOffsets[6] = offset[0];// leafs end blind meta data begins
553  mBufferOffsets[7] = GridBlindMetaData::memUsage(mBlindMetaData.size()); // meta ends and blind data begins
554  mBufferOffsets[8] = 0;// blind data
555  for (auto& i : mBlindMetaData) mBufferOffsets[8] += i.size; // blind data
556 
557  // Compute the prefixed sum
558  for (int i = 2; i < 9; ++i) {
559  mBufferOffsets[i] += mBufferOffsets[i - 1];
560  }
561 
562  GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
563  mBufferPtr = handle.data();
564 
565  if (mVerbose) {
566  openvdb::util::printBytes(std::cout, mBufferOffsets[8], "Allocated", " for the NanoVDB grid\n");
567  }
568  return handle;// is converted to r-value so return value is move constructed!
569 }// OpenToNanoVDB::initHandle
570 
571 //================================================================================================
572 
573 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
575  processGrid(const OpenGridT& openGrid)
576 {
577  auto *nanoGrid = reinterpret_cast<NanoGridT*>(mBufferPtr + mBufferOffsets[0]);
578  if (!openGrid.transform().baseMap()->isLinear()) {
579  OPENVDB_THROW(openvdb::ValueError, "processGrid: OpenToNanoVDB only supports grids with affine transforms");
580  }
581  auto affineMap = openGrid.transform().baseMap()->getAffineMap();
582  auto *data = nanoGrid->data();
583  data->mMagic = NANOVDB_MAGIC_NUMBER;
584  data->mChecksum = 0u;
585  data->mVersion = Version();
586  data->mFlags = static_cast<uint32_t>(GridFlags::IsBreadthFirst);
587  data->mGridIndex = 0;
588  data->mGridCount = 1;
589  data->mGridSize = mBufferOffsets[8];
590  data->mWorldBBox = BBox<Vec3R>();
591  data->mBlindMetadataOffset = 0;
592  data->mBlindMetadataCount = 0;
593 
594  const std::string gridName = openGrid.getName();
595  strncpy(data->mGridName, gridName.c_str(), GridData::MaxNameSize-1);
596  data->mGridName[GridData::MaxNameSize-1] ='\0';// null terminate
597  if (gridName.length() >= GridData::MaxNameSize) {
598  data->setLongGridNameOn();// grid name is long so store it as blind data
599  }
600  mDelta = NanoValueT(0); // dummy value
601  switch (openGrid.getGridClass()) { // set grid class
604  OPENVDB_THROW(openvdb::ValueError, "processGrid: Level sets are expected to be floating point types");
605  data->mGridClass = GridClass::LevelSet;
606  mDelta = NanoValueT(openGrid.voxelSize()[0]); // skip a node if max < -mDelta || min > mDelta
607  break;
609  data->mGridClass = GridClass::FogVolume;
610  break;
612  data->mGridClass = GridClass::Staggered;
613  break;
614  default:
615  data->mGridClass = GridClass::Unknown;
616  }
617 
618  // mapping from the OpenVDB build type to the NanoVDB build type and GridType enum
619  if (std::is_same<NanoBuildT, float>::value) { // resolved at compiletime
620  data->mGridType = GridType::Float;
622  data->mGridType = GridType::Double;
624  data->mGridType = GridType::Int16;
626  data->mGridType = GridType::Int32;
628  data->mGridType = GridType::Int64;
630  data->mGridType = GridType::Vec3f;
632  data->mGridType = GridType::UInt32;
634  data->mGridType = GridType::UInt32;
635  data->mGridClass = GridClass::PointIndex;
637  data->mGridType = GridType::UInt32;
638  data->mGridClass = GridClass::PointData;
640  data->mGridType = GridType::Mask;
641  data->mGridClass = GridClass::Topology;
643  data->mGridType = GridType::Boolean;
645  data->mGridType = GridType::Fp4;
647  data->mGridType = GridType::Fp8;
649  data->mGridType = GridType::Fp16;
651  data->mGridType = GridType::FpN;
653  data->mGridType = GridType::Vec4f;
655  data->mGridType = GridType::Vec4d;
656  } else {
657  OPENVDB_THROW(openvdb::ValueError, "processGrid: Unsupported value type");
658  }
659  { // set affine map
660  if (openGrid.hasUniformVoxels()) {
661  data->mVoxelSize = nanovdb::Vec3R(affineMap->voxelSize()[0]);
662  } else {
663  data->mVoxelSize = affineMap->voxelSize();
664  }
665  const auto mat = affineMap->getMat4();
666  // Only support non-tapered at the moment:
667  data->mMap.set(mat, mat.inverse(), 1.0);
668  }
669 
670  this->processTree(openGrid.tree());// calls processRoot
671 
672  if (auto size = mBlindMetaData.size()) {
673  auto *metaData = this->processMetadata(openGrid);
674  data->mBlindMetadataOffset = PtrDiff(metaData, nanoGrid);
675  data->mBlindMetadataCount = static_cast<uint32_t>(size);
676  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
677  metaData->setBlindData(blindData);
678  }
679  return nanoGrid;
680 }// OpenToNanoVDB::processGrid
681 
682 //================================================================================================
683 
684 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
686  processTree(const OpenTreeT& openTree)
687 {
688  auto *nanoTree = reinterpret_cast<NanoTreeT*>(mBufferPtr + mBufferOffsets[1]);
689  auto *data = nanoTree->data();
690 
691  data->setRoot( this->processRoot( openTree.root()) );
692 
693  NanoUpperT *nanoUpper = mArray2.empty() ? nullptr : reinterpret_cast<NanoUpperT*>(mBufferPtr + mBufferOffsets[3]);
694  data->setFirstNode(nanoUpper);
695 
696  NanoLowerT *nanoLower = mArray1.empty() ? nullptr : reinterpret_cast<NanoLowerT*>(mBufferPtr + mBufferOffsets[4]);
697  data->setFirstNode(nanoLower);
698 
699  NanoLeafT *nanoLeaf = mArray0.empty() ? nullptr : reinterpret_cast<NanoLeafT*>(mBufferPtr + mBufferOffsets[5]);
700  data->setFirstNode(nanoLeaf);
701 
702  data->mNodeCount[0] = mArray0.size();
703  data->mNodeCount[1] = mArray1.size();
704  data->mNodeCount[2] = mArray2.size();
705 
706 #if 1// count active tiles and voxels
707 
708  // Count number of active leaf level tiles
709  data->mTileCount[0] = reduce(mArray1, uint32_t(0), [&](auto &r, uint32_t sum){
710  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray1[i].node->getValueMask().countOn();
711  return sum;}, std::plus<uint32_t>());
712 
713  // Count number of active lower internal node tiles
714  data->mTileCount[1] = reduce(mArray2, uint32_t(0), [&](auto &r, uint32_t sum){
715  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray2[i].node->getValueMask().countOn();
716  return sum;}, std::plus<uint32_t>());
717 
718  // Count number of active upper internal node tiles
719  uint32_t sum = 0;
720  for (auto it = openTree.root().cbeginValueOn(); it; ++it) ++sum;
721  data->mTileCount[2] = sum;
722 
723  data->mVoxelCount = reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum){
724  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->valueMask().countOn();
725  return sum;}, std::plus<uint64_t>());
726 
727  data->mVoxelCount += data->mTileCount[0]*NanoLeafT::NUM_VALUES;
728  data->mVoxelCount += data->mTileCount[1]*NanoLowerT::NUM_VALUES;
729  data->mVoxelCount += data->mTileCount[2]*NanoUpperT::NUM_VALUES;
730 
731 #else
732 
733  data->mTileCount[0] = 0;
734  data->mTileCount[1] = 0;
735  data->mTileCount[2] = 0;
736  data->mVoxelCount = 0;
737 
738 #endif
739 
740  return nanoTree;
741 }// OpenToNanoVDB::processTree
742 
743 //================================================================================================
744 
745 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
747  processRoot(const OpenRootT& openRoot)
748 {
749  auto *nanoRoot = reinterpret_cast<NanoRootT*>(mBufferPtr + mBufferOffsets[2]);
750  auto* data = nanoRoot->data();
751  data->mBackground = openRoot.background();
752  data->mTableSize = 0;// incremented below
753  data->mMinimum = data->mMaximum = data->mBackground;
754  data->mBBox.min() = openvdb::Coord::max(); // set to an empty bounding box
755  data->mBBox.max() = openvdb::Coord::min();
756 
757  OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
758  for (auto iter = openRoot.cbeginChildAll(); iter; ++iter) {
759  auto* tile = data->tile(data->mTableSize++);
760  if (const OpenUpperT *openChild = iter.probeChild( value )) {
761  tile->setChild(iter.getCoord(), this->decode(openChild), data);
762  } else {
763  tile->setValue(iter.getCoord(), iter.isValueOn(), value);
764  }
765  }
766  return nanoRoot;
767 } // OpenToNanoVDB::processRoot
768 
769 //================================================================================================
770 
771 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
772 template<typename OpenNodeT>
774  processNodes(std::vector<NodePair<OpenNodeT>>& openNodes)
775 {
776  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
777  static_assert(NanoNodeT::LEVEL == 1 || NanoNodeT::LEVEL == 2, "Expected internal node");
778  auto kernel = [&](const Range1D& r) {
779  uint8_t* ptr = mBufferPtr + mBufferOffsets[5 - NanoNodeT::LEVEL];// 3 or 4
780  OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
781  for (auto i = r.begin(); i != r.end(); ++i) {
782  auto *openNode = openNodes[i].node;
783  auto *nanoNode = PtrAdd<NanoNodeT>(ptr, openNodes[i].offset);
784  auto* data = nanoNode->data();
785  this->encode(openNode, nanoNode);
786  data->mValueMask = openNode->getValueMask(); // copy value mask
787  data->mChildMask = openNode->getChildMask(); // copy child mask
788  for (auto iter = openNode->cbeginChildAll(); iter; ++iter) {
789  if (const auto *openChild = iter.probeChild(value)) {
790  data->setChild(iter.pos(), this->decode(openChild));
791  } else {
792  data->setValue(iter.pos(), value);
793  }
794  }
795  }
796  };
797  forEach(openNodes, 1, kernel);
798 } // OpenToNanoVDB::processNodes
799 
800 //================================================================================================
801 
802 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
803 template<typename T>
804 inline typename std::enable_if<!std::is_same<typename OpenGridType<openvdb::ValueMask>::LeafT, typename T::OpenNodeT>::value &&
805  !std::is_same<typename OpenGridType<bool>::LeafT, typename T::OpenNodeT>::value &&
811 {
812  auto kernel = [&](const auto& r) {
813  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
814  for (auto i = r.begin(); i != r.end(); ++i) {
815  auto *openLeaf = openLeafs[i].node;
816  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
817  auto* data = nanoLeaf->data();
818  this->encode(openLeaf, nanoLeaf);
819  data->mFlags = 0u;
820  data->mValueMask = openLeaf->valueMask(); // copy value mask
821  auto *src = reinterpret_cast<const NanoValueT*>(openLeaf->buffer().data());
822  for (NanoValueT *dst = data->mValues, *end = dst + OpenLeafT::size(); dst != end; dst += 4, src += 4) {
823  dst[0] = src[0]; // copy *all* voxel values in sets of four, i.e. loop-unrolling
824  dst[1] = src[1];
825  dst[2] = src[2];
826  dst[3] = src[3];
827  }
828  }
829  };
830  forEach(openLeafs, 8, kernel);
831 } // OpenToNanoVDB::processLeafs<T>
832 
833 //================================================================================================
834 
835 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
836 template<typename T>
841 {
842  using ArrayT = typename NanoLeafT::DataType::ArrayType;
843  using FloatT = typename std::conditional<NanoLeafT::DataType::bitWidth()>=16, double, float>::type;// 16 compression and higher requires double
844  DitherLUT lut(mDitherOn);
845 
846  auto kernel = [&](const auto& r) {
847  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
848  for (auto i = r.begin(); i != r.end(); ++i) {
849  auto *openLeaf = openLeafs[i].node;
850  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
851  auto* data = nanoLeaf->data();
852  this->encode(openLeaf, nanoLeaf);
853  data->mFlags = 0u;
854  data->mValueMask = openLeaf->valueMask(); // copy value mask
855  auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
856  // compute extrema values
858  for (int i=0; i<512; ++i) {
859  const float v = src[i];
860  if (v < min) min = v;
861  if (v > max) max = v;
862  }
863  data->init(min, max, NanoLeafT::DataType::bitWidth());
864  // perform quantization relative to the values in the curret leaf node
865  const FloatT encode = FloatT((1 << NanoLeafT::DataType::bitWidth()) - 1)/(max-min);
866  auto *code = reinterpret_cast<ArrayT*>(data->mCode);
867  int offset = 0;
868  if (std::is_same<Fp4, NanoBuildT>::value) {// resolved at compile-time
869  for (int i=0; i<128; ++i) {
870  auto tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
871  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
872  tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
873  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
874  }
875  } else {
876  for (int i=0; i<128; ++i) {
877  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
878  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
879  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
880  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
881  }
882  }
883  }
884  };
885  forEach(openLeafs, 8, kernel);
886 } // OpenToNanoVDB::processLeafs<Fp4, Fp8, Fp16>
887 
888 //================================================================================================
889 
890 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
891 template<typename T>
894 {
895  static_assert(is_same<float, OpenBuildT>::value, "Expected OpenBuildT == float");
896 
897  DitherLUT lut(mDitherOn);
898  auto kernel = [&](const auto& r) {
899  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
900  for (auto i = r.begin(); i != r.end(); ++i) {
901  auto *openLeaf = openLeafs[i].node;
902  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
903  auto* data = nanoLeaf->data();
904  this->encode(openLeaf, nanoLeaf);
905  const uint8_t logBitWidth = uint8_t(mCodec[i].log2);
906  data->mFlags = logBitWidth << 5;// pack logBitWidth into 3 MSB of mFlag
907  data->mValueMask = openLeaf->valueMask(); // copy value mask
908  auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
909  const float min = mCodec[i].min, max = mCodec[i].max;
910  data->init(min, max, uint8_t(1) << logBitWidth);
911  // perform quantization relative to the values in the curret leaf node
912  int offset = 0;
913  switch (logBitWidth) {
914  case 0u: {// 1 bit
915  auto *dst = reinterpret_cast<uint8_t*>(data+1);
916  const float encode = 1.0f/(max - min);
917  for (int j=0; j<64; ++j) {
918  uint8_t a = 0;
919  for (int k=0; k<8; ++k) {
920  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << k;
921  }
922  *dst++ = a;
923  }
924  }
925  break;
926  case 1u: {// 2 bits
927  auto *dst = reinterpret_cast<uint8_t*>(data+1);
928  const float encode = 3.0f/(max - min);
929  for (int j=0; j<128; ++j) {
930  auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
931  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 2;
932  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 4;
933  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 6 | a;
934  }
935  }
936  break;
937  case 2u: {// 4 bits
938  auto *dst = reinterpret_cast<uint8_t*>(data+1);
939  const float encode = 15.0f/(max - min);
940  for (int j=0; j<128; ++j) {
941  auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
942  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
943  a = uint8_t(encode * (*src++ - min) + lut(offset++));
944  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
945  }
946  }
947  break;
948  case 3u: {// 8 bits
949  auto *dst = reinterpret_cast<uint8_t*>(data+1);
950  const float encode = 255.0f/(max - min);
951  for (int j=0; j<128; ++j) {
952  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
953  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
954  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
955  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
956  }
957  }
958  break;
959  default: {// 16 bits
960  auto *dst = reinterpret_cast<uint16_t*>(data+1);
961  const double encode = 65535.0/(max - min);// note that double is required!
962  for (int j=0; j<128; ++j) {
963  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
964  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
965  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
966  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
967  }
968  }
969  }// end switch
970  }
971  };// kernel
972  forEach(openLeafs, 8, kernel);
973 } // OpenToNanoVDB::processLeafs<FpN>
974 
975 //================================================================================================
976 
977 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
978 template<typename T>
979 inline typename std::enable_if<std::is_same<T, typename OpenGridType<bool>::LeafT>::value>::type
981 {
982  auto kernel = [&](const auto& r) {
983  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
984  for (auto i = r.begin(); i != r.end(); ++i) {
985  auto *openLeaf = openLeafs[i].node;
986  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
987  auto* data = nanoLeaf->data();
988  this->encode(openLeaf, nanoLeaf);
989  data->mFlags = 0u;
990  data->mValueMask = openLeaf->valueMask(); // copy value mask
991  data->mValues = *reinterpret_cast<const nanovdb::Mask<3>*>(openLeaf->buffer().data()); // copy values
992  }
993  };
994  forEach(openLeafs, 8, kernel);
995 } // OpenToNanoVDB::processLeafs<bool>
996 
997 //================================================================================================
998 
999 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1000 template<typename T>
1001 inline typename std::enable_if<std::is_same<T, typename OpenGridType<openvdb::ValueMask>::LeafT>::value>::type
1003 {
1004  auto kernel = [&](const auto& r) {
1005  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1006  for (auto i = r.begin(); i != r.end(); ++i) {
1007  auto *openLeaf = openLeafs[i].node;
1008  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
1009  auto* data = nanoLeaf->data();
1010  this->encode(openLeaf, nanoLeaf);
1011  data->mFlags = 0u;
1012  data->mValueMask = openLeaf->valueMask(); // copy value mask
1013  }
1014  };
1015  forEach(openLeafs, 8, kernel);
1016 } // OpenToNanoVDB::processLeafs<ValueMask>
1017 
1018 //================================================================================================
1019 
1020 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1022 {
1023  return reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum) {
1024  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->getLastValue();
1025  return sum;}, std::plus<uint64_t>());
1026 }// OpenToNanoVDB::pointCount
1027 
1028 //================================================================================================
1029 
1030 /// @brief Performs: nanoNode.origin = openNode.origin
1031 /// openNode.origin = nanoNode offset
1032 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1033 template <typename OpenNodeT, typename NanoNodeT>
1035 encode(const OpenNodeT *openNode, NanoNodeT *nanoNode)
1036 {
1037  static_assert(is_same<NanoNodeT, typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type>::value, "Type mismatch");
1038  openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1039  nanoNode->data()->setOrigin(ijk);
1040  reinterpret_cast<int64_t&>(ijk) = PtrDiff(nanoNode, mBufferPtr);
1041 }// OpenToNanoVDB::encode
1042 
1043 //================================================================================================
1044 
1045 /// @brief Performs: nanoNode offset = openNode.origin
1046 /// openNode.origin = nanoNode.origin
1047 /// return nanoNode offset
1048 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1049 template <typename OpenNodeT>
1051 decode(const OpenNodeT *openNode)
1052 {
1053  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1054  openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1055  NanoNodeT *nanoNode = PtrAdd<NanoNodeT>(mBufferPtr, reinterpret_cast<int64_t&>(ijk));
1056  Coord tmp = nanoNode->origin();
1057  ijk[0] = tmp[0];
1058  ijk[1] = tmp[1];
1059  ijk[2] = tmp[2];
1060  return nanoNode;
1061 }// OpenToNanoVDB::decode
1062 
1063 //================================================================================================
1064 
1065 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1066 template <typename NodeT>
1067 struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::NodePair {
1068  using OpenNodeT = NodeT;
1069  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1070  NodePair(const NodeT *ptr, size_t n) : node(ptr), offset(n) {}
1071  const NodeT *node;// pointer to OpenVDB node
1072  uint64_t offset;// byte offset to matching NanoVDB node, relative to the first
1073 };// OpenToNanoVDB::NodePair
1074 
1075 //================================================================================================
1076 
1077 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1078 struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::BlindMetaData
1079 {
1080  BlindMetaData(const std::string& n, const std::string& t, size_t i, size_t c, size_t s)
1081  : name(n)
1082  , typeName(t)
1083  , index(i)
1084  , count(c)
1085  , size(AlignUp<NANOVDB_DATA_ALIGNMENT>(c * s))
1086  {
1087  }
1088  const std::string name, typeName;
1089  const size_t index, count, size;
1090  bool operator<(const BlindMetaData& other) const { return index < other.index; } // required by std::set
1091 }; // OpenToNanoVDB::BlindMetaData
1092 
1093 //================================================================================================
1094 
1095 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1096 template <typename T>
1100 {
1101  mBlindMetaData.clear();
1102  const size_t length = openGrid.getName().length();
1103  if (length >= GridData::MaxNameSize) {
1104  mBlindMetaData.emplace("grid name", "uint8_t", 0, 1, length + 1);// Null-terminated byte strings
1105  }
1106 }// OpenToNanoVDB::preProcessMetadata<T>
1107 
1108 //================================================================================================
1109 
1110 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1111 template <typename T>
1114 {
1115  mBlindMetaData.clear();
1116  if (const uint64_t pointCount = this->pointCount()) {
1117  mBlindMetaData.emplace("index", "uint32_t", 0, pointCount, sizeof(uint32_t));
1118  }
1119  const size_t length = openGrid.getName().length();
1120  if (length >= GridData::MaxNameSize) {
1121  mBlindMetaData.emplace("grid name", "uint8_t", mBlindMetaData.size(), 1, length + 1);// Null-terminated byte strings
1122  }
1123 }// OpenToNanoVDB::preProcessMetadata<PointIndexGrid>
1124 
1125 //================================================================================================
1126 
1127 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1128 template <typename T>
1131 {
1132  mBlindMetaData.clear();
1133  size_t counter = 0;
1134  if (const uint64_t pointCount = this->pointCount()) {
1135  auto *openLeaf = openGrid.tree().cbeginLeaf().getLeaf();
1136  const auto& attributeSet = openLeaf->attributeSet();
1137  const auto& descriptor = attributeSet.descriptor();
1138  const auto& nameMap = descriptor.map();
1139  for (auto it = nameMap.begin(); it != nameMap.end(); ++it) {
1140  const size_t index = it->second;
1141  auto& attArray = openLeaf->constAttributeArray(index);
1142  mBlindMetaData.emplace(it->first, descriptor.valueType(index), index, pointCount, attArray.valueTypeSize());
1143  }
1144  counter += nameMap.size();
1145  }
1146  const size_t length = openGrid.getName().length();
1147  if (length >= GridData::MaxNameSize) {
1148  mBlindMetaData.emplace("grid name", "uint8_t", counter, 1, length + 1);// Null-terminated byte strings
1149  }
1150 }// OpenToNanoVDB::preProcessMetadata<PointDataGrid>
1151 
1152 //================================================================================================
1153 
1154 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1155 template<typename T>
1159  processMetadata(const T& openGrid)
1160 {
1161  if (mBlindMetaData.empty()) {
1162  return nullptr;
1163  }
1164  assert(mBlindMetaData.size() == 1);// only the grid name is expected
1165  auto it = mBlindMetaData.cbegin();
1166  assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 0);
1167  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1168  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1169  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1170  // write the blind meta data
1171  metaData->setBlindData(blindData);
1172  metaData->mElementCount = it->count;
1173  metaData->mFlags = 0;
1174  metaData->mSemantic = GridBlindDataSemantic::Unknown;
1175  metaData->mDataClass = GridBlindDataClass::GridName;
1176  metaData->mDataType = GridType::Unknown;
1177  // write the actual bind data
1178  strcpy(blindData, openGrid.getName().c_str());
1179  return metaData;
1180 }// OpenToNanoVDB::processMetadata<T>
1181 
1182 //================================================================================================
1183 
1184 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1185 template<typename T>
1188 {
1189  if (mBlindMetaData.empty()) {
1190  return nullptr;
1191  }
1192  assert(mBlindMetaData.size() == 1 || mBlindMetaData.size() == 2);// point index and maybe long grid name
1193  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1194  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1195 
1196  auto it = mBlindMetaData.cbegin();
1197  const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1198 
1199  using LeafDataT = typename NanoLeafT::DataType;
1200  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1201 
1202  auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1203  data0->mMinimum = 0; // start of prefix sum
1204  data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1205  for (uint32_t i = 1; i < leafCount; ++i) {
1206  auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1207  data1->mMinimum = data0->mMinimum + data0->mMaximum;
1208  data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1209  data0 = data1;
1210  }
1211 
1212  // write blind meta data for the point offsets
1213  assert(it->count == data0->mMinimum + data0->mMaximum);
1214  assert(it->name == "index" && it->typeName == "uint32_t" && it->index == 0);
1215  metaData[0].setBlindData( blindData );
1216  metaData[0].mElementCount = it->count;
1217  metaData[0].mFlags = 0;
1218  metaData[0].mSemantic = GridBlindDataSemantic::Unknown;
1219  metaData[0].mDataClass = GridBlindDataClass::IndexArray;
1220  metaData[0].mDataType = GridType::UInt32;
1221  if (it->name.length() >= GridBlindMetaData::MaxNameSize) {
1222  std::stringstream ss;
1223  ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1225  }
1226  memcpy(metaData[0].mName, it->name.c_str(), it->name.size() + 1);
1227 
1228  // write point offsets as blind data
1229  forEach(mArray0, 16, [&](const auto& r) {
1230  for (auto i = r.begin(); i != r.end(); ++i) {
1231  auto *data = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1232  uint32_t* p = reinterpret_cast<uint32_t*>(blindData) + data->mMinimum;
1233  for (uint32_t idx : mArray0[i].node->indices()) *p++ = idx;
1234  }
1235  });
1236  blindData += it->size;// add point offsets
1237 
1238  // write long grid name if it exists
1239  ++it;
1240  if (it != mBlindMetaData.end()) {
1241  assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 1);
1242  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1243  metaData[1].setBlindData( blindData );
1244  metaData[1].mElementCount = it->count;
1245  metaData[1].mFlags = 0;
1246  metaData[1].mSemantic = GridBlindDataSemantic::Unknown;
1247  metaData[1].mDataClass = GridBlindDataClass::GridName;
1248  metaData[1].mDataType = GridType::Unknown;
1249  strcpy(blindData, openGrid.getName().c_str());
1250  }
1251  return metaData;
1252 }// OpenToNanoVDB::processMetadata<PointIndex32>
1253 
1254 //================================================================================================
1255 
1256 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1257 template<typename T>
1260 {
1261  if (mBlindMetaData.empty()) {
1262  return nullptr;
1263  }
1264 
1265  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1266  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1267 
1268  const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1269 
1270  using LeafDataT = typename NanoLeafT::DataType;
1271  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1272 
1273  auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1274  data0->mMinimum = 0; // start of prefix sum
1275  data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1276  for (uint32_t i = 1; i < leafCount; ++i) {
1277  auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1278  data1->mMinimum = data0->mMinimum + data0->mMaximum;
1279  data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1280  data0 = data1;
1281  }
1282 
1283  size_t i=0;
1284  for (auto it = mBlindMetaData.cbegin(); it != mBlindMetaData.end(); ++it, ++i) {
1285  metaData[i].setBlindData( blindData );
1286  metaData[i].mElementCount = it->count;
1287  metaData[i].mFlags = 0;
1288  if (it->name == "grid name") {
1289  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1290  metaData[i].mDataClass = GridBlindDataClass::GridName;
1291  metaData[i].mDataType = GridType::Unknown;
1292  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1293  strcpy((char*)blindData, openGrid.getName().c_str());
1294  } else {
1295  assert(it->count == data0->mMinimum + data0->mMaximum);
1296  metaData[i].mDataClass = GridBlindDataClass::AttributeArray;
1297  if (it->name.length()>= GridBlindMetaData::MaxNameSize) {
1298  std::stringstream ss;
1299  ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1301  }
1302 
1303  memcpy(metaData[i].mName, it->name.c_str(), it->name.size() + 1);
1304  if (it->typeName == "vec3s") {
1305  metaData[i].mDataType = GridType::Vec3f;
1306  this->copyPointAttribute(it->index, (openvdb::Vec3f*)blindData);
1307  if (it->name == "P") {
1308  metaData[i].mSemantic = GridBlindDataSemantic::PointPosition;
1309  } else if (it->name == "V") {
1310  metaData[i].mSemantic = GridBlindDataSemantic::PointVelocity;
1311  } else if (it->name == "Cd") {
1312  metaData[i].mSemantic = GridBlindDataSemantic::PointColor;
1313  } else if (it->name == "N") {
1314  metaData[i].mSemantic = GridBlindDataSemantic::PointNormal;
1315  } else {
1316  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1317  }
1318  } else if (it->typeName == "int32") {
1319  metaData[i].mDataType = GridType::Int32;
1320  this->copyPointAttribute(it->index, (int32_t*)blindData);
1321  if (it->name == "id") {
1322  metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1323  } else {
1324  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1325  }
1326  } else if (it->typeName == "int64") {
1327  metaData[i].mDataType = GridType::Int64;
1328  this->copyPointAttribute(it->index, (int64_t*)blindData);
1329  if (it->name == "id") {
1330  metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1331  } else {
1332  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1333  }
1334  } else if (it->typeName == "float") {
1335  metaData[i].mDataType = GridType::Float;
1336  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1337  this->copyPointAttribute(it->index, (float*)blindData);
1338  } else {
1339  std::stringstream ss;
1340  ss << "Unsupported point attribute type: \"" << it->typeName << "\"";
1342  }
1343  }
1344  blindData += it->size;
1345  } // loop over bind data
1346  return metaData;
1347 }// OpenToNanoVDB::processMetadata<PointDataIndex32>
1348 
1349 //================================================================================================
1350 
1351 
1352 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1353 template<typename AttT, typename CodecT>
1355  copyPointAttribute(size_t attIdx, AttT *attPtr)
1356 {
1357  static_assert(std::is_same<typename OpenLeafT::ValueType, openvdb::PointDataIndex32>::value, "Expected value to openvdb::PointData");
1358  using LeafDataT = typename NanoLeafT::DataType;
1359  using HandleT = openvdb::points::AttributeHandle<AttT, CodecT>;
1360  forEach(mArray0, 16, [&](const auto& r) {
1361  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1362  for (auto i = r.begin(); i != r.end(); ++i) {
1363  auto* openLeaf = mArray0[i].node;
1364  auto *nanoData = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1365  HandleT handle(openLeaf->constAttributeArray(attIdx));
1366  AttT* p = attPtr + nanoData->mMinimum;
1367  for (auto iter = openLeaf->beginIndexOn(); iter; ++iter) {
1368  *p++ = handle.get(*iter);
1369  }
1370  }
1371  });
1372 }// OpenToNanoVDB::copyPointAttribute
1373 
1374 //================================================================================================
1375 
1376 template<typename BufferT, typename OpenTreeT, typename NanoBuildT>
1379  StatsMode sMode,
1380  ChecksumMode cMode,
1381  int verbose)
1382 {
1383  using OpenBuildT = typename OpenTreeT::BuildType;
1385  return s(grid, sMode, cMode, verbose);
1386 }// openToNanoVDB
1387 
1388 //================================================================================================
1389 
1390 template<typename BufferT>
1393  StatsMode sMode,
1394  ChecksumMode cMode,
1395  int verbose)
1396 {
1397  // We need to define these types because they are not defined in OpenVDB
1398  using openvdb_Vec4fTree = typename openvdb::tree::Tree4<openvdb::Vec4f, 5, 4, 3>::Type;
1399  using openvdb_Vec4dTree = typename openvdb::tree::Tree4<openvdb::Vec4d, 5, 4, 3>::Type;
1400  using openvdb_Vec4fGrid = openvdb::Grid<openvdb_Vec4fTree>;
1401  using openvdb_Vec4dGrid = openvdb::Grid<openvdb_Vec4dTree>;
1402 
1403  if (auto grid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
1404  return openToNanoVDB<BufferT, openvdb::FloatTree>(*grid, sMode, cMode, verbose);
1405  } else if (auto grid = openvdb::GridBase::grid<openvdb::DoubleGrid>(base)) {
1406  return openToNanoVDB<BufferT, openvdb::DoubleTree>(*grid, sMode, cMode, verbose);
1407  } else if (auto grid = openvdb::GridBase::grid<openvdb::Int32Grid>(base)) {
1408  return openToNanoVDB<BufferT, openvdb::Int32Tree>(*grid, sMode, cMode, verbose);
1409  } else if (auto grid = openvdb::GridBase::grid<openvdb::Int64Grid>(base)) {
1410  return openToNanoVDB<BufferT, openvdb::Int64Tree>(*grid, sMode, cMode, verbose);
1411  } else if (auto grid = openvdb::GridBase::grid<openvdb::Grid<openvdb::UInt32Tree>>(base)) {
1412  return openToNanoVDB<BufferT, openvdb::UInt32Tree>(*grid, sMode, cMode, verbose);
1413  } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3fGrid>(base)) {
1414  return openToNanoVDB<BufferT, openvdb::Vec3fTree>(*grid, sMode, cMode, verbose);
1415  } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3dGrid>(base)) {
1416  return openToNanoVDB<BufferT, openvdb::Vec3dTree>(*grid, sMode, cMode, verbose);
1417  } else if (auto grid = openvdb::GridBase::grid<openvdb::tools::PointIndexGrid>(base)) {
1418  return openToNanoVDB<BufferT, openvdb::tools::PointIndexTree>(*grid, sMode, cMode, verbose);
1419  } else if (auto grid = openvdb::GridBase::grid<openvdb::points::PointDataGrid>(base)) {
1420  return openToNanoVDB<BufferT, openvdb::points::PointDataTree>(*grid, sMode, cMode, verbose);
1421  } else if (auto grid = openvdb::GridBase::grid<openvdb::MaskGrid>(base)) {
1422  return openToNanoVDB<BufferT, openvdb::MaskTree>(*grid, sMode, cMode, verbose);
1423  } else if (auto grid = openvdb::GridBase::grid<openvdb::BoolGrid>(base)) {
1424  return openToNanoVDB<BufferT, openvdb::BoolTree>(*grid, sMode, cMode, verbose);
1425  } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4fGrid>(base)) {
1426  return openToNanoVDB<BufferT, openvdb_Vec4fTree>(*grid, sMode, cMode, verbose);
1427  } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4dGrid>(base)) {
1428  return openToNanoVDB<BufferT, openvdb_Vec4dTree>(*grid, sMode, cMode, verbose);
1429  } else {
1430  OPENVDB_THROW(openvdb::RuntimeError, "Unrecognized OpenVDB grid type");
1431  }
1432 }// openToNanoVDB
1433 
1434 } // namespace nanovdb
1435 
1436 #endif // NANOVDB_OPENTONANOVDB_H_HAS_BEEN_INCLUDED
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:149
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:147
Grid< PointDataTree > PointDataGrid
Point data grid.
Definition: PointDataGrid.h:194
void setRoot(const RootT *root)
Definition: NanoVDB.h:2509
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2542
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:408
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:88
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2307
DataType * data()
Definition: NanoVDB.h:2825
const size_t size
Definition: OpenToNanoVDB.h:1089
A unified wrapper for tbb::parallel_invoke and a naive std::thread analog.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
This class will convert an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
Definition: OpenToNanoVDB.h:173
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
T Type
Definition: OpenToNanoVDB.h:37
ChecksumMode
List of different modes for computing for a checksum.
Definition: GridChecksum.h:33
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
uint64_t memUsage() const
Return the actual memory footprint of this root node.
Definition: NanoVDB.h:2860
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:3933
bool operator<(const BlindMetaData &other) const
Definition: OpenToNanoVDB.h:1090
void setStats(StatsMode mode=StatsMode::Default)
Definition: OpenToNanoVDB.h:225
A simple vector class with three double components, similar to openvdb::math::Vec4.
Definition: NanoVDB.h:1188
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:121
static const int MaxNameSize
Definition: NanoVDB.h:2069
OPENVDB_API int printBytes(std::ostream &os, uint64_t bytes, const std::string &head="", const std::string &tail="\n", bool exact=false, int width=8, int precision=3)
LeafData< BuildT, CoordT, MaskT, Log2Dim > DataType
Definition: NanoVDB.h:3691
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:124
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:135
Computes a pair of 32bit checksums, og a Grid, by means of Cyclic Redundancy Check (CRC) ...
Bit-compacted representation of all three version numbers.
Definition: NanoVDB.h:540
DataType * data()
Definition: NanoVDB.h:2569
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:134
static uint64_t memUsage()
return memory usage in bytes for the class
Definition: NanoVDB.h:2574
uint64_t AlignUp(uint64_t byteCount)
round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp<sizeof(size_t)(n) ...
Definition: NanoVDB.h:847
void enableDithering(bool on=true)
Definition: OpenToNanoVDB.h:223
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:123
A unified wrapper for tbb::parallel_reduce and a naive std::future analog.
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
#define NANOVDB_DATA_ALIGNMENT
Definition: NanoVDB.h:116
Definition: Exceptions.h:65
const std::string typeName
Definition: OpenToNanoVDB.h:1088
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:70
OracleT & oracle()
return a reference to the compression oracle
Definition: OpenToNanoVDB.h:219
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:125
OpenToNanoVDB()
Default c-tor.
Definition: OpenToNanoVDB.h:348
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:148
Definition: NanoVDB.h:184
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:133
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:1794
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:137
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:146
A simple vector class with three double components, similar to openvdb::math::Vec3.
Definition: NanoVDB.h:856
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:2798
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:138
static GridType::Ptr grid(const GridBase::Ptr &)
Return the result of downcasting a GridBase pointer to a Grid pointer of the specified type...
Definition: Grid.h:1202
uint8_t * data() override
Returns a non-const pointer to the data.
Definition: GridHandle.h:115
ValueType mMinimum
Definition: NanoVDB.h:3369
_TreeType TreeType
Definition: Grid.h:582
GridHandle< BufferT > operator()(const OpenGridT &grid, const BufferT &allocator=BufferT())
Return a shared pointer to a NanoVDB grid handle constructed from the specified OpenVDB grid...
Definition: OpenToNanoVDB.h:379
Maps one type (e.g. the build types above) to other (actual) types.
Definition: NanoVDB.h:382
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition: Reduce.h:41
static size_t memUsage()
Return memory usage in bytes for the class.
Definition: NanoVDB.h:3156
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:102
Definition: NanoVDB.h:2067
BuildT ArrayType
Definition: NanoVDB.h:3361
BlindMetaData(const std::string &n, const std::string &t, size_t i, size_t c, size_t s)
Definition: OpenToNanoVDB.h:1080
Generates a NanoVDB grid from any volume or function.
void setVerbose(int mode=1)
Definition: OpenToNanoVDB.h:221
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:120
Defines look up table to do dithering of 8^3 leaf nodes.
Definition: DitherLUT.h:19
Grid< PointIndexTree > PointIndexGrid
Point index grid.
Definition: PointIndexGrid.h:60
Definition: Exceptions.h:13
Vec3< double > Vec3R
Definition: NanoVDB.h:1173
Definition: Range.h:28
ValueT value
Definition: GridBuilder.h:1287
Definition: Exceptions.h:63
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:122
void updateChecksum(NanoGrid< ValueT > &grid, ChecksumMode mode=ChecksumMode::Default)
Updates the checksum of a grid.
Definition: GridChecksum.h:272
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition: HostBuffer.h:109
void gridStats(NanoGrid< BuildT > &grid, StatsMode mode=StatsMode::Default)
Re-computes the min/max, stats and bbox information for an existing NanoVDB Grid. ...
Definition: GridStats.h:713
Compression oracle based on absolute difference.
Definition: GridBuilder.h:38
Definition: Types.h:417
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
Definition: Mat.h:187
Dummy type for a voxel with a binary mask value, e.g. the active state.
Definition: NanoVDB.h:189
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:150
static constexpr uint32_t SIZE
Definition: NanoVDB.h:3704
ValueT mBackground
Definition: NanoVDB.h:2721
Definition: OpenToNanoVDB.h:1078
Codec
Optional compression codecs.
Definition: IO.h:61
void setBlindData(void *ptr)
Definition: NanoVDB.h:2084
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3120
const size_t index
Definition: OpenToNanoVDB.h:1089
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
Definition: Types.h:416
GridHandle< BufferT > openToNanoVDB(const openvdb::GridBase::Ptr &base, StatsMode sMode=StatsMode::Default, ChecksumMode cMode=ChecksumMode::Default, int verbose=0)
Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHa...
Definition: OpenToNanoVDB.h:1392
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
static const int MaxNameSize
Definition: NanoVDB.h:2186
static uint64_t memUsage()
Return memory usage in bytes for this class only.
Definition: NanoVDB.h:2332
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition: NanoVDB.h:433
Definition: Types.h:418
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:151
static constexpr uint64_t NUM_VALUES
Definition: NanoVDB.h:3707
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:136
Converts OpenVDB types to NanoVDB types, e.g. openvdb::Vec3f to nanovdb::Vec3f Template specializatio...
Definition: OpenToNanoVDB.h:37
openvdb::points::PointDataGrid GridT
Definition: OpenToNanoVDB.h:145
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:3683
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:859
void setChecksum(ChecksumMode mode=ChecksumMode::Default)
Definition: OpenToNanoVDB.h:227
C++11 implementation of std::is_floating_point.
Definition: NanoVDB.h:355
static constexpr uint64_t NUM_VALUES
Definition: NanoVDB.h:3140
static uint64_t memUsage(uint64_t blindDataCount=0)
return memory usage in bytes for the class (note this computes for all blindMetaData structures...
Definition: NanoVDB.h:2079
C++11 implementation of std::is_same.
Definition: NanoVDB.h:326
Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids...
Definition: OpenToNanoVDB.h:117
Re-computes min/max/avg/var/bbox information for each node in a pre-existing NanoVDB grid...
tree::Tree4< float, 5, 4, 3 >::Type FloatTree
Definition: openvdb.h:24
openvdb::tools::PointIndexGrid GridT
Definition: OpenToNanoVDB.h:132
PointIndex< Index32, 0 > PointIndex32
Definition: Types.h:178