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> 49 #include <type_traits> 53 #include <unordered_map> 101 template<
typename Gr
idT>
104 typename GridT::ValueType isoValue,
134 template<
typename Gr
idT>
137 typename GridT::ValueType isoValue = 0,
190 template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
191 typename 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);
248 template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
249 typename 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);
311 template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
312 std::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);
374 template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
375 std::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);
412 template<
typename Gr
idT>
438 template<
typename Gr
idT,
typename MaskTreeT>
442 bool ignoreActiveTiles =
false,
457 template<
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>
584 bool initExt(
const SdfGridT &sdfGrid,
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();
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;
709 template <
typename SdfGr
idT,
typename ExtValueT>
714 template <
typename SdfGr
idT,
typename ExtValueT>
716 : mSdfGrid(nullptr), mExtGrid(nullptr), mSweepingVoxelCount(0), mBoundaryVoxelCount(0), mSweepDirection(
FastSweepingDomain::
SWEEP_ALL), mIsInputSdf(true)
720 template <
typename SdfGr
idT,
typename ExtValueT>
726 if (mExtGridInput) mExtGridInput.reset();
727 mSweepingVoxelCount = mBoundaryVoxelCount = 0;
732 template <
typename SdfGr
idT,
typename ExtValueT>
738 mSweepMask.voxelizeActiveTiles();
741 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
742 LeafManagerT leafManager(mSweepMask);
744 mSweepMaskLeafOrigins.resize(leafManager.leafCount());
746 auto kernel = [&](
const LeafT& leaf,
size_t leafIdx) {
747 mSweepMaskLeafOrigins[leafIdx] = leaf.origin();
750 leafManager.foreach(kernel,
true, 1024);
752 mBoundaryVoxelCount = 0;
755 const size_t totalCount = mSdfGrid->constTree().activeVoxelCount();
756 assert( totalCount >= mSweepingVoxelCount );
757 mBoundaryVoxelCount = totalCount - mSweepingVoxelCount;
761 template <
typename SdfGr
idT,
typename ExtValueT>
765 mSdfGrid = fogGrid.deepCopy();
768 kernel.
run(isoValue);
772 template <
typename SdfGr
idT,
typename ExtValueT>
773 template <
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;
789 mExtGridInput = extGrid->deepCopy();
791 mExtGrid->topologyUnion( *mSdfGrid );
792 InitExt<OpT> kernel(*
this);
793 kernel.run(isoValue, op);
798 template <
typename SdfGr
idT,
typename ExtValueT>
802 mSdfGrid = sdfGrid.deepCopy();
803 mSweepDirection = mode;
805 kernel.
run(dilate, nn);
809 template <
typename SdfGr
idT,
typename ExtValueT>
810 template<
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);
841 template <
typename SdfGr
idT,
typename ExtValueT>
849 " a non-null reference extension grid input.");
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 906 template <
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;
944 template <
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 1054 template <
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();
1115 stencil.
moveTo(ijk, value);
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++)) {
1134 if (d < std::numeric_limits<SdfValueT>::max()) sum += 1/(d*d);
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;
1163 template <
typename SdfGr
idT,
typename ExtValueT>
1164 template <
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 1195 mParent->mSweepMask.clear();
1196 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1200 OpPoolT opPool(opPrototype);
1204 tbb::parallel_for(mgr.
leafRange(32), *
this);
1208 #ifdef BENCHMARK_FAST_SWEEPING 1209 timer.
restart(
"Initialize tiles");
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());
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);
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++)) {
1299 if (d < std::numeric_limits<SdfValueT>::max()) {
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);
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;
1338 template <
typename SdfGr
idT,
typename ExtValueT>
1339 template <
typename MaskTreeT>
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 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);
1370 #ifdef BENCHMARK_FAST_SWEEPING 1371 timer.
restart(
"Initializing grid and sweep mask");
1374 mParent->mSweepMask.clear();
1375 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
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 1410 template <
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]; }
1534 NN(
const SdfAccT &a,
const Coord &p,
int i) : v(math::
Abs(a.getValue(ijk(p,i)))), n(i) {}
1535 inline Coord
operator()(
const Coord &p)
const {
return ijk(p, n); }
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) {
1663 D = SdfValueT(2) * h * h -
math::Pow2(d1.v - d2.
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;
1771 template<
typename Gr
idT>
1774 typename GridT::ValueType isoValue,
1778 if (fs.
initSdf(fogGrid, isoValue,
false)) fs.
sweep(nIter);
1782 template<
typename Gr
idT>
1785 typename GridT::ValueType isoValue,
1789 if (fs.
initSdf(sdfGrid, isoValue,
true)) fs.
sweep(nIter);
1793 template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1794 typename 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);
1809 template<
typename SdfGr
idT,
typename OpT,
typename ExtValueT>
1810 typename 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);
1825 template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1826 std::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);
1841 template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
1842 std::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);
1857 template<
typename Gr
idT>
1870 template<
typename Gr
idT,
typename MaskTreeT>
1874 bool ignoreActiveTiles,
1878 if (fs.
initMask(sdfGrid, mask, ignoreActiveTiles)) fs.
sweep(nIter);
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) 1909 #endif // OPENVDB_USE_EXPLICIT_INSTANTIATION 1916 #endif // OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
LeafNodeT * probeLeaf(const Coord &xyz)
Return a pointer to the leaf node that contains voxel (x, y, z), or nullptr if no such node exists...
Definition: ValueAccessor.h:379
SharedPtr< Grid > Ptr
Definition: Grid.h:579
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:345
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Templated class to compute the minimum and maximum values.
Definition: Stats.h:30
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
size_t MinIndex(const Vec3T &v)
Return the index [0,1,2] of the smallest value in a 3D vector.
Definition: Math.h:938
Functions to efficiently compute histograms, extrema (min/max) and statistics (mean, variance, etc.) of grid values.
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
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
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
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:644
Definition: LeafManager.h:101
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:917
float Sqrt(float x)
Return the square root of a floating-point value.
Definition: Math.h:764
To facilitate threading over the nodes of a tree, cache node pointers in linear arrays, one for each level of the tree.
Definition: NodeManager.h:30
Implementation of morphological dilation and erosion.
Definition: Exceptions.h:13
ValueT value
Definition: GridBuilder.h:1287
Definition: Exceptions.h:63
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
Index32 Index
Definition: Types.h:54
__hostdev__ uint32_t hash(uint32_t x)
Definition: common.h:13
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
double restart()
Re-start timer.
Definition: CpuTimer.h:150
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) that is stored in this grid...
double stop() const
Returns and prints time in milliseconds since construction or start was called.
Definition: CpuTimer.h:128
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.
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147
Definition: Stencils.h:1231
Coord Abs(const Coord &xyz)
Definition: Coord.h:514
Type Pow2(Type x)
Return x2.
Definition: Math.h:551
Simple timer for basic profiling.
Definition: CpuTimer.h:66
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
const ValueType & getValue(unsigned int pos=0) const
Return the value from the stencil buffer with linear offset pos.
Definition: Stencils.h:97
Definition: ValueAccessor.h:182
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
math::Transform & transform()
Return a reference to this grid's transform, which might be shared with other grids.
Definition: Grid.h:415
void moveTo(const Coord &ijk)
Initialize the stencil buffer with the values of voxel (i, j, k) and its neighbors.
Definition: Stencils.h:47
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202