OpenVDB 9.1.0
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>
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
32namespace nanovdb {
33
34/// @brief Converts OpenVDB types to NanoVDB types, e.g. openvdb::Vec3f to nanovdb::Vec3f
35/// Template specializations are defined below.
36template<typename T>
37struct OpenToNanoType { using Type = T; };
38
39//================================================================================================
40
41/// @brief Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHandle
42template<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>
55template<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
67template<>
69{
71 static_assert(sizeof(Type) == sizeof(openvdb::Coord), "Mismatching sizeof");
72};
73
74/// @brief Template specialization for openvdb::CoordBBox
75template<>
77{
79 static_assert(sizeof(Type) == sizeof(openvdb::CoordBBox), "Mismatching sizeof");
80};
81
82/// @brief Template specialization for openvdb::math::BBox
83template<typename T>
84struct OpenToNanoType<openvdb::math::BBox<T>>
85{
87 static_assert(sizeof(Type) == sizeof(openvdb::math::BBox<T>), "Mismatching sizeof");
88};
89
90/// @brief Template specialization for openvdb::math::Vec3
91template<typename T>
92struct 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
99template<typename T>
100struct 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
107template<>
109{
111};
112
113//================================================================================================
114
115/// @brief Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids
116template <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
129template <>
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
142template <>
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
169template<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");
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
212public:
213 /// @brief Default c-tor
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
239private:
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>
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
347template<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
359template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename 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
376template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename 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
423template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
424template <typename T>
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
506template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
507GridHandle<BufferT> OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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
566template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
567NanoGrid<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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
677template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
678NanoTree<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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
738template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
739NanoRoot<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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
764template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
765template<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
795template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
796template<typename T>
797inline 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
828template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
829template<typename T>
833OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<T>& openLeafs)
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
883template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
884template<typename T>
886OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<T>& openLeafs)
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
970template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
971template<typename T>
972inline typename std::enable_if<std::is_same<T, typename OpenGridType<bool>::LeafT>::value>::type
973OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<NodePair<T>>& openLeafs)
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
992template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
993template<typename T>
994inline typename std::enable_if<std::is_same<T, typename OpenGridType<openvdb::ValueMask>::LeafT>::value>::type
995OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<NodePair<T>>& openLeafs)
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
1013template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1014uint64_t OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::pointCount()
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
1025template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1026template <typename OpenNodeT, typename NanoNodeT>
1027inline void OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1028encode(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
1041template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1042template <typename OpenNodeT>
1043inline typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1044decode(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
1058template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1059template <typename NodeT>
1060struct 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
1070template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1071struct 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
1088template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1089template <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
1103template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1104template <typename T>
1106OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::preProcessMetadata(const T& openGrid)
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
1120template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1121template <typename T>
1123OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::preProcessMetadata(const T& openGrid)
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
1147template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1148template<typename T>
1151OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
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
1177template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1178template<typename T>
1179inline typename std::enable_if<std::is_same<T, openvdb::tools::PointIndexGrid>::value,GridBlindMetaData*>::type
1180OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processMetadata(const T& openGrid)
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
1249template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1250template<typename T>
1251inline typename std::enable_if<std::is_same<T, openvdb::points::PointDataGrid>::value,GridBlindMetaData*>::type
1252OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processMetadata(const T& openGrid)
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
1345template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1346template<typename AttT, typename CodecT>
1347inline void OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
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
1369template<typename BufferT, typename OpenTreeT, typename NanoBuildT>
1370GridHandle<BufferT>
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
1383template<typename BufferT>
1384GridHandle<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
Defines look up table to do dithering of 8^3 leaf nodes.
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
Generates a NanoVDB grid from any volume or function.
ValueT value
Definition: GridBuilder.h:1287
Computes a pair of 32bit checksums, og a Grid, by means of Cyclic Redundancy Check (CRC)
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
Re-computes min/max/avg/var/bbox information for each node in a pre-existing NanoVDB grid.
A unified wrapper for tbb::parallel_invoke and a naive std::thread analog.
#define NANOVDB_DATA_ALIGNMENT
Definition: NanoVDB.h:116
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:102
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
A unified wrapper for tbb::parallel_reduce and a naive std::future analog.
Compression oracle based on absolute difference.
Definition: GridBuilder.h:39
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:860
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:71
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2309
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition: HostBuffer.h:110
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3122
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:3685
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:1796
This class will convert an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
Definition: OpenToNanoVDB.h:174
void setStats(StatsMode mode=StatsMode::Default)
Definition: OpenToNanoVDB.h:225
void setChecksum(ChecksumMode mode=ChecksumMode::Default)
Definition: OpenToNanoVDB.h:227
void enableDithering(bool on=true)
Definition: OpenToNanoVDB.h:223
OracleT & oracle()
return a reference to the compression oracle
Definition: OpenToNanoVDB.h:219
void setVerbose(int mode=1)
Definition: OpenToNanoVDB.h:221
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
OpenToNanoVDB()
Default c-tor.
Definition: OpenToNanoVDB.h:348
Definition: Range.h:28
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:2800
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2544
Dummy type for a voxel with a binary mask value, e.g. the active state.
Definition: NanoVDB.h:189
A simple vector class with three double components, similar to openvdb::math::Vec3.
Definition: NanoVDB.h:1044
A simple vector class with three double components, similar to openvdb::math::Vec4.
Definition: NanoVDB.h:1189
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
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:573
_TreeType TreeType
Definition: Grid.h:578
Definition: Exceptions.h:63
Definition: Exceptions.h:65
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:249
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:43
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:46
const Int32 * data() const
Definition: Coord.h:139
Definition: Vec3.h:24
Codec
Optional compression codecs.
Definition: IO.h:61
Definition: NanoVDB.h:184
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
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition: NanoVDB.h:433
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition: Reduce.h:42
Vec3< double > Vec3R
Definition: NanoVDB.h:1173
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
void updateChecksum(NanoGrid< ValueT > &grid, ChecksumMode mode=ChecksumMode::Default)
Updates the checksum of a grid.
Definition: GridChecksum.h:272
GridHandle< BufferT > openToNanoVDB(const openvdb::Grid< OpenTreeT > &grid, StatsMode sMode=StatsMode::Default, ChecksumMode cMode=ChecksumMode::Default, int verbose=0)
Forward declaration of free-standing function that converts a typed OpenVDB Grid into a NanoVDB GridH...
Definition: OpenToNanoVDB.h:1371
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
ChecksumMode
List of different modes for computing for a checksum.
Definition: GridChecksum.h:33
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
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
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
Grid< PointDataTree > PointDataGrid
Point data grid.
Definition: PointDataGrid.h:194
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
Grid< PointIndexTree > PointIndexGrid
Point index grid.
Definition: PointIndexGrid.h:60
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
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)
@ GRID_FOG_VOLUME
Definition: Types.h:417
@ GRID_STAGGERED
Definition: Types.h:418
@ GRID_LEVEL_SET
Definition: Types.h:416
PointIndex< Index32, 0 > PointIndex32
Definition: Types.h:178
tree::Tree4< float, 5, 4, 3 >::Type FloatTree
Definition: openvdb.h:55
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Maps one type (e.g. the build types above) to other (actual) types.
Definition: NanoVDB.h:383
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
static const int MaxNameSize
Definition: NanoVDB.h:2070
static const int MaxNameSize
Definition: NanoVDB.h:2187
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:3934
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:150
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:147
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:146
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:149
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:148
openvdb::points::PointDataGrid GridT
Definition: OpenToNanoVDB.h:145
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:151
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:137
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:134
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:133
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:136
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:135
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:138
openvdb::tools::PointIndexGrid GridT
Definition: OpenToNanoVDB.h:132
Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids.
Definition: OpenToNanoVDB.h:118
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:124
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:121
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:120
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:123
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:122
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:125
Converts OpenVDB types to NanoVDB types, e.g. openvdb::Vec3f to nanovdb::Vec3f Template specializatio...
Definition: OpenToNanoVDB.h:37
T Type
Definition: OpenToNanoVDB.h:37
Definition: OpenToNanoVDB.h:1072
BlindMetaData(const std::string &n, const std::string &t, size_t i, size_t c, size_t s)
Definition: OpenToNanoVDB.h:1073
bool operator<(const BlindMetaData &other) const
Definition: OpenToNanoVDB.h:1083
const size_t index
Definition: OpenToNanoVDB.h:1082
const size_t count
Definition: OpenToNanoVDB.h:1082
const std::string name
Definition: OpenToNanoVDB.h:1081
static const bool value
Definition: NanoVDB.h:357
C++11 implementation of std::is_same.
Definition: NanoVDB.h:327
static constexpr bool value
Definition: NanoVDB.h:328