OpenVDB  9.1.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 * float(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;// local copy since it's very lightweight
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 += oracle(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  std::vector<uint32_t> nodeCount = openTree.nodeCount();
517  mArray0.reserve(nodeCount[0]);
518  mArray1.reserve(nodeCount[1]);
519  mArray2.reserve(nodeCount[2]);
520 
521  uint64_t offset[3] = {0};
522  for (auto it2 = openRoot.cbeginChildOn(); it2; ++it2) {
523  mArray2.emplace_back(&(*it2), offset[2]);
524  offset[2] += NanoUpperT::memUsage();
525  for (auto it1 = it2->cbeginChildOn(); it1; ++it1) {
526  mArray1.emplace_back(&(*it1), offset[1]);
527  offset[1] += NanoLowerT::memUsage();
528  for (auto it0 = it1->cbeginChildOn(); it0; ++it0) {
529  mArray0.emplace_back(&(*it0), offset[0]);
530  offset[0] += sizeof(NanoLeafT);
531  }
532  }
533  }
534 
535  this->template compression<NanoBuildT>(openGrid, offset[0]);
536 
537  this->preProcessMetadata(openGrid);
538 
539  mBufferOffsets[0] = 0;// grid is always plated at the beginning of the buffer!
540  mBufferOffsets[1] = NanoGridT::memUsage(); // grid ends and tree begins
541  mBufferOffsets[2] = NanoTreeT::memUsage(); // tree ends and root begins
542  mBufferOffsets[3] = NanoRootT::memUsage(openTree.root().getTableSize()); // root ends and upper internal nodes begins
543  mBufferOffsets[4] = offset[2];// upper ends and lower internal nodes
544  mBufferOffsets[5] = offset[1];// lower ends and leaf nodes begins
545  mBufferOffsets[6] = offset[0];// leafs end blind meta data begins
546  mBufferOffsets[7] = GridBlindMetaData::memUsage(mBlindMetaData.size()); // meta ends and blind data begins
547  mBufferOffsets[8] = 0;// blind data
548  for (auto& i : mBlindMetaData) mBufferOffsets[8] += i.size; // blind data
549 
550  // Compute the prefixed sum
551  for (int i = 2; i < 9; ++i) {
552  mBufferOffsets[i] += mBufferOffsets[i - 1];
553  }
554 
555  GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
556  mBufferPtr = handle.data();
557 
558  if (mVerbose) {
559  openvdb::util::printBytes(std::cout, mBufferOffsets[8], "Allocated", " for the NanoVDB grid\n");
560  }
561  return handle;// is converted to r-value so return value is move constructed!
562 }// OpenToNanoVDB::initHandle
563 
564 //================================================================================================
565 
566 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
568  processGrid(const OpenGridT& openGrid)
569 {
570  auto *nanoGrid = reinterpret_cast<NanoGridT*>(mBufferPtr + mBufferOffsets[0]);
571  if (!openGrid.transform().baseMap()->isLinear()) {
572  OPENVDB_THROW(openvdb::ValueError, "processGrid: OpenToNanoVDB only supports grids with affine transforms");
573  }
574  auto affineMap = openGrid.transform().baseMap()->getAffineMap();
575  auto *data = nanoGrid->data();
576  data->mMagic = NANOVDB_MAGIC_NUMBER;
577  data->mChecksum = 0u;
578  data->mVersion = Version();
579  data->mFlags = static_cast<uint32_t>(GridFlags::IsBreadthFirst);
580  data->mGridIndex = 0;
581  data->mGridCount = 1;
582  data->mGridSize = mBufferOffsets[8];
583  data->mWorldBBox = BBox<Vec3R>();
584  data->mBlindMetadataOffset = 0;
585  data->mBlindMetadataCount = 0;
586 
587  const std::string gridName = openGrid.getName();
588  strncpy(data->mGridName, gridName.c_str(), GridData::MaxNameSize-1);
589  data->mGridName[GridData::MaxNameSize-1] ='\0';// null terminate
590  if (gridName.length() >= GridData::MaxNameSize) {
591  data->setLongGridNameOn();// grid name is long so store it as blind data
592  }
593  mDelta = NanoValueT(0); // dummy value
594  switch (openGrid.getGridClass()) { // set grid class
597  OPENVDB_THROW(openvdb::ValueError, "processGrid: Level sets are expected to be floating point types");
598  data->mGridClass = GridClass::LevelSet;
599  mDelta = NanoValueT(openGrid.voxelSize()[0]); // skip a node if max < -mDelta || min > mDelta
600  break;
602  data->mGridClass = GridClass::FogVolume;
603  break;
605  data->mGridClass = GridClass::Staggered;
606  break;
607  default:
608  data->mGridClass = GridClass::Unknown;
609  }
610 
611  // mapping from the OpenVDB build type to the NanoVDB build type and GridType enum
612  if (std::is_same<NanoBuildT, float>::value) { // resolved at compiletime
613  data->mGridType = GridType::Float;
615  data->mGridType = GridType::Double;
617  data->mGridType = GridType::Int16;
619  data->mGridType = GridType::Int32;
621  data->mGridType = GridType::Int64;
623  data->mGridType = GridType::Vec3f;
625  data->mGridType = GridType::UInt32;
627  data->mGridType = GridType::UInt32;
628  data->mGridClass = GridClass::PointIndex;
630  data->mGridType = GridType::UInt32;
631  data->mGridClass = GridClass::PointData;
633  data->mGridType = GridType::Mask;
634  data->mGridClass = GridClass::Topology;
636  data->mGridType = GridType::Boolean;
638  data->mGridType = GridType::Fp4;
640  data->mGridType = GridType::Fp8;
642  data->mGridType = GridType::Fp16;
644  data->mGridType = GridType::FpN;
646  data->mGridType = GridType::Vec4f;
648  data->mGridType = GridType::Vec4d;
649  } else {
650  OPENVDB_THROW(openvdb::ValueError, "processGrid: Unsupported value type");
651  }
652  { // set affine map
653  if (openGrid.hasUniformVoxels()) {
654  data->mVoxelSize = nanovdb::Vec3R(affineMap->voxelSize()[0]);
655  } else {
656  data->mVoxelSize = affineMap->voxelSize();
657  }
658  const auto mat = affineMap->getMat4();
659  // Only support non-tapered at the moment:
660  data->mMap.set(mat, mat.inverse(), 1.0);
661  }
662 
663  this->processTree(openGrid.tree());// calls processRoot
664 
665  if (auto size = mBlindMetaData.size()) {
666  auto *metaData = this->processMetadata(openGrid);
667  data->mBlindMetadataOffset = PtrDiff(metaData, nanoGrid);
668  data->mBlindMetadataCount = static_cast<uint32_t>(size);
669  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
670  metaData->setBlindData(blindData);
671  }
672  return nanoGrid;
673 }// OpenToNanoVDB::processGrid
674 
675 //================================================================================================
676 
677 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
679  processTree(const OpenTreeT& openTree)
680 {
681  auto *nanoTree = reinterpret_cast<NanoTreeT*>(mBufferPtr + mBufferOffsets[1]);
682  auto *data = nanoTree->data();
683 
684  data->setRoot( this->processRoot( openTree.root()) );
685 
686  NanoUpperT *nanoUpper = mArray2.empty() ? nullptr : reinterpret_cast<NanoUpperT*>(mBufferPtr + mBufferOffsets[3]);
687  data->setFirstNode(nanoUpper);
688 
689  NanoLowerT *nanoLower = mArray1.empty() ? nullptr : reinterpret_cast<NanoLowerT*>(mBufferPtr + mBufferOffsets[4]);
690  data->setFirstNode(nanoLower);
691 
692  NanoLeafT *nanoLeaf = mArray0.empty() ? nullptr : reinterpret_cast<NanoLeafT*>(mBufferPtr + mBufferOffsets[5]);
693  data->setFirstNode(nanoLeaf);
694 
695  data->mNodeCount[0] = static_cast<uint32_t>(mArray0.size());
696  data->mNodeCount[1] = static_cast<uint32_t>(mArray1.size());
697  data->mNodeCount[2] = static_cast<uint32_t>(mArray2.size());
698 
699 #if 1// count active tiles and voxels
700 
701  // Count number of active leaf level tiles
702  data->mTileCount[0] = reduce(mArray1, uint32_t(0), [&](auto &r, uint32_t sum){
703  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray1[i].node->getValueMask().countOn();
704  return sum;}, std::plus<uint32_t>());
705 
706  // Count number of active lower internal node tiles
707  data->mTileCount[1] = reduce(mArray2, uint32_t(0), [&](auto &r, uint32_t sum){
708  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray2[i].node->getValueMask().countOn();
709  return sum;}, std::plus<uint32_t>());
710 
711  // Count number of active upper internal node tiles
712  uint32_t sum = 0;
713  for (auto it = openTree.root().cbeginValueOn(); it; ++it) ++sum;
714  data->mTileCount[2] = sum;
715 
716  data->mVoxelCount = reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum){
717  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->valueMask().countOn();
718  return sum;}, std::plus<uint64_t>());
719 
720  data->mVoxelCount += data->mTileCount[0]*NanoLeafT::NUM_VALUES;
721  data->mVoxelCount += data->mTileCount[1]*NanoLowerT::NUM_VALUES;
722  data->mVoxelCount += data->mTileCount[2]*NanoUpperT::NUM_VALUES;
723 
724 #else
725 
726  data->mTileCount[0] = 0;
727  data->mTileCount[1] = 0;
728  data->mTileCount[2] = 0;
729  data->mVoxelCount = 0;
730 
731 #endif
732 
733  return nanoTree;
734 }// OpenToNanoVDB::processTree
735 
736 //================================================================================================
737 
738 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
740  processRoot(const OpenRootT& openRoot)
741 {
742  auto *nanoRoot = reinterpret_cast<NanoRootT*>(mBufferPtr + mBufferOffsets[2]);
743  auto* data = nanoRoot->data();
744  data->mBackground = openRoot.background();
745  data->mTableSize = 0;// incremented below
746  data->mMinimum = data->mMaximum = data->mBackground;
747  data->mBBox.min() = openvdb::Coord::max(); // set to an empty bounding box
748  data->mBBox.max() = openvdb::Coord::min();
749 
750  OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
751  for (auto iter = openRoot.cbeginChildAll(); iter; ++iter) {
752  auto* tile = data->tile(data->mTableSize++);
753  if (const OpenUpperT *openChild = iter.probeChild( value )) {
754  tile->setChild(iter.getCoord(), this->decode(openChild), data);
755  } else {
756  tile->setValue(iter.getCoord(), iter.isValueOn(), value);
757  }
758  }
759  return nanoRoot;
760 } // OpenToNanoVDB::processRoot
761 
762 //================================================================================================
763 
764 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
765 template<typename OpenNodeT>
767  processNodes(std::vector<NodePair<OpenNodeT>>& openNodes)
768 {
769  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
770  static_assert(NanoNodeT::LEVEL == 1 || NanoNodeT::LEVEL == 2, "Expected internal node");
771  auto kernel = [&](const Range1D& r) {
772  uint8_t* ptr = mBufferPtr + mBufferOffsets[5 - NanoNodeT::LEVEL];// 3 or 4
773  OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
774  for (auto i = r.begin(); i != r.end(); ++i) {
775  auto *openNode = openNodes[i].node;
776  auto *nanoNode = PtrAdd<NanoNodeT>(ptr, openNodes[i].offset);
777  auto* data = nanoNode->data();
778  this->encode(openNode, nanoNode);
779  data->mValueMask = openNode->getValueMask(); // copy value mask
780  data->mChildMask = openNode->getChildMask(); // copy child mask
781  for (auto iter = openNode->cbeginChildAll(); iter; ++iter) {
782  if (const auto *openChild = iter.probeChild(value)) {
783  data->setChild(iter.pos(), this->decode(openChild));
784  } else {
785  data->setValue(iter.pos(), value);
786  }
787  }
788  }
789  };
790  forEach(openNodes, 1, kernel);
791 } // OpenToNanoVDB::processNodes
792 
793 //================================================================================================
794 
795 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
796 template<typename T>
797 inline typename std::enable_if<!std::is_same<typename OpenGridType<openvdb::ValueMask>::LeafT, typename T::OpenNodeT>::value &&
798  !std::is_same<typename OpenGridType<bool>::LeafT, typename T::OpenNodeT>::value &&
804 {
805  auto kernel = [&](const auto& r) {
806  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
807  for (auto i = r.begin(); i != r.end(); ++i) {
808  auto *openLeaf = openLeafs[i].node;
809  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
810  auto* data = nanoLeaf->data();
811  this->encode(openLeaf, nanoLeaf);
812  data->mFlags = 0u;
813  data->mValueMask = openLeaf->valueMask(); // copy value mask
814  auto *src = reinterpret_cast<const NanoValueT*>(openLeaf->buffer().data());
815  for (NanoValueT *dst = data->mValues, *end = dst + OpenLeafT::size(); dst != end; dst += 4, src += 4) {
816  dst[0] = src[0]; // copy *all* voxel values in sets of four, i.e. loop-unrolling
817  dst[1] = src[1];
818  dst[2] = src[2];
819  dst[3] = src[3];
820  }
821  }
822  };
823  forEach(openLeafs, 8, kernel);
824 } // OpenToNanoVDB::processLeafs<T>
825 
826 //================================================================================================
827 
828 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
829 template<typename T>
834 {
835  using ArrayT = typename NanoLeafT::DataType::ArrayType;
836  using FloatT = typename std::conditional<NanoLeafT::DataType::bitWidth()>=16, double, float>::type;// 16 compression and higher requires double
837  DitherLUT lut(mDitherOn);
838 
839  auto kernel = [&](const auto& r) {
840  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
841  for (auto i = r.begin(); i != r.end(); ++i) {
842  auto *openLeaf = openLeafs[i].node;
843  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
844  auto* data = nanoLeaf->data();
845  this->encode(openLeaf, nanoLeaf);
846  data->mFlags = 0u;
847  data->mValueMask = openLeaf->valueMask(); // copy value mask
848  auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
849  // compute extrema values
851  for (int i=0; i<512; ++i) {
852  const float v = src[i];
853  if (v < min) min = v;
854  if (v > max) max = v;
855  }
856  data->init(min, max, NanoLeafT::DataType::bitWidth());
857  // perform quantization relative to the values in the curret leaf node
858  const FloatT encode = FloatT((1 << NanoLeafT::DataType::bitWidth()) - 1)/(max-min);
859  auto *code = reinterpret_cast<ArrayT*>(data->mCode);
860  int offset = 0;
861  if (std::is_same<Fp4, NanoBuildT>::value) {// resolved at compile-time
862  for (int i=0; i<128; ++i) {
863  auto tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
864  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
865  tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
866  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
867  }
868  } else {
869  for (int i=0; i<128; ++i) {
870  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
871  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
872  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
873  *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
874  }
875  }
876  }
877  };
878  forEach(openLeafs, 8, kernel);
879 } // OpenToNanoVDB::processLeafs<Fp4, Fp8, Fp16>
880 
881 //================================================================================================
882 
883 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
884 template<typename T>
887 {
888  static_assert(is_same<float, OpenBuildT>::value, "Expected OpenBuildT == float");
889 
890  DitherLUT lut(mDitherOn);
891  auto kernel = [&](const auto& r) {
892  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
893  for (auto i = r.begin(); i != r.end(); ++i) {
894  auto *openLeaf = openLeafs[i].node;
895  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
896  auto* data = nanoLeaf->data();
897  this->encode(openLeaf, nanoLeaf);
898  const uint8_t logBitWidth = uint8_t(mCodec[i].log2);
899  data->mFlags = logBitWidth << 5;// pack logBitWidth into 3 MSB of mFlag
900  data->mValueMask = openLeaf->valueMask(); // copy value mask
901  auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
902  const float min = mCodec[i].min, max = mCodec[i].max;
903  data->init(min, max, uint8_t(1) << logBitWidth);
904  // perform quantization relative to the values in the curret leaf node
905  int offset = 0;
906  switch (logBitWidth) {
907  case 0u: {// 1 bit
908  auto *dst = reinterpret_cast<uint8_t*>(data+1);
909  const float encode = 1.0f/(max - min);
910  for (int j=0; j<64; ++j) {
911  uint8_t a = 0;
912  for (int k=0; k<8; ++k) {
913  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << k;
914  }
915  *dst++ = a;
916  }
917  }
918  break;
919  case 1u: {// 2 bits
920  auto *dst = reinterpret_cast<uint8_t*>(data+1);
921  const float encode = 3.0f/(max - min);
922  for (int j=0; j<128; ++j) {
923  auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
924  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 2;
925  a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 4;
926  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 6 | a;
927  }
928  }
929  break;
930  case 2u: {// 4 bits
931  auto *dst = reinterpret_cast<uint8_t*>(data+1);
932  const float encode = 15.0f/(max - min);
933  for (int j=0; j<128; ++j) {
934  auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
935  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
936  a = uint8_t(encode * (*src++ - min) + lut(offset++));
937  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
938  }
939  }
940  break;
941  case 3u: {// 8 bits
942  auto *dst = reinterpret_cast<uint8_t*>(data+1);
943  const float encode = 255.0f/(max - min);
944  for (int j=0; j<128; ++j) {
945  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
946  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
947  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
948  *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
949  }
950  }
951  break;
952  default: {// 16 bits
953  auto *dst = reinterpret_cast<uint16_t*>(data+1);
954  const double encode = 65535.0/(max - min);// note that double is required!
955  for (int j=0; j<128; ++j) {
956  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
957  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
958  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
959  *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
960  }
961  }
962  }// end switch
963  }
964  };// kernel
965  forEach(openLeafs, 8, kernel);
966 } // OpenToNanoVDB::processLeafs<FpN>
967 
968 //================================================================================================
969 
970 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
971 template<typename T>
972 inline typename std::enable_if<std::is_same<T, typename OpenGridType<bool>::LeafT>::value>::type
974 {
975  auto kernel = [&](const auto& r) {
976  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
977  for (auto i = r.begin(); i != r.end(); ++i) {
978  auto *openLeaf = openLeafs[i].node;
979  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
980  auto* data = nanoLeaf->data();
981  this->encode(openLeaf, nanoLeaf);
982  data->mFlags = 0u;
983  data->mValueMask = openLeaf->valueMask(); // copy value mask
984  data->mValues = *reinterpret_cast<const nanovdb::Mask<3>*>(openLeaf->buffer().data()); // copy values
985  }
986  };
987  forEach(openLeafs, 8, kernel);
988 } // OpenToNanoVDB::processLeafs<bool>
989 
990 //================================================================================================
991 
992 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
993 template<typename T>
994 inline typename std::enable_if<std::is_same<T, typename OpenGridType<openvdb::ValueMask>::LeafT>::value>::type
996 {
997  auto kernel = [&](const auto& r) {
998  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
999  for (auto i = r.begin(); i != r.end(); ++i) {
1000  auto *openLeaf = openLeafs[i].node;
1001  auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
1002  auto* data = nanoLeaf->data();
1003  this->encode(openLeaf, nanoLeaf);
1004  data->mFlags = 0u;
1005  data->mValueMask = openLeaf->valueMask(); // copy value mask
1006  }
1007  };
1008  forEach(openLeafs, 8, kernel);
1009 } // OpenToNanoVDB::processLeafs<ValueMask>
1010 
1011 //================================================================================================
1012 
1013 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1015 {
1016  return reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum) {
1017  for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->getLastValue();
1018  return sum;}, std::plus<uint64_t>());
1019 }// OpenToNanoVDB::pointCount
1020 
1021 //================================================================================================
1022 
1023 /// @brief Performs: nanoNode.origin = openNode.origin
1024 /// openNode.origin = nanoNode offset
1025 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1026 template <typename OpenNodeT, typename NanoNodeT>
1028 encode(const OpenNodeT *openNode, NanoNodeT *nanoNode)
1029 {
1030  static_assert(is_same<NanoNodeT, typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type>::value, "Type mismatch");
1031  openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1032  nanoNode->data()->setOrigin(ijk);
1033  reinterpret_cast<int64_t&>(ijk) = PtrDiff(nanoNode, mBufferPtr);
1034 }// OpenToNanoVDB::encode
1035 
1036 //================================================================================================
1037 
1038 /// @brief Performs: nanoNode offset = openNode.origin
1039 /// openNode.origin = nanoNode.origin
1040 /// return nanoNode offset
1041 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1042 template <typename OpenNodeT>
1044 decode(const OpenNodeT *openNode)
1045 {
1046  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1047  openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1048  NanoNodeT *nanoNode = PtrAdd<NanoNodeT>(mBufferPtr, reinterpret_cast<int64_t&>(ijk));
1049  Coord tmp = nanoNode->origin();
1050  ijk[0] = tmp[0];
1051  ijk[1] = tmp[1];
1052  ijk[2] = tmp[2];
1053  return nanoNode;
1054 }// OpenToNanoVDB::decode
1055 
1056 //================================================================================================
1057 
1058 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1059 template <typename NodeT>
1060 struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::NodePair {
1061  using OpenNodeT = NodeT;
1062  using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1063  NodePair(const NodeT *ptr, size_t n) : node(ptr), offset(n) {}
1064  const NodeT *node;// pointer to OpenVDB node
1065  uint64_t offset;// byte offset to matching NanoVDB node, relative to the first
1066 };// OpenToNanoVDB::NodePair
1067 
1068 //================================================================================================
1069 
1070 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1071 struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::BlindMetaData
1072 {
1073  BlindMetaData(const std::string& n, const std::string& t, size_t i, size_t c, size_t s)
1074  : name(n)
1075  , typeName(t)
1076  , index(i)
1077  , count(c)
1078  , size(AlignUp<NANOVDB_DATA_ALIGNMENT>(c * s))
1079  {
1080  }
1081  const std::string name, typeName;
1082  const size_t index, count, size;
1083  bool operator<(const BlindMetaData& other) const { return index < other.index; } // required by std::set
1084 }; // OpenToNanoVDB::BlindMetaData
1085 
1086 //================================================================================================
1087 
1088 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1089 template <typename T>
1093 {
1094  mBlindMetaData.clear();
1095  const size_t length = openGrid.getName().length();
1096  if (length >= GridData::MaxNameSize) {
1097  mBlindMetaData.emplace("grid name", "uint8_t", 0, 1, length + 1);// Null-terminated byte strings
1098  }
1099 }// OpenToNanoVDB::preProcessMetadata<T>
1100 
1101 //================================================================================================
1102 
1103 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1104 template <typename T>
1107 {
1108  mBlindMetaData.clear();
1109  if (const uint64_t pointCount = this->pointCount()) {
1110  mBlindMetaData.emplace("index", "uint32_t", 0, pointCount, sizeof(uint32_t));
1111  }
1112  const size_t length = openGrid.getName().length();
1113  if (length >= GridData::MaxNameSize) {
1114  mBlindMetaData.emplace("grid name", "uint8_t", mBlindMetaData.size(), 1, length + 1);// Null-terminated byte strings
1115  }
1116 }// OpenToNanoVDB::preProcessMetadata<PointIndexGrid>
1117 
1118 //================================================================================================
1119 
1120 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1121 template <typename T>
1124 {
1125  mBlindMetaData.clear();
1126  size_t counter = 0;
1127  if (const uint64_t pointCount = this->pointCount()) {
1128  auto *openLeaf = openGrid.tree().cbeginLeaf().getLeaf();
1129  const auto& attributeSet = openLeaf->attributeSet();
1130  const auto& descriptor = attributeSet.descriptor();
1131  const auto& nameMap = descriptor.map();
1132  for (auto it = nameMap.begin(); it != nameMap.end(); ++it) {
1133  const size_t index = it->second;
1134  auto& attArray = openLeaf->constAttributeArray(index);
1135  mBlindMetaData.emplace(it->first, descriptor.valueType(index), index, pointCount, attArray.valueTypeSize());
1136  }
1137  counter += nameMap.size();
1138  }
1139  const size_t length = openGrid.getName().length();
1140  if (length >= GridData::MaxNameSize) {
1141  mBlindMetaData.emplace("grid name", "uint8_t", counter, 1, length + 1);// Null-terminated byte strings
1142  }
1143 }// OpenToNanoVDB::preProcessMetadata<PointDataGrid>
1144 
1145 //================================================================================================
1146 
1147 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1148 template<typename T>
1152  processMetadata(const T& openGrid)
1153 {
1154  if (mBlindMetaData.empty()) {
1155  return nullptr;
1156  }
1157  assert(mBlindMetaData.size() == 1);// only the grid name is expected
1158  auto it = mBlindMetaData.cbegin();
1159  assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 0);
1160  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1161  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1162  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1163  // write the blind meta data
1164  metaData->setBlindData(blindData);
1165  metaData->mElementCount = it->count;
1166  metaData->mFlags = 0;
1167  metaData->mSemantic = GridBlindDataSemantic::Unknown;
1168  metaData->mDataClass = GridBlindDataClass::GridName;
1169  metaData->mDataType = GridType::Unknown;
1170  // write the actual bind data
1171  strcpy(blindData, openGrid.getName().c_str());
1172  return metaData;
1173 }// OpenToNanoVDB::processMetadata<T>
1174 
1175 //================================================================================================
1176 
1177 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1178 template<typename T>
1181 {
1182  if (mBlindMetaData.empty()) {
1183  return nullptr;
1184  }
1185  assert(mBlindMetaData.size() == 1 || mBlindMetaData.size() == 2);// point index and maybe long grid name
1186  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1187  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1188 
1189  auto it = mBlindMetaData.cbegin();
1190  const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1191 
1192  using LeafDataT = typename NanoLeafT::DataType;
1193  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1194 
1195  auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1196  data0->mMinimum = 0; // start of prefix sum
1197  data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1198  for (uint32_t i = 1; i < leafCount; ++i) {
1199  auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1200  data1->mMinimum = data0->mMinimum + data0->mMaximum;
1201  data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1202  data0 = data1;
1203  }
1204 
1205  // write blind meta data for the point offsets
1206  assert(it->count == data0->mMinimum + data0->mMaximum);
1207  assert(it->name == "index" && it->typeName == "uint32_t" && it->index == 0);
1208  metaData[0].setBlindData( blindData );
1209  metaData[0].mElementCount = it->count;
1210  metaData[0].mFlags = 0;
1211  metaData[0].mSemantic = GridBlindDataSemantic::Unknown;
1212  metaData[0].mDataClass = GridBlindDataClass::IndexArray;
1213  metaData[0].mDataType = GridType::UInt32;
1214  if (it->name.length() >= GridBlindMetaData::MaxNameSize) {
1215  std::stringstream ss;
1216  ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1218  }
1219  memcpy(metaData[0].mName, it->name.c_str(), it->name.size() + 1);
1220 
1221  // write point offsets as blind data
1222  forEach(mArray0, 16, [&](const auto& r) {
1223  for (auto i = r.begin(); i != r.end(); ++i) {
1224  auto *data = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1225  uint32_t* p = reinterpret_cast<uint32_t*>(blindData) + data->mMinimum;
1226  for (uint32_t idx : mArray0[i].node->indices()) *p++ = idx;
1227  }
1228  });
1229  blindData += it->size;// add point offsets
1230 
1231  // write long grid name if it exists
1232  ++it;
1233  if (it != mBlindMetaData.end()) {
1234  assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 1);
1235  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1236  metaData[1].setBlindData( blindData );
1237  metaData[1].mElementCount = it->count;
1238  metaData[1].mFlags = 0;
1239  metaData[1].mSemantic = GridBlindDataSemantic::Unknown;
1240  metaData[1].mDataClass = GridBlindDataClass::GridName;
1241  metaData[1].mDataType = GridType::Unknown;
1242  strcpy(blindData, openGrid.getName().c_str());
1243  }
1244  return metaData;
1245 }// OpenToNanoVDB::processMetadata<PointIndex32>
1246 
1247 //================================================================================================
1248 
1249 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1250 template<typename T>
1253 {
1254  if (mBlindMetaData.empty()) {
1255  return nullptr;
1256  }
1257 
1258  auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1259  auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1260 
1261  const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1262 
1263  using LeafDataT = typename NanoLeafT::DataType;
1264  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1265 
1266  auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1267  data0->mMinimum = 0; // start of prefix sum
1268  data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1269  for (uint32_t i = 1; i < leafCount; ++i) {
1270  auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1271  data1->mMinimum = data0->mMinimum + data0->mMaximum;
1272  data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1273  data0 = data1;
1274  }
1275 
1276  size_t i=0;
1277  for (auto it = mBlindMetaData.cbegin(); it != mBlindMetaData.end(); ++it, ++i) {
1278  metaData[i].setBlindData( blindData );
1279  metaData[i].mElementCount = it->count;
1280  metaData[i].mFlags = 0;
1281  if (it->name == "grid name") {
1282  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1283  metaData[i].mDataClass = GridBlindDataClass::GridName;
1284  metaData[i].mDataType = GridType::Unknown;
1285  assert(openGrid.getName().length() >= GridData::MaxNameSize);
1286  strcpy((char*)blindData, openGrid.getName().c_str());
1287  } else {
1288  assert(it->count == data0->mMinimum + data0->mMaximum);
1289  metaData[i].mDataClass = GridBlindDataClass::AttributeArray;
1290  if (it->name.length()>= GridBlindMetaData::MaxNameSize) {
1291  std::stringstream ss;
1292  ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1294  }
1295 
1296  memcpy(metaData[i].mName, it->name.c_str(), it->name.size() + 1);
1297  if (it->typeName == "vec3s") {
1298  metaData[i].mDataType = GridType::Vec3f;
1299  this->copyPointAttribute(it->index, (openvdb::Vec3f*)blindData);
1300  if (it->name == "P") {
1301  metaData[i].mSemantic = GridBlindDataSemantic::PointPosition;
1302  } else if (it->name == "V") {
1303  metaData[i].mSemantic = GridBlindDataSemantic::PointVelocity;
1304  } else if (it->name == "Cd") {
1305  metaData[i].mSemantic = GridBlindDataSemantic::PointColor;
1306  } else if (it->name == "N") {
1307  metaData[i].mSemantic = GridBlindDataSemantic::PointNormal;
1308  } else {
1309  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1310  }
1311  } else if (it->typeName == "int32") {
1312  metaData[i].mDataType = GridType::Int32;
1313  this->copyPointAttribute(it->index, (int32_t*)blindData);
1314  if (it->name == "id") {
1315  metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1316  } else {
1317  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1318  }
1319  } else if (it->typeName == "int64") {
1320  metaData[i].mDataType = GridType::Int64;
1321  this->copyPointAttribute(it->index, (int64_t*)blindData);
1322  if (it->name == "id") {
1323  metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1324  } else {
1325  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1326  }
1327  } else if (it->typeName == "float") {
1328  metaData[i].mDataType = GridType::Float;
1329  metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1330  this->copyPointAttribute(it->index, (float*)blindData);
1331  } else {
1332  std::stringstream ss;
1333  ss << "Unsupported point attribute type: \"" << it->typeName << "\"";
1335  }
1336  }
1337  blindData += it->size;
1338  } // loop over bind data
1339  return metaData;
1340 }// OpenToNanoVDB::processMetadata<PointDataIndex32>
1341 
1342 //================================================================================================
1343 
1344 
1345 template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1346 template<typename AttT, typename CodecT>
1348  copyPointAttribute(size_t attIdx, AttT *attPtr)
1349 {
1350  static_assert(std::is_same<typename OpenLeafT::ValueType, openvdb::PointDataIndex32>::value, "Expected value to openvdb::PointData");
1351  using LeafDataT = typename NanoLeafT::DataType;
1352  using HandleT = openvdb::points::AttributeHandle<AttT, CodecT>;
1353  forEach(mArray0, 16, [&](const auto& r) {
1354  uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1355  for (auto i = r.begin(); i != r.end(); ++i) {
1356  auto* openLeaf = mArray0[i].node;
1357  auto *nanoData = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1358  HandleT handle(openLeaf->constAttributeArray(attIdx));
1359  AttT* p = attPtr + nanoData->mMinimum;
1360  for (auto iter = openLeaf->beginIndexOn(); iter; ++iter) {
1361  *p++ = handle.get(*iter);
1362  }
1363  }
1364  });
1365 }// OpenToNanoVDB::copyPointAttribute
1366 
1367 //================================================================================================
1368 
1369 template<typename BufferT, typename OpenTreeT, typename NanoBuildT>
1372  StatsMode sMode,
1373  ChecksumMode cMode,
1374  int verbose)
1375 {
1376  using OpenBuildT = typename OpenTreeT::BuildType;
1378  return s(grid, sMode, cMode, verbose);
1379 }// openToNanoVDB
1380 
1381 //================================================================================================
1382 
1383 template<typename BufferT>
1386  StatsMode sMode,
1387  ChecksumMode cMode,
1388  int verbose)
1389 {
1390  // We need to define these types because they are not defined in OpenVDB
1391  using openvdb_Vec4fTree = typename openvdb::tree::Tree4<openvdb::Vec4f, 5, 4, 3>::Type;
1392  using openvdb_Vec4dTree = typename openvdb::tree::Tree4<openvdb::Vec4d, 5, 4, 3>::Type;
1393  using openvdb_Vec4fGrid = openvdb::Grid<openvdb_Vec4fTree>;
1394  using openvdb_Vec4dGrid = openvdb::Grid<openvdb_Vec4dTree>;
1395 
1396  if (auto grid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
1397  return openToNanoVDB<BufferT, openvdb::FloatTree>(*grid, sMode, cMode, verbose);
1398  } else if (auto grid = openvdb::GridBase::grid<openvdb::DoubleGrid>(base)) {
1399  return openToNanoVDB<BufferT, openvdb::DoubleTree>(*grid, sMode, cMode, verbose);
1400  } else if (auto grid = openvdb::GridBase::grid<openvdb::Int32Grid>(base)) {
1401  return openToNanoVDB<BufferT, openvdb::Int32Tree>(*grid, sMode, cMode, verbose);
1402  } else if (auto grid = openvdb::GridBase::grid<openvdb::Int64Grid>(base)) {
1403  return openToNanoVDB<BufferT, openvdb::Int64Tree>(*grid, sMode, cMode, verbose);
1404  } else if (auto grid = openvdb::GridBase::grid<openvdb::Grid<openvdb::UInt32Tree>>(base)) {
1405  return openToNanoVDB<BufferT, openvdb::UInt32Tree>(*grid, sMode, cMode, verbose);
1406  } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3fGrid>(base)) {
1407  return openToNanoVDB<BufferT, openvdb::Vec3fTree>(*grid, sMode, cMode, verbose);
1408  } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3dGrid>(base)) {
1409  return openToNanoVDB<BufferT, openvdb::Vec3dTree>(*grid, sMode, cMode, verbose);
1410  } else if (auto grid = openvdb::GridBase::grid<openvdb::tools::PointIndexGrid>(base)) {
1411  return openToNanoVDB<BufferT, openvdb::tools::PointIndexTree>(*grid, sMode, cMode, verbose);
1412  } else if (auto grid = openvdb::GridBase::grid<openvdb::points::PointDataGrid>(base)) {
1413  return openToNanoVDB<BufferT, openvdb::points::PointDataTree>(*grid, sMode, cMode, verbose);
1414  } else if (auto grid = openvdb::GridBase::grid<openvdb::MaskGrid>(base)) {
1415  return openToNanoVDB<BufferT, openvdb::MaskTree>(*grid, sMode, cMode, verbose);
1416  } else if (auto grid = openvdb::GridBase::grid<openvdb::BoolGrid>(base)) {
1417  return openToNanoVDB<BufferT, openvdb::BoolTree>(*grid, sMode, cMode, verbose);
1418  } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4fGrid>(base)) {
1419  return openToNanoVDB<BufferT, openvdb_Vec4fTree>(*grid, sMode, cMode, verbose);
1420  } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4dGrid>(base)) {
1421  return openToNanoVDB<BufferT, openvdb_Vec4dTree>(*grid, sMode, cMode, verbose);
1422  } else {
1423  OPENVDB_THROW(openvdb::RuntimeError, "Unrecognized OpenVDB grid type");
1424  }
1425 }// openToNanoVDB
1426 
1427 } // namespace nanovdb
1428 
1429 #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:2510
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2543
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:2308
DataType * data()
Definition: NanoVDB.h:2826
const size_t size
Definition: OpenToNanoVDB.h:1082
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)
A unified wrapper for tbb::parallel_invoke and a naive std::thread analog.
Definition: Mat.h:187
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
Definition: Types.h:417
#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:2861
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:3934
bool operator<(const BlindMetaData &other) const
Definition: OpenToNanoVDB.h:1083
void setStats(StatsMode mode=StatsMode::Default)
Definition: OpenToNanoVDB.h:225
Definition: Exceptions.h:63
A simple vector class with three double components, similar to openvdb::math::Vec4.
Definition: NanoVDB.h:1188
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:121
static const int MaxNameSize
Definition: NanoVDB.h:2070
LeafData< BuildT, CoordT, MaskT, Log2Dim > DataType
Definition: NanoVDB.h:3692
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:2570
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:134
static uint64_t memUsage()
return memory usage in bytes for the class
Definition: NanoVDB.h:2575
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:1081
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
Definition: Types.h:416
OpenToNanoVDB()
Default c-tor.
Definition: OpenToNanoVDB.h:348
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:1795
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:137
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:146
tree::Tree4< float, 5, 4, 3 >::Type FloatTree
Definition: openvdb.h:55
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:2799
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:138
uint8_t * data() override
Returns a non-const pointer to the data.
Definition: GridHandle.h:115
ValueType mMinimum
Definition: NanoVDB.h:3370
Definition: Types.h:418
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:42
static size_t memUsage()
Return memory usage in bytes for the class.
Definition: NanoVDB.h:3157
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:102
Definition: NanoVDB.h:2068
BuildT ArrayType
Definition: NanoVDB.h:3362
BlindMetaData(const std::string &n, const std::string &t, size_t i, size_t c, size_t s)
Definition: OpenToNanoVDB.h:1073
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
Definition: Exceptions.h:13
Vec3< double > Vec3R
Definition: NanoVDB.h:1173
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
Definition: Range.h:28
PointIndex< Index32, 0 > PointIndex32
Definition: Types.h:178
ValueT value
Definition: GridBuilder.h:1287
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
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
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:3705
ValueT mBackground
Definition: NanoVDB.h:2722
Definition: OpenToNanoVDB.h:1071
Codec
Optional compression codecs.
Definition: IO.h:61
void setBlindData(void *ptr)
Definition: NanoVDB.h:2085
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3121
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
const size_t index
Definition: OpenToNanoVDB.h:1082
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
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:1385
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
_TreeType TreeType
Definition: Grid.h:578
static const int MaxNameSize
Definition: NanoVDB.h:2187
static uint64_t memUsage()
Return memory usage in bytes for this class only.
Definition: NanoVDB.h:2333
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition: NanoVDB.h:433
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:151
static constexpr uint64_t NUM_VALUES
Definition: NanoVDB.h:3708
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:3684
Grid< PointIndexTree > PointIndexGrid
Point index grid.
Definition: PointIndexGrid.h:60
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:859
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
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:3141
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:2080
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...
openvdb::tools::PointIndexGrid GridT
Definition: OpenToNanoVDB.h:132
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:1194