17#ifndef NANOVDB_GRIDBUILDER_H_HAS_BEEN_INCLUDED
18#define NANOVDB_GRIDBUILDER_H_HAS_BEEN_INCLUDED
43 AbsDiff(
float tolerance = -1.0f) : mTolerance(tolerance) {}
54 return Abs(exact - approx) <= mTolerance;
70 RelDiff(
float tolerance = -1.0f) : mTolerance(tolerance) {}
81 return Abs(exact - approx)/
Max(
Abs(exact),
Abs(approx)) <= mTolerance;
92template<
typename ValueT,
typename BuildT = ValueT,
typename StatsT = Stats<ValueT>>
96 template<
typename ChildT>
98 template<
typename ChildT>
101 struct Codec {
float min, max; uint16_t log2, size;};
104 using SrcNode1 = BuildNode<SrcNode0>;
105 using SrcNode2 = BuildNode<SrcNode1>;
106 using SrcRootT = BuildRoot<SrcNode2>;
117 uint64_t mBufferOffsets[9];
119 uint64_t mBlindDataSize;
121 std::vector<SrcNode0*> mArray0;
122 std::vector<SrcNode1*> mArray1;
123 std::vector<SrcNode2*> mArray2;
124 std::unique_ptr<Codec[]> mCodec;
131 template<
typename OracleT,
typename BufferT>
134 template <
typename T,
typename OracleT>
135 inline typename std::enable_if<!is_same<T, FpN>::value>::type
136 compression(uint64_t&, OracleT) {}
138 template <
typename T,
typename OracleT>
139 inline typename std::enable_if<is_same<T, FpN>::value>::type
140 compression(uint64_t &offset, OracleT oracle);
143 typename std::enable_if<!is_same<Fp4, typename T::BuildType>::value &&
147 processLeafs(std::vector<T*>&);
150 typename std::enable_if<is_same<Fp4, typename T::BuildType>::value ||
153 processLeafs(std::vector<T*>&);
156 typename std::enable_if<is_same<FpN, typename T::BuildType>::value>::type
157 processLeafs(std::vector<T*>&);
159 template<
typename SrcNodeT>
160 void processNodes(std::vector<SrcNodeT*>&);
166 DstGridT* processGrid(
const Map&,
const std::string&);
168 template<
typename T,
typename FlagT>
169 typename std::enable_if<!std::is_floating_point<T>::value>::type
170 setFlag(
const T&,
const T&, FlagT& flag)
const { flag &= ~FlagT(1); }
172 template<
typename T,
typename FlagT>
173 typename std::enable_if<std::is_floating_point<T>::value>::type
174 setFlag(
const T& min,
const T& max, FlagT& flag)
const;
181 uint64_t blindDataSize = 0);
207 template<
typename OracleT = AbsDiff,
typename BufferT = HostBuffer>
210 const std::string& name =
"",
211 const OracleT& oracle = OracleT(),
212 const BufferT& buffer = BufferT());
215 template<
typename OracleT = AbsDiff,
typename BufferT = HostBuffer>
217 const std::string& name =
"",
218 const OracleT& oracle = OracleT(),
219 const BufferT& buffer = BufferT());
232 template<
typename Func>
239template<
typename ValueT,
typename BuildT,
typename StatsT>
244 , mBlindDataSize(blindDataSize)
253template<
typename ValueT,
typename BuildT,
typename StatsT>
254template<
typename Func>
258 static_assert(
is_same<ValueT,
typename std::result_of<Func(
const Coord&)>::type>
::value,
"GridBuilder: mismatched ValueType");
262 const CoordBBox leafBBox(voxelBBox[0] >> LeafT::TOTAL, voxelBBox[1] >> LeafT::TOTAL);
265 LeafT* leaf =
nullptr;
266 for (
auto it = b.begin(); it; ++it) {
267 Coord min(*it << LeafT::TOTAL), max(min +
Coord(LeafT::DIM - 1));
268 const CoordBBox bbox(min.maxComponent(voxelBBox.min()),
269 max.minComponent(voxelBBox.max()));
270 if (leaf ==
nullptr) {
271 leaf =
new LeafT(bbox[0], mRoot.mBackground,
false);
273 leaf->mOrigin = bbox[0] & ~LeafT::MASK;
276 leaf->mDstOffset = 0;
277 for (
auto ijk = bbox.begin(); ijk; ++ijk) {
278 const auto v = func(*ijk);
279 if (v == mRoot.mBackground) {
282 leaf->setValue(*ijk, v);
284 if (!leaf->mValueMask.isOff()) {
285 if (leaf->mValueMask.isOn()) {
286 const auto first = leaf->getFirstValue();
289 if (leaf->mValues[n++] != first)
break;
291 if (n == 512) leaf->mDstOffset = 1;
293 std::lock_guard<std::mutex> guard(mutex);
306 for (
auto it2 = mRoot.mTable.begin(); it2 != mRoot.mTable.end(); ++it2) {
307 if (
auto *upper = it2->second.child) {
308 for (
auto it1 = upper->mChildMask.beginOn(); it1; ++it1) {
309 auto *lower = upper->mTable[*it1].child;
310 for (
auto it0 = lower->mChildMask.beginOn(); it0; ++it0) {
311 auto *leaf = lower->mTable[*it0].child;
312 if (leaf->mDstOffset) {
313 lower->mTable[*it0].value = leaf->getFirstValue();
314 lower->mChildMask.setOff(*it0);
315 lower->mValueMask.setOn(*it0);
319 if (lower->mChildMask.isOff()) {
320 const auto first = lower->getFirstValue();
323 if (lower->mTable[n++].value != first)
break;
326 upper->mTable[*it1].value = first;
327 upper->mChildMask.setOff(*it1);
328 upper->mValueMask.setOn(*it1);
333 if (upper->mChildMask.isOff()) {
334 const auto first = upper->getFirstValue();
337 if (upper->mTable[n++].value != first)
break;
340 it2->second.value = first;
341 it2->second.state = upper->mValueMask.isOn();
342 it2->second.child =
nullptr;
352template<
typename ValueT,
typename BuildT,
typename StatsT>
353template<
typename OracleT,
typename BufferT>
355initHandle(
const OracleT &oracle,
const BufferT& buffer)
360 mArray0.reserve(mRoot.template nodeCount<SrcNode0>());
361 mArray1.reserve(mRoot.template nodeCount<SrcNode1>());
362 mArray2.reserve(mRoot.template nodeCount<SrcNode2>());
364 uint64_t offset[3] = {0};
365 for (
auto it2 = mRoot.mTable.begin(); it2 != mRoot.mTable.end(); ++it2) {
366 if (SrcNode2 *upper = it2->second.child) {
367 upper->mDstOffset = offset[2];
368 mArray2.emplace_back(upper);
369 offset[2] += DstNode2::memUsage();
370 for (
auto it1 = upper->mChildMask.beginOn(); it1; ++it1) {
371 SrcNode1 *lower = upper->mTable[*it1].child;
372 lower->mDstOffset = offset[1];
373 mArray1.emplace_back(lower);
374 offset[1] += DstNode1::memUsage();
375 for (
auto it0 = lower->mChildMask.beginOn(); it0; ++it0) {
376 SrcNode0 *leaf = lower->mTable[*it0].child;
377 leaf->mDstOffset = offset[0];
378 mArray0.emplace_back(leaf);
379 offset[0] +=
sizeof(DstNode0);
385 this->
template compression<BuildT, OracleT>(offset[0], oracle);
387 mBufferOffsets[0] = 0;
388 mBufferOffsets[1] = DstGridT::memUsage();
389 mBufferOffsets[2] = DstTreeT::memUsage();
390 mBufferOffsets[3] = DstRootT::memUsage(
static_cast<uint32_t
>(mRoot.mTable.size()));
391 mBufferOffsets[4] = offset[2];
392 mBufferOffsets[5] = offset[1];
393 mBufferOffsets[6] = offset[0];
395 mBufferOffsets[8] = mBlindDataSize;
398 for (
int i = 2; i < 9; ++i) {
399 mBufferOffsets[i] += mBufferOffsets[i - 1];
402 GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
403 mBufferPtr = handle.data();
409template<
typename ValueT,
typename BuildT,
typename StatsT>
410template <
typename T,
typename OracleT>
411inline typename std::enable_if<is_same<T, FpN>::value>::type
412GridBuilder<ValueT, BuildT, StatsT>::compression(uint64_t &offset, OracleT oracle)
418 static const float halfWidth = 3.0f;
419 oracle.setTolerance(0.1f * mRoot.mBackground / halfWidth);
421 oracle.setTolerance(0.01f);
423 oracle.setTolerance(0.0f);
427 const size_t size = mArray0.size();
428 mCodec.reset(
new Codec[size]);
430 DitherLUT lut(mDitherOn);
431 auto kernel = [&](
const Range1D &r) {
432 for (
auto i=r.begin(); i!=r.end(); ++i) {
433 const float *data = mArray0[i]->mValues;
434 float min = std::numeric_limits<float>::max(),
max = -
min;
435 for (
int j=0; j<512; ++j) {
442 const float range =
max -
min;
443 uint16_t logBitWidth = 0;
444 while (range > 0.0f && logBitWidth < 4u) {
445 const uint32_t mask = (uint32_t(1) << (uint32_t(1) << logBitWidth)) - 1u;
446 const float encode = mask/range;
447 const float decode = range/mask;
450 const float exact = data[j];
451 const uint32_t code = uint32_t(encode*(exact - min) + lut(j));
452 const float approx = code * decode +
min;
453 j += oracle(exact, approx) ? 1 : 513;
458 mCodec[i].log2 = logBitWidth;
459 mCodec[i].size = DstNode0::DataType::memUsage(1u << logBitWidth);
465 uint32_t counters[5+1] = {0};
466 ++counters[mCodec[0].log2];
467 for (
size_t i=1; i<size; ++i) {
468 ++counters[mCodec[i].log2];
469 mArray0[i]->mDstOffset = mArray0[i-1]->mDstOffset + mCodec[i-1].size;
471 std::cout <<
"\n" << oracle << std::endl;
472 std::cout <<
"Dithering: " << (mDitherOn ?
"enabled" :
"disabled") << std::endl;
474 for (uint32_t i=0; i<=5; ++i) {
475 if (uint32_t n = counters[i]) {
476 avg += n * float(1 << i);
477 printf(
"%2i bits: %6u leaf nodes, i.e. %4.1f%%\n",1<<i, n, 100.0f*n/
float(size));
480 printf(
"%4.1f bits per value on average\n", avg/
float(size));
482 for (
size_t i=1; i<size; ++i) {
483 mArray0[i]->mDstOffset = mArray0[i-1]->mDstOffset + mCodec[i-1].size;
486 offset = mArray0[size-1]->mDstOffset + mCodec[size-1].size;
491template<
typename ValueT,
typename BuildT,
typename StatsT>
498 mArray0.reserve(mRoot.template nodeCount<SrcNode0>());
499 mArray1.reserve(mRoot.template nodeCount<SrcNode1>());
500 mArray2.reserve(mRoot.template nodeCount<SrcNode2>());
502 for (
auto it2 = mRoot.mTable.begin(); it2 != mRoot.mTable.end(); ++it2) {
503 if (SrcNode2 *upper = it2->second.child) {
504 mArray2.emplace_back(upper);
505 for (
auto it1 = upper->mChildMask.beginOn(); it1; ++it1) {
506 SrcNode1 *lower = upper->mTable[*it1].child;
507 mArray1.emplace_back(lower);
508 for (
auto it0 = lower->mChildMask.beginOn(); it0; ++it0) {
509 mArray0.emplace_back(lower->mTable[*it0].child);
516 const ValueT outside = mRoot.mBackground;
518 for (
auto i = r.begin(); i != r.end(); ++i)
519 mArray0[i]->signedFloodFill(outside);
522 for (
auto i = r.begin(); i != r.end(); ++i)
523 mArray1[i]->signedFloodFill(outside);
526 for (
auto i = r.begin(); i != r.end(); ++i)
527 mArray2[i]->signedFloodFill(outside);
529 mRoot.signedFloodFill(outside);
535template<
typename ValueT,
typename BuildT,
typename StatsT>
536template<
typename OracleT,
typename BufferT>
540 const std::string& name,
541 const OracleT& oracle,
542 const BufferT& buffer)
545 throw std::runtime_error(
"GridBuilder: voxel size is zero or negative");
548 map.
set(dx, p0, 1.0);
549 return this->getHandle(map, name, oracle, buffer);
554template<
typename ValueT,
typename BuildT,
typename StatsT>
555template<
typename OracleT,
typename BufferT>
558 const std::string& name,
559 const OracleT& oracle,
560 const BufferT& buffer)
563 throw std::runtime_error(
"Level sets are expected to be floating point types");
565 throw std::runtime_error(
"Fog volumes are expected to be floating point types");
568 auto handle = this->
template initHandle<OracleT, BufferT>(oracle, buffer);
570 this->processLeafs(mArray0);
572 this->processNodes(mArray1);
574 this->processNodes(mArray2);
576 auto *grid = this->processGrid(map, name);
587template<
typename ValueT,
typename BuildT,
typename StatsT>
588template<
typename T,
typename FlagT>
589inline typename std::enable_if<std::is_floating_point<T>::value>::type
591 setFlag(
const T& min,
const T& max, FlagT& flag)
const
593 if (mDelta > 0 && (min > mDelta || max < -mDelta)) {
602template<
typename ValueT,
typename BuildT,
typename StatsT>
606 this->sdfToLevelSet();
608 const ValueT d = -mRoot.mBackground, w = 1.0f / d;
609 auto op = [&](ValueT& v) ->
bool {
614 v = v > d ? v * w : ValueT(1);
617 auto kernel0 = [&](
const Range1D& r) {
618 for (
auto i = r.begin(); i != r.end(); ++i) {
620 for (uint32_t i = 0; i < SrcNode0::SIZE; ++i)
624 auto kernel1 = [&](
const Range1D& r) {
625 for (
auto i = r.begin(); i != r.end(); ++i) {
626 SrcNode1* node = mArray1[i];
627 for (uint32_t i = 0; i < SrcNode1::SIZE; ++i) {
628 if (node->mChildMask.isOn(i)) {
629 SrcNode0* leaf = node->mTable[i].child;
632 node->mChildMask.setOff(i);
636 node->
mValueMask.set(i, op(node->mTable[i].value));
641 auto kernel2 = [&](
const Range1D& r) {
642 for (
auto i = r.begin(); i != r.end(); ++i) {
643 SrcNode2* node = mArray2[i];
644 for (uint32_t i = 0; i < SrcNode2::SIZE; ++i) {
645 if (node->mChildMask.isOn(i)) {
646 SrcNode1*
child = node->mTable[i].child;
647 if (
child->mChildMask.isOff() &&
child->mValueMask.isOff()) {
648 node->mTable[i].value =
child->getFirstValue();
649 node->mChildMask.setOff(i);
653 node->mValueMask.set(i, op(node->mTable[i].value));
662 for (
auto it = mRoot.mTable.begin(); it != mRoot.mTable.end(); ++it) {
663 SrcNode2*
child = it->second.child;
664 if (
child ==
nullptr) {
665 it->second.state = op(it->second.value);
666 }
else if (
child->mChildMask.isOff() &&
child->mValueMask.isOff()) {
667 it->second.value =
child->getFirstValue();
668 it->second.state =
false;
669 it->second.child =
nullptr;
678template<
typename ValueT,
typename BuildT,
typename StatsT>
680inline typename std::enable_if<!is_same<Fp4, typename T::BuildType>::value &&
689 auto kernel = [&](
const Range1D& r) {
690 auto *ptr = mBufferPtr + mBufferOffsets[5];
691 for (
auto i = r.begin(); i != r.end(); ++i) {
692 auto *srcLeaf = srcLeafs[i];
693 auto *dstLeaf = PtrAdd<DstNode0>(ptr, srcLeaf->mDstOffset);
694 auto *data = dstLeaf->data();
695 if (DstNode0::DataType::padding()>0u) {
696 std::memset(data, 0, DstNode0::DataType::memUsage());
698 data->mBBoxDif[0] = 0u;
699 data->mBBoxDif[1] = 0u;
700 data->mBBoxDif[2] = 0u;
702 data->mMinimum = data->mMaximum = ValueT();
703 data->mAverage = data->mStdDevi = 0;
705 srcLeaf->mDstNode = dstLeaf;
706 data->mBBoxMin = srcLeaf->mOrigin;
707 data->mValueMask = srcLeaf->mValueMask;
708 const ValueT* src = srcLeaf->mValues;
709 for (ValueT *dst = data->mValues, *end = dst + SrcNode0::SIZE; dst != end; dst += 4, src += 4) {
722template<
typename ValueT,
typename BuildT,
typename StatsT>
724inline typename std::enable_if<is_same<Fp4, typename T::BuildType>::value ||
727GridBuilder<ValueT, BuildT, StatsT>::
728 processLeafs(std::vector<T*>& srcLeafs)
731 using ArrayT =
typename DstNode0::DataType::ArrayType;
732 using FloatT =
typename std::conditional<DstNode0::DataType::bitWidth()>=16, double,
float>::type;
733 static constexpr FloatT UNITS = FloatT((1 << DstNode0::DataType::bitWidth()) - 1);
734 DitherLUT lut(mDitherOn);
736 auto kernel = [&](
const Range1D& r) {
737 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
738 for (
auto i = r.begin(); i != r.end(); ++i) {
739 auto *srcLeaf = srcLeafs[i];
740 auto *dstLeaf = PtrAdd<DstNode0>(ptr, srcLeaf->mDstOffset);
741 srcLeaf->mDstNode = dstLeaf;
742 auto *data = dstLeaf->data();
743 if (DstNode0::DataType::padding()>0u) {
744 std::memset(data, 0, DstNode0::DataType::memUsage());
746 data->mFlags = data->mBBoxDif[2] = data->mBBoxDif[1] = data->mBBoxDif[0] = 0u;
747 data->mDev = data->mAvg = data->mMax = data->mMin = 0u;
749 data->mBBoxMin = srcLeaf->mOrigin;
750 data->mValueMask = srcLeaf->mValueMask;
751 const float* src = srcLeaf->mValues;
753 float min = std::numeric_limits<float>::max(),
max = -
min;
754 for (
int i=0; i<512; ++i) {
755 const float v = src[i];
756 if (v < min)
min = v;
757 if (v > max)
max = v;
759 data->init(min, max, DstNode0::DataType::bitWidth());
761 const FloatT encode = UNITS/(
max-
min);
762 auto *code =
reinterpret_cast<ArrayT*
>(data->mCode);
765 for (
int j=0; j<128; ++j) {
766 auto tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
767 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
768 tmp = ArrayT(encode * (*src++ - min) + lut(offset++));
769 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++)) << 4 | tmp;
772 for (
int j=0; j<128; ++j) {
773 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
774 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
775 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
776 *code++ = ArrayT(encode * (*src++ - min) + lut(offset++));
786template<
typename ValueT,
typename BuildT,
typename StatsT>
788inline typename std::enable_if<is_same<FpN, typename T::BuildType>::value>::type
789GridBuilder<ValueT, BuildT, StatsT>::
790 processLeafs(std::vector<T*>& srcLeafs)
794 DitherLUT lut(mDitherOn);
795 auto kernel = [&](
const Range1D& r) {
796 uint8_t* ptr = mBufferPtr + mBufferOffsets[5];
797 for (
auto i = r.begin(); i != r.end(); ++i) {
798 auto *srcLeaf = srcLeafs[i];
799 auto *dstLeaf = PtrAdd<DstNode0>(ptr, srcLeaf->mDstOffset);
800 auto *data = dstLeaf->data();
801 data->mBBoxMin = srcLeaf->mOrigin;
802 data->mBBoxDif[0] = 0u;
803 data->mBBoxDif[1] = 0u;
804 data->mBBoxDif[2] = 0u;
805 srcLeaf->mDstNode = dstLeaf;
806 const uint8_t logBitWidth = uint8_t(mCodec[i].log2);
807 data->mFlags = logBitWidth << 5;
808 data->mValueMask = srcLeaf->mValueMask;
809 const float* src = srcLeaf->mValues;
810 const float min = mCodec[i].min,
max = mCodec[i].max;
811 data->init(min, max, uint8_t(1) << logBitWidth);
814 switch (logBitWidth) {
816 auto *dst =
reinterpret_cast<uint8_t*
>(data+1);
817 const float encode = 1.0f/(
max -
min);
818 for (
int j=0; j<64; ++j) {
820 for (
int k=0; k<8; ++k) {
821 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << k;
828 auto *dst =
reinterpret_cast<uint8_t*
>(data+1);
829 const float encode = 3.0f/(
max -
min);
830 for (
int j=0; j<128; ++j) {
831 auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
832 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 2;
833 a |= uint8_t(encode * (*src++ - min) + lut(offset++)) << 4;
834 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 6 | a;
839 auto *dst =
reinterpret_cast<uint8_t*
>(data+1);
840 const float encode = 15.0f/(
max -
min);
841 for (
int j=0; j<128; ++j) {
842 auto a = uint8_t(encode * (*src++ - min) + lut(offset++));
843 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
844 a = uint8_t(encode * (*src++ - min) + lut(offset++));
845 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++)) << 4 | a;
850 auto *dst =
reinterpret_cast<uint8_t*
>(data+1);
851 const float encode = 255.0f/(
max -
min);
852 for (
int j=0; j<128; ++j) {
853 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
854 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
855 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
856 *dst++ = uint8_t(encode * (*src++ - min) + lut(offset++));
861 auto *dst =
reinterpret_cast<uint16_t*
>(data+1);
862 const double encode = 65535.0/(
max -
min);
863 for (
int j=0; j<128; ++j) {
864 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
865 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
866 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
867 *dst++ = uint16_t(encode * (*src++ - min) + lut(offset++));
878template<
typename ValueT,
typename BuildT,
typename StatsT>
879template<
typename SrcNodeT>
880void GridBuilder<ValueT, BuildT, StatsT>::
881 processNodes(std::vector<SrcNodeT*>& srcNodes)
883 using DstNodeT =
typename SrcNodeT::NanoNodeT;
884 static_assert(DstNodeT::LEVEL == 1 || DstNodeT::LEVEL == 2,
"Expected internal node");
885 auto kernel = [&](
const Range1D& r) {
886 uint8_t* ptr = mBufferPtr + mBufferOffsets[5 - DstNodeT::LEVEL];
887 for (
auto i = r.begin(); i != r.end(); ++i) {
888 SrcNodeT *srcNode = srcNodes[i];
889 DstNodeT *dstNode = PtrAdd<DstNodeT>(ptr, srcNode->mDstOffset);
890 auto *data = dstNode->data();
891 if (DstNodeT::DataType::padding()>0u) std::memset(data, 0, DstNodeT::memUsage());
892 srcNode->mDstNode = dstNode;
893 data->mBBox[0] = srcNode->mOrigin;
894 data->mValueMask = srcNode->mValueMask;
895 data->mChildMask = srcNode->mChildMask;
896 for (uint32_t j = 0; j != SrcNodeT::SIZE; ++j) {
897 if (data->mChildMask.isOn(j)) {
898 data->setChild(j, srcNode->mTable[j].child->mDstNode);
900 data->setValue(j, srcNode->mTable[j].value);
909template<
typename ValueT,
typename BuildT,
typename StatsT>
910NanoRoot<BuildT>* GridBuilder<ValueT, BuildT, StatsT>::processRoot()
912 auto *dstRoot =
reinterpret_cast<DstRootT*
>(mBufferPtr + mBufferOffsets[2]);
913 auto *data = dstRoot->data();
914 if (data->padding()>0) std::memset(data, 0, DstRootT::memUsage(uint32_t(mRoot.mTable.size())));
915 data->mTableSize = uint32_t(mRoot.mTable.size());
916 data->mMinimum = data->mMaximum = data->mBackground = mRoot.mBackground;
920 for (
auto iter = mRoot.mTable.begin(); iter != mRoot.mTable.end(); ++iter) {
921 auto *dstTile = data->tile(tileID++);
922 if (
auto* srcChild = iter->second.child) {
923 dstTile->setChild(srcChild->mOrigin, srcChild->mDstNode, data);
925 dstTile->setValue(iter->first, iter->second.state, iter->second.value);
933template<
typename ValueT,
typename BuildT,
typename StatsT>
934NanoTree<BuildT>* GridBuilder<ValueT, BuildT, StatsT>::processTree()
936 auto *dstTree =
reinterpret_cast<DstTreeT*
>(mBufferPtr + mBufferOffsets[1]);
937 auto *data = dstTree->data();
938 data->setRoot( this->processRoot() );
940 DstNode2 *node2 = mArray2.empty() ? nullptr :
reinterpret_cast<DstNode2*
>(mBufferPtr + mBufferOffsets[3]);
941 data->setFirstNode(node2);
943 DstNode1 *node1 = mArray1.empty() ? nullptr :
reinterpret_cast<DstNode1*
>(mBufferPtr + mBufferOffsets[4]);
944 data->setFirstNode(node1);
946 DstNode0 *node0 = mArray0.empty() ? nullptr :
reinterpret_cast<DstNode0*
>(mBufferPtr + mBufferOffsets[5]);
947 data->setFirstNode(node0);
949 data->mNodeCount[0] =
static_cast<uint32_t
>(mArray0.size());
950 data->mNodeCount[1] =
static_cast<uint32_t
>(mArray1.size());
951 data->mNodeCount[2] =
static_cast<uint32_t
>(mArray2.size());
954 data->mTileCount[0] =
reduce(mArray1, uint32_t(0), [&](
Range1D &r, uint32_t sum){
955 for (
auto i=r.begin(); i!=r.end(); ++i) sum += mArray1[i]->mValueMask.countOn();
956 return sum;}, std::plus<uint32_t>());
959 data->mTileCount[1] =
reduce(mArray2, uint32_t(0), [&](
Range1D &r, uint32_t sum){
960 for (
auto i=r.begin(); i!=r.end(); ++i) sum += mArray2[i]->mValueMask.countOn();
961 return sum;}, std::plus<uint32_t>());
965 for (
auto &tile : mRoot.mTable) {
966 if (tile.second.child==
nullptr && tile.second.state) ++sum;
968 data->mTileCount[2] = sum;
971 data->mVoxelCount =
reduce(mArray0, uint64_t(0), [&](
Range1D &r, uint64_t sum){
972 for (
auto i=r.begin(); i!=r.end(); ++i) sum += mArray0[i]->mValueMask.countOn();
973 return sum;}, std::plus<uint64_t>());
975 data->mVoxelCount += data->mTileCount[0]*DstNode0::NUM_VALUES;
976 data->mVoxelCount += data->mTileCount[1]*DstNode1::NUM_VALUES;
977 data->mVoxelCount += data->mTileCount[2]*DstNode2::NUM_VALUES;
984template<
typename ValueT,
typename BuildT,
typename StatsT>
985NanoGrid<BuildT>* GridBuilder<ValueT, BuildT, StatsT>::
986processGrid(
const Map& map,
987 const std::string& name)
989 auto *dstGrid =
reinterpret_cast<DstGridT*
>(mBufferPtr + mBufferOffsets[0]);
991 auto* data = dstGrid->data();
993 data->mChecksum = 0u;
994 data->mVersion = Version();
996 data->mGridIndex = 0;
997 data->mGridCount = 1;
998 data->mGridSize = mBufferOffsets[8];
999 data->mWorldBBox = BBox<Vec3R>();
1000 data->mBlindMetadataOffset = 0;
1001 data->mBlindMetadataCount = 0;
1002 data->mGridClass = mGridClass;
1003 data->mGridType = mapToGridType<BuildT>();
1008 if (!
isValid(data->mGridType, data->mGridClass)) {
1009 std::stringstream ss;
1010 ss <<
"Invalid combination of GridType("<<int(data->mGridType)
1011 <<
") and GridClass("<<int(data->mGridClass)<<
"). See NanoVDB.h for details!";
1012 throw std::runtime_error(ss.str());
1018 std::stringstream ss;
1020 throw std::runtime_error(ss.str());
1023 data->mVoxelSize = map.applyMap(
Vec3d(1)) - map.applyMap(
Vec3d(0));
1026 if (mBlindDataSize>0) {
1027 auto *metaData =
reinterpret_cast<GridBlindMetaData*
>(mBufferPtr + mBufferOffsets[6]);
1028 data->mBlindMetadataOffset =
PtrDiff(metaData, dstGrid);
1029 data->mBlindMetadataCount = 1u;
1030 auto *blindData =
reinterpret_cast<char*
>(mBufferPtr + mBufferOffsets[7]);
1031 metaData->setBlindData(blindData);
1039template<
typename ValueT,
typename BuildT,
typename StatsT>
1040template<
typename ChildT>
1041struct GridBuilder<ValueT, BuildT, StatsT>::BuildRoot
1043 using ValueType =
typename ChildT::ValueType;
1044 using ChildType = ChildT;
1045 static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
1062 using MapT = std::map<Coord, Tile>;
1066 BuildRoot(
const ValueT& background)
1067 : mBackground(background)
1070 BuildRoot(
const BuildRoot&) =
delete;
1071 BuildRoot(BuildRoot&&) =
default;
1072 BuildRoot& operator=(
const BuildRoot&) =
delete;
1073 BuildRoot& operator=(BuildRoot&&) =
default;
1075 ~BuildRoot() { this->clear(); }
1077 bool empty()
const {
return mTable.empty(); }
1081 for (
auto iter = mTable.begin(); iter != mTable.end(); ++iter)
1082 delete iter->second.child;
1086 static Coord CoordToKey(
const Coord& ijk) {
return ijk & ~ChildT::MASK; }
1088 template<
typename AccT>
1089 bool isActiveAndCache(
const Coord& ijk, AccT& acc)
const
1091 auto iter = mTable.find(CoordToKey(ijk));
1092 if (iter == mTable.end())
1094 if (iter->second.child) {
1095 acc.insert(ijk, iter->second.child);
1096 return iter->second.child->isActiveAndCache(ijk, acc);
1098 return iter->second.state;
1101 const ValueT& getValue(
const Coord& ijk)
const
1103 auto iter = mTable.find(CoordToKey(ijk));
1104 if (iter == mTable.end()) {
1106 }
else if (iter->second.child) {
1107 return iter->second.child->getValue(ijk);
1109 return iter->second.value;
1113 template<
typename AccT>
1114 const ValueT& getValueAndCache(
const Coord& ijk, AccT& acc)
const
1116 auto iter = mTable.find(CoordToKey(ijk));
1117 if (iter == mTable.end())
1119 if (iter->second.child) {
1120 acc.insert(ijk, iter->second.child);
1121 return iter->second.child->getValueAndCache(ijk, acc);
1123 return iter->second.value;
1126 template<
typename AccT>
1127 void setValueAndCache(
const Coord& ijk,
const ValueT&
value, AccT& acc)
1129 ChildT*
child =
nullptr;
1130 const Coord key = CoordToKey(ijk);
1131 auto iter = mTable.find(key);
1132 if (iter == mTable.end()) {
1133 child =
new ChildT(ijk, mBackground,
false);
1134 mTable[key] = Tile(
child);
1135 }
else if (iter->second.child !=
nullptr) {
1136 child = iter->second.child;
1138 child =
new ChildT(ijk, iter->second.value, iter->second.state);
1139 iter->second.child =
child;
1142 acc.insert(ijk,
child);
1146 template<
typename NodeT>
1147 uint32_t nodeCount()
const
1150 static_assert(NodeT::LEVEL < LEVEL,
"Root::getNodes: LEVEL error");
1152 for (
auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
1153 if (iter->second.child ==
nullptr)
1158 sum += iter->second.child->template nodeCount<NodeT>();
1164 template<
typename NodeT>
1165 void getNodes(std::vector<NodeT*>& array)
1168 static_assert(NodeT::LEVEL < LEVEL,
"Root::getNodes: LEVEL error");
1169 for (
auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
1170 if (iter->second.child ==
nullptr)
1173 array.push_back(
reinterpret_cast<NodeT*
>(iter->second.child));
1175 iter->second.child->getNodes(array);
1180 void addChild(ChildT*&
child)
1183 const Coord key = CoordToKey(
child->mOrigin);
1184 auto iter = mTable.find(key);
1185 if (iter != mTable.end() && iter->second.child !=
nullptr) {
1186 delete iter->second.child;
1187 iter->second.child =
child;
1189 mTable[key] = Tile(
child);
1194 template<
typename NodeT>
1195 void addNode(NodeT*& node)
1198 this->addChild(
reinterpret_cast<ChildT*&
>(node));
1200 ChildT*
child =
nullptr;
1201 const Coord key = CoordToKey(node->mOrigin);
1202 auto iter = mTable.find(key);
1203 if (iter == mTable.end()) {
1204 child =
new ChildT(node->mOrigin, mBackground,
false);
1205 mTable[key] = Tile(
child);
1206 }
else if (iter->second.child !=
nullptr) {
1207 child = iter->second.child;
1209 child =
new ChildT(node->mOrigin, iter->second.value, iter->second.state);
1210 iter->second.child =
child;
1212 child->addNode(node);
1216 template<
typename T>
1217 typename std::enable_if<std::is_floating_point<T>::value>::type
1220 template<
typename T>
1221 typename std::enable_if<!std::is_floating_point<T>::value>::type
1227template<
typename ValueT,
typename BuildT,
typename StatsT>
1228template<
typename ChildT>
1230inline typename std::enable_if<std::is_floating_point<T>::value>::type
1231GridBuilder<ValueT, BuildT, StatsT>::BuildRoot<ChildT>::
1232 signedFloodFill(T outside)
1234 std::map<Coord, ChildT*> nodeKeys;
1235 for (
auto iter = mTable.begin(); iter != mTable.end(); ++iter) {
1236 if (iter->second.child ==
nullptr)
1238 nodeKeys.insert(std::pair<Coord, ChildT*>(iter->first, iter->second.child));
1243 auto b = nodeKeys.begin(), e = nodeKeys.end();
1246 for (
auto a = b++; b != e; ++a, ++b) {
1247 Coord d = b->first - a->first;
1248 if (d[0] != 0 || d[1] != 0 || d[2] ==
int(ChildT::DIM))
1250 const ValueT fill[] = {a->second->getLastValue(), b->second->getFirstValue()};
1251 if (!(fill[0] < 0) || !(fill[1] < 0))
1253 Coord c = a->first + Coord(0u, 0u, ChildT::DIM);
1254 for (; c[2] != b->first[2]; c[2] += ChildT::DIM) {
1255 const Coord key = SrcRootT::CoordToKey(c);
1256 mTable[key] =
typename SrcRootT::Tile(-outside,
false);
1263template<
typename ValueT,
typename BuildT,
typename StatsT>
1264template<
typename ChildT>
1265struct GridBuilder<ValueT, BuildT, StatsT>::
1268 using ValueType = ValueT;
1269 using BuildType = BuildT;
1270 using ChildType = ChildT;
1271 static constexpr uint32_t LOG2DIM = ChildT::LOG2DIM + 1;
1272 static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL;
1273 static constexpr uint32_t DIM = 1u << TOTAL;
1274 static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM);
1275 static constexpr int32_t MASK = DIM - 1;
1276 static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
1277 static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL);
1278 using MaskT = Mask<LOG2DIM>;
1279 using NanoNodeT =
typename NanoNode<BuildT, LEVEL>::Type;
1303 BuildNode(
const Coord& origin,
const ValueT&
value,
bool state)
1304 : mOrigin(origin & ~MASK)
1309 for (uint32_t i = 0; i < SIZE; ++i) {
1310 mTable[i].value =
value;
1313 BuildNode(
const BuildNode&) =
delete;
1314 BuildNode(BuildNode&&) =
delete;
1315 BuildNode& operator=(
const BuildNode&) =
delete;
1316 BuildNode& operator=(BuildNode&&) =
delete;
1319 for (
auto iter = mChildMask.beginOn(); iter; ++iter) {
1320 delete mTable[*iter].child;
1324 static uint32_t CoordToOffset(
const Coord& ijk)
1326 return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) +
1327 (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) +
1328 ((ijk[2] & MASK) >> ChildT::TOTAL);
1331 static Coord OffsetToLocalCoord(uint32_t n)
1334 const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
1335 return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1));
1338 void localToGlobalCoord(Coord& ijk)
const
1340 ijk <<= ChildT::TOTAL;
1344 Coord offsetToGlobalCoord(uint32_t n)
const
1346 Coord ijk = BuildNode::OffsetToLocalCoord(n);
1347 this->localToGlobalCoord(ijk);
1351 template<
typename AccT>
1352 bool isActiveAndCache(
const Coord& ijk, AccT& acc)
const
1354 const uint32_t n = CoordToOffset(ijk);
1355 if (mChildMask.isOn(n)) {
1356 acc.insert(ijk,
const_cast<ChildT*
>(mTable[n].
child));
1357 return mTable[n].child->isActiveAndCache(ijk, acc);
1359 return mValueMask.isOn(n);
1362 ValueT getFirstValue()
const {
return mChildMask.isOn(0) ? mTable[0].child->getFirstValue() : mTable[0].value; }
1363 ValueT getLastValue()
const {
return mChildMask.isOn(SIZE - 1) ? mTable[SIZE - 1].child->getLastValue() : mTable[SIZE - 1].value; }
1365 const ValueT& getValue(
const Coord& ijk)
const
1367 const uint32_t n = CoordToOffset(ijk);
1368 if (mChildMask.isOn(n)) {
1369 return mTable[n].child->getValue(ijk);
1371 return mTable[n].value;
1374 template<
typename AccT>
1375 const ValueT& getValueAndCache(
const Coord& ijk, AccT& acc)
const
1377 const uint32_t n = CoordToOffset(ijk);
1378 if (mChildMask.isOn(n)) {
1379 acc.insert(ijk,
const_cast<ChildT*
>(mTable[n].
child));
1380 return mTable[n].child->getValueAndCache(ijk, acc);
1382 return mTable[n].value;
1385 void setValue(
const Coord& ijk,
const ValueT&
value)
1387 const uint32_t n = CoordToOffset(ijk);
1388 ChildT*
child =
nullptr;
1389 if (mChildMask.isOn(n)) {
1390 child = mTable[n].child;
1392 child =
new ChildT(ijk, mTable[n].
value, mValueMask.isOn(n));
1393 mTable[n].child =
child;
1394 mChildMask.setOn(n);
1399 template<
typename AccT>
1400 void setValueAndCache(
const Coord& ijk,
const ValueT&
value, AccT& acc)
1402 const uint32_t n = CoordToOffset(ijk);
1403 ChildT*
child =
nullptr;
1404 if (mChildMask.isOn(n)) {
1405 child = mTable[n].child;
1407 child =
new ChildT(ijk, mTable[n].
value, mValueMask.isOn(n));
1408 mTable[n].child =
child;
1409 mChildMask.setOn(n);
1411 acc.insert(ijk,
child);
1415 template<
typename NodeT>
1416 uint32_t nodeCount()
const
1422 sum += mChildMask.countOn();
1424 for (
auto iter = mChildMask.beginOn(); iter; ++iter) {
1425 sum += mTable[*iter].child->template nodeCount<NodeT>();
1431 template<
typename NodeT>
1432 void getNodes(std::vector<NodeT*>& array)
1436 for (
auto iter = mChildMask.beginOn(); iter; ++iter) {
1438 array.push_back(
reinterpret_cast<NodeT*
>(mTable[*iter].
child));
1440 mTable[*iter].child->getNodes(array);
1445 void addChild(ChildT*&
child)
1448 const uint32_t n = CoordToOffset(
child->mOrigin);
1449 if (mChildMask.isOn(n)) {
1450 delete mTable[n].child;
1452 mChildMask.setOn(n);
1454 mTable[n].child =
child;
1458 template<
typename NodeT>
1459 void addNode(NodeT*& node)
1462 this->addChild(
reinterpret_cast<ChildT*&
>(node));
1464 const uint32_t n = CoordToOffset(node->mOrigin);
1465 ChildT*
child =
nullptr;
1466 if (mChildMask.isOn(n)) {
1467 child = mTable[n].child;
1469 child =
new ChildT(node->mOrigin, mTable[n].value, mValueMask.isOn(n));
1470 mTable[n].child =
child;
1471 mChildMask.setOn(n);
1473 child->addNode(node);
1477 template<
typename T>
1478 typename std::enable_if<std::is_floating_point<T>::value>::type
1480 template<
typename T>
1481 typename std::enable_if<!std::is_floating_point<T>::value>::type
1487template<
typename ValueT,
typename BuildT,
typename StatsT>
1488template<
typename ChildT>
1490inline typename std::enable_if<std::is_floating_point<T>::value>::type
1491GridBuilder<ValueT, BuildT, StatsT>::BuildNode<ChildT>::
1492 signedFloodFill(T outside)
1494 const uint32_t first = *mChildMask.beginOn();
1495 if (first < NUM_VALUES) {
1496 bool xInside = mTable[first].child->getFirstValue() < 0;
1497 bool yInside = xInside, zInside = xInside;
1498 for (uint32_t x = 0; x != (1 << LOG2DIM); ++x) {
1499 const uint32_t x00 = x << (2 * LOG2DIM);
1500 if (mChildMask.isOn(x00)) {
1501 xInside = mTable[x00].child->getLastValue() < 0;
1504 for (uint32_t y = 0; y != (1u << LOG2DIM); ++y) {
1505 const uint32_t xy0 = x00 + (y << LOG2DIM);
1506 if (mChildMask.isOn(xy0))
1507 yInside = mTable[xy0].
child->getLastValue() < 0;
1509 for (uint32_t z = 0; z != (1 << LOG2DIM); ++z) {
1510 const uint32_t xyz = xy0 + z;
1511 if (mChildMask.isOn(xyz)) {
1512 zInside = mTable[xyz].child->getLastValue() < 0;
1514 mTable[xyz].value = zInside ? -outside : outside;
1524template<
typename ValueT,
typename BuildT,
typename StatsT>
1530 static constexpr uint32_t LOG2DIM = 3;
1531 static constexpr uint32_t TOTAL = LOG2DIM;
1532 static constexpr uint32_t DIM = 1u << TOTAL;
1533 static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM;
1534 static constexpr int32_t MASK = DIM - 1;
1535 static constexpr uint32_t LEVEL = 0;
1536 static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL);
1542 ValueT mValues[SIZE];
1549 : mOrigin(ijk & ~MASK)
1553 ValueT* target = mValues;
1568 return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK);
1574 const int32_t m = n & ((1 << 2 * LOG2DIM) - 1);
1575 return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & MASK);
1586 this->localToGlobalCoord(ijk);
1590 template<
typename AccT>
1593 return mValueMask.
isOn(CoordToOffset(ijk));
1601 return mValues[CoordToOffset(ijk)];
1604 template<
typename AccT>
1607 return mValues[CoordToOffset(ijk)];
1610 template<
typename AccT>
1613 const uint32_t n = CoordToOffset(ijk);
1614 mValueMask.
setOn(n);
1620 const uint32_t n = CoordToOffset(ijk);
1621 mValueMask.
setOn(n);
1625 template<
typename NodeT>
1628 template<
typename NodeT>
1631 template<
typename NodeT>
1638 template<
typename T>
1639 typename std::enable_if<std::is_floating_point<T>::value>::type
1640 signedFloodFill(T outside);
1641 template<
typename T>
1642 typename std::enable_if<!std::is_floating_point<T>::value>::type
1648template<
typename ValueT,
typename BuildT,
typename StatsT>
1650inline typename std::enable_if<std::is_floating_point<T>::value>::type
1654 const uint32_t first = *
mValueMask.beginOn();
1656 bool xInside =
mValues[first] < 0, yInside = xInside, zInside = xInside;
1657 for (uint32_t x = 0; x !=
DIM; ++x) {
1658 const uint32_t x00 = x << (2 *
LOG2DIM);
1662 for (uint32_t y = 0; y !=
DIM; ++y) {
1663 const uint32_t xy0 = x00 + (y <<
LOG2DIM);
1667 for (uint32_t z = 0; z != (1 <<
LOG2DIM); ++z) {
1668 const uint32_t xyz = xy0 + z;
1672 mValues[xyz] = zInside ? -outside : outside;
1682template<
typename ValueT,
typename BuildT,
typename StatsT>
1688 , mNode{nullptr, nullptr, nullptr, &root}
1691 template<
typename NodeT>
1694 return (ijk[0] & ~NodeT::MASK) == mKeys[NodeT::LEVEL][0] &&
1695 (ijk[1] & ~NodeT::MASK) == mKeys[NodeT::LEVEL][1] &&
1696 (ijk[2] & ~NodeT::MASK) == mKeys[NodeT::LEVEL][2];
1700 if (this->isCached<SrcNode0>(ijk)) {
1701 return ((
SrcNode0*)mNode[0])->getValueAndCache(ijk, *
this);
1702 }
else if (this->isCached<SrcNode1>(ijk)) {
1703 return ((SrcNode1*)mNode[1])->getValueAndCache(ijk, *
this);
1704 }
else if (this->isCached<SrcNode2>(ijk)) {
1705 return ((SrcNode2*)mNode[2])->getValueAndCache(ijk, *
this);
1707 return ((SrcRootT*)mNode[3])->getValueAndCache(ijk, *
this);
1712 if (this->isCached<SrcNode0>(ijk)) {
1714 }
else if (this->isCached<SrcNode1>(ijk)) {
1715 ((SrcNode1*)mNode[1])->setValueAndCache(ijk,
value, *
this);
1716 }
else if (this->isCached<SrcNode2>(ijk)) {
1717 ((SrcNode2*)mNode[2])->setValueAndCache(ijk,
value, *
this);
1719 ((SrcRootT*)mNode[3])->setValueAndCache(ijk,
value, *
this);
1726 if (this->isCached<SrcNode0>(ijk)) {
1727 return ((
SrcNode0*)mNode[0])->isActiveAndCache(ijk, *
this);
1728 }
else if (this->isCached<SrcNode1>(ijk)) {
1729 return ((SrcNode1*)mNode[1])->isActiveAndCache(ijk, *
this);
1730 }
else if (this->isCached<SrcNode2>(ijk)) {
1731 return ((SrcNode2*)mNode[2])->isActiveAndCache(ijk, *
this);
1733 return ((SrcRootT*)mNode[3])->isActiveAndCache(ijk, *
this);
1736 template<
typename NodeT>
1739 mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
1740 mNode[NodeT::LEVEL] = node;
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.
ValueT value
Definition: GridBuilder.h:1290
NanoNodeT * mDstNode
Definition: GridBuilder.h:1299
uint64_t mDstOffset
Definition: GridBuilder.h:1300
ChildT * child
Definition: GridBuilder.h:1289
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_ASSERT(x)
Definition: NanoVDB.h:173
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:121
Custom Range class that is compatible with the tbb::blocked_range classes.
A unified wrapper for tbb::parallel_reduce and a naive std::future analog.
Compression oracle based on absolute difference.
Definition: GridBuilder.h:39
bool operator()(float exact, float approx) const
Return true if the approximate value is within the accepted absolute error bounds of the exact value.
Definition: GridBuilder.h:52
float getTolerance() const
Definition: GridBuilder.h:47
AbsDiff(float tolerance=-1.0f)
Definition: GridBuilder.h:43
AbsDiff(const AbsDiff &)=default
void setTolerance(float tolerance)
Definition: GridBuilder.h:46
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:967
Allows for the construction of NanoVDB grids without any dependency.
Definition: GridBuilder.h:94
GridHandle< BufferT > getHandle(double voxelSize=1.0, const Vec3d &gridOrigin=Vec3d(0), const std::string &name="", const OracleT &oracle=OracleT(), const BufferT &buffer=BufferT())
Return an instance of a GridHandle (invoking move semantics)
Definition: GridBuilder.h:538
GridHandle< BufferT > getHandle(const Map &map, const std::string &name="", const OracleT &oracle=OracleT(), const BufferT &buffer=BufferT())
Return an instance of a GridHandle (invoking move semantics)
Definition: GridBuilder.h:557
GridBuilder(ValueT background=ValueT(), GridClass gClass=GridClass::Unknown, uint64_t blindDataSize=0)
Definition: GridBuilder.h:241
void setStats(StatsMode mode=StatsMode::Default)
Definition: GridBuilder.h:200
void setChecksum(ChecksumMode mode=ChecksumMode::Default)
Definition: GridBuilder.h:202
void enableDithering(bool on=true)
Definition: GridBuilder.h:198
ValueAccessor getAccessor()
Definition: GridBuilder.h:183
void setVerbose(int mode=1)
Definition: GridBuilder.h:196
void setGridClass(GridClass mode=GridClass::Unknown)
Definition: GridBuilder.h:204
void sdfToLevelSet()
Performs multi-threaded bottom-up signed-distance flood-filling and changes GridClass to LevelSet.
Definition: GridBuilder.h:493
void operator()(const Func &func, const CoordBBox &bbox, ValueT delta=ValueT(0))
Sets grids values in domain of the bbox to those returned by the specified func with the expected sig...
Definition: GridBuilder.h:256
void sdfToFog()
Performs multi-threaded bottom-up signed-distance flood-filling followed by level-set -> FOG volume c...
Definition: GridBuilder.h:604
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:2556
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3521
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:4252
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:1957
bool isOn(uint32_t n) const
Return true if the given bit is set.
Definition: NanoVDB.h:2085
void setOn(uint32_t n)
Set the specified bit on.
Definition: NanoVDB.h:2109
Compression oracle based on relative difference.
Definition: GridBuilder.h:66
RelDiff(float tolerance=-1.0f)
Definition: GridBuilder.h:70
bool operator()(float exact, float approx) const
Return true if the approximate value is within the accepted relative error bounds of the exact value.
Definition: GridBuilder.h:79
RelDiff(const RelDiff &)=default
float getTolerance() const
Definition: GridBuilder.h:74
void setTolerance(float tolerance)
Definition: GridBuilder.h:73
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:3074
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2799
Definition: NanoVDB.h:208
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition: NanoVDB.h:535
T Abs(T x)
Definition: NanoVDB.h:854
T reduce(RangeT range, const T &identity, const FuncT &func, const JoinT &join)
Definition: Reduce.h:42
GridClass
Classes (defined in OpenVDB) that are currently supported by NanoVDB.
Definition: NanoVDB.h:281
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1809
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:277
Vec3< double > Vec3d
Definition: NanoVDB.h:1288
std::ostream & operator<<(std::ostream &os, const AbsDiff &diff)
Definition: GridBuilder.h:58
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
Type Max(Type a, Type b)
Definition: NanoVDB.h:779
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
Range< 1, size_t > Range1D
Definition: Range.h:30
static bool isValid(const void *p)
return true if the specified pointer is aligned and not NULL
Definition: NanoVDB.h:504
Definition: GridBuilder.h:1527
void addNode(NodeT *&)
Definition: GridBuilder.h:1629
Coord offsetToGlobalCoord(uint32_t n) const
Definition: GridBuilder.h:1583
void getNodes(std::vector< NodeT * > &)
Definition: GridBuilder.h:1626
const ValueT & getValue(const Coord &ijk) const
Definition: GridBuilder.h:1599
static uint32_t CoordToOffset(const Coord &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: GridBuilder.h:1566
BuildLeaf(const BuildLeaf &)=delete
static constexpr uint32_t DIM
Definition: GridBuilder.h:1532
std::enable_if<!std::is_floating_point< T >::value >::type signedFloodFill(T)
Definition: GridBuilder.h:1643
uint32_t nodeCount() const
Definition: GridBuilder.h:1632
void localToGlobalCoord(Coord &ijk) const
Definition: GridBuilder.h:1578
BuildLeaf & operator=(const BuildLeaf &)=delete
ValueT ValueType
Definition: GridBuilder.h:1528
bool isActiveAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1591
ValueT getFirstValue() const
Definition: GridBuilder.h:1596
ValueT getLastValue() const
Definition: GridBuilder.h:1597
void setValue(const Coord &ijk, const ValueT &value)
Definition: GridBuilder.h:1618
BuildLeaf & operator=(BuildLeaf &&)=delete
static Coord OffsetToLocalCoord(uint32_t n)
Definition: GridBuilder.h:1571
std::enable_if< std::is_floating_point< T >::value >::type signedFloodFill(T outside)
Definition: GridBuilder.h:1652
Mask< LOG2DIM > mValueMask
Definition: GridBuilder.h:1541
BuildLeaf(const Coord &ijk, const ValueT &value, bool state)
Definition: GridBuilder.h:1548
static constexpr uint32_t LOG2DIM
Definition: GridBuilder.h:1530
BuildLeaf(BuildLeaf &&)=delete
typename NanoNode< BuildT, 0 >::Type NanoLeafT
Definition: GridBuilder.h:1538
void setValueAndCache(const Coord &ijk, const ValueT &value, const AccT &)
Definition: GridBuilder.h:1611
static constexpr uint32_t SIZE
Definition: GridBuilder.h:1533
ValueT mValues[SIZE]
Definition: GridBuilder.h:1542
const ValueT & getValueAndCache(const Coord &ijk, const AccT &) const
Definition: GridBuilder.h:1605
Coord mOrigin
Definition: GridBuilder.h:1540
BuildT BuildType
Definition: GridBuilder.h:1529
Definition: GridBuilder.h:1282
Tile(ChildT *c=nullptr)
Definition: GridBuilder.h:1283
Definition: GridBuilder.h:1047
ValueT value
Definition: GridBuilder.h:1059
Tile(const ValueT &v, bool s)
Definition: GridBuilder.h:1052
Tile(ChildT *c=nullptr)
Definition: GridBuilder.h:1048
ChildT * child
Definition: GridBuilder.h:1058
bool state
Definition: GridBuilder.h:1060
Definition: GridBuilder.h:1685
bool isValueOn(const Coord &ijk)
Definition: GridBuilder.h:1735
ValueAccessor(SrcRootT &root)
Definition: GridBuilder.h:1686
const ValueT & getValue(const Coord &ijk)
Definition: GridBuilder.h:1698
bool isActive(const Coord &ijk)
Definition: GridBuilder.h:1724
SrcNode0 * setValue(const Coord &ijk, const ValueT &value)
Sets value in a leaf node and returns it.
Definition: GridBuilder.h:1710
bool isCached(const Coord &ijk) const
Definition: GridBuilder.h:1692
void insert(const Coord &ijk, NodeT *node)
Definition: GridBuilder.h:1737
static const int MaxNameSize
Definition: NanoVDB.h:2433
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation.
Definition: NanoVDB.h:2224
void set(const Mat3T &mat, const Mat3T &invMat, const Vec3T &translate, double taper)
Initialize the member data.
Definition: NanoVDB.h:2279
Maximum floating-point values.
Definition: NanoVDB.h:745
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:4567
C++11 implementation of std::is_floating_point.
Definition: NanoVDB.h:414
C++11 implementation of std::is_same.
Definition: NanoVDB.h:357
static constexpr bool value
Definition: NanoVDB.h:358