27#ifndef OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
28#define OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
41#ifdef BENCHMARK_FAST_SWEEPING
45#include <tbb/parallel_for.h>
46#include <tbb/enumerable_thread_specific.h>
47#include <tbb/task_group.h>
53#include <unordered_map>
101template<
typename Gr
idT>
104 typename GridT::ValueType isoValue,
134template<
typename Gr
idT>
137 typename GridT::ValueType isoValue = 0,
190template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
191typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
194 const ExtValueT& background,
195 typename FogGridT::ValueType isoValue,
198 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
248template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
249typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
252 const ExtValueT &background,
253 typename SdfGridT::ValueType isoValue = 0,
256 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
311template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
312std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
315 const ExtValueT &background,
316 typename FogGridT::ValueType isoValue,
319 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
374template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
375std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
378 const ExtValueT &background,
379 typename SdfGridT::ValueType isoValue = 0,
382 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
407template<
typename Gr
idT>
433template<
typename Gr
idT,
typename MaskTreeT>
437 bool ignoreActiveTiles =
false,
452template<
typename SdfGr
idT,
typename ExtValueT =
typename SdfGr
idT::ValueType>
456 "FastSweeping requires SdfGridT to have floating-point values");
458 using SdfValueT =
typename SdfGridT::ValueType;
459 using SdfTreeT =
typename SdfGridT::TreeType;
464 using ExtGridT =
typename SdfGridT::template ValueConverter<ExtValueT>::Type;
465 using ExtTreeT =
typename ExtGridT::TreeType;
469 using SweepMaskTreeT =
typename SdfTreeT::template ValueConverter<ValueMask>::Type;
492 typename SdfGridT::Ptr
sdfGrid() {
return mSdfGrid; }
500 typename ExtGridT::Ptr
extGrid() {
return mExtGrid; }
530 bool initSdf(
const SdfGridT &sdfGrid, SdfValueT isoValue,
bool isInputSdf);
578 template <
typename ExtOpT>
581 const ExtValueT &background,
585 const typename ExtGridT::ConstPtr extGrid =
nullptr);
608 bool initDilate(
const SdfGridT &sdfGrid,
631 template<
typename MaskTreeT>
632 bool initMask(
const SdfGridT &sdfGrid,
const Grid<MaskTreeT> &mask,
bool ignoreActiveTiles =
false);
646 void sweep(
int nIter = 1,
647 bool finalize =
true);
659 bool isValid()
const {
return mSweepingVoxelCount > 0 && mBoundaryVoxelCount > 0; }
675 void computeSweepMaskLeafOrigins();
685 struct SweepingKernel;
688 static const Coord mOffset[6];
691 typename SdfGridT::Ptr mSdfGrid;
692 typename ExtGridT::Ptr mExtGrid;
693 typename ExtGridT::Ptr mExtGridInput;
694 SweepMaskTreeT mSweepMask;
695 std::vector<Coord> mSweepMaskLeafOrigins;
696 size_t mSweepingVoxelCount, mBoundaryVoxelCount;
704template <
typename SdfGr
idT,
typename ExtValueT>
705const Coord FastSweeping<SdfGridT, ExtValueT>::mOffset[6] = {{-1,0,0},{1,0,0},
709template <
typename SdfGr
idT,
typename ExtValueT>
711 : mSdfGrid(nullptr), mExtGrid(nullptr), mSweepingVoxelCount(0), mBoundaryVoxelCount(0), mSweepDirection(
FastSweepingDomain::
SWEEP_ALL), mIsInputSdf(true)
715template <
typename SdfGr
idT,
typename ExtValueT>
721 if (mExtGridInput) mExtGridInput.reset();
722 mSweepingVoxelCount = mBoundaryVoxelCount = 0;
727template <
typename SdfGr
idT,
typename ExtValueT>
733 mSweepMask.voxelizeActiveTiles();
736 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
737 LeafManagerT leafManager(mSweepMask);
739 mSweepMaskLeafOrigins.resize(leafManager.leafCount());
740 std::atomic<size_t> sweepingVoxelCount{0};
741 auto kernel = [&](
const LeafT& leaf,
size_t leafIdx) {
742 mSweepMaskLeafOrigins[leafIdx] = leaf.origin();
743 sweepingVoxelCount += leaf.onVoxelCount();
745 leafManager.foreach(kernel,
true, 1024);
747 mBoundaryVoxelCount = 0;
748 mSweepingVoxelCount = sweepingVoxelCount;
750 const size_t totalCount = mSdfGrid->constTree().activeVoxelCount();
751 assert( totalCount >= mSweepingVoxelCount );
752 mBoundaryVoxelCount = totalCount - mSweepingVoxelCount;
756template <
typename SdfGr
idT,
typename ExtValueT>
760 mSdfGrid = fogGrid.deepCopy();
761 mIsInputSdf = isInputSdf;
763 kernel.
run(isoValue);
767template <
typename SdfGr
idT,
typename ExtValueT>
768template <
typename OpT>
774 if (extGrid->transform() != fogGrid.transform())
775 OPENVDB_THROW(
RuntimeError,
"FastSweeping::initExt extension grid input should have the same transform as Fog/SDF grid!");
779 mSdfGrid = fogGrid.deepCopy();
780 mExtGrid = createGrid<ExtGridT>( background );
781 mSweepDirection = mode;
782 mIsInputSdf = isInputSdf;
784 mExtGridInput = extGrid->deepCopy();
786 mExtGrid->topologyUnion( *mSdfGrid );
787 InitExt<OpT> kernel(*
this);
788 kernel.run(isoValue, op);
793template <
typename SdfGr
idT,
typename ExtValueT>
797 mSdfGrid = sdfGrid.deepCopy();
798 mSweepDirection = mode;
800 kernel.
run(dilate, nn);
804template <
typename SdfGr
idT,
typename ExtValueT>
805template<
typename MaskTreeT>
809 mSdfGrid = sdfGrid.deepCopy();
811 if (mSdfGrid->transform() != mask.
transform()) {
816 using T =
typename MaskTreeT::template ValueConverter<bool>::Type;
818 tmp->
tree().voxelizeActiveTiles();
819 MaskKernel<T> kernel(*
this);
820 kernel.run(tmp->
tree());
822 if (ignoreActiveTiles || !mask.
tree().hasActiveTiles()) {
823 MaskKernel<MaskTreeT> kernel(*
this);
824 kernel.run(mask.
tree());
826 using T =
typename MaskTreeT::template ValueConverter<ValueMask>::Type;
828 tmp.voxelizeActiveTiles(
true);
829 MaskKernel<T> kernel(*
this);
836template <
typename SdfGr
idT,
typename ExtValueT>
844 " a non-null reference extension grid input.");
846 if (this->boundaryVoxelCount() == 0) {
848 }
else if (this->sweepingVoxelCount() == 0) {
853 std::deque<SweepingKernel> kernels;
854 for (
int i = 0; i < 4; i++) kernels.emplace_back(*
this);
857#ifdef BENCHMARK_FAST_SWEEPING
862 tbb::task_group tasks;
863 tasks.run([&] { kernels[0].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]+a[2]; }); });
864 tasks.run([&] { kernels[1].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]-a[2]; }); });
865 tasks.run([&] { kernels[2].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]+a[2]; }); });
866 tasks.run([&] { kernels[3].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]-a[2]; }); });
869#ifdef BENCHMARK_FAST_SWEEPING
875 for (
int i = 0; i < nIter; ++i) {
880#ifdef BENCHMARK_FAST_SWEEPING
884 auto e = kernel.
run(*mSdfGrid);
886#ifdef BENCHMARK_FAST_SWEEPING
887 std::cerr <<
"Min = " << e.min() <<
" Max = " << e.max() << std::endl;
888 timer.
restart(
"Changing asymmetric background value");
892#ifdef BENCHMARK_FAST_SWEEPING
901template <
typename SdfGr
idT,
typename ExtValueT>
912 tbb::parallel_reduce(mgr.
leafRange(), *
this);
918 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
919 for (
auto voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
920 const SdfValueT v = *voxelIter;
921 if (v < mMin) mMin = v;
922 if (v > mMax) mMax = v;
929 if (other.
mMin < mMin) mMin = other.
mMin;
930 if (other.
mMax > mMax) mMax = other.
mMax;
939template <
typename SdfGr
idT,
typename ExtValueT>
945 mBackground(parent.mSdfGrid->background())
947 mSdfGridInput = mParent->mSdfGrid->deepCopy();
954#ifdef BENCHMARK_FAST_SWEEPING
959#ifdef BENCHMARK_FAST_SWEEPING
960 timer.
restart(
"Changing background value");
965 #ifdef BENCHMARK_FAST_SWEEPING
966 timer.
restart(
"Dilating and updating mgr (parallel)");
976#ifdef BENCHMARK_FAST_SWEEPING
977 timer.
restart(
"Initializing grid and sweep mask");
980 mParent->mSweepMask.clear();
981 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
984 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
988 LeafManagerT leafManager(mParent->mSdfGrid->tree());
990 auto kernel = [&](LeafT& leaf,
size_t ) {
992 const SdfValueT background = mBackground;
993 auto* maskLeaf = mParent->mSweepMask.probeLeaf(leaf.origin());
994 SdfConstAccT sdfInputAcc(mSdfGridInput->tree());
996 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
997 const SdfValueT
value = *voxelIter;
998 SdfValueT inputValue;
999 const Coord ijk = voxelIter.getCoord();
1002 maskLeaf->setValueOff(voxelIter.pos());
1006 voxelIter.setValue(
value > 0 ? Unknown : -Unknown);
1009 if (
value > 0) voxelIter.setValue(Unknown);
1011 maskLeaf->setValueOff(voxelIter.pos());
1012 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1013 if ( !isInputOn ) voxelIter.setValueOff();
1014 else voxelIter.setValue(inputValue);
1018 if (
value < 0) voxelIter.setValue(-Unknown);
1020 maskLeaf->setValueOff(voxelIter.pos());
1021 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1022 if ( !isInputOn ) voxelIter.setValueOff();
1023 else voxelIter.setValue(inputValue);
1031 leafManager.foreach( kernel );
1034 mParent->computeSweepMaskLeafOrigins();
1036#ifdef BENCHMARK_FAST_SWEEPING
1049template <
typename SdfGr
idT,
typename ExtValueT>
1054 mSdfGrid(parent.mSdfGrid.get()), mIsoValue(0), mAboveSign(0) {}
1060 mIsoValue = isoValue;
1061 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1062 SdfTreeT &tree = mSdfGrid->tree();
1063 const bool hasActiveTiles = tree.hasActiveTiles();
1065 if (mParent->mIsInputSdf && hasActiveTiles) {
1069#ifdef BENCHMARK_FAST_SWEEPING
1072 mParent->mSweepMask.clear();
1073 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1077 tbb::parallel_for(mgr.
leafRange(32), *
this);
1081#ifdef BENCHMARK_FAST_SWEEPING
1082 timer.
restart(
"Initialize tiles - new");
1086 mgr.foreachBottomUp(*
this);
1088 if (hasActiveTiles) tree.voxelizeActiveTiles();
1092 mParent->computeSweepMaskLeafOrigins();
1100 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1101 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1102 SdfValueT* sdf = leafIter.buffer(1).data();
1103 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1104 const SdfValueT
value = *voxelIter;
1105 const bool isAbove =
value > isoValue;
1106 if (!voxelIter.isValueOn()) {
1107 sdf[voxelIter.pos()] = isAbove ? above : -above;
1109 const Coord ijk = voxelIter.getCoord();
1113 sdf[voxelIter.pos()] = isAbove ? above : -above;
1117 const SdfValueT delta =
value - isoValue;
1119 sdf[voxelIter.pos()] = 0;
1122 for (
int i=0; i<6;) {
1125 if (mask.test(i++)) {
1139 template<
typename RootOrInternalNodeT>
1143 for (
auto it = node.cbeginValueAll(); it; ++it) {
1144 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1145 v = v > isoValue ? above : -above;
1158template <
typename SdfGr
idT,
typename ExtValueT>
1159template <
typename OpT>
1163 using OpPoolT = tbb::enumerable_thread_specific<OpT>;
1165 mOpPool(
nullptr), mSdfGrid(parent.mSdfGrid.get()),
1166 mExtGrid(parent.mExtGrid.get()), mIsoValue(0), mAboveSign(0) {}
1167 InitExt(
const InitExt&) =
default;
1168 InitExt&
operator=(
const InitExt&) =
delete;
1169 void run(SdfValueT isoValue,
const OpT &opPrototype)
1171 static_assert(std::is_convertible<
decltype(opPrototype(Vec3d(0))),ExtValueT>::
value,
"Invalid return type of functor");
1176 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1177 mIsoValue = isoValue;
1178 auto &tree1 = mSdfGrid->tree();
1179 auto &tree2 = mExtGrid->tree();
1180 const bool hasActiveTiles = tree1.hasActiveTiles();
1182 if (mParent->mIsInputSdf && hasActiveTiles) {
1186#ifdef BENCHMARK_FAST_SWEEPING
1187 util::CpuTimer timer(
"Initialize voxels");
1190 mParent->mSweepMask.clear();
1191 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1195 OpPoolT opPool(opPrototype);
1199 tbb::parallel_for(mgr.leafRange(32), *
this);
1200 mgr.swapLeafBuffer(1);
1203#ifdef BENCHMARK_FAST_SWEEPING
1204 timer.restart(
"Initialize tiles");
1207 tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree1);
1208 mgr.foreachBottomUp(*
this);
1210 if (hasActiveTiles) {
1211#ifdef BENCHMARK_FAST_SWEEPING
1212 timer.restart(
"Voxelizing active tiles");
1214 tree1.voxelizeActiveTiles();
1215 tree2.voxelizeActiveTiles();
1221 mParent->computeSweepMaskLeafOrigins();
1223#ifdef BENCHMARK_FAST_SWEEPING
1230 void sumHelper(ExtT& sum2, ExtT ext,
bool update,
const SdfT& )
const {
if (update) sum2 = ext; }
1234 void sumHelper(ExtT& sum2, ExtT ext,
bool ,
const SdfT& d2)
const { sum2 +=
static_cast<ExtValueT
>(d2 * ext); }
1237 ExtT extValHelper(ExtT extSum,
const SdfT& )
const {
return extSum; }
1240 ExtT extValHelper(ExtT extSum,
const SdfT& sdfSum)
const {
return ExtT((SdfT(1) / sdfSum) * extSum); }
1242 void operator()(
const LeafRange& r)
const
1244 ExtAccT acc(mExtGrid->tree());
1245 SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
1246 math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
1247 const math::Transform& xform = mExtGrid->transform();
1248 typename OpPoolT::reference op = mOpPool->local();
1250 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1251 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1252 SdfValueT *sdf = leafIter.buffer(1).data();
1253 ExtValueT *ext = acc.probeLeaf(leafIter->origin())->buffer().data();
1254 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1255 const SdfValueT
value = *voxelIter;
1256 const bool isAbove =
value > isoValue;
1257 if (!voxelIter.isValueOn()) {
1258 sdf[voxelIter.pos()] = isAbove ? above : -above;
1260 const Coord ijk = voxelIter.getCoord();
1261 stencil.moveTo(ijk,
value);
1262 const auto mask = stencil.intersectionMask( isoValue );
1264 sdf[voxelIter.pos()] = isAbove ? above : -above;
1268 sweepMaskAcc.setValueOff(ijk);
1269 const SdfValueT delta =
value - isoValue;
1271 sdf[voxelIter.pos()] = 0;
1272 ext[voxelIter.pos()] = ExtValueT(op(xform.indexToWorld(ijk)));
1275 ExtValueT sum2 = zeroVal<ExtValueT>();
1281 for (
int n=0, i=0; i<6;) {
1283 if (mask.test(i++)) {
1287 if (mask.test(i++)) {
1297 const Vec3R xyz(
static_cast<SdfValueT
>(ijk[0])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][0]),
1298 static_cast<SdfValueT
>(ijk[1])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][1]),
1299 static_cast<SdfValueT
>(ijk[2])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][2]));
1301 sumHelper(sum2, ExtValueT(op(xform.indexToWorld(xyz))), d < minD, d2);
1302 if (d < minD) minD = d;
1305 ext[voxelIter.pos()] = extValHelper(sum2, sum1);
1306 sdf[voxelIter.pos()] = isAbove ? h /
math::Sqrt(sum1) : -h / math::
Sqrt(sum1);
1314 template<
typename RootOrInternalNodeT>
1315 void operator()(
const RootOrInternalNodeT& node)
const
1318 for (
auto it = node.cbeginValueAll(); it; ++it) {
1319 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1320 v = v > isoValue ? above : -above;
1328 SdfValueT mIsoValue;
1329 SdfValueT mAboveSign;
1333template <
typename SdfGr
idT,
typename ExtValueT>
1334template <
typename MaskTreeT>
1335struct FastSweeping<SdfGridT, ExtValueT>::MaskKernel
1337 using LeafRange =
typename tree::LeafManager<const MaskTreeT>::LeafRange;
1339 mSdfGrid(parent.mSdfGrid.get()) {}
1340 MaskKernel(
const MaskKernel &parent) =
default;
1341 MaskKernel&
operator=(
const MaskKernel&) =
delete;
1343 void run(
const MaskTreeT &mask)
1345#ifdef BENCHMARK_FAST_SWEEPING
1346 util::CpuTimer timer;
1348 auto &lsTree = mSdfGrid->tree();
1352#ifdef BENCHMARK_FAST_SWEEPING
1353 timer.restart(
"Changing background value");
1357#ifdef BENCHMARK_FAST_SWEEPING
1358 timer.restart(
"Union with mask");
1360 lsTree.topologyUnion(mask);
1363 tree::LeafManager<const MaskTreeT> mgr(mask);
1365#ifdef BENCHMARK_FAST_SWEEPING
1366 timer.restart(
"Initializing grid and sweep mask");
1369 mParent->mSweepMask.clear();
1370 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1372 using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
1373 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1374 LeafManagerT leafManager(mParent->mSweepMask);
1376 auto kernel = [&](LeafT& leaf,
size_t ) {
1378 SdfAccT acc(mSdfGrid->tree());
1381 SdfValueT *data = acc.probeLeaf(leaf.origin())->buffer().data();
1382 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1383 if (
math::Abs( data[voxelIter.pos()] ) < Unknown ) {
1385 voxelIter.setValue(
false);
1389 leafManager.foreach( kernel );
1392 mParent->computeSweepMaskLeafOrigins();
1394#ifdef BENCHMARK_FAST_SWEEPING
1405template <
typename SdfGr
idT,
typename ExtValueT>
1413 template<
typename HashOp>
1416#ifdef BENCHMARK_FAST_SWEEPING
1421 const SweepMaskTreeT& maskTree = mParent->mSweepMask;
1424 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1425 LeafManagerT leafManager(maskTree);
1432 constexpr int maskOffset = LeafT::DIM * 3;
1433 constexpr int maskRange = maskOffset * 2;
1436 std::vector<int8_t> leafSliceMasks(leafManager.leafCount()*maskRange);
1437 auto kernel1 = [&](
const LeafT& leaf,
size_t leafIdx) {
1438 const size_t leafOffset = leafIdx * maskRange;
1439 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1440 const Coord ijk = LeafT::offsetToLocalCoord(voxelIter.pos());
1441 leafSliceMasks[leafOffset +
hash(ijk) + maskOffset] = uint8_t(1);
1444 leafManager.foreach( kernel1 );
1449 using ThreadLocalMap = std::unordered_map<int64_t, std::deque<size_t>>;
1450 tbb::enumerable_thread_specific<ThreadLocalMap> pool;
1451 auto kernel2 = [&](
const LeafT& leaf,
size_t leafIdx) {
1452 ThreadLocalMap& map = pool.local();
1453 const Coord& origin = leaf.origin();
1454 const int64_t leafKey =
hash(origin);
1455 const size_t leafOffset = leafIdx * maskRange;
1456 for (
int sliceIdx = 0; sliceIdx < maskRange; sliceIdx++) {
1457 if (leafSliceMasks[leafOffset + sliceIdx] == uint8_t(1)) {
1458 const int64_t voxelSliceKey = leafKey+sliceIdx-maskOffset;
1459 map[voxelSliceKey].emplace_back(leafIdx);
1463 leafManager.foreach( kernel2 );
1468 for (
auto poolIt = pool.begin(); poolIt != pool.end(); ++poolIt) {
1469 const ThreadLocalMap& map = *poolIt;
1470 for (
const auto& it : map) {
1471 for (
const size_t leafIdx : it.second) {
1472 mVoxelSliceMap[it.first].emplace_back(leafIdx, NodeMaskPtrT());
1478 mVoxelSliceKeys.reserve(mVoxelSliceMap.size());
1479 for (
const auto& it : mVoxelSliceMap) {
1480 mVoxelSliceKeys.push_back(it.first);
1484 auto kernel3 = [&](tbb::blocked_range<size_t>& range) {
1485 for (
size_t i = range.begin(); i < range.end(); i++) {
1486 const int64_t key = mVoxelSliceKeys[i];
1487 for (
auto& it : mVoxelSliceMap[key]) {
1488 it.second = std::make_unique<NodeMaskT>();
1492 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel3);
1499 auto kernel4 = [&](tbb::blocked_range<size_t>& range) {
1500 for (
size_t i = range.begin(); i < range.end(); i++) {
1501 const int64_t voxelSliceKey = mVoxelSliceKeys[i];
1502 LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceKey];
1503 for (LeafSlice& leafSlice : leafSliceArray) {
1504 const size_t leafIdx = leafSlice.first;
1505 NodeMaskPtrT& nodeMask = leafSlice.second;
1506 const LeafT& leaf = leafManager.leaf(leafIdx);
1507 const Coord& origin = leaf.origin();
1508 const int64_t leafKey =
hash(origin);
1509 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1510 const Index voxelIdx = voxelIter.pos();
1511 const Coord ijk = LeafT::offsetToLocalCoord(voxelIdx);
1512 const int64_t key = leafKey +
hash(ijk);
1513 if (key == voxelSliceKey) {
1514 nodeMask->setOn(voxelIdx);
1520 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel4);
1527 inline static Coord ijk(
const Coord &p,
int i) {
return p + FastSweeping::mOffset[i]; }
1532 inline operator bool()
const {
return v < SdfValueT(1000); }
1537 ExtT
twoNghbr(
const NN& d1,
const NN& d2,
const SdfT& ,
const ExtT& v1,
const ExtT& v2)
const {
return d1.
v < d2.
v ? v1 : v2; }
1541 ExtT
twoNghbr(
const NN& d1,
const NN& d2,
const SdfT& w,
const ExtT& v1,
const ExtT& v2)
const {
return ExtT(w*(d1.
v*v1 + d2.
v*v2)); }
1545 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& ,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1553 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& w,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1554 return ExtT(w*(d1.
v*v1 + d2.
v*v2 + d3.
v*v3));
1559 typename ExtGridT::TreeType *tree2 = mParent->mExtGrid ? &mParent->mExtGrid->tree() :
nullptr;
1560 typename ExtGridT::TreeType *tree3 = mParent->mExtGridInput ? &mParent->mExtGridInput->tree() :
nullptr;
1562 const SdfValueT h =
static_cast<SdfValueT
>(mParent->mSdfGrid->voxelSize()[0]);
1563 const SdfValueT sqrt2h =
math::Sqrt(SdfValueT(2))*h;
1565 const bool isInputSdf = mParent->mIsInputSdf;
1572 const std::vector<Coord>& leafNodeOrigins = mParent->mSweepMaskLeafOrigins;
1574 int64_t voxelSliceIndex(0);
1576 auto kernel = [&](
const tbb::blocked_range<size_t>& range) {
1577 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1579 SdfAccT acc1(mParent->mSdfGrid->tree());
1580 auto acc2 = std::unique_ptr<ExtAccT>(tree2 ?
new ExtAccT(*tree2) :
nullptr);
1581 auto acc3 = std::unique_ptr<ExtAccT>(tree3 ?
new ExtAccT(*tree3) :
nullptr);
1582 SdfValueT absV, sign, update, D;
1585 const LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceIndex];
1589 for (
size_t i = range.begin(); i < range.end(); ++i) {
1594 const LeafSlice& leafSlice = leafSliceArray[i];
1595 const size_t leafIdx = leafSlice.first;
1596 const NodeMaskPtrT& nodeMask = leafSlice.second;
1598 const Coord& origin = leafNodeOrigins[leafIdx];
1601 for (
auto indexIter = nodeMask->beginOn(); indexIter; ++indexIter) {
1604 ijk = origin + LeafT::offsetToLocalCoord(indexIter.pos());
1611 if (!(d1 || d2 || d3))
continue;
1616 SdfValueT &
value =
const_cast<SdfValueT&
>(acc1.
getValue(ijk));
1619 sign =
value >= SdfValueT(0) ? SdfValueT(1) : SdfValueT(-1);
1625 if (d2 < d1) std::swap(d1, d2);
1626 if (d3 < d2) std::swap(d2, d3);
1627 if (d2 < d1) std::swap(d1, d2);
1633 if (update <= d2.
v) {
1634 if (update < absV) {
1635 value = sign * update;
1638 ExtValueT updateExt = acc2->getValue(d1(ijk));
1640 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1641 else updateExt = (
value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1644 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1645 else updateExt = (
value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1647 acc2->setValue(ijk, updateExt);
1657 if (d2.
v <= sqrt2h + d1.
v) {
1659 update = SdfValueT(0.5) * (d1.
v + d2.
v + std::sqrt(D));
1660 if (update > d2.
v && update <= d3.
v) {
1661 if (update < absV) {
1662 value = sign * update;
1667 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v);
1668 const ExtValueT v1 = acc2->getValue(d1(ijk));
1669 const ExtValueT v2 = acc2->getValue(d2(ijk));
1670 const ExtValueT extVal = twoNghbr(d1, d2, w, v1, v2);
1672 ExtValueT updateExt = extVal;
1674 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1675 else updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1678 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1679 else updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1681 acc2->setValue(ijk, updateExt);
1692 const SdfValueT d123 = d1.
v + d2.
v + d3.
v;
1693 D = d123*d123 - SdfValueT(3)*(d1.
v*d1.
v + d2.
v*d2.
v + d3.
v*d3.
v - h * h);
1694 if (D >= SdfValueT(0)) {
1695 update = SdfValueT(1.0/3.0) * (d123 + std::sqrt(D));
1697 if (update < absV) {
1698 value = sign * update;
1704 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v+d3.
v);
1705 const ExtValueT v1 = acc2->getValue(d1(ijk));
1706 const ExtValueT v2 = acc2->getValue(d2(ijk));
1707 const ExtValueT v3 = acc2->getValue(d3(ijk));
1708 const ExtValueT extVal = threeNghbr(d1, d2, d3, w, v1, v2, v3);
1710 ExtValueT updateExt = extVal;
1712 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1713 else updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1716 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1717 else updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1719 acc2->setValue(ijk, updateExt);
1727#ifdef BENCHMARK_FAST_SWEEPING
1731 for (
size_t i = 0; i < mVoxelSliceKeys.size(); i++) {
1732 voxelSliceIndex = mVoxelSliceKeys[i];
1733 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1736#ifdef BENCHMARK_FAST_SWEEPING
1737 timer.
restart(
"Backward sweeps");
1739 for (
size_t i = mVoxelSliceKeys.size(); i > 0; i--) {
1740 voxelSliceIndex = mVoxelSliceKeys[i-1];
1741 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1744#ifdef BENCHMARK_FAST_SWEEPING
1750 using NodeMaskT =
typename SweepMaskTreeT::LeafNodeType::NodeMaskType;
1751 using NodeMaskPtrT = std::unique_ptr<NodeMaskT>;
1754 using LeafSlice = std::pair<size_t, NodeMaskPtrT>;
1755 using LeafSliceArray = std::deque<LeafSlice>;
1756 using VoxelSliceMap = std::map<int64_t, LeafSliceArray>;
1760 VoxelSliceMap mVoxelSliceMap;
1761 std::vector<int64_t> mVoxelSliceKeys;
1766template<
typename Gr
idT>
1769 typename GridT::ValueType isoValue,
1773 if (fs.initSdf(fogGrid, isoValue,
false)) fs.
sweep(nIter);
1774 return fs.sdfGrid();
1777template<
typename Gr
idT>
1780 typename GridT::ValueType isoValue,
1784 if (fs.initSdf(sdfGrid, isoValue,
true)) fs.
sweep(nIter);
1785 return fs.sdfGrid();
1788template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1789typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
1792 const ExtValueT& background,
1793 typename FogGridT::ValueType isoValue,
1796 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1799 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1800 fs.
sweep(nIter,
true);
1801 return fs.extGrid();
1804template<
typename SdfGr
idT,
typename OpT,
typename ExtValueT>
1805typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
1808 const ExtValueT &background,
1809 typename SdfGridT::ValueType isoValue,
1812 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1815 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1816 fs.
sweep(nIter,
true);
1817 return fs.extGrid();
1820template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1821std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1824 const ExtValueT &background,
1825 typename FogGridT::ValueType isoValue,
1828 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1831 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1832 fs.
sweep(nIter,
true);
1833 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1836template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
1837std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1840 const ExtValueT &background,
1841 typename SdfGridT::ValueType isoValue,
1844 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1847 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1848 fs.
sweep(nIter,
true);
1849 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1852template<
typename Gr
idT>
1861 if (fs.initDilate(sdfGrid, dilation, nn, mode)) fs.
sweep(nIter);
1862 return fs.sdfGrid();
1865template<
typename Gr
idT,
typename MaskTreeT>
1869 bool ignoreActiveTiles,
1873 if (fs.initMask(sdfGrid, mask, ignoreActiveTiles)) fs.
sweep(nIter);
1874 return fs.sdfGrid();
1883#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1885#ifdef OPENVDB_INSTANTIATE_FASTSWEEPING
1889#define _FUNCTION(TreeT) \
1890 Grid<TreeT>::Ptr fogToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1894#define _FUNCTION(TreeT) \
1895 Grid<TreeT>::Ptr sdfToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1899#define _FUNCTION(TreeT) \
1900 Grid<TreeT>::Ptr dilateSdf(const Grid<TreeT>&, int, NearestNeighbors, int, FastSweepingDomain)
ValueT value
Definition: GridBuilder.h:1287
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Implementation of morphological dilation and erosion.
Functions to efficiently compute histograms, extrema (min/max) and statistics (mean,...
math::Transform & transform()
Return a reference to this grid's transform, which might be shared with other grids.
Definition: Grid.h:415
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) that is stored in this grid.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:577
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:917
SharedPtr< Grid > Ptr
Definition: Grid.h:579
Definition: Exceptions.h:63
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:564
const ValueType & getValue(unsigned int pos=0) const
Return the value from the stencil buffer with linear offset pos.
Definition: Stencils.h:97
std::bitset< 6 > intersectionMask(const ValueType &isoValue=zeroVal< ValueType >()) const
Return true a bit-mask where the 6 bits indicates if the center of the stencil intersects the iso-con...
Definition: Stencils.h:188
void moveTo(const Coord &ijk)
Initialize the stencil buffer with the values of voxel (i, j, k) and its neighbors.
Definition: Stencils.h:47
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:25
Definition: Stencils.h:1232
Templated class to compute the minimum and maximum values.
Definition: Stats.h:31
Definition: LeafManager.h:102
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:85
bool swapLeafBuffer(size_t bufferIdx, bool serial=false)
Swap each leaf node's buffer with the nth corresponding auxiliary buffer, where n = bufferIdx.
Definition: LeafManager.h:359
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:345
To facilitate threading over the nodes of a tree, cache node pointers in linear arrays,...
Definition: NodeManager.h:531
Definition: ValueAccessor.h:183
void setValueOff(const Coord &xyz, const ValueType &value)
Set the value of the voxel at the given coordinates and mark the voxel as inactive.
Definition: ValueAccessor.h:266
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:219
Simple timer for basic profiling.
Definition: CpuTimer.h:67
double stop() const
Returns and prints time in milliseconds since construction or start was called.
Definition: CpuTimer.h:128
double restart()
Re-start timer.
Definition: CpuTimer.h:150
__hostdev__ uint32_t hash(uint32_t x)
Definition: common.h:13
bool isValid(GridType gridType, GridClass gridClass)
return true if the combination of GridType and GridClass is valid.
Definition: NanoVDB.h:520
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: NanoVDB.h:795
void run(const char *ax, openvdb::GridBase &grid)
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:764
Coord Abs(const Coord &xyz)
Definition: Coord.h:514
size_t MinIndex(const Vec3T &v)
Return the index [0,1,2] of the smallest value in a 3D vector.
Definition: Math.h:938
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance.
Definition: Math.h:350
Index32 Index
Definition: Types.h:54
@ GRID_LEVEL_SET
Definition: Types.h:337
math::Vec3< Real > Vec3R
Definition: Types.h:72
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147