27#ifndef OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
28#define OPENVDB_TOOLS_FASTSWEEPING_HAS_BEEN_INCLUDED
44#ifdef BENCHMARK_FAST_SWEEPING
48#include <tbb/parallel_for.h>
49#include <tbb/enumerable_thread_specific.h>
50#include <tbb/task_group.h>
56#include <unordered_map>
104template<
typename Gr
idT>
106fogToSdf(
const GridT &fogGrid,
107 typename GridT::ValueType isoValue,
137template<
typename Gr
idT>
139sdfToSdf(
const GridT &sdfGrid,
140 typename GridT::ValueType isoValue = 0,
193template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
194typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
195fogToExt(
const FogGridT &fogGrid,
197 const ExtValueT& background,
198 typename FogGridT::ValueType isoValue,
200 FastSweepingDomain mode = FastSweepingDomain::SWEEP_ALL,
201 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
251template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
252typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
255 const ExtValueT &background,
256 typename SdfGridT::ValueType isoValue = 0,
259 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
314template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
315std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
318 const ExtValueT &background,
319 typename FogGridT::ValueType isoValue,
322 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
377template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
378std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
381 const ExtValueT &background,
382 typename SdfGridT::ValueType isoValue = 0,
385 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid =
nullptr);
415template<
typename Gr
idT>
441template<
typename Gr
idT,
typename MaskTreeT>
445 bool ignoreActiveTiles =
false,
460template<
typename SdfGr
idT,
typename ExtValueT =
typename SdfGr
idT::ValueType>
463 static_assert(std::is_floating_point<typename SdfGridT::ValueType>::value,
464 "FastSweeping requires SdfGridT to have floating-point values");
466 using SdfValueT =
typename SdfGridT::ValueType;
467 using SdfTreeT =
typename SdfGridT::TreeType;
472 using ExtGridT =
typename SdfGridT::template ValueConverter<ExtValueT>::Type;
473 using ExtTreeT =
typename ExtGridT::TreeType;
477 using SweepMaskTreeT =
typename SdfTreeT::template ValueConverter<ValueMask>::Type;
500 typename SdfGridT::Ptr
sdfGrid() {
return mSdfGrid; }
508 typename ExtGridT::Ptr
extGrid() {
return mExtGrid; }
538 bool initSdf(
const SdfGridT &sdfGrid, SdfValueT isoValue,
bool isInputSdf);
586 template <
typename ExtOpT>
589 const ExtValueT &background,
593 const typename ExtGridT::ConstPtr
extGrid =
nullptr);
639 template<
typename MaskTreeT>
654 void sweep(
int nIter = 1,
655 bool finalize =
true);
667 bool isValid()
const {
return mSweepingVoxelCount > 0 && mBoundaryVoxelCount > 0; }
683 void computeSweepMaskLeafOrigins();
693 struct PruneMinMaxFltKernel;
694 struct SweepingKernel;
700 typename SdfGridT::Ptr mSdfGrid;
701 typename ExtGridT::Ptr mExtGrid;
702 typename ExtGridT::Ptr mExtGridInput;
703 SweepMaskTreeT mSweepMask;
704 std::vector<Coord> mSweepMaskLeafOrigins;
705 size_t mSweepingVoxelCount, mBoundaryVoxelCount;
713template <
typename SdfGr
idT,
typename ExtValueT>
714const Coord FastSweeping<SdfGridT, ExtValueT>::mOffset[6] = {{-1,0,0},{1,0,0},
718template <
typename SdfGr
idT,
typename ExtValueT>
720 : mSdfGrid(nullptr), mExtGrid(nullptr), mSweepingVoxelCount(0), mBoundaryVoxelCount(0), mSweepDirection(
FastSweepingDomain::
SWEEP_ALL), mIsInputSdf(true)
724template <
typename SdfGr
idT,
typename ExtValueT>
730 if (mExtGridInput) mExtGridInput.reset();
731 mSweepingVoxelCount = mBoundaryVoxelCount = 0;
736template <
typename SdfGr
idT,
typename ExtValueT>
737void FastSweeping<SdfGridT, ExtValueT>::computeSweepMaskLeafOrigins()
742 mSweepMask.voxelizeActiveTiles();
745 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
746 LeafManagerT leafManager(mSweepMask);
748 mSweepMaskLeafOrigins.resize(leafManager.leafCount());
749 std::atomic<size_t> sweepingVoxelCount{0};
750 auto kernel = [&](
const LeafT& leaf,
size_t leafIdx) {
751 mSweepMaskLeafOrigins[leafIdx] = leaf.origin();
752 sweepingVoxelCount += leaf.onVoxelCount();
754 leafManager.foreach(kernel,
true, 1024);
756 mBoundaryVoxelCount = 0;
757 mSweepingVoxelCount = sweepingVoxelCount;
759 const size_t totalCount = mSdfGrid->constTree().activeVoxelCount();
761 mBoundaryVoxelCount = totalCount - mSweepingVoxelCount;
765template <
typename SdfGr
idT,
typename ExtValueT>
769 mSdfGrid = fogGrid.deepCopy();
772 kernel.
run(isoValue);
776template <
typename SdfGr
idT,
typename ExtValueT>
777template <
typename OpT>
783 if (
extGrid->transform() != fogGrid.transform())
784 OPENVDB_THROW(
RuntimeError,
"FastSweeping::initExt extension grid input should have the same transform as Fog/SDF grid!");
788 mSdfGrid = fogGrid.deepCopy();
790 mSweepDirection = mode;
793 mExtGridInput =
extGrid->deepCopy();
795 mExtGrid->topologyUnion( *mSdfGrid );
796 InitExt<OpT> kernel(*
this);
797 kernel.run(isoValue, op);
802template <
typename SdfGr
idT,
typename ExtValueT>
807 mSweepDirection = mode;
809 kernel.
run(dilate, nn);
813template <
typename SdfGr
idT,
typename ExtValueT>
814template<
typename MaskTreeT>
820 if (mSdfGrid->transform() != mask.
transform()) {
827 using T =
typename MaskTreeT::template ValueConverter<bool>::Type;
829 tmp->
tree().voxelizeActiveTiles();
830 MaskKernel<T> kernel(*
this);
831 kernel.run(tmp->
tree());
835 if (ignoreActiveTiles || !mask.
tree().hasActiveTiles()) {
836 MaskKernel<MaskTreeT> kernel(*
this);
837 kernel.run(mask.
tree());
839 using T =
typename MaskTreeT::template ValueConverter<ValueMask>::Type;
841 tmp.voxelizeActiveTiles(
true);
842 MaskKernel<T> kernel(*
this);
848template <
typename SdfGr
idT,
typename ExtValueT>
856 " a non-null reference extension grid input.");
860 }
else if (this->sweepingVoxelCount() == 0) {
865 std::deque<SweepingKernel> kernels;
866 for (
int i = 0; i < 4; i++) kernels.emplace_back(*
this);
869#ifdef BENCHMARK_FAST_SWEEPING
874 tbb::task_group tasks;
875 tasks.run([&] { kernels[0].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]+a[2]; }); });
876 tasks.run([&] { kernels[1].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]-a[2]; }); });
877 tasks.run([&] { kernels[2].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]+a[2]; }); });
878 tasks.run([&] { kernels[3].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]-a[2]; }); });
881#ifdef BENCHMARK_FAST_SWEEPING
887 for (
int i = 0; i < nIter; ++i) {
892#ifdef BENCHMARK_FAST_SWEEPING
896 auto e = kernel.
run(*mSdfGrid);
903#ifdef BENCHMARK_FAST_SWEEPING
904 std::cerr <<
"Min = " << e.min() <<
" Max = " << e.max() << std::endl;
905 timer.
restart(
"Changing asymmetric background value");
909#ifdef BENCHMARK_FAST_SWEEPING
920template <
typename SdfGr
idT,
typename ExtValueT>
931 tbb::parallel_reduce(mgr.
leafRange(), *
this);
937 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
938 for (
auto voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
939 const SdfValueT v = *voxelIter;
940 const bool vEqFltMin = v == -std::numeric_limits<SdfValueT>::max();
941 const bool vEqFltMax = v == std::numeric_limits<SdfValueT>::max();
942 if (v <
mMin && !vEqFltMin)
mMin = v;
943 if (v >
mMax && !vEqFltMax)
mMax = v;
964template <
typename SdfGr
idT,
typename ExtValueT>
969 void operator()(
typename SdfTreeT::RootNodeType& node,
size_t = 1)
const {
970 for (
auto iter = node.beginValueAll(); iter; ++iter) {
971 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
974 if (*iter == std::numeric_limits<SdfValueT>::max()) {
981 template<
typename NodeT>
984 for (
auto iter = node.beginValueAll(); iter; ++iter) {
985 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
988 if (*iter == std::numeric_limits<SdfValueT>::max()) {
995 void operator()(
typename SdfTreeT::LeafNodeType& leaf,
size_t = 1)
const
997 for (
auto iter = leaf.beginValueOn(); iter; ++iter) {
998 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
1001 if (*iter == std::numeric_limits<SdfValueT>::max()) {
1002 iter.setValue(
mMax);
1012template <
typename SdfGr
idT,
typename ExtValueT>
1027#ifdef BENCHMARK_FAST_SWEEPING
1032#ifdef BENCHMARK_FAST_SWEEPING
1033 timer.
restart(
"Changing background value");
1035 static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1038 #ifdef BENCHMARK_FAST_SWEEPING
1039 timer.
restart(
"Dilating and updating mgr (parallel)");
1043 const int delta = 5;
1049#ifdef BENCHMARK_FAST_SWEEPING
1050 timer.
restart(
"Initializing grid and sweep mask");
1054 mParent->mSweepMask.topologyUnion(
mParent->mSdfGrid->constTree());
1057 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1061 LeafManagerT leafManager(
mParent->mSdfGrid->tree());
1063 auto kernel = [&](LeafT& leaf,
size_t ) {
1064 static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1066 auto* maskLeaf =
mParent->mSweepMask.probeLeaf(leaf.origin());
1069 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1070 const SdfValueT value = *voxelIter;
1071 SdfValueT inputValue;
1072 const Coord ijk = voxelIter.getCoord();
1075 maskLeaf->setValueOff(voxelIter.pos());
1079 voxelIter.setValue(value > 0 ? Unknown : -Unknown);
1082 if (value > 0) voxelIter.setValue(Unknown);
1084 maskLeaf->setValueOff(voxelIter.pos());
1085 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1086 if ( !isInputOn ) voxelIter.setValueOff();
1087 else voxelIter.setValue(inputValue);
1091 if (value < 0) voxelIter.setValue(-Unknown);
1093 maskLeaf->setValueOff(voxelIter.pos());
1094 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1095 if ( !isInputOn ) voxelIter.setValueOff();
1096 else voxelIter.setValue(inputValue);
1104 leafManager.foreach( kernel );
1107 mParent->computeSweepMaskLeafOrigins();
1109#ifdef BENCHMARK_FAST_SWEEPING
1122template <
typename SdfGr
idT,
typename ExtValueT>
1136 const bool hasActiveTiles =
tree.hasActiveTiles();
1138 if (
mParent->mIsInputSdf && hasActiveTiles) {
1142#ifdef BENCHMARK_FAST_SWEEPING
1146 mParent->mSweepMask.topologyUnion(
mParent->mSdfGrid->constTree());
1150 tbb::parallel_for(mgr.
leafRange(32), *
this);
1154#ifdef BENCHMARK_FAST_SWEEPING
1155 timer.
restart(
"Initialize tiles - new");
1159 mgr.foreachBottomUp(*
this);
1160 tree.root().setBackground(std::numeric_limits<SdfValueT>::max(),
false);
1161 if (hasActiveTiles)
tree.voxelizeActiveTiles();
1165 mParent->computeSweepMaskLeafOrigins();
1170 SweepMaskAccT sweepMaskAcc(
mParent->mSweepMask);
1172 const SdfValueT isoValue =
mIsoValue, above =
mAboveSign*std::numeric_limits<SdfValueT>::max();
1174 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1175 SdfValueT* sdf = leafIter.buffer(1).data();
1176 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1177 const SdfValueT value = *voxelIter;
1178 const bool isAbove = value > isoValue;
1179 if (!voxelIter.isValueOn()) {
1180 sdf[voxelIter.pos()] = isAbove ? above : -above;
1182 const Coord ijk = voxelIter.getCoord();
1183 stencil.
moveTo(ijk, value);
1186 sdf[voxelIter.pos()] = isAbove ? above : -above;
1190 const SdfValueT delta = value - isoValue;
1192 sdf[voxelIter.pos()] = 0;
1195 for (
int i=0; i<6;) {
1196 SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
1198 if (mask.test(i++)) {
1202 if (d < std::numeric_limits<SdfValueT>::max()) sum += 1/(d*d);
1212 template<
typename RootOrInternalNodeT>
1215 const SdfValueT isoValue =
mIsoValue, above =
mAboveSign*std::numeric_limits<SdfValueT>::max();
1216 for (
auto it = node.cbeginValueAll(); it; ++it) {
1217 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1218 v = v > isoValue ? above : -above;
1231template <
typename SdfGr
idT,
typename ExtValueT>
1232template <
typename OpT>
1236 using OpPoolT = tbb::enumerable_thread_specific<OpT>;
1238 mOpPool(
nullptr), mSdfGrid(parent.mSdfGrid.get()),
1239 mExtGrid(parent.mExtGrid.get()), mIsoValue(0), mAboveSign(0) {}
1240 InitExt(
const InitExt&) =
default;
1241 InitExt&
operator=(
const InitExt&) =
delete;
1242 void run(SdfValueT isoValue,
const OpT &opPrototype)
1244 static_assert(std::is_convertible<
decltype(opPrototype(
Vec3d(0))),ExtValueT>::value,
"Invalid return type of functor");
1249 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1250 mIsoValue = isoValue;
1251 auto &tree1 = mSdfGrid->tree();
1252 auto &tree2 = mExtGrid->tree();
1253 const bool hasActiveTiles = tree1.hasActiveTiles();
1255 if (mParent->mIsInputSdf && hasActiveTiles) {
1256 OPENVDB_THROW(RuntimeError,
"FastSweeping: A SDF should not have active tiles!");
1259#ifdef BENCHMARK_FAST_SWEEPING
1263 mParent->mSweepMask.clear();
1264 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1268 OpPoolT opPool(opPrototype);
1271 tree::LeafManager<SdfTreeT> mgr(tree1, 1);
1272 tbb::parallel_for(mgr.leafRange(32), *this);
1273 mgr.swapLeafBuffer(1);
1276#ifdef BENCHMARK_FAST_SWEEPING
1277 timer.
restart(
"Initialize tiles");
1280 tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree1);
1281 mgr.foreachBottomUp(*this);
1282 tree1.root().setBackground(std::numeric_limits<SdfValueT>::max(), false);
1283 if (hasActiveTiles) {
1284#ifdef BENCHMARK_FAST_SWEEPING
1285 timer.restart(
"Voxelizing active tiles");
1287 tree1.voxelizeActiveTiles();
1288 tree2.voxelizeActiveTiles();
1294 mParent->computeSweepMaskLeafOrigins();
1296#ifdef BENCHMARK_FAST_SWEEPING
1302 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1303 void sumHelper(ExtT& sum2, ExtT ext,
bool update,
const SdfT& )
const {
if (update) sum2 = ext; }
1306 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1307 void sumHelper(ExtT& sum2, ExtT ext,
bool ,
const SdfT& d2)
const { sum2 +=
static_cast<ExtValueT
>(d2 * ext); }
1309 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1310 ExtT extValHelper(ExtT extSum,
const SdfT& )
const {
return extSum; }
1312 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1313 ExtT extValHelper(ExtT extSum,
const SdfT& sdfSum)
const {
return ExtT((SdfT(1) / sdfSum) * extSum); }
1315 void operator()(
const LeafRange& r)
const
1317 ExtAccT acc(mExtGrid->tree());
1318 SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
1319 math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
1320 const math::Transform& xform = mExtGrid->transform();
1321 typename OpPoolT::reference op = mOpPool->local();
1322 const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
1323 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1324 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1325 SdfValueT *sdf = leafIter.buffer(1).data();
1326 ExtValueT *ext = acc.probeLeaf(leafIter->origin())->buffer().data();
1327 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1328 const SdfValueT value = *voxelIter;
1329 const bool isAbove = value > isoValue;
1330 if (!voxelIter.isValueOn()) {
1331 sdf[voxelIter.pos()] = isAbove ? above : -above;
1333 const Coord ijk = voxelIter.getCoord();
1334 stencil.moveTo(ijk, value);
1335 const auto mask = stencil.intersectionMask( isoValue );
1337 sdf[voxelIter.pos()] = isAbove ? above : -above;
1341 sweepMaskAcc.setValueOff(ijk);
1342 const SdfValueT delta = value - isoValue;
1344 sdf[voxelIter.pos()] = 0;
1345 ext[voxelIter.pos()] = ExtValueT(op(xform.indexToWorld(ijk)));
1353 SdfValueT minD = std::numeric_limits<SdfValueT>::max();
1354 for (
int n=0, i=0; i<6;) {
1355 SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
1356 if (mask.test(i++)) {
1357 d =
math::Abs(delta/(value-stencil.getValue(i)));
1360 if (mask.test(i++)) {
1361 d2 =
math::Abs(delta/(value-stencil.getValue(i)));
1367 if (d < std::numeric_limits<SdfValueT>::max()) {
1370 const Vec3R xyz(
static_cast<SdfValueT
>(ijk[0])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][0]),
1371 static_cast<SdfValueT
>(ijk[1])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][1]),
1372 static_cast<SdfValueT
>(ijk[2])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][2]));
1374 sumHelper(sum2, ExtValueT(op(xform.indexToWorld(xyz))), d < minD, d2);
1375 if (d < minD) minD = d;
1378 ext[voxelIter.pos()] = extValHelper(sum2, sum1);
1379 sdf[voxelIter.pos()] = isAbove ? h /
math::Sqrt(sum1) : -h / math::
Sqrt(sum1);
1387 template<
typename RootOrInternalNodeT>
1388 void operator()(
const RootOrInternalNodeT& node)
const
1390 const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
1391 for (
auto it = node.cbeginValueAll(); it; ++it) {
1392 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1393 v = v > isoValue ? above : -above;
1401 SdfValueT mIsoValue;
1402 SdfValueT mAboveSign;
1406template <
typename SdfGr
idT,
typename ExtValueT>
1407template <
typename MaskTreeT>
1408struct FastSweeping<SdfGridT, ExtValueT>::MaskKernel
1410 using LeafRange =
typename tree::LeafManager<const MaskTreeT>::LeafRange;
1411 MaskKernel(FastSweeping &parent) : mParent(&parent),
1412 mSdfGrid(parent.mSdfGrid.get()) {}
1413 MaskKernel(
const MaskKernel &parent) =
default;
1414 MaskKernel& operator=(
const MaskKernel&) =
delete;
1416 void run(
const MaskTreeT &mask)
1418#ifdef BENCHMARK_FAST_SWEEPING
1419 util::CpuTimer timer;
1421 auto &lsTree = mSdfGrid->tree();
1423 static const SdfValueT
Unknown = std::numeric_limits<SdfValueT>::max();
1425#ifdef BENCHMARK_FAST_SWEEPING
1426 timer.restart(
"Changing background value");
1430#ifdef BENCHMARK_FAST_SWEEPING
1431 timer.restart(
"Union with mask");
1433 lsTree.topologyUnion(mask);
1436 tree::LeafManager<const MaskTreeT> mgr(mask);
1438#ifdef BENCHMARK_FAST_SWEEPING
1439 timer.restart(
"Initializing grid and sweep mask");
1442 mParent->mSweepMask.clear();
1443 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1445 using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
1446 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1447 LeafManagerT leafManager(mParent->mSweepMask);
1449 auto kernel = [&](LeafT& leaf,
size_t ) {
1450 static const SdfValueT
Unknown = std::numeric_limits<SdfValueT>::max();
1451 SdfAccT acc(mSdfGrid->tree());
1454 SdfValueT *data = acc.probeLeaf(leaf.origin())->buffer().data();
1455 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1456 if (math::Abs( data[voxelIter.pos()] ) < Unknown ) {
1458 voxelIter.setValue(
false);
1462 leafManager.foreach( kernel );
1465 mParent->computeSweepMaskLeafOrigins();
1467#ifdef BENCHMARK_FAST_SWEEPING
1473 FastSweeping *mParent;
1478template <
typename SdfGr
idT,
typename ExtValueT>
1486 template<
typename HashOp>
1489#ifdef BENCHMARK_FAST_SWEEPING
1494 const SweepMaskTreeT& maskTree = mParent->mSweepMask;
1497 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1498 LeafManagerT leafManager(maskTree);
1505 constexpr int maskOffset = LeafT::DIM * 3;
1506 constexpr int maskRange = maskOffset * 2;
1509 std::vector<int8_t> leafSliceMasks(leafManager.leafCount()*maskRange);
1510 auto kernel1 = [&](
const LeafT& leaf,
size_t leafIdx) {
1511 const size_t leafOffset = leafIdx * maskRange;
1512 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1513 const Coord ijk = LeafT::offsetToLocalCoord(voxelIter.pos());
1514 leafSliceMasks[leafOffset +
hash(ijk) + maskOffset] = uint8_t(1);
1517 leafManager.foreach( kernel1 );
1522 using ThreadLocalMap = std::unordered_map<int64_t, std::deque<size_t>>;
1523 tbb::enumerable_thread_specific<ThreadLocalMap> pool;
1524 auto kernel2 = [&](
const LeafT& leaf,
size_t leafIdx) {
1525 ThreadLocalMap& map = pool.local();
1526 const Coord& origin = leaf.origin();
1527 const int64_t leafKey =
hash(origin);
1528 const size_t leafOffset = leafIdx * maskRange;
1529 for (
int sliceIdx = 0; sliceIdx < maskRange; sliceIdx++) {
1530 if (leafSliceMasks[leafOffset + sliceIdx] == uint8_t(1)) {
1531 const int64_t voxelSliceKey = leafKey+sliceIdx-maskOffset;
1532 map[voxelSliceKey].emplace_back(leafIdx);
1536 leafManager.foreach( kernel2 );
1541 for (
auto poolIt = pool.begin(); poolIt != pool.end(); ++poolIt) {
1542 const ThreadLocalMap& map = *poolIt;
1543 for (
const auto& it : map) {
1544 for (
const size_t leafIdx : it.second) {
1545 mVoxelSliceMap[it.first].emplace_back(leafIdx, NodeMaskPtrT());
1551 mVoxelSliceKeys.reserve(mVoxelSliceMap.size());
1552 for (
const auto& it : mVoxelSliceMap) {
1553 mVoxelSliceKeys.push_back(it.first);
1557 auto kernel3 = [&](tbb::blocked_range<size_t>& range) {
1558 for (
size_t i = range.begin(); i < range.end(); i++) {
1559 const int64_t key = mVoxelSliceKeys[i];
1560 for (
auto& it : mVoxelSliceMap[key]) {
1561 it.second = std::make_unique<NodeMaskT>();
1565 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel3);
1572 auto kernel4 = [&](tbb::blocked_range<size_t>& range) {
1573 for (
size_t i = range.begin(); i < range.end(); i++) {
1574 const int64_t voxelSliceKey = mVoxelSliceKeys[i];
1575 LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceKey];
1576 for (LeafSlice& leafSlice : leafSliceArray) {
1577 const size_t leafIdx = leafSlice.first;
1578 NodeMaskPtrT& nodeMask = leafSlice.second;
1579 const LeafT& leaf = leafManager.leaf(leafIdx);
1580 const Coord& origin = leaf.origin();
1581 const int64_t leafKey =
hash(origin);
1582 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1583 const Index voxelIdx = voxelIter.pos();
1584 const Coord ijk = LeafT::offsetToLocalCoord(voxelIdx);
1585 const int64_t key = leafKey +
hash(ijk);
1586 if (key == voxelSliceKey) {
1587 nodeMask->setOn(voxelIdx);
1593 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel4);
1600 inline static Coord ijk(
const Coord &p,
int i) {
return p + FastSweeping::mOffset[i]; }
1605 inline operator bool()
const {
return v < SdfValueT(1000); }
1609 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1610 ExtT
twoNghbr(
const NN& d1,
const NN& d2,
const SdfT& ,
const ExtT& v1,
const ExtT& v2)
const {
return d1.
v < d2.
v ? v1 : v2; }
1613 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1614 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)); }
1617 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1618 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& ,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1625 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1626 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& w,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1627 return ExtT(w*(d1.
v*v1 + d2.
v*v2 + d3.
v*v3));
1632 typename ExtGridT::TreeType *tree2 = mParent->mExtGrid ? &mParent->mExtGrid->tree() :
nullptr;
1633 typename ExtGridT::TreeType *tree3 = mParent->mExtGridInput ? &mParent->mExtGridInput->tree() :
nullptr;
1635 const SdfValueT h =
static_cast<SdfValueT
>(mParent->mSdfGrid->voxelSize()[0]);
1636 const SdfValueT sqrt2h =
math::Sqrt(SdfValueT(2))*h;
1638 const bool isInputSdf = mParent->mIsInputSdf;
1645 const std::vector<Coord>& leafNodeOrigins = mParent->mSweepMaskLeafOrigins;
1647 int64_t voxelSliceIndex(0);
1649 auto kernel = [&](
const tbb::blocked_range<size_t>& range) {
1650 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1652 SdfAccT acc1(mParent->mSdfGrid->tree());
1653 auto acc2 = std::unique_ptr<ExtAccT>(tree2 ?
new ExtAccT(*tree2) :
nullptr);
1654 auto acc3 = std::unique_ptr<ExtAccT>(tree3 ?
new ExtAccT(*tree3) :
nullptr);
1655 SdfValueT absV, sign, update, D;
1658 const LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceIndex];
1662 for (
size_t i = range.begin(); i < range.end(); ++i) {
1667 const LeafSlice& leafSlice = leafSliceArray[i];
1668 const size_t leafIdx = leafSlice.first;
1669 const NodeMaskPtrT& nodeMask = leafSlice.second;
1671 const Coord& origin = leafNodeOrigins[leafIdx];
1674 for (
auto indexIter = nodeMask->beginOn(); indexIter; ++indexIter) {
1677 ijk = origin + LeafT::offsetToLocalCoord(indexIter.pos());
1680 d1 = std::min(
NN(acc1, ijk, 0),
NN(acc1, ijk, 1));
1681 d2 = std::min(
NN(acc1, ijk, 2),
NN(acc1, ijk, 3));
1682 d3 = std::min(
NN(acc1, ijk, 4),
NN(acc1, ijk, 5));
1684 if (!(d1 || d2 || d3))
continue;
1689 SdfValueT &value =
const_cast<SdfValueT&
>(acc1.
getValue(ijk));
1692 sign = value >= SdfValueT(0) ? SdfValueT(1) : SdfValueT(-1);
1698 if (d2 < d1) std::swap(d1, d2);
1699 if (d3 < d2) std::swap(d2, d3);
1700 if (d2 < d1) std::swap(d1, d2);
1706 if (update <= d2.
v) {
1707 if (update < absV) {
1708 value = sign * update;
1711 ExtValueT updateExt = acc2->getValue(d1(ijk));
1713 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1714 else updateExt = (value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1717 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1718 else updateExt = (value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1720 acc2->setValue(ijk, updateExt);
1730 if (d2.
v <= sqrt2h + d1.
v) {
1732 update = SdfValueT(0.5) * (d1.
v + d2.
v + std::sqrt(D));
1733 if (update > d2.
v && update <= d3.
v) {
1734 if (update < absV) {
1735 value = sign * update;
1740 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v);
1741 const ExtValueT v1 = acc2->getValue(d1(ijk));
1742 const ExtValueT v2 = acc2->getValue(d2(ijk));
1743 const ExtValueT extVal =
twoNghbr(d1, d2, w, v1, v2);
1745 ExtValueT updateExt = extVal;
1747 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1748 else updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1751 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1752 else updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1754 acc2->setValue(ijk, updateExt);
1765 const SdfValueT d123 = d1.
v + d2.
v + d3.
v;
1766 D = d123*d123 - SdfValueT(3)*(d1.
v*d1.
v + d2.
v*d2.
v + d3.
v*d3.
v - h * h);
1767 if (D >= SdfValueT(0)) {
1768 update = SdfValueT(1.0/3.0) * (d123 + std::sqrt(D));
1770 if (update < absV) {
1771 value = sign * update;
1777 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v+d3.
v);
1778 const ExtValueT v1 = acc2->getValue(d1(ijk));
1779 const ExtValueT v2 = acc2->getValue(d2(ijk));
1780 const ExtValueT v3 = acc2->getValue(d3(ijk));
1781 const ExtValueT extVal =
threeNghbr(d1, d2, d3, w, v1, v2, v3);
1783 ExtValueT updateExt = extVal;
1785 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1786 else updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1789 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1790 else updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1792 acc2->setValue(ijk, updateExt);
1800#ifdef BENCHMARK_FAST_SWEEPING
1804 for (
size_t i = 0; i < mVoxelSliceKeys.size(); i++) {
1805 voxelSliceIndex = mVoxelSliceKeys[i];
1806 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1809#ifdef BENCHMARK_FAST_SWEEPING
1810 timer.
restart(
"Backward sweeps");
1812 for (
size_t i = mVoxelSliceKeys.size(); i > 0; i--) {
1813 voxelSliceIndex = mVoxelSliceKeys[i-1];
1814 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1817#ifdef BENCHMARK_FAST_SWEEPING
1823 using NodeMaskT =
typename SweepMaskTreeT::LeafNodeType::NodeMaskType;
1824 using NodeMaskPtrT = std::unique_ptr<NodeMaskT>;
1827 using LeafSlice = std::pair<size_t, NodeMaskPtrT>;
1828 using LeafSliceArray = std::deque<LeafSlice>;
1829 using VoxelSliceMap = std::map<int64_t, LeafSliceArray>;
1833 VoxelSliceMap mVoxelSliceMap;
1834 std::vector<int64_t> mVoxelSliceKeys;
1839template<
typename Gr
idT>
1842 typename GridT::ValueType isoValue,
1846 if (fs.initSdf(fogGrid, isoValue,
false)) fs.sweep(nIter);
1847 return fs.sdfGrid();
1850template<
typename Gr
idT>
1853 typename GridT::ValueType isoValue,
1857 if (fs.initSdf(sdfGrid, isoValue,
true)) fs.sweep(nIter);
1858 return fs.sdfGrid();
1861template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1862typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
1865 const ExtValueT& background,
1866 typename FogGridT::ValueType isoValue,
1869 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1872 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1873 fs.sweep(nIter,
true);
1874 return fs.extGrid();
1877template<
typename SdfGr
idT,
typename OpT,
typename ExtValueT>
1878typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
1881 const ExtValueT &background,
1882 typename SdfGridT::ValueType isoValue,
1885 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1888 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1889 fs.sweep(nIter,
true);
1890 return fs.extGrid();
1893template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1894std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1897 const ExtValueT &background,
1898 typename FogGridT::ValueType isoValue,
1901 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1904 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1905 fs.sweep(nIter,
true);
1906 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1909template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
1910std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1913 const ExtValueT &background,
1914 typename SdfGridT::ValueType isoValue,
1917 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1920 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1921 fs.sweep(nIter,
true);
1922 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1925template<
typename Gr
idT>
1934 if (fs.initDilate(sdfGrid, dilation, nn, mode)) fs.sweep(nIter);
1935 return fs.sdfGrid();
1938template<
typename Gr
idT,
typename MaskTreeT>
1942 bool ignoreActiveTiles,
1946 if (fs.initMask(sdfGrid, mask, ignoreActiveTiles)) fs.sweep(nIter);
1947 return fs.sdfGrid();
1956#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1958#ifdef OPENVDB_INSTANTIATE_FASTSWEEPING
1962#define _FUNCTION(TreeT) \
1963 Grid<TreeT>::Ptr fogToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1967#define _FUNCTION(TreeT) \
1968 Grid<TreeT>::Ptr sdfToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1972#define _FUNCTION(TreeT) \
1973 Grid<TreeT>::Ptr dilateSdf(const Grid<TreeT>&, int, NearestNeighbors, int, FastSweepingDomain)
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
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.
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:412
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:571
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition Grid.h:906
SharedPtr< Grid > Ptr
Definition Grid.h:573
Definition Exceptions.h:63
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
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:185
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:26
Definition Stencils.h:1229
Templated class to compute the minimum and maximum values.
Definition Stats.h:32
Definition LeafManager.h:103
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
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:360
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition LeafManager.h:346
To facilitate threading over the nodes of a tree, cache node pointers in linear arrays,...
Definition NodeManager.h:532
void foreachTopDown(const NodeOp &op, bool threaded=true, size_t grainSize=1)
Definition NodeManager.h:632
void setValueOff(const Coord &xyz, const ValueType &value)
Set a particular value at the given coordinate and mark the coordinate as inactive.
Definition ValueAccessor.h:607
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition ValueAccessor.h:455
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:16
@ Unknown
Definition NanoVDB.h:223
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.
bool isApproxZero(const Type &x, const Type &tolerance)
Return true if x is equal to zero to within the given tolerance.
Definition Math.h:360
float Sqrt(float x)
Return the square root of a floating-point value.
Definition Math.h:829
size_t MinIndex(const Vec3T &v)
Return the index [0,1,2] of the smallest value in a 3D vector.
Definition Math.h:999
Vec3< double > Vec3d
Definition Vec3.h:708
Coord Abs(const Coord &xyz)
Definition Coord.h:518
Type Pow2(Type x)
Return x2.
Definition Math.h:570
Definition PointDataGrid.h:48
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
Index32 Index
Definition Types.h:34
@ GRID_LEVEL_SET
Definition Types.h:526
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
math::Vec3< Real > Vec3R
Definition Types.h:53
GridType::Ptr createGrid()
Create a new grid of type GridType with background value zero.
Definition Grid.h:1795
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:286
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:230