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);
412template<
typename Gr
idT>
438template<
typename Gr
idT,
typename MaskTreeT>
442 bool ignoreActiveTiles =
false,
457template<
typename SdfGr
idT,
typename ExtValueT =
typename SdfGr
idT::ValueType>
461 "FastSweeping requires SdfGridT to have floating-point values");
463 using SdfValueT =
typename SdfGridT::ValueType;
464 using SdfTreeT =
typename SdfGridT::TreeType;
469 using ExtGridT =
typename SdfGridT::template ValueConverter<ExtValueT>::Type;
470 using ExtTreeT =
typename ExtGridT::TreeType;
474 using SweepMaskTreeT =
typename SdfTreeT::template ValueConverter<ValueMask>::Type;
497 typename SdfGridT::Ptr
sdfGrid() {
return mSdfGrid; }
505 typename ExtGridT::Ptr
extGrid() {
return mExtGrid; }
535 bool initSdf(
const SdfGridT &sdfGrid, SdfValueT isoValue,
bool isInputSdf);
583 template <
typename ExtOpT>
586 const ExtValueT &background,
590 const typename ExtGridT::ConstPtr extGrid =
nullptr);
613 bool initDilate(
const SdfGridT &sdfGrid,
636 template<
typename MaskTreeT>
637 bool initMask(
const SdfGridT &sdfGrid,
const Grid<MaskTreeT> &mask,
bool ignoreActiveTiles =
false);
651 void sweep(
int nIter = 1,
652 bool finalize =
true);
664 bool isValid()
const {
return mSweepingVoxelCount > 0 && mBoundaryVoxelCount > 0; }
680 void computeSweepMaskLeafOrigins();
690 struct SweepingKernel;
693 static const Coord mOffset[6];
696 typename SdfGridT::Ptr mSdfGrid;
697 typename ExtGridT::Ptr mExtGrid;
698 typename ExtGridT::Ptr mExtGridInput;
699 SweepMaskTreeT mSweepMask;
700 std::vector<Coord> mSweepMaskLeafOrigins;
701 size_t mSweepingVoxelCount, mBoundaryVoxelCount;
709template <
typename SdfGr
idT,
typename ExtValueT>
710const Coord FastSweeping<SdfGridT, ExtValueT>::mOffset[6] = {{-1,0,0},{1,0,0},
714template <
typename SdfGr
idT,
typename ExtValueT>
716 : mSdfGrid(nullptr), mExtGrid(nullptr), mSweepingVoxelCount(0), mBoundaryVoxelCount(0), mSweepDirection(
FastSweepingDomain::
SWEEP_ALL), mIsInputSdf(true)
720template <
typename SdfGr
idT,
typename ExtValueT>
726 if (mExtGridInput) mExtGridInput.reset();
727 mSweepingVoxelCount = mBoundaryVoxelCount = 0;
732template <
typename SdfGr
idT,
typename ExtValueT>
738 mSweepMask.voxelizeActiveTiles();
741 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
742 LeafManagerT leafManager(mSweepMask);
744 mSweepMaskLeafOrigins.resize(leafManager.leafCount());
745 std::atomic<size_t> sweepingVoxelCount{0};
746 auto kernel = [&](
const LeafT& leaf,
size_t leafIdx) {
747 mSweepMaskLeafOrigins[leafIdx] = leaf.origin();
748 sweepingVoxelCount += leaf.onVoxelCount();
750 leafManager.foreach(kernel,
true, 1024);
752 mBoundaryVoxelCount = 0;
753 mSweepingVoxelCount = sweepingVoxelCount;
755 const size_t totalCount = mSdfGrid->constTree().activeVoxelCount();
756 assert( totalCount >= mSweepingVoxelCount );
757 mBoundaryVoxelCount = totalCount - mSweepingVoxelCount;
761template <
typename SdfGr
idT,
typename ExtValueT>
765 mSdfGrid = fogGrid.deepCopy();
766 mIsInputSdf = isInputSdf;
768 kernel.
run(isoValue);
772template <
typename SdfGr
idT,
typename ExtValueT>
773template <
typename OpT>
779 if (extGrid->transform() != fogGrid.transform())
780 OPENVDB_THROW(
RuntimeError,
"FastSweeping::initExt extension grid input should have the same transform as Fog/SDF grid!");
784 mSdfGrid = fogGrid.deepCopy();
785 mExtGrid = createGrid<ExtGridT>( background );
786 mSweepDirection = mode;
787 mIsInputSdf = isInputSdf;
789 mExtGridInput = extGrid->deepCopy();
791 mExtGrid->topologyUnion( *mSdfGrid );
792 InitExt<OpT> kernel(*
this);
793 kernel.run(isoValue, op);
798template <
typename SdfGr
idT,
typename ExtValueT>
802 mSdfGrid = sdfGrid.deepCopy();
803 mSweepDirection = mode;
805 kernel.
run(dilate, nn);
809template <
typename SdfGr
idT,
typename ExtValueT>
810template<
typename MaskTreeT>
814 mSdfGrid = sdfGrid.deepCopy();
816 if (mSdfGrid->transform() != mask.
transform()) {
821 using T =
typename MaskTreeT::template ValueConverter<bool>::Type;
823 tmp->
tree().voxelizeActiveTiles();
824 MaskKernel<T> kernel(*
this);
825 kernel.run(tmp->
tree());
827 if (ignoreActiveTiles || !mask.
tree().hasActiveTiles()) {
828 MaskKernel<MaskTreeT> kernel(*
this);
829 kernel.run(mask.
tree());
831 using T =
typename MaskTreeT::template ValueConverter<ValueMask>::Type;
833 tmp.voxelizeActiveTiles(
true);
834 MaskKernel<T> kernel(*
this);
841template <
typename SdfGr
idT,
typename ExtValueT>
849 " a non-null reference extension grid input.");
851 if (this->boundaryVoxelCount() == 0) {
853 }
else if (this->sweepingVoxelCount() == 0) {
858 std::deque<SweepingKernel> kernels;
859 for (
int i = 0; i < 4; i++) kernels.emplace_back(*
this);
862#ifdef BENCHMARK_FAST_SWEEPING
867 tbb::task_group tasks;
868 tasks.run([&] { kernels[0].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]+a[2]; }); });
869 tasks.run([&] { kernels[1].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]-a[2]; }); });
870 tasks.run([&] { kernels[2].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]+a[2]; }); });
871 tasks.run([&] { kernels[3].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]-a[2]; }); });
874#ifdef BENCHMARK_FAST_SWEEPING
880 for (
int i = 0; i < nIter; ++i) {
885#ifdef BENCHMARK_FAST_SWEEPING
889 auto e = kernel.
run(*mSdfGrid);
891#ifdef BENCHMARK_FAST_SWEEPING
892 std::cerr <<
"Min = " << e.min() <<
" Max = " << e.max() << std::endl;
893 timer.
restart(
"Changing asymmetric background value");
897#ifdef BENCHMARK_FAST_SWEEPING
906template <
typename SdfGr
idT,
typename ExtValueT>
917 tbb::parallel_reduce(mgr.
leafRange(), *
this);
923 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
924 for (
auto voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
925 const SdfValueT v = *voxelIter;
926 if (v < mMin) mMin = v;
927 if (v > mMax) mMax = v;
934 if (other.
mMin < mMin) mMin = other.
mMin;
935 if (other.
mMax > mMax) mMax = other.
mMax;
944template <
typename SdfGr
idT,
typename ExtValueT>
950 mBackground(parent.mSdfGrid->background())
952 mSdfGridInput = mParent->mSdfGrid->deepCopy();
959#ifdef BENCHMARK_FAST_SWEEPING
964#ifdef BENCHMARK_FAST_SWEEPING
965 timer.
restart(
"Changing background value");
970 #ifdef BENCHMARK_FAST_SWEEPING
971 timer.
restart(
"Dilating and updating mgr (parallel)");
981#ifdef BENCHMARK_FAST_SWEEPING
982 timer.
restart(
"Initializing grid and sweep mask");
985 mParent->mSweepMask.clear();
986 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
989 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
993 LeafManagerT leafManager(mParent->mSdfGrid->tree());
995 auto kernel = [&](LeafT& leaf,
size_t ) {
997 const SdfValueT background = mBackground;
998 auto* maskLeaf = mParent->mSweepMask.probeLeaf(leaf.origin());
999 SdfConstAccT sdfInputAcc(mSdfGridInput->tree());
1001 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1002 const SdfValueT
value = *voxelIter;
1003 SdfValueT inputValue;
1004 const Coord ijk = voxelIter.getCoord();
1007 maskLeaf->setValueOff(voxelIter.pos());
1011 voxelIter.setValue(
value > 0 ? Unknown : -Unknown);
1014 if (
value > 0) voxelIter.setValue(Unknown);
1016 maskLeaf->setValueOff(voxelIter.pos());
1017 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1018 if ( !isInputOn ) voxelIter.setValueOff();
1019 else voxelIter.setValue(inputValue);
1023 if (
value < 0) voxelIter.setValue(-Unknown);
1025 maskLeaf->setValueOff(voxelIter.pos());
1026 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1027 if ( !isInputOn ) voxelIter.setValueOff();
1028 else voxelIter.setValue(inputValue);
1036 leafManager.foreach( kernel );
1039 mParent->computeSweepMaskLeafOrigins();
1041#ifdef BENCHMARK_FAST_SWEEPING
1054template <
typename SdfGr
idT,
typename ExtValueT>
1059 mSdfGrid(parent.mSdfGrid.get()), mIsoValue(0), mAboveSign(0) {}
1065 mIsoValue = isoValue;
1066 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1067 SdfTreeT &tree = mSdfGrid->tree();
1068 const bool hasActiveTiles = tree.hasActiveTiles();
1070 if (mParent->mIsInputSdf && hasActiveTiles) {
1074#ifdef BENCHMARK_FAST_SWEEPING
1077 mParent->mSweepMask.clear();
1078 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1082 tbb::parallel_for(mgr.
leafRange(32), *
this);
1086#ifdef BENCHMARK_FAST_SWEEPING
1087 timer.
restart(
"Initialize tiles - new");
1091 mgr.foreachBottomUp(*
this);
1093 if (hasActiveTiles) tree.voxelizeActiveTiles();
1097 mParent->computeSweepMaskLeafOrigins();
1105 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1106 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1107 SdfValueT* sdf = leafIter.buffer(1).data();
1108 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1109 const SdfValueT
value = *voxelIter;
1110 const bool isAbove =
value > isoValue;
1111 if (!voxelIter.isValueOn()) {
1112 sdf[voxelIter.pos()] = isAbove ? above : -above;
1114 const Coord ijk = voxelIter.getCoord();
1118 sdf[voxelIter.pos()] = isAbove ? above : -above;
1122 const SdfValueT delta =
value - isoValue;
1124 sdf[voxelIter.pos()] = 0;
1127 for (
int i=0; i<6;) {
1130 if (mask.test(i++)) {
1144 template<
typename RootOrInternalNodeT>
1148 for (
auto it = node.cbeginValueAll(); it; ++it) {
1149 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1150 v = v > isoValue ? above : -above;
1163template <
typename SdfGr
idT,
typename ExtValueT>
1164template <
typename OpT>
1168 using OpPoolT = tbb::enumerable_thread_specific<OpT>;
1170 mOpPool(
nullptr), mSdfGrid(parent.mSdfGrid.get()),
1171 mExtGrid(parent.mExtGrid.get()), mIsoValue(0), mAboveSign(0) {}
1172 InitExt(
const InitExt&) =
default;
1173 InitExt&
operator=(
const InitExt&) =
delete;
1174 void run(SdfValueT isoValue,
const OpT &opPrototype)
1176 static_assert(std::is_convertible<
decltype(opPrototype(Vec3d(0))),ExtValueT>
::value,
"Invalid return type of functor");
1181 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1182 mIsoValue = isoValue;
1183 auto &tree1 = mSdfGrid->tree();
1184 auto &tree2 = mExtGrid->tree();
1185 const bool hasActiveTiles = tree1.hasActiveTiles();
1187 if (mParent->mIsInputSdf && hasActiveTiles) {
1191#ifdef BENCHMARK_FAST_SWEEPING
1192 util::CpuTimer timer(
"Initialize voxels");
1195 mParent->mSweepMask.clear();
1196 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1200 OpPoolT opPool(opPrototype);
1204 tbb::parallel_for(mgr.leafRange(32), *
this);
1205 mgr.swapLeafBuffer(1);
1208#ifdef BENCHMARK_FAST_SWEEPING
1209 timer.restart(
"Initialize tiles");
1212 tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree1);
1213 mgr.foreachBottomUp(*
this);
1215 if (hasActiveTiles) {
1216#ifdef BENCHMARK_FAST_SWEEPING
1217 timer.restart(
"Voxelizing active tiles");
1219 tree1.voxelizeActiveTiles();
1220 tree2.voxelizeActiveTiles();
1226 mParent->computeSweepMaskLeafOrigins();
1228#ifdef BENCHMARK_FAST_SWEEPING
1235 void sumHelper(ExtT& sum2, ExtT ext,
bool update,
const SdfT& )
const {
if (update) sum2 = ext; }
1239 void sumHelper(ExtT& sum2, ExtT ext,
bool ,
const SdfT& d2)
const { sum2 +=
static_cast<ExtValueT
>(d2 * ext); }
1242 ExtT extValHelper(ExtT extSum,
const SdfT& )
const {
return extSum; }
1245 ExtT extValHelper(ExtT extSum,
const SdfT& sdfSum)
const {
return ExtT((SdfT(1) / sdfSum) * extSum); }
1247 void operator()(
const LeafRange& r)
const
1249 ExtAccT acc(mExtGrid->tree());
1250 SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
1251 math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
1252 const math::Transform& xform = mExtGrid->transform();
1253 typename OpPoolT::reference op = mOpPool->local();
1255 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1256 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1257 SdfValueT *sdf = leafIter.buffer(1).data();
1258 ExtValueT *ext = acc.probeLeaf(leafIter->origin())->buffer().data();
1259 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1260 const SdfValueT
value = *voxelIter;
1261 const bool isAbove =
value > isoValue;
1262 if (!voxelIter.isValueOn()) {
1263 sdf[voxelIter.pos()] = isAbove ? above : -above;
1265 const Coord ijk = voxelIter.getCoord();
1266 stencil.moveTo(ijk,
value);
1267 const auto mask = stencil.intersectionMask( isoValue );
1269 sdf[voxelIter.pos()] = isAbove ? above : -above;
1273 sweepMaskAcc.setValueOff(ijk);
1274 const SdfValueT delta =
value - isoValue;
1276 sdf[voxelIter.pos()] = 0;
1277 ext[voxelIter.pos()] = ExtValueT(op(xform.indexToWorld(ijk)));
1280 ExtValueT sum2 = zeroVal<ExtValueT>();
1286 for (
int n=0, i=0; i<6;) {
1288 if (mask.test(i++)) {
1292 if (mask.test(i++)) {
1302 const Vec3R xyz(
static_cast<SdfValueT
>(ijk[0])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][0]),
1303 static_cast<SdfValueT
>(ijk[1])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][1]),
1304 static_cast<SdfValueT
>(ijk[2])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][2]));
1306 sumHelper(sum2, ExtValueT(op(xform.indexToWorld(xyz))), d < minD, d2);
1307 if (d < minD) minD = d;
1310 ext[voxelIter.pos()] = extValHelper(sum2, sum1);
1311 sdf[voxelIter.pos()] = isAbove ? h /
math::Sqrt(sum1) : -h / math::
Sqrt(sum1);
1319 template<
typename RootOrInternalNodeT>
1320 void operator()(
const RootOrInternalNodeT& node)
const
1323 for (
auto it = node.cbeginValueAll(); it; ++it) {
1324 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1325 v = v > isoValue ? above : -above;
1333 SdfValueT mIsoValue;
1334 SdfValueT mAboveSign;
1338template <
typename SdfGr
idT,
typename ExtValueT>
1339template <
typename MaskTreeT>
1340struct FastSweeping<SdfGridT, ExtValueT>::MaskKernel
1342 using LeafRange =
typename tree::LeafManager<const MaskTreeT>::LeafRange;
1344 mSdfGrid(parent.mSdfGrid.get()) {}
1345 MaskKernel(
const MaskKernel &parent) =
default;
1346 MaskKernel&
operator=(
const MaskKernel&) =
delete;
1348 void run(
const MaskTreeT &mask)
1350#ifdef BENCHMARK_FAST_SWEEPING
1351 util::CpuTimer timer;
1353 auto &lsTree = mSdfGrid->tree();
1357#ifdef BENCHMARK_FAST_SWEEPING
1358 timer.restart(
"Changing background value");
1362#ifdef BENCHMARK_FAST_SWEEPING
1363 timer.restart(
"Union with mask");
1365 lsTree.topologyUnion(mask);
1368 tree::LeafManager<const MaskTreeT> mgr(mask);
1370#ifdef BENCHMARK_FAST_SWEEPING
1371 timer.restart(
"Initializing grid and sweep mask");
1374 mParent->mSweepMask.clear();
1375 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1377 using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
1378 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1379 LeafManagerT leafManager(mParent->mSweepMask);
1381 auto kernel = [&](LeafT& leaf,
size_t ) {
1383 SdfAccT acc(mSdfGrid->tree());
1386 SdfValueT *data = acc.probeLeaf(leaf.origin())->buffer().data();
1387 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1388 if (
math::Abs( data[voxelIter.pos()] ) < Unknown ) {
1390 voxelIter.setValue(
false);
1394 leafManager.foreach( kernel );
1397 mParent->computeSweepMaskLeafOrigins();
1399#ifdef BENCHMARK_FAST_SWEEPING
1410template <
typename SdfGr
idT,
typename ExtValueT>
1418 template<
typename HashOp>
1421#ifdef BENCHMARK_FAST_SWEEPING
1426 const SweepMaskTreeT& maskTree = mParent->mSweepMask;
1429 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1430 LeafManagerT leafManager(maskTree);
1437 constexpr int maskOffset = LeafT::DIM * 3;
1438 constexpr int maskRange = maskOffset * 2;
1441 std::vector<int8_t> leafSliceMasks(leafManager.leafCount()*maskRange);
1442 auto kernel1 = [&](
const LeafT& leaf,
size_t leafIdx) {
1443 const size_t leafOffset = leafIdx * maskRange;
1444 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1445 const Coord ijk = LeafT::offsetToLocalCoord(voxelIter.pos());
1446 leafSliceMasks[leafOffset +
hash(ijk) + maskOffset] = uint8_t(1);
1449 leafManager.foreach( kernel1 );
1454 using ThreadLocalMap = std::unordered_map<int64_t, std::deque<size_t>>;
1455 tbb::enumerable_thread_specific<ThreadLocalMap> pool;
1456 auto kernel2 = [&](
const LeafT& leaf,
size_t leafIdx) {
1457 ThreadLocalMap& map = pool.local();
1458 const Coord& origin = leaf.origin();
1459 const int64_t leafKey =
hash(origin);
1460 const size_t leafOffset = leafIdx * maskRange;
1461 for (
int sliceIdx = 0; sliceIdx < maskRange; sliceIdx++) {
1462 if (leafSliceMasks[leafOffset + sliceIdx] == uint8_t(1)) {
1463 const int64_t voxelSliceKey = leafKey+sliceIdx-maskOffset;
1464 map[voxelSliceKey].emplace_back(leafIdx);
1468 leafManager.foreach( kernel2 );
1473 for (
auto poolIt = pool.begin(); poolIt != pool.end(); ++poolIt) {
1474 const ThreadLocalMap& map = *poolIt;
1475 for (
const auto& it : map) {
1476 for (
const size_t leafIdx : it.second) {
1477 mVoxelSliceMap[it.first].emplace_back(leafIdx, NodeMaskPtrT());
1483 mVoxelSliceKeys.reserve(mVoxelSliceMap.size());
1484 for (
const auto& it : mVoxelSliceMap) {
1485 mVoxelSliceKeys.push_back(it.first);
1489 auto kernel3 = [&](tbb::blocked_range<size_t>& range) {
1490 for (
size_t i = range.begin(); i < range.end(); i++) {
1491 const int64_t key = mVoxelSliceKeys[i];
1492 for (
auto& it : mVoxelSliceMap[key]) {
1493 it.second = std::make_unique<NodeMaskT>();
1497 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel3);
1504 auto kernel4 = [&](tbb::blocked_range<size_t>& range) {
1505 for (
size_t i = range.begin(); i < range.end(); i++) {
1506 const int64_t voxelSliceKey = mVoxelSliceKeys[i];
1507 LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceKey];
1508 for (LeafSlice& leafSlice : leafSliceArray) {
1509 const size_t leafIdx = leafSlice.first;
1510 NodeMaskPtrT& nodeMask = leafSlice.second;
1511 const LeafT& leaf = leafManager.leaf(leafIdx);
1512 const Coord& origin = leaf.origin();
1513 const int64_t leafKey =
hash(origin);
1514 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1515 const Index voxelIdx = voxelIter.pos();
1516 const Coord ijk = LeafT::offsetToLocalCoord(voxelIdx);
1517 const int64_t key = leafKey +
hash(ijk);
1518 if (key == voxelSliceKey) {
1519 nodeMask->setOn(voxelIdx);
1525 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel4);
1532 inline static Coord ijk(
const Coord &p,
int i) {
return p + FastSweeping::mOffset[i]; }
1537 inline operator bool()
const {
return v < SdfValueT(1000); }
1542 ExtT
twoNghbr(
const NN& d1,
const NN& d2,
const SdfT& ,
const ExtT& v1,
const ExtT& v2)
const {
return d1.
v < d2.
v ? v1 : v2; }
1546 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)); }
1550 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& ,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1558 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& w,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1559 return ExtT(w*(d1.
v*v1 + d2.
v*v2 + d3.
v*v3));
1564 typename ExtGridT::TreeType *tree2 = mParent->mExtGrid ? &mParent->mExtGrid->tree() :
nullptr;
1565 typename ExtGridT::TreeType *tree3 = mParent->mExtGridInput ? &mParent->mExtGridInput->tree() :
nullptr;
1567 const SdfValueT h =
static_cast<SdfValueT
>(mParent->mSdfGrid->voxelSize()[0]);
1568 const SdfValueT sqrt2h =
math::Sqrt(SdfValueT(2))*h;
1570 const bool isInputSdf = mParent->mIsInputSdf;
1577 const std::vector<Coord>& leafNodeOrigins = mParent->mSweepMaskLeafOrigins;
1579 int64_t voxelSliceIndex(0);
1581 auto kernel = [&](
const tbb::blocked_range<size_t>& range) {
1582 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1584 SdfAccT acc1(mParent->mSdfGrid->tree());
1585 auto acc2 = std::unique_ptr<ExtAccT>(tree2 ?
new ExtAccT(*tree2) :
nullptr);
1586 auto acc3 = std::unique_ptr<ExtAccT>(tree3 ?
new ExtAccT(*tree3) :
nullptr);
1587 SdfValueT absV, sign, update, D;
1590 const LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceIndex];
1594 for (
size_t i = range.begin(); i < range.end(); ++i) {
1599 const LeafSlice& leafSlice = leafSliceArray[i];
1600 const size_t leafIdx = leafSlice.first;
1601 const NodeMaskPtrT& nodeMask = leafSlice.second;
1603 const Coord& origin = leafNodeOrigins[leafIdx];
1606 for (
auto indexIter = nodeMask->beginOn(); indexIter; ++indexIter) {
1609 ijk = origin + LeafT::offsetToLocalCoord(indexIter.pos());
1616 if (!(d1 || d2 || d3))
continue;
1621 SdfValueT &
value =
const_cast<SdfValueT&
>(acc1.
getValue(ijk));
1624 sign =
value >= SdfValueT(0) ? SdfValueT(1) : SdfValueT(-1);
1630 if (d2 < d1) std::swap(d1, d2);
1631 if (d3 < d2) std::swap(d2, d3);
1632 if (d2 < d1) std::swap(d1, d2);
1638 if (update <= d2.
v) {
1639 if (update < absV) {
1640 value = sign * update;
1643 ExtValueT updateExt = acc2->getValue(d1(ijk));
1645 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1646 else updateExt = (
value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1649 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1650 else updateExt = (
value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1652 acc2->setValue(ijk, updateExt);
1662 if (d2.
v <= sqrt2h + d1.
v) {
1664 update = SdfValueT(0.5) * (d1.
v + d2.
v + std::sqrt(D));
1665 if (update > d2.
v && update <= d3.
v) {
1666 if (update < absV) {
1667 value = sign * update;
1672 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v);
1673 const ExtValueT v1 = acc2->getValue(d1(ijk));
1674 const ExtValueT v2 = acc2->getValue(d2(ijk));
1675 const ExtValueT extVal = twoNghbr(d1, d2, w, v1, v2);
1677 ExtValueT updateExt = extVal;
1679 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1680 else updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1683 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1684 else updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1686 acc2->setValue(ijk, updateExt);
1697 const SdfValueT d123 = d1.
v + d2.
v + d3.
v;
1698 D = d123*d123 - SdfValueT(3)*(d1.
v*d1.
v + d2.
v*d2.
v + d3.
v*d3.
v - h * h);
1699 if (D >= SdfValueT(0)) {
1700 update = SdfValueT(1.0/3.0) * (d123 + std::sqrt(D));
1702 if (update < absV) {
1703 value = sign * update;
1709 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v+d3.
v);
1710 const ExtValueT v1 = acc2->getValue(d1(ijk));
1711 const ExtValueT v2 = acc2->getValue(d2(ijk));
1712 const ExtValueT v3 = acc2->getValue(d3(ijk));
1713 const ExtValueT extVal = threeNghbr(d1, d2, d3, w, v1, v2, v3);
1715 ExtValueT updateExt = extVal;
1717 if (
isInputSdf) updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1718 else updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1721 if (
isInputSdf) updateExt = (
value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1722 else updateExt = (
value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1724 acc2->setValue(ijk, updateExt);
1732#ifdef BENCHMARK_FAST_SWEEPING
1736 for (
size_t i = 0; i < mVoxelSliceKeys.size(); i++) {
1737 voxelSliceIndex = mVoxelSliceKeys[i];
1738 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1741#ifdef BENCHMARK_FAST_SWEEPING
1742 timer.
restart(
"Backward sweeps");
1744 for (
size_t i = mVoxelSliceKeys.size(); i > 0; i--) {
1745 voxelSliceIndex = mVoxelSliceKeys[i-1];
1746 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1749#ifdef BENCHMARK_FAST_SWEEPING
1755 using NodeMaskT =
typename SweepMaskTreeT::LeafNodeType::NodeMaskType;
1756 using NodeMaskPtrT = std::unique_ptr<NodeMaskT>;
1759 using LeafSlice = std::pair<size_t, NodeMaskPtrT>;
1760 using LeafSliceArray = std::deque<LeafSlice>;
1761 using VoxelSliceMap = std::map<int64_t, LeafSliceArray>;
1765 VoxelSliceMap mVoxelSliceMap;
1766 std::vector<int64_t> mVoxelSliceKeys;
1771template<
typename Gr
idT>
1774 typename GridT::ValueType isoValue,
1778 if (fs.initSdf(fogGrid, isoValue,
false)) fs.
sweep(nIter);
1779 return fs.sdfGrid();
1782template<
typename Gr
idT>
1785 typename GridT::ValueType isoValue,
1789 if (fs.initSdf(sdfGrid, isoValue,
true)) fs.
sweep(nIter);
1790 return fs.sdfGrid();
1793template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1794typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
1797 const ExtValueT& background,
1798 typename FogGridT::ValueType isoValue,
1801 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1804 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1805 fs.
sweep(nIter,
true);
1806 return fs.extGrid();
1809template<
typename SdfGr
idT,
typename OpT,
typename ExtValueT>
1810typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
1813 const ExtValueT &background,
1814 typename SdfGridT::ValueType isoValue,
1817 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1820 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1821 fs.
sweep(nIter,
true);
1822 return fs.extGrid();
1825template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1826std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1829 const ExtValueT &background,
1830 typename FogGridT::ValueType isoValue,
1833 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1836 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1837 fs.
sweep(nIter,
true);
1838 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1841template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
1842std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1845 const ExtValueT &background,
1846 typename SdfGridT::ValueType isoValue,
1849 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1852 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1853 fs.
sweep(nIter,
true);
1854 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1857template<
typename Gr
idT>
1866 if (fs.initDilate(sdfGrid, dilation, nn, mode)) fs.
sweep(nIter);
1867 return fs.sdfGrid();
1870template<
typename Gr
idT,
typename MaskTreeT>
1874 bool ignoreActiveTiles,
1878 if (fs.initMask(sdfGrid, mask, ignoreActiveTiles)) fs.
sweep(nIter);
1879 return fs.sdfGrid();
1888#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1890#ifdef OPENVDB_INSTANTIATE_FASTSWEEPING
1894#define _FUNCTION(TreeT) \
1895 Grid<TreeT>::Ptr fogToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1899#define _FUNCTION(TreeT) \
1900 Grid<TreeT>::Ptr sdfToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1904#define _FUNCTION(TreeT) \
1905 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:413
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:573
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:913
SharedPtr< Grid > Ptr
Definition: Grid.h:575
Definition: Exceptions.h:63
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:644
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
OPENVDB_AX_API void run(const char *ax, openvdb::GridBase &grid, const AttributeBindings &bindings={})
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
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
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:515
size_t MinIndex(const Vec3T &v)
Return the index [0,1,2] of the smallest value in a 3D vector.
Definition: Math.h:938
Index32 Index
Definition: Types.h:54
@ GRID_LEVEL_SET
Definition: Types.h:416
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