OpenVDB: nanovdb/util/OpenToNanoVDB.h Source File

OpenVDB 9.0.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>
15#include <openvdb/points/PointDataGrid.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
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>
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
42template<typename BufferT = HostBuffer>
43 GridHandle<BufferT>
44 openToNanoVDB(const openvdb::GridBase::Ptr& base,
45 StatsMode sMode = StatsMode::Default,
46 ChecksumMode cMode = ChecksumMode::Default,
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>
58 GridHandle<BufferT>
59 openToNanoVDB(const openvdb::Grid<OpenTreeT>& grid,
60 StatsMode sMode = StatsMode::Default,
61 ChecksumMode cMode = ChecksumMode::Default,
62 int verbose = 0);
63
64//================================================================================================
65
66/// @brief Template specialization for openvdb::Coord
67template<>
68 struct OpenToNanoType<openvdb::Coord>
69{
70 using Type = nanovdb::Coord;
71 static_assert(sizeof(Type) == sizeof(openvdb::Coord), "Mismatching sizeof");
72};
73
74/// @brief Template specialization for openvdb::CoordBBox
75template<>
76 struct OpenToNanoType<openvdb::CoordBBox>
77{
78 using Type = nanovdb::CoordBBox;
79 static_assert(sizeof(Type) == sizeof(openvdb::CoordBBox), "Mismatching sizeof");
80};
81
82/// @brief Template specialization for openvdb::math::BBox
83template<typename T>
84 struct OpenToNanoType<openvdb::math::BBox<T>>
85{
86 using Type = nanovdb::BBox<T>;
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>
92 struct OpenToNanoType<openvdb::math::Vec3<T>>
93{
94 using Type = nanovdb::Vec3<T>;
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>
100 struct OpenToNanoType<openvdb::math::Vec4<T>>
101{
102 using Type = nanovdb::Vec4<T>;
103 static_assert(sizeof(Type) == sizeof(openvdb::math::Vec4<T>), "Mismatching sizeof");
104};
105
106/// @brief Template specialization for openvdb::ValueMask
107template<>
108 struct OpenToNanoType<openvdb::ValueMask>
109{
110 using Type = nanovdb::ValueMask;
111};
112
113//================================================================================================
114
115/// @brief Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids
116template <typename BuildT>
117 struct OpenGridType
118{
119 using GridT = openvdb::Grid<typename openvdb::tree::Tree4<BuildT, 5, 4, 3>::Type>;
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 <>
130 struct OpenGridType<openvdb::PointIndex32>
131{
132 using GridT = openvdb::tools::PointIndexGrid;// 5, 4, 3
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 <>
143 struct OpenGridType<openvdb::PointDataIndex32>
144{
145 using GridT = openvdb::points::PointDataGrid;// 5, 4, 3
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>
173 class OpenToNanoVDB
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
188 using NanoLeafT = NanoLeaf<NanoBuildT>;
189 using NanoLowerT= NanoLower<NanoBuildT>;
190 using NanoUpperT= NanoUpper<NanoBuildT>;
191 using NanoRootT = NanoRoot<NanoBuildT>;
192 using NanoTreeT = NanoTree<NanoBuildT>;
193 using NanoGridT = NanoGrid<NanoBuildT>;
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
212public:
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
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>
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 &&
269 !std::is_same<Fp4, typename T::NanoNodeT::BuildType>::value &&
270 !std::is_same<Fp8, typename T::NanoNodeT::BuildType>::value &&
271 !std::is_same<Fp16,typename T::NanoNodeT::BuildType>::value &&
272 !std::is_same<FpN, typename T::NanoNodeT::BuildType>::value>::type
273 processLeafs(std::vector<T> &leafs);
274
275 template<typename T>
276 typename std::enable_if<std::is_same<Fp4, typename T::NanoNodeT::BuildType>::value ||
277 std::is_same<Fp8, typename T::NanoNodeT::BuildType>::value ||
278 std::is_same<Fp16, typename T::NanoNodeT::BuildType>::value>::type
279 processLeafs(std::vector<T> &leafs);
280
281 template<typename T>
282 typename std::enable_if<std::is_same<FpN, typename T::NanoNodeT::BuildType>::value>::type
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>
297 typename std::enable_if<!std::is_same<T, openvdb::tools::PointIndexGrid>::value &&
298 !std::is_same<T, openvdb::points::PointDataGrid>::value>::type
299 preProcessMetadata(const T& openGrid);
300
301 template <typename T>
302 typename std::enable_if<std::is_same<T, openvdb::tools::PointIndexGrid>::value>::type
303 preProcessMetadata(const T& openGrid);
304
305 template <typename T>
306 typename std::enable_if<std::is_same<T, openvdb::points::PointDataGrid>::value>::type
307 preProcessMetadata(const T& openGrid);
308
309 //////////////////////
310
311 /// @brief Private methods to process the blind metadata
312 template<typename T>
313 typename std::enable_if<!std::is_same<T, openvdb::tools::PointIndexGrid>::value &&
314 !std::is_same<T, openvdb::points::PointDataGrid>::value, GridBlindMetaData*>::type
315 processMetadata(const T& openGrid);
316
317 template<typename T>
318 typename std::enable_if<std::is_same<T, openvdb::tools::PointIndexGrid>::value, GridBlindMetaData*>::type
319 processMetadata(const T& openGrid);
320
321 template<typename T>
322 typename std::enable_if<std::is_same<T, openvdb::points::PointDataGrid>::value, GridBlindMetaData*>::type
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>
348OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::OpenToNanoVDB()
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>
360inline GridHandle<BufferT>
361 OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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>
377inline GridHandle<BufferT>
378OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, 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
405 if (std::is_same<OpenBuildT, openvdb::PointIndex32>::value ||
406 std::is_same<OpenBuildT, openvdb::PointDataIndex32>::value) {
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>
425inline typename std::enable_if<std::is_same<T, FpN>::value>::type
426 OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
427 compression(const OpenGridT& openGrid, uint64_t &offset)
428{
429 static_assert(is_same<float, OpenBuildT>::value, "compression: expected OpenBuildT == float");
430 static_assert(is_same<FpN, NanoBuildT>::value, "compression: expected NanoBuildT == FpN");
431 if (is_same<AbsDiff, OracleT>::value && mOracle.getTolerance() < 0.0f) {// default tolerance for level set and fog volumes
432 if (openGrid.getGridClass() == openvdb::GRID_LEVEL_SET) {
433 mOracle.setTolerance(0.1f * openGrid.voxelSize()[0]);// range of ls: [-3dx; 3dx]
434 } else if (openGrid.getGridClass() == openvdb::GRID_FOG_VOLUME) {
435 mOracle.setTolerance(0.01f);// range of FOG volumes: [0;1]
436 } else {
437 mOracle.setTolerance(0.0f);
438 }
439 }
440
441 const size_t size = mArray0.size();
442 mCodec.reset(new Codec[size]);
443
444 DitherLUT lut(mDitherOn);
445 auto kernel = [&](const auto &r) {
446 const OracleT oracle = mOracle;
447 for (auto i=r.begin(); i!=r.end(); ++i) {
448 const float *data = mArray0[i].node->buffer().data();
449 float min = std::numeric_limits<float>::max(), max = -min;
450 for (int j=0; j<512; ++j) {
451 float v = data[j];
452 if (v<min) min=v;
453 if (v>max) max=v;
454 }
455 mCodec[i].min = min;
456 mCodec[i].max = max;
457 const float range = max - min;
458 uint16_t logBitWidth = 0;// 0,1,2,3,4 => 1,2,4,8,16 bits
459 while (range > 0.0f && logBitWidth < 4u) {
460 const uint32_t mask = (uint32_t(1) << (uint32_t(1) << logBitWidth)) - 1u;
461 const float encode = mask/range;
462 const float decode = range/mask;
463 int j = 0;
464 do {
465 const float exact = data[j];// exact value
466 const uint32_t code = uint32_t(encode*(exact - min) + lut(j));
467 const float approx = code * decode + min;// approximate value
468 j += mOracle(exact, approx) ? 1 : 513;
469 } while(j < 512);
470 if (j == 512) break;
471 ++logBitWidth;
472 }
473 mCodec[i].log2 = logBitWidth;
474 mCodec[i].size = NanoLeafT::DataType::memUsage(1u<<logBitWidth);
475 }
476 };// kernel
477 forEach(0, size, 4, kernel);
478
479 if (mVerbose) {
480 uint32_t counters[5+1] = {0};
481 ++counters[mCodec[0].log2];
482 for (size_t i=1; i<size; ++i) {
483 ++counters[mCodec[i].log2];
484 mArray0[i].offset = mArray0[i-1].offset + mCodec[i-1].size;
485 }
486 std::cout << "\n" << mOracle << std::endl;
487 std::cout << "Dithering: " << (mDitherOn ? "enabled" : "disabled") << std::endl;
488 float avg = 0.0f;
489 for (uint32_t i=0; i<=5; ++i) {
490 if (uint32_t n = counters[i]) {
491 avg += n * float(1 << i);
492 printf("%2i bits: %6u leaf nodes, i.e. %4.1f%%\n",1<<i, n, 100.0f*n/float(size));
493 }
494 }
495 printf("%4.1f bits per value on average\n", avg/float(size));
496 } else {
497 for (size_t i=1; i<size; ++i) {
498 mArray0[i].offset = mArray0[i-1].offset + mCodec[i-1].size;
499 }
500 }
501 offset = mArray0[size-1].offset + mCodec[size-1].size;
502}// OpenToNanoVDB::compression
503
504//================================================================================================
505
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#if OPENVDB_ABI_VERSION_NUMBER >= 7
517 std::vector<uint32_t> nodeCount = openTree.nodeCount();
518#else
519 std::vector<uint32_t> nodeCount(openTree.treeDepth());
520 for (auto it = openTree.cbeginNode(); it; ++it) {
521 ++(nodeCount[it.getDepth()]);
522 }
523#endif
524 mArray0.reserve(nodeCount[0]);
525 mArray1.reserve(nodeCount[1]);
526 mArray2.reserve(nodeCount[2]);
527
528 uint64_t offset[3] = {0};
529 for (auto it2 = openRoot.cbeginChildOn(); it2; ++it2) {
530 mArray2.emplace_back(&(*it2), offset[2]);
531 offset[2] += NanoUpperT::memUsage();
532 for (auto it1 = it2->cbeginChildOn(); it1; ++it1) {
533 mArray1.emplace_back(&(*it1), offset[1]);
534 offset[1] += NanoLowerT::memUsage();
535 for (auto it0 = it1->cbeginChildOn(); it0; ++it0) {
536 mArray0.emplace_back(&(*it0), offset[0]);
537 offset[0] += sizeof(NanoLeafT);
538 }
539 }
540 }
541
542 this->template compression<NanoBuildT>(openGrid, offset[0]);
543
544 this->preProcessMetadata(openGrid);
545
546 mBufferOffsets[0] = 0;// grid is always plated at the beginning of the buffer!
547 mBufferOffsets[1] = NanoGridT::memUsage(); // grid ends and tree begins
548 mBufferOffsets[2] = NanoTreeT::memUsage(); // tree ends and root begins
549 mBufferOffsets[3] = NanoRootT::memUsage(openTree.root().getTableSize()); // root ends and upper internal nodes begins
550 mBufferOffsets[4] = offset[2];// upper ends and lower internal nodes
551 mBufferOffsets[5] = offset[1];// lower ends and leaf nodes begins
552 mBufferOffsets[6] = offset[0];// leafs end blind meta data begins
553 mBufferOffsets[7] = GridBlindMetaData::memUsage(mBlindMetaData.size()); // meta ends and blind data begins
554 mBufferOffsets[8] = 0;// blind data
555 for (auto& i : mBlindMetaData) mBufferOffsets[8] += i.size; // blind data
556
557 // Compute the prefixed sum
558 for (int i = 2; i < 9; ++i) {
559 mBufferOffsets[i] += mBufferOffsets[i - 1];
560 }
561
562 GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
563 mBufferPtr = handle.data();
564
565 if (mVerbose) {
566 openvdb::util::printBytes(std::cout, mBufferOffsets[8], "Allocated", " for the NanoVDB grid\n");
567 }
568 return handle;// is converted to r-value so return value is move constructed!
569}// OpenToNanoVDB::initHandle
570
571//================================================================================================
572
573template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
574NanoGrid<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
575 processGrid(const OpenGridT& openGrid)
576{
577 auto *nanoGrid = reinterpret_cast<NanoGridT*>(mBufferPtr + mBufferOffsets[0]);
578 if (!openGrid.transform().baseMap()->isLinear()) {
579 OPENVDB_THROW(openvdb::ValueError, "processGrid: OpenToNanoVDB only supports grids with affine transforms");
580 }
581 auto affineMap = openGrid.transform().baseMap()->getAffineMap();
582 auto *data = nanoGrid->data();
583 data->mMagic = NANOVDB_MAGIC_NUMBER;
584 data->mChecksum = 0u;
585 data->mVersion = Version();
586 data->mFlags = static_cast<uint32_t>(GridFlags::IsBreadthFirst);
587 data->mGridIndex = 0;
588 data->mGridCount = 1;
589 data->mGridSize = mBufferOffsets[8];
590 data->mWorldBBox = BBox<Vec3R>();
591 data->mBlindMetadataOffset = 0;
592 data->mBlindMetadataCount = 0;
593
594 const std::string gridName = openGrid.getName();
595 strncpy(data->mGridName, gridName.c_str(), GridData::MaxNameSize-1);
596 data->mGridName[GridData::MaxNameSize-1] ='\0';// null terminate
597 if (gridName.length() >= GridData::MaxNameSize) {
598 data->setLongGridNameOn();// grid name is long so store it as blind data
599 }
600 mDelta = NanoValueT(0); // dummy value
601 switch (openGrid.getGridClass()) { // set grid class
602 case openvdb::GRID_LEVEL_SET:
603 if (!is_floating_point<OpenValueT>::value)
604 OPENVDB_THROW(openvdb::ValueError, "processGrid: Level sets are expected to be floating point types");
605 data->mGridClass = GridClass::LevelSet;
606 mDelta = NanoValueT(openGrid.voxelSize()[0]); // skip a node if max < -mDelta || min > mDelta
607 break;
608 case openvdb::GRID_FOG_VOLUME:
609 data->mGridClass = GridClass::FogVolume;
610 break;
611 case openvdb::GRID_STAGGERED:
612 data->mGridClass = GridClass::Staggered;
613 break;
614 default:
615 data->mGridClass = GridClass::Unknown;
616 }
617
618 // mapping from the OpenVDB build type to the NanoVDB build type and GridType enum
619 if (std::is_same<NanoBuildT, float>::value) { // resolved at compiletime
620 data->mGridType = GridType::Float;
621 } else if (std::is_same<NanoBuildT, double>::value) {
622 data->mGridType = GridType::Double;
623 } else if (std::is_same<NanoBuildT, int16_t>::value) {
624 data->mGridType = GridType::Int16;
625 } else if (std::is_same<NanoBuildT, int32_t>::value) {
626 data->mGridType = GridType::Int32;
627 } else if (std::is_same<NanoBuildT, int64_t>::value) {
628 data->mGridType = GridType::Int64;
629 } else if (std::is_same<NanoBuildT, Vec3f>::value) {
630 data->mGridType = GridType::Vec3f;
631 } else if (std::is_same<NanoBuildT, openvdb::Index32>::value) {
632 data->mGridType = GridType::UInt32;
633 } else if (std::is_same<NanoBuildT, openvdb::PointIndex32>::value) {
634 data->mGridType = GridType::UInt32;
635 data->mGridClass = GridClass::PointIndex;
636 } else if (std::is_same<NanoBuildT, openvdb::PointDataIndex32>::value) {
637 data->mGridType = GridType::UInt32;
638 data->mGridClass = GridClass::PointData;
639 } else if (std::is_same<NanoBuildT, ValueMask>::value) {
640 data->mGridType = GridType::Mask;
641 data->mGridClass = GridClass::Topology;
642 } else if (std::is_same<NanoBuildT, bool>::value) {
643 data->mGridType = GridType::Boolean;
644 } else if (std::is_same<NanoBuildT, Fp4>::value) {
645 data->mGridType = GridType::Fp4;
646 } else if (std::is_same<NanoBuildT, Fp8>::value) {
647 data->mGridType = GridType::Fp8;
648 } else if (std::is_same<NanoBuildT, Fp16>::value) {
649 data->mGridType = GridType::Fp16;
650 } else if (std::is_same<NanoBuildT, FpN>::value) {
651 data->mGridType = GridType::FpN;
652 } else if (std::is_same<NanoBuildT, Vec4f>::value) {
653 data->mGridType = GridType::Vec4f;
654 } else if (std::is_same<NanoBuildT, Vec4d>::value) {
655 data->mGridType = GridType::Vec4d;
656 } else {
657 OPENVDB_THROW(openvdb::ValueError, "processGrid: Unsupported value type");
658 }
659 { // set affine map
660 if (openGrid.hasUniformVoxels()) {
661 data->mVoxelSize = nanovdb::Vec3R(affineMap->voxelSize()[0]);
662 } else {
663 data->mVoxelSize = affineMap->voxelSize();
664 }
665 const auto mat = affineMap->getMat4();
666 // Only support non-tapered at the moment:
667 data->mMap.set(mat, mat.inverse(), 1.0);
668 }
669
670 this->processTree(openGrid.tree());// calls processRoot
671
672 if (auto size = mBlindMetaData.size()) {
673 auto *metaData = this->processMetadata(openGrid);
674 data->mBlindMetadataOffset = PtrDiff(metaData, nanoGrid);
675 data->mBlindMetadataCount = static_cast<uint32_t>(size);
676 auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
677 metaData->setBlindData(blindData);
678 }
679 return nanoGrid;
680}// OpenToNanoVDB::processGrid
681
682//================================================================================================
683
684template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
685NanoTree<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
686 processTree(const OpenTreeT& openTree)
687{
688 auto *nanoTree = reinterpret_cast<NanoTreeT*>(mBufferPtr + mBufferOffsets[1]);
689 auto *data = nanoTree->data();
690
691 data->setRoot( this->processRoot( openTree.root()) );
692
693 NanoUpperT *nanoUpper = mArray2.empty() ? nullptr : reinterpret_cast<NanoUpperT*>(mBufferPtr + mBufferOffsets[3]);
694 data->setFirstNode(nanoUpper);
695
696 NanoLowerT *nanoLower = mArray1.empty() ? nullptr : reinterpret_cast<NanoLowerT*>(mBufferPtr + mBufferOffsets[4]);
697 data->setFirstNode(nanoLower);
698
699 NanoLeafT *nanoLeaf = mArray0.empty() ? nullptr : reinterpret_cast<NanoLeafT*>(mBufferPtr + mBufferOffsets[5]);
700 data->setFirstNode(nanoLeaf);
701
702 data->mNodeCount[0] = mArray0.size();
703 data->mNodeCount[1] = mArray1.size();
704 data->mNodeCount[2] = mArray2.size();
705
706#if 1// count active tiles and voxels
707
708 // Count number of active leaf level tiles
709 data->mTileCount[0] = reduce(mArray1, uint32_t(0), [&](auto &r, uint32_t sum){
710 for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray1[i].node->getValueMask().countOn();
711 return sum;}, std::plus<uint32_t>());
712
713 // Count number of active lower internal node tiles
714 data->mTileCount[1] = reduce(mArray2, uint32_t(0), [&](auto &r, uint32_t sum){
715 for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray2[i].node->getValueMask().countOn();
716 return sum;}, std::plus<uint32_t>());
717
718 // Count number of active upper internal node tiles
719 uint32_t sum = 0;
720 for (auto it = openTree.root().cbeginValueOn(); it; ++it) ++sum;
721 data->mTileCount[2] = sum;
722
723 data->mVoxelCount = reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum){
724 for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->valueMask().countOn();
725 return sum;}, std::plus<uint64_t>());
726
727 data->mVoxelCount += data->mTileCount[0]*NanoLeafT::NUM_VALUES;
728 data->mVoxelCount += data->mTileCount[1]*NanoLowerT::NUM_VALUES;
729 data->mVoxelCount += data->mTileCount[2]*NanoUpperT::NUM_VALUES;
730
731#else
732
733 data->mTileCount[0] = 0;
734 data->mTileCount[1] = 0;
735 data->mTileCount[2] = 0;
736 data->mVoxelCount = 0;
737
738#endif
739
740 return nanoTree;
741}// OpenToNanoVDB::processTree
742
743//================================================================================================
744
745template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
746NanoRoot<NanoBuildT>* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
747 processRoot(const OpenRootT& openRoot)
748{
749 auto *nanoRoot = reinterpret_cast<NanoRootT*>(mBufferPtr + mBufferOffsets[2]);
750 auto* data = nanoRoot->data();
751 data->mBackground = openRoot.background();
752 data->mTableSize = 0;// incremented below
753 data->mMinimum = data->mMaximum = data->mBackground;
754 data->mBBox.min() = openvdb::Coord::max(); // set to an empty bounding box
755 data->mBBox.max() = openvdb::Coord::min();
756
757 OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
758 for (auto iter = openRoot.cbeginChildAll(); iter; ++iter) {
759 auto* tile = data->tile(data->mTableSize++);
760 if (const OpenUpperT *openChild = iter.probeChild( value )) {
761 tile->setChild(iter.getCoord(), this->decode(openChild), data);
762 } else {
763 tile->setValue(iter.getCoord(), iter.isValueOn(), value);
764 }
765 }
766 return nanoRoot;
767} // OpenToNanoVDB::processRoot
768
769//================================================================================================
770
771template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
772template<typename OpenNodeT>
773 void OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
774 processNodes(std::vector<NodePair<OpenNodeT>>& openNodes)
775{
776 using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
777 static_assert(NanoNodeT::LEVEL == 1 || NanoNodeT::LEVEL == 2, "Expected internal node");
778 auto kernel = [&](const Range1D& r) {
779 uint8_t* ptr = mBufferPtr + mBufferOffsets[5 - NanoNodeT::LEVEL];// 3 or 4
780 OpenValueT value = openvdb::zeroVal<OpenValueT>();// to avoid compiler warning
781 for (auto i = r.begin(); i != r.end(); ++i) {
782 auto *openNode = openNodes[i].node;
783 auto *nanoNode = PtrAdd<NanoNodeT>(ptr, openNodes[i].offset);
784 auto* data = nanoNode->data();
785 this->encode(openNode, nanoNode);
786 data->mValueMask = openNode->getValueMask(); // copy value mask
787 data->mChildMask = openNode->getChildMask(); // copy child mask
788 for (auto iter = openNode->cbeginChildAll(); iter; ++iter) {
789 if (const auto *openChild = iter.probeChild(value)) {
790 data->setChild(iter.pos(), this->decode(openChild));
791 } else {
792 data->setValue(iter.pos(), value);
793 }
794 }
795 }
796 };
797 forEach(openNodes, 1, kernel);
798} // OpenToNanoVDB::processNodes
799
800//================================================================================================
801
802template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
803template<typename T>
804inline typename std::enable_if<!std::is_same<typename OpenGridType<openvdb::ValueMask>::LeafT, typename T::OpenNodeT>::value &&
805 !std::is_same<typename OpenGridType<bool>::LeafT, typename T::OpenNodeT>::value &&
806 !std::is_same<Fp4, typename T::NanoNodeT::BuildType>::value &&
807 !std::is_same<Fp8, typename T::NanoNodeT::BuildType>::value &&
808 !std::is_same<Fp16,typename T::NanoNodeT::BuildType>::value &&
809 !std::is_same<FpN, typename T::NanoNodeT::BuildType>::value>::type
810 OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<T>& openLeafs)
811{
812 auto kernel = [&](const auto& r) {
813 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
814 for (auto i = r.begin(); i != r.end(); ++i) {
815 auto *openLeaf = openLeafs[i].node;
816 auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
817 auto* data = nanoLeaf->data();
818 this->encode(openLeaf, nanoLeaf);
819 data->mFlags = 0u;
820 data->mValueMask = openLeaf->valueMask(); // copy value mask
821 auto *src = reinterpret_cast<const NanoValueT*>(openLeaf->buffer().data());
822 for (NanoValueT *dst = data->mValues, *end = dst + OpenLeafT::size(); dst != end; dst += 4, src += 4) {
823 dst[0] = src[0]; // copy *all* voxel values in sets of four, i.e. loop-unrolling
824 dst[1] = src[1];
825 dst[2] = src[2];
826 dst[3] = src[3];
827 }
828 }
829 };
830 forEach(openLeafs, 8, kernel);
831} // OpenToNanoVDB::processLeafs<T>
832
833//================================================================================================
834
835template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
836template<typename T>
837inline typename std::enable_if<std::is_same<Fp4, typename T::NanoNodeT::BuildType>::value ||
838 std::is_same<Fp8, typename T::NanoNodeT::BuildType>::value ||
839 std::is_same<Fp16, typename T::NanoNodeT::BuildType>::value>::type
840OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<T>& openLeafs)
841{
842 using ArrayT = typename NanoLeafT::DataType::ArrayType;
843 using FloatT = typename std::conditional<NanoLeafT::DataType::bitWidth()>=16, double, float>::type;// 16 compression and higher requires double
844 DitherLUT lut(mDitherOn);
845
846 auto kernel = [&](const auto& r) {
847 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
848 for (auto i = r.begin(); i != r.end(); ++i) {
849 auto *openLeaf = openLeafs[i].node;
850 auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
851 auto* data = nanoLeaf->data();
852 this->encode(openLeaf, nanoLeaf);
853 data->mFlags = 0u;
854 data->mValueMask = openLeaf->valueMask(); // copy value mask
855 auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
856 // compute extrema values
857 float min = std::numeric_limits<float>::max(), max = -min;
858 for (int i=0; i<512; ++i) {
859 const float v = src[i];
860 if (v < min) min = v;
861 if (v > max) max = v;
862 }
863 data->init(min, max, NanoLeafT::DataType::bitWidth());
864 // perform quantization relative to the values in the curret leaf node
865 const FloatT encode = FloatT((1 << NanoLeafT::DataType::bitWidth()) - 1)/(max-min);
866 auto *code = reinterpret_cast<ArrayT*>(data->mCode);
867 int offset = 0;
868 if (std::is_same<Fp4, NanoBuildT>::value) {// resolved at compile-time
869 for (int i=0; i<128; ++i) {
870 auto tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
871 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
872 tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
873 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
874 }
875 } else {
876 for (int i=0; i<128; ++i) {
877 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
878 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
879 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
880 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
881 }
882 }
883 }
884 };
885 forEach(openLeafs, 8, kernel);
886} // OpenToNanoVDB::processLeafs<Fp4, Fp8, Fp16>
887
888//================================================================================================
889
890template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
891template<typename T>
892inline typename std::enable_if<std::is_same<FpN, typename T::NanoNodeT::BuildType>::value>::type
893OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<T>& openLeafs)
894{
895 static_assert(is_same<float, OpenBuildT>::value, "Expected OpenBuildT == float");
896
897 DitherLUT lut(mDitherOn);
898 auto kernel = [&](const auto& r) {
899 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
900 for (auto i = r.begin(); i != r.end(); ++i) {
901 auto *openLeaf = openLeafs[i].node;
902 auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
903 auto* data = nanoLeaf->data();
904 this->encode(openLeaf, nanoLeaf);
905 const uint8_t logBitWidth = uint8_t(mCodec[i].log2);
906 data->mFlags = logBitWidth << 5;// pack logBitWidth into 3 MSB of mFlag
907 data->mValueMask = openLeaf->valueMask(); // copy value mask
908 auto *src = reinterpret_cast<const float*>(openLeaf->buffer().data());
909 const float min = mCodec[i].min, max = mCodec[i].max;
910 data->init(min, max, uint8_t(1) << logBitWidth);
911 // perform quantization relative to the values in the curret leaf node
912 int offset = 0;
913 switch (logBitWidth) {
914 case 0u: {// 1 bit
915 auto *dst = reinterpret_cast<uint8_t*>(data+1);
916 const float encode = 1.0f/(max - min);
917 for (int j=0; j<64; ++j) {
918 uint8_t a = 0;
919 for (int k=0; k<8; ++k) {
920 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << k;
921 }
922 *dst++ = a;
923 }
924 }
925 break;
926 case 1u: {// 2 bits
927 auto *dst = reinterpret_cast<uint8_t*>(data+1);
928 const float encode = 3.0f/(max - min);
929 for (int j=0; j<128; ++j) {
930 auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
931 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 2;
932 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 4;
933 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 6 | a;
934 }
935 }
936 break;
937 case 2u: {// 4 bits
938 auto *dst = reinterpret_cast<uint8_t*>(data+1);
939 const float encode = 15.0f/(max - min);
940 for (int j=0; j<128; ++j) {
941 auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
942 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
943 a = uint8_t(encode * (*src++ - min) + lut(offset++));
944 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
945 }
946 }
947 break;
948 case 3u: {// 8 bits
949 auto *dst = reinterpret_cast<uint8_t*>(data+1);
950 const float encode = 255.0f/(max - min);
951 for (int j=0; j<128; ++j) {
952 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
953 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
954 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
955 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
956 }
957 }
958 break;
959 default: {// 16 bits
960 auto *dst = reinterpret_cast<uint16_t*>(data+1);
961 const double encode = 65535.0/(max - min);// note that double is required!
962 for (int j=0; j<128; ++j) {
963 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
964 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
965 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
966 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
967 }
968 }
969 }// end switch
970 }
971 };// kernel
972 forEach(openLeafs, 8, kernel);
973} // OpenToNanoVDB::processLeafs<FpN>
974
975//================================================================================================
976
977template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
978template<typename T>
979inline typename std::enable_if<std::is_same<T, typename OpenGridType<bool>::LeafT>::value>::type
980OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<NodePair<T>>& openLeafs)
981{
982 auto kernel = [&](const auto& r) {
983 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
984 for (auto i = r.begin(); i != r.end(); ++i) {
985 auto *openLeaf = openLeafs[i].node;
986 auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
987 auto* data = nanoLeaf->data();
988 this->encode(openLeaf, nanoLeaf);
989 data->mFlags = 0u;
990 data->mValueMask = openLeaf->valueMask(); // copy value mask
991 data->mValues = *reinterpret_cast<const nanovdb::Mask<3>*>(openLeaf->buffer().data()); // copy values
992 }
993 };
994 forEach(openLeafs, 8, kernel);
995} // OpenToNanoVDB::processLeafs<bool>
996
997//================================================================================================
998
999template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1000template<typename T>
1001inline typename std::enable_if<std::is_same<T, typename OpenGridType<openvdb::ValueMask>::LeafT>::value>::type
1002OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processLeafs(std::vector<NodePair<T>>& openLeafs)
1003{
1004 auto kernel = [&](const auto& r) {
1005 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1006 for (auto i = r.begin(); i != r.end(); ++i) {
1007 auto *openLeaf = openLeafs[i].node;
1008 auto *nanoLeaf = PtrAdd<NanoLeafT>(ptr, openLeafs[i].offset);
1009 auto* data = nanoLeaf->data();
1010 this->encode(openLeaf, nanoLeaf);
1011 data->mFlags = 0u;
1012 data->mValueMask = openLeaf->valueMask(); // copy value mask
1013 }
1014 };
1015 forEach(openLeafs, 8, kernel);
1016} // OpenToNanoVDB::processLeafs<ValueMask>
1017
1018//================================================================================================
1019
1020template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1021uint64_t OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::pointCount()
1022{
1023 return reduce(mArray0, uint64_t(0), [&](auto &r, uint64_t sum) {
1024 for (auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i].node->getLastValue();
1025 return sum;}, std::plus<uint64_t>());
1026}// OpenToNanoVDB::pointCount
1027
1028//================================================================================================
1029
1030/// @brief Performs: nanoNode.origin = openNode.origin
1031/// openNode.origin = nanoNode offset
1032template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1033template <typename OpenNodeT, typename NanoNodeT>
1034inline void OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1035encode(const OpenNodeT *openNode, NanoNodeT *nanoNode)
1036{
1037 static_assert(is_same<NanoNodeT, typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type>::value, "Type mismatch");
1038 openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1039 nanoNode->data()->setOrigin(ijk);
1040 reinterpret_cast<int64_t&>(ijk) = PtrDiff(nanoNode, mBufferPtr);
1041}// OpenToNanoVDB::encode
1042
1043//================================================================================================
1044
1045/// @brief Performs: nanoNode offset = openNode.origin
1046/// openNode.origin = nanoNode.origin
1047/// return nanoNode offset
1048template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1049template <typename OpenNodeT>
1050inline typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type* OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1051decode(const OpenNodeT *openNode)
1052{
1053 using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1054 openvdb::Coord &ijk = const_cast<openvdb::Coord&>(openNode->origin());
1055 NanoNodeT *nanoNode = PtrAdd<NanoNodeT>(mBufferPtr, reinterpret_cast<int64_t&>(ijk));
1056 Coord tmp = nanoNode->origin();
1057 ijk[0] = tmp[0];
1058 ijk[1] = tmp[1];
1059 ijk[2] = tmp[2];
1060 return nanoNode;
1061}// OpenToNanoVDB::decode
1062
1063//================================================================================================
1064
1065template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1066template <typename NodeT>
1067struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::NodePair {
1068 using OpenNodeT = NodeT;
1069 using NanoNodeT = typename NanoNode<NanoBuildT, OpenNodeT::LEVEL>::Type;
1070 NodePair(const NodeT *ptr, size_t n) : node(ptr), offset(n) {}
1071 const NodeT *node;// pointer to OpenVDB node
1072 uint64_t offset;// byte offset to matching NanoVDB node, relative to the first
1073};// OpenToNanoVDB::NodePair
1074
1075//================================================================================================
1076
1077template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1078 struct OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::BlindMetaData
1079{
1080 BlindMetaData(const std::string& n, const std::string& t, size_t i, size_t c, size_t s)
1081 : name(n)
1082 , typeName(t)
1083 , index(i)
1084 , count(c)
1085 , size(AlignUp<NANOVDB_DATA_ALIGNMENT>(c * s))
1086 {
1087 }
1088 const std::string name, typeName;
1089 const size_t index, count, size;
1090 bool operator<(const BlindMetaData& other) const { return index < other.index; } // required by std::set
1091}; // OpenToNanoVDB::BlindMetaData
1092
1093//================================================================================================
1094
1095template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1096template <typename T>
1097inline typename std::enable_if<!std::is_same<T, openvdb::tools::PointIndexGrid>::value &&
1098 !std::is_same<T, openvdb::points::PointDataGrid>::value>::type
1099 OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::preProcessMetadata(const T& openGrid)
1100{
1101 mBlindMetaData.clear();
1102 const size_t length = openGrid.getName().length();
1103 if (length >= GridData::MaxNameSize) {
1104 mBlindMetaData.emplace("grid name", "uint8_t", 0, 1, length + 1);// Null-terminated byte strings
1105 }
1106}// OpenToNanoVDB::preProcessMetadata<T>
1107
1108//================================================================================================
1109
1110template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1111template <typename T>
1112inline typename std::enable_if<std::is_same<T, openvdb::tools::PointIndexGrid>::value>::type
1113OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::preProcessMetadata(const T& openGrid)
1114{
1115 mBlindMetaData.clear();
1116 if (const uint64_t pointCount = this->pointCount()) {
1117 mBlindMetaData.emplace("index", "uint32_t", 0, pointCount, sizeof(uint32_t));
1118 }
1119 const size_t length = openGrid.getName().length();
1120 if (length >= GridData::MaxNameSize) {
1121 mBlindMetaData.emplace("grid name", "uint8_t", mBlindMetaData.size(), 1, length + 1);// Null-terminated byte strings
1122 }
1123}// OpenToNanoVDB::preProcessMetadata<PointIndexGrid>
1124
1125//================================================================================================
1126
1127template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1128template <typename T>
1129inline typename std::enable_if<std::is_same<T, openvdb::points::PointDataGrid>::value>::type
1130OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::preProcessMetadata(const T& openGrid)
1131{
1132 mBlindMetaData.clear();
1133 size_t counter = 0;
1134 if (const uint64_t pointCount = this->pointCount()) {
1135 auto *openLeaf = openGrid.tree().cbeginLeaf().getLeaf();
1136 const auto& attributeSet = openLeaf->attributeSet();
1137 const auto& descriptor = attributeSet.descriptor();
1138 const auto& nameMap = descriptor.map();
1139 for (auto it = nameMap.begin(); it != nameMap.end(); ++it) {
1140 const size_t index = it->second;
1141 auto& attArray = openLeaf->constAttributeArray(index);
1142 mBlindMetaData.emplace(it->first, descriptor.valueType(index), index, pointCount, attArray.valueTypeSize());
1143 }
1144 counter += nameMap.size();
1145 }
1146 const size_t length = openGrid.getName().length();
1147 if (length >= GridData::MaxNameSize) {
1148 mBlindMetaData.emplace("grid name", "uint8_t", counter, 1, length + 1);// Null-terminated byte strings
1149 }
1150}// OpenToNanoVDB::preProcessMetadata<PointDataGrid>
1151
1152//================================================================================================
1153
1154template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1155template<typename T>
1156inline typename std::enable_if<!std::is_same<T, openvdb::tools::PointIndexGrid>::value &&
1157 !std::is_same<T, openvdb::points::PointDataGrid>::value,GridBlindMetaData*>::type
1158OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1159 processMetadata(const T& openGrid)
1160{
1161 if (mBlindMetaData.empty()) {
1162 return nullptr;
1163 }
1164 assert(mBlindMetaData.size() == 1);// only the grid name is expected
1165 auto it = mBlindMetaData.cbegin();
1166 assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 0);
1167 assert(openGrid.getName().length() >= GridData::MaxNameSize);
1168 auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1169 auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1170 // write the blind meta data
1171 metaData->setBlindData(blindData);
1172 metaData->mElementCount = it->count;
1173 metaData->mFlags = 0;
1174 metaData->mSemantic = GridBlindDataSemantic::Unknown;
1175 metaData->mDataClass = GridBlindDataClass::GridName;
1176 metaData->mDataType = GridType::Unknown;
1177 // write the actual bind data
1178 strcpy(blindData, openGrid.getName().c_str());
1179 return metaData;
1180}// OpenToNanoVDB::processMetadata<T>
1181
1182//================================================================================================
1183
1184template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1185template<typename T>
1186inline typename std::enable_if<std::is_same<T, openvdb::tools::PointIndexGrid>::value,GridBlindMetaData*>::type
1187OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processMetadata(const T& openGrid)
1188{
1189 if (mBlindMetaData.empty()) {
1190 return nullptr;
1191 }
1192 assert(mBlindMetaData.size() == 1 || mBlindMetaData.size() == 2);// point index and maybe long grid name
1193 auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1194 auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1195
1196 auto it = mBlindMetaData.cbegin();
1197 const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1198
1199 using LeafDataT = typename NanoLeafT::DataType;
1200 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1201
1202 auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1203 data0->mMinimum = 0; // start of prefix sum
1204 data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1205 for (uint32_t i = 1; i < leafCount; ++i) {
1206 auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1207 data1->mMinimum = data0->mMinimum + data0->mMaximum;
1208 data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1209 data0 = data1;
1210 }
1211
1212 // write blind meta data for the point offsets
1213 assert(it->count == data0->mMinimum + data0->mMaximum);
1214 assert(it->name == "index" && it->typeName == "uint32_t" && it->index == 0);
1215 metaData[0].setBlindData( blindData );
1216 metaData[0].mElementCount = it->count;
1217 metaData[0].mFlags = 0;
1218 metaData[0].mSemantic = GridBlindDataSemantic::Unknown;
1219 metaData[0].mDataClass = GridBlindDataClass::IndexArray;
1220 metaData[0].mDataType = GridType::UInt32;
1221 if (it->name.length() >= GridBlindMetaData::MaxNameSize) {
1222 std::stringstream ss;
1223 ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1224 OPENVDB_THROW(openvdb::ValueError, ss.str());
1225 }
1226 memcpy(metaData[0].mName, it->name.c_str(), it->name.size() + 1);
1227
1228 // write point offsets as blind data
1229 forEach(mArray0, 16, [&](const auto& r) {
1230 for (auto i = r.begin(); i != r.end(); ++i) {
1231 auto *data = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1232 uint32_t* p = reinterpret_cast<uint32_t*>(blindData) + data->mMinimum;
1233 for (uint32_t idx : mArray0[i].node->indices()) *p++ = idx;
1234 }
1235 });
1236 blindData += it->size;// add point offsets
1237
1238 // write long grid name if it exists
1239 ++it;
1240 if (it != mBlindMetaData.end()) {
1241 assert(it->name == "grid name" && it->typeName == "uint8_t" && it->index == 1);
1242 assert(openGrid.getName().length() >= GridData::MaxNameSize);
1243 metaData[1].setBlindData( blindData );
1244 metaData[1].mElementCount = it->count;
1245 metaData[1].mFlags = 0;
1246 metaData[1].mSemantic = GridBlindDataSemantic::Unknown;
1247 metaData[1].mDataClass = GridBlindDataClass::GridName;
1248 metaData[1].mDataType = GridType::Unknown;
1249 strcpy(blindData, openGrid.getName().c_str());
1250 }
1251 return metaData;
1252}// OpenToNanoVDB::processMetadata<PointIndex32>
1253
1254//================================================================================================
1255
1256template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1257template<typename T>
1258inline typename std::enable_if<std::is_same<T, openvdb::points::PointDataGrid>::value,GridBlindMetaData*>::type
1259OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::processMetadata(const T& openGrid)
1260{
1261 if (mBlindMetaData.empty()) {
1262 return nullptr;
1263 }
1264
1265 auto *metaData = reinterpret_cast<GridBlindMetaData*>(mBufferPtr + mBufferOffsets[6]);
1266 auto *blindData = reinterpret_cast<char*>(mBufferPtr + mBufferOffsets[7]);
1267
1268 const uint32_t leafCount = static_cast<uint32_t>(mArray0.size());
1269
1270 using LeafDataT = typename NanoLeafT::DataType;
1271 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1272
1273 auto *data0 = reinterpret_cast<LeafDataT*>(ptr + mArray0[0].offset);
1274 data0->mMinimum = 0; // start of prefix sum
1275 data0->mMaximum = data0->mValues[NanoLeafT::SIZE - 1u];
1276 for (uint32_t i = 1; i < leafCount; ++i) {
1277 auto *data1 = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1278 data1->mMinimum = data0->mMinimum + data0->mMaximum;
1279 data1->mMaximum = data1->mValues[NanoLeafT::SIZE - 1u];
1280 data0 = data1;
1281 }
1282
1283 size_t i=0;
1284 for (auto it = mBlindMetaData.cbegin(); it != mBlindMetaData.end(); ++it, ++i) {
1285 metaData[i].setBlindData( blindData );
1286 metaData[i].mElementCount = it->count;
1287 metaData[i].mFlags = 0;
1288 if (it->name == "grid name") {
1289 metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1290 metaData[i].mDataClass = GridBlindDataClass::GridName;
1291 metaData[i].mDataType = GridType::Unknown;
1292 assert(openGrid.getName().length() >= GridData::MaxNameSize);
1293 strcpy((char*)blindData, openGrid.getName().c_str());
1294 } else {
1295 assert(it->count == data0->mMinimum + data0->mMaximum);
1296 metaData[i].mDataClass = GridBlindDataClass::AttributeArray;
1297 if (it->name.length()>= GridBlindMetaData::MaxNameSize) {
1298 std::stringstream ss;
1299 ss << "Point attribute name \"" << it->name << "\" is more than " << (GridBlindMetaData::MaxNameSize-1) << " characters";
1300 OPENVDB_THROW(openvdb::ValueError, ss.str());
1301 }
1302
1303 memcpy(metaData[i].mName, it->name.c_str(), it->name.size() + 1);
1304 if (it->typeName == "vec3s") {
1305 metaData[i].mDataType = GridType::Vec3f;
1306 this->copyPointAttribute(it->index, (openvdb::Vec3f*)blindData);
1307 if (it->name == "P") {
1308 metaData[i].mSemantic = GridBlindDataSemantic::PointPosition;
1309 } else if (it->name == "V") {
1310 metaData[i].mSemantic = GridBlindDataSemantic::PointVelocity;
1311 } else if (it->name == "Cd") {
1312 metaData[i].mSemantic = GridBlindDataSemantic::PointColor;
1313 } else if (it->name == "N") {
1314 metaData[i].mSemantic = GridBlindDataSemantic::PointNormal;
1315 } else {
1316 metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1317 }
1318 } else if (it->typeName == "int32") {
1319 metaData[i].mDataType = GridType::Int32;
1320 this->copyPointAttribute(it->index, (int32_t*)blindData);
1321 if (it->name == "id") {
1322 metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1323 } else {
1324 metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1325 }
1326 } else if (it->typeName == "int64") {
1327 metaData[i].mDataType = GridType::Int64;
1328 this->copyPointAttribute(it->index, (int64_t*)blindData);
1329 if (it->name == "id") {
1330 metaData[i].mSemantic = GridBlindDataSemantic::PointId;
1331 } else {
1332 metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1333 }
1334 } else if (it->typeName == "float") {
1335 metaData[i].mDataType = GridType::Float;
1336 metaData[i].mSemantic = GridBlindDataSemantic::Unknown;
1337 this->copyPointAttribute(it->index, (float*)blindData);
1338 } else {
1339 std::stringstream ss;
1340 ss << "Unsupported point attribute type: \"" << it->typeName << "\"";
1341 OPENVDB_THROW(openvdb::ValueError, ss.str());
1342 }
1343 }
1344 blindData += it->size;
1345 } // loop over bind data
1346 return metaData;
1347}// OpenToNanoVDB::processMetadata<PointDataIndex32>
1348
1349//================================================================================================
1350
1351
1352template<typename OpenBuildT, typename NanoBuildT, typename OracleT, typename BufferT>
1353template<typename AttT, typename CodecT>
1354inline void OpenToNanoVDB<OpenBuildT, NanoBuildT, OracleT, BufferT>::
1355 copyPointAttribute(size_t attIdx, AttT *attPtr)
1356{
1357 static_assert(std::is_same<typename OpenLeafT::ValueType, openvdb::PointDataIndex32>::value, "Expected value to openvdb::PointData");
1358 using LeafDataT = typename NanoLeafT::DataType;
1359 using HandleT = openvdb::points::AttributeHandle<AttT, CodecT>;
1360 forEach(mArray0, 16, [&](const auto& r) {
1361 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
1362 for (auto i = r.begin(); i != r.end(); ++i) {
1363 auto* openLeaf = mArray0[i].node;
1364 auto *nanoData = reinterpret_cast<LeafDataT*>(ptr + mArray0[i].offset);
1365 HandleT handle(openLeaf->constAttributeArray(attIdx));
1366 AttT* p = attPtr + nanoData->mMinimum;
1367 for (auto iter = openLeaf->beginIndexOn(); iter; ++iter) {
1368 *p++ = handle.get(*iter);
1369 }
1370 }
1371 });
1372}// OpenToNanoVDB::copyPointAttribute
1373
1374//================================================================================================
1375
1376template<typename BufferT, typename OpenTreeT, typename NanoBuildT>
1377GridHandle<BufferT>
1378openToNanoVDB(const openvdb::Grid<OpenTreeT>& grid,
1379 StatsMode sMode,
1380 ChecksumMode cMode,
1381 int verbose)
1382{
1383 using OpenBuildT = typename OpenTreeT::BuildType;
1384 OpenToNanoVDB<OpenBuildT, NanoBuildT, AbsDiff, BufferT> s;
1385 return s(grid, sMode, cMode, verbose);
1386}// openToNanoVDB
1387
1388//================================================================================================
1389
1390template<typename BufferT>
1391GridHandle<BufferT>
1392 openToNanoVDB(const openvdb::GridBase::Ptr& base,
1393 StatsMode sMode,
1394 ChecksumMode cMode,
1395 int verbose)
1396{
1397 // We need to define these types because they are not defined in OpenVDB
1398 using openvdb_Vec4fTree = typename openvdb::tree::Tree4<openvdb::Vec4f, 5, 4, 3>::Type;
1399 using openvdb_Vec4dTree = typename openvdb::tree::Tree4<openvdb::Vec4d, 5, 4, 3>::Type;
1400 using openvdb_Vec4fGrid = openvdb::Grid<openvdb_Vec4fTree>;
1401 using openvdb_Vec4dGrid = openvdb::Grid<openvdb_Vec4dTree>;
1402
1403 if (auto grid = openvdb::GridBase::grid<openvdb::FloatGrid>(base)) {
1404 return openToNanoVDB<BufferT, openvdb::FloatTree>(*grid, sMode, cMode, verbose);
1405 } else if (auto grid = openvdb::GridBase::grid<openvdb::DoubleGrid>(base)) {
1406 return openToNanoVDB<BufferT, openvdb::DoubleTree>(*grid, sMode, cMode, verbose);
1407 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int32Grid>(base)) {
1408 return openToNanoVDB<BufferT, openvdb::Int32Tree>(*grid, sMode, cMode, verbose);
1409 } else if (auto grid = openvdb::GridBase::grid<openvdb::Int64Grid>(base)) {
1410 return openToNanoVDB<BufferT, openvdb::Int64Tree>(*grid, sMode, cMode, verbose);
1411 } else if (auto grid = openvdb::GridBase::grid<openvdb::Grid<openvdb::UInt32Tree>>(base)) {
1412 return openToNanoVDB<BufferT, openvdb::UInt32Tree>(*grid, sMode, cMode, verbose);
1413 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3fGrid>(base)) {
1414 return openToNanoVDB<BufferT, openvdb::Vec3fTree>(*grid, sMode, cMode, verbose);
1415 } else if (auto grid = openvdb::GridBase::grid<openvdb::Vec3dGrid>(base)) {
1416 return openToNanoVDB<BufferT, openvdb::Vec3dTree>(*grid, sMode, cMode, verbose);
1417 } else if (auto grid = openvdb::GridBase::grid<openvdb::tools::PointIndexGrid>(base)) {
1418 return openToNanoVDB<BufferT, openvdb::tools::PointIndexTree>(*grid, sMode, cMode, verbose);
1419 } else if (auto grid = openvdb::GridBase::grid<openvdb::points::PointDataGrid>(base)) {
1420 return openToNanoVDB<BufferT, openvdb::points::PointDataTree>(*grid, sMode, cMode, verbose);
1421 } else if (auto grid = openvdb::GridBase::grid<openvdb::MaskGrid>(base)) {
1422 return openToNanoVDB<BufferT, openvdb::MaskTree>(*grid, sMode, cMode, verbose);
1423 } else if (auto grid = openvdb::GridBase::grid<openvdb::BoolGrid>(base)) {
1424 return openToNanoVDB<BufferT, openvdb::BoolTree>(*grid, sMode, cMode, verbose);
1425 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4fGrid>(base)) {
1426 return openToNanoVDB<BufferT, openvdb_Vec4fTree>(*grid, sMode, cMode, verbose);
1427 } else if (auto grid = openvdb::GridBase::grid<openvdb_Vec4dGrid>(base)) {
1428 return openToNanoVDB<BufferT, openvdb_Vec4dTree>(*grid, sMode, cMode, verbose);
1429 } else {
1430 OPENVDB_THROW(openvdb::RuntimeError, "Unrecognized OpenVDB grid type");
1431 }
1432}// openToNanoVDB
1433
1434} // namespace nanovdb
1435
1436#endif // NANOVDB_OPENTONANOVDB_H_HAS_BEEN_INCLUDED
DitherLUT.h
Defines look up table to do dithering of 8^3 leaf nodes.
ForEach.h
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
GridBuilder.h
Generates a NanoVDB grid from any volume or function.
value
ValueT value
Definition: GridBuilder.h:1287
GridChecksum.h
Computes a pair of 32bit checksums, og a Grid, by means of Cyclic Redundancy Check (CRC)
GridHandle.h
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
GridStats.h
Re-computes min/max/avg/var/bbox information for each node in a pre-existing NanoVDB grid.
Invoke.h
A unified wrapper for tbb::parallel_invoke and a naive std::thread analog.
NANOVDB_DATA_ALIGNMENT
#define NANOVDB_DATA_ALIGNMENT
Definition: NanoVDB.h:116
NANOVDB_MAGIC_NUMBER
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:102
PointDataGrid.h
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Reduce.h
A unified wrapper for tbb::parallel_reduce and a naive std::future analog.
nanovdb::AbsDiff
Compression oracle based on absolute difference.
Definition: GridBuilder.h:39
nanovdb::Coord
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:860
nanovdb::GridHandle
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:71
nanovdb::Grid
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2308
nanovdb::HostBuffer
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition: HostBuffer.h:110
nanovdb::InternalNode
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3121
nanovdb::LeafNode
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:3684
nanovdb::Mask
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:1795
nanovdb::OpenToNanoVDB
This class will convert an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
Definition: OpenToNanoVDB.h:174
nanovdb::OpenToNanoVDB::setStats
void setStats(StatsMode mode=StatsMode::Default)
Definition: OpenToNanoVDB.h:225
nanovdb::OpenToNanoVDB::setChecksum
void setChecksum(ChecksumMode mode=ChecksumMode::Default)
Definition: OpenToNanoVDB.h:227
nanovdb::OpenToNanoVDB::enableDithering
void enableDithering(bool on=true)
Definition: OpenToNanoVDB.h:223
nanovdb::OpenToNanoVDB::oracle
OracleT & oracle()
return a reference to the compression oracle
Definition: OpenToNanoVDB.h:219
nanovdb::OpenToNanoVDB::setVerbose
void setVerbose(int mode=1)
Definition: OpenToNanoVDB.h:221
nanovdb::OpenToNanoVDB::operator()
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
nanovdb::OpenToNanoVDB::OpenToNanoVDB
OpenToNanoVDB()
Default c-tor.
Definition: OpenToNanoVDB.h:348
nanovdb::Range
Definition: Range.h:28
nanovdb::RootNode
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:2799
nanovdb::Tree
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2543
nanovdb::ValueMask
Dummy type for a voxel with a binary mask value, e.g. the active state.
Definition: NanoVDB.h:189
nanovdb::Vec3
A simple vector class with three double components, similar to openvdb::math::Vec3.
Definition: NanoVDB.h:1044
nanovdb::Vec4
A simple vector class with three double components, similar to openvdb::math::Vec4.
Definition: NanoVDB.h:1189
openvdb::v9_0::GridBase::grid
static GridType::Ptr grid(const GridBase::Ptr &)
Return the result of downcasting a GridBase pointer to a Grid pointer of the specified type,...
Definition: Grid.h:1202
openvdb::v9_0::GridBase::Ptr
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
openvdb::v9_0::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
openvdb::v9_0::Grid::TreeType
_TreeType TreeType
Definition: Grid.h:582
openvdb::v9_0::RuntimeError
Definition: Exceptions.h:63
openvdb::v9_0::ValueError
Definition: Exceptions.h:65
openvdb::v9_0::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:248
openvdb::v9_0::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
openvdb::v9_0::math::Coord::min
static Coord min()
Return the smallest possible coordinate.
Definition: Coord.h:43
openvdb::v9_0::math::Coord::max
static Coord max()
Return the largest possible coordinate.
Definition: Coord.h:46
openvdb::v9_0::math::Coord::data
const Int32 * data() const
Definition: Coord.h:139
openvdb::v9_0::math::Vec3
Definition: Vec3.h:24
nanovdb::io::Codec
Codec
Optional compression codecs.
Definition: IO.h:61
nanovdb
Definition: Camera.h:16
nanovdb::GridClass::FogVolume
@ FogVolume
nanovdb::GridClass::Unknown
@ Unknown
nanovdb::GridClass::Topology
@ Topology
nanovdb::GridClass::PointIndex
@ PointIndex
nanovdb::GridClass::PointData
@ PointData
nanovdb::GridClass::Staggered
@ Staggered
nanovdb::GridClass::LevelSet
@ LevelSet
nanovdb::GridType::Float
@ Float
nanovdb::GridType::Boolean
@ Boolean
nanovdb::GridType::Vec4f
@ Vec4f
nanovdb::GridType::Int16
@ Int16
nanovdb::GridType::Fp4
@ Fp4
nanovdb::GridType::Mask
@ Mask
nanovdb::GridType::Vec4d
@ Vec4d
nanovdb::GridType::Fp8
@ Fp8
nanovdb::GridType::Unknown
@ Unknown
nanovdb::GridType::FpN
@ FpN
nanovdb::GridType::Int32
@ Int32
nanovdb::GridType::Double
@ Double
nanovdb::GridType::UInt32
@ UInt32
nanovdb::GridType::Vec3f
@ Vec3f
nanovdb::GridType::Int64
@ Int64
nanovdb::GridType::Fp16
@ Fp16
nanovdb::GridFlags::IsBreadthFirst
@ IsBreadthFirst
nanovdb::Vec3R
Vec3< double > Vec3R
Definition: NanoVDB.h:1173
nanovdb::GridBlindDataClass::IndexArray
@ IndexArray
nanovdb::GridBlindDataClass::AttributeArray
@ AttributeArray
nanovdb::GridBlindDataClass::GridName
@ GridName
nanovdb::CoordBBox
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
nanovdb::StatsMode
StatsMode
Grid flags which indicate what extra information is present in the grid buffer.
Definition: GridStats.h:32
nanovdb::StatsMode::BBox
@ BBox
nanovdb::StatsMode::Default
@ Default
nanovdb::updateChecksum
void updateChecksum(NanoGrid< ValueT > &grid, ChecksumMode mode=ChecksumMode::Default)
Updates the checksum of a grid.
Definition: GridChecksum.h:272
nanovdb::openToNanoVDB
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:1378
nanovdb::PtrDiff
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition: NanoVDB.h:433
nanovdb::forEach
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
nanovdb::gridStats
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
nanovdb::reduce
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition: Reduce.h:41
nanovdb::ChecksumMode
ChecksumMode
List of different modes for computing for a checksum.
Definition: GridChecksum.h:33
nanovdb::ChecksumMode::Default
@ Default
nanovdb::GridBlindDataSemantic::PointPosition
@ PointPosition
nanovdb::GridBlindDataSemantic::PointColor
@ PointColor
nanovdb::GridBlindDataSemantic::PointVelocity
@ PointVelocity
nanovdb::GridBlindDataSemantic::Unknown
@ Unknown
nanovdb::GridBlindDataSemantic::PointNormal
@ PointNormal
nanovdb::GridBlindDataSemantic::PointId
@ PointId
nanovdb::openToNanoVDB
GridHandle< BufferT > openToNanoVDB(const openvdb::GridBase::Ptr &base, StatsMode sMode=StatsMode::Default, ChecksumMode cMode=ChecksumMode::Default, int verbose=0)
Forward declaration of free-standing function that converts an OpenVDB GridBase into a NanoVDB GridHa...
Definition: OpenToNanoVDB.h:1392
nanovdb::FloatTree
NanoTree< float > FloatTree
Definition: NanoVDB.h:3961
nanovdb::AlignUp
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
openvdb::v9_0::points::pointCount
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
openvdb::v9_0::points::PointDataGrid
Grid< PointDataTree > PointDataGrid
Point data grid.
Definition: PointDataGrid.h:194
openvdb::v9_0::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
openvdb::v9_0::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
openvdb::v9_0::tools::PointIndexGrid
Grid< PointIndexTree > PointIndexGrid
Point index grid.
Definition: PointIndexGrid.h:60
openvdb::v9_0::tools::memUsage
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:408
openvdb::v9_0::util::printBytes
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)
openvdb::v9_0::GRID_FOG_VOLUME
@ GRID_FOG_VOLUME
Definition: Types.h:338
openvdb::v9_0::GRID_STAGGERED
@ GRID_STAGGERED
Definition: Types.h:339
openvdb::v9_0::GRID_LEVEL_SET
@ GRID_LEVEL_SET
Definition: Types.h:337
openvdb::v9_0::PointIndex32
PointIndex< Index32, 0 > PointIndex32
Definition: Types.h:178
openvdb::v9_0::PointDataIndex32
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:181
openvdb
Definition: Exceptions.h:13
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
CpuTimer.h
openvdb.h
nanovdb::BBox< Coord >
nanovdb::BuildToValueMap
Maps one type (e.g. the build types above) to other (actual) types.
Definition: NanoVDB.h:383
nanovdb::GridBlindMetaData::memUsage
static uint64_t memUsage(uint64_t blindDataCount=0)
return memory usage in bytes for the class (note this computes for all blindMetaData structures....
Definition: NanoVDB.h:2079
nanovdb::GridBlindMetaData::MaxNameSize
static const int MaxNameSize
Definition: NanoVDB.h:2069
nanovdb::GridData::MaxNameSize
static const int MaxNameSize
Definition: NanoVDB.h:2186
nanovdb::NanoNode
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:3933
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::LeafT
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:150
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::RootT
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:147
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::TreeT
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:146
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::LowerT
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:149
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::UpperT
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:148
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::GridT
openvdb::points::PointDataGrid GridT
Definition: OpenToNanoVDB.h:145
nanovdb::OpenGridType< openvdb::PointDataIndex32 >::ValueT
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:151
nanovdb::OpenGridType< openvdb::PointIndex32 >::LeafT
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:137
nanovdb::OpenGridType< openvdb::PointIndex32 >::RootT
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:134
nanovdb::OpenGridType< openvdb::PointIndex32 >::TreeT
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:133
nanovdb::OpenGridType< openvdb::PointIndex32 >::LowerT
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:136
nanovdb::OpenGridType< openvdb::PointIndex32 >::UpperT
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:135
nanovdb::OpenGridType< openvdb::PointIndex32 >::ValueT
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:138
nanovdb::OpenGridType< openvdb::PointIndex32 >::GridT
openvdb::tools::PointIndexGrid GridT
Definition: OpenToNanoVDB.h:132
nanovdb::OpenGridType
Grid trait that defines OpenVDB grids with the exact same configuration as NanoVDB grids.
Definition: OpenToNanoVDB.h:118
nanovdb::OpenGridType::LeafT
typename LowerT::ChildNodeType LeafT
Definition: OpenToNanoVDB.h:124
nanovdb::OpenGridType::RootT
typename TreeT::RootNodeType RootT
Definition: OpenToNanoVDB.h:121
nanovdb::OpenGridType::TreeT
typename GridT::TreeType TreeT
Definition: OpenToNanoVDB.h:120
nanovdb::OpenGridType::LowerT
typename UpperT::ChildNodeType LowerT
Definition: OpenToNanoVDB.h:123
nanovdb::OpenGridType::UpperT
typename RootT::ChildNodeType UpperT
Definition: OpenToNanoVDB.h:122
nanovdb::OpenGridType::ValueT
typename LeafT::ValueType ValueT
Definition: OpenToNanoVDB.h:125
nanovdb::OpenToNanoType
Converts OpenVDB types to NanoVDB types, e.g. openvdb::Vec3f to nanovdb::Vec3f Template specializatio...
Definition: OpenToNanoVDB.h:37
nanovdb::OpenToNanoType::Type
T Type
Definition: OpenToNanoVDB.h:37
nanovdb::OpenToNanoVDB::BlindMetaData
Definition: OpenToNanoVDB.h:1079
nanovdb::OpenToNanoVDB::BlindMetaData::BlindMetaData
BlindMetaData(const std::string &n, const std::string &t, size_t i, size_t c, size_t s)
Definition: OpenToNanoVDB.h:1080
nanovdb::OpenToNanoVDB::BlindMetaData::operator<
bool operator<(const BlindMetaData &other) const
Definition: OpenToNanoVDB.h:1090
nanovdb::OpenToNanoVDB::BlindMetaData::index
const size_t index
Definition: OpenToNanoVDB.h:1089
nanovdb::OpenToNanoVDB::BlindMetaData::count
const size_t count
Definition: OpenToNanoVDB.h:1089
nanovdb::OpenToNanoVDB::BlindMetaData::name
const std::string name
Definition: OpenToNanoVDB.h:1088
nanovdb::is_floating_point::value
static const bool value
Definition: NanoVDB.h:357
nanovdb::is_same
C++11 implementation of std::is_same.
Definition: NanoVDB.h:327
nanovdb::is_same::value
static constexpr bool value
Definition: NanoVDB.h:328