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()) {
825 using T =
typename MaskTreeT::template ValueConverter<bool>::Type;
827 tmp->
tree().voxelizeActiveTiles();
828 MaskKernel<T> kernel(*
this);
829 kernel.run(tmp->
tree());
831 if (ignoreActiveTiles || !mask.
tree().hasActiveTiles()) {
832 MaskKernel<MaskTreeT> kernel(*
this);
833 kernel.run(mask.
tree());
835 using T =
typename MaskTreeT::template ValueConverter<ValueMask>::Type;
837 tmp.voxelizeActiveTiles(
true);
838 MaskKernel<T> kernel(*
this);
845template <
typename SdfGr
idT,
typename ExtValueT>
853 " a non-null reference extension grid input.");
857 }
else if (this->sweepingVoxelCount() == 0) {
862 std::deque<SweepingKernel> kernels;
863 for (
int i = 0; i < 4; i++) kernels.emplace_back(*
this);
866#ifdef BENCHMARK_FAST_SWEEPING
871 tbb::task_group tasks;
872 tasks.run([&] { kernels[0].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]+a[2]; }); });
873 tasks.run([&] { kernels[1].computeVoxelSlices([](
const Coord &a){
return a[0]+a[1]-a[2]; }); });
874 tasks.run([&] { kernels[2].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]+a[2]; }); });
875 tasks.run([&] { kernels[3].computeVoxelSlices([](
const Coord &a){
return a[0]-a[1]-a[2]; }); });
878#ifdef BENCHMARK_FAST_SWEEPING
884 for (
int i = 0; i < nIter; ++i) {
889#ifdef BENCHMARK_FAST_SWEEPING
893 auto e = kernel.
run(*mSdfGrid);
900#ifdef BENCHMARK_FAST_SWEEPING
901 std::cerr <<
"Min = " << e.min() <<
" Max = " << e.max() << std::endl;
902 timer.
restart(
"Changing asymmetric background value");
906#ifdef BENCHMARK_FAST_SWEEPING
917template <
typename SdfGr
idT,
typename ExtValueT>
928 tbb::parallel_reduce(mgr.
leafRange(), *
this);
934 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
935 for (
auto voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
936 const SdfValueT v = *voxelIter;
937 const bool vEqFltMin = v == -std::numeric_limits<SdfValueT>::max();
938 const bool vEqFltMax = v == std::numeric_limits<SdfValueT>::max();
939 if (v <
mMin && !vEqFltMin)
mMin = v;
940 if (v >
mMax && !vEqFltMax)
mMax = v;
961template <
typename SdfGr
idT,
typename ExtValueT>
966 void operator()(
typename SdfTreeT::RootNodeType& node,
size_t = 1)
const {
967 for (
auto iter = node.beginValueAll(); iter; ++iter) {
968 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
971 if (*iter == std::numeric_limits<SdfValueT>::max()) {
978 template<
typename NodeT>
981 for (
auto iter = node.beginValueAll(); iter; ++iter) {
982 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
985 if (*iter == std::numeric_limits<SdfValueT>::max()) {
992 void operator()(
typename SdfTreeT::LeafNodeType& leaf,
size_t = 1)
const
994 for (
auto iter = leaf.beginValueOn(); iter; ++iter) {
995 if (*iter == -std::numeric_limits<SdfValueT>::max()) {
998 if (*iter == std::numeric_limits<SdfValueT>::max()) {
1009template <
typename SdfGr
idT,
typename ExtValueT>
1024#ifdef BENCHMARK_FAST_SWEEPING
1029#ifdef BENCHMARK_FAST_SWEEPING
1030 timer.
restart(
"Changing background value");
1032 static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1035 #ifdef BENCHMARK_FAST_SWEEPING
1036 timer.
restart(
"Dilating and updating mgr (parallel)");
1040 const int delta = 5;
1046#ifdef BENCHMARK_FAST_SWEEPING
1047 timer.
restart(
"Initializing grid and sweep mask");
1051 mParent->mSweepMask.topologyUnion(
mParent->mSdfGrid->constTree());
1054 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1058 LeafManagerT leafManager(
mParent->mSdfGrid->tree());
1060 auto kernel = [&](LeafT& leaf,
size_t ) {
1061 static const SdfValueT Unknown = std::numeric_limits<SdfValueT>::max();
1063 auto* maskLeaf =
mParent->mSweepMask.probeLeaf(leaf.origin());
1066 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1067 const SdfValueT value = *voxelIter;
1068 SdfValueT inputValue;
1069 const Coord ijk = voxelIter.getCoord();
1072 maskLeaf->setValueOff(voxelIter.pos());
1076 voxelIter.setValue(value > 0 ? Unknown : -Unknown);
1079 if (value > 0) voxelIter.setValue(Unknown);
1081 maskLeaf->setValueOff(voxelIter.pos());
1082 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1083 if ( !isInputOn ) voxelIter.setValueOff();
1084 else voxelIter.setValue(inputValue);
1088 if (value < 0) voxelIter.setValue(-Unknown);
1090 maskLeaf->setValueOff(voxelIter.pos());
1091 bool isInputOn = sdfInputAcc.probeValue(ijk, inputValue);
1092 if ( !isInputOn ) voxelIter.setValueOff();
1093 else voxelIter.setValue(inputValue);
1101 leafManager.foreach( kernel );
1104 mParent->computeSweepMaskLeafOrigins();
1106#ifdef BENCHMARK_FAST_SWEEPING
1119template <
typename SdfGr
idT,
typename ExtValueT>
1133 const bool hasActiveTiles =
tree.hasActiveTiles();
1135 if (
mParent->mIsInputSdf && hasActiveTiles) {
1139#ifdef BENCHMARK_FAST_SWEEPING
1143 mParent->mSweepMask.topologyUnion(
mParent->mSdfGrid->constTree());
1147 tbb::parallel_for(mgr.
leafRange(32), *
this);
1151#ifdef BENCHMARK_FAST_SWEEPING
1152 timer.
restart(
"Initialize tiles - new");
1156 mgr.foreachBottomUp(*
this);
1157 tree.root().setBackground(std::numeric_limits<SdfValueT>::max(),
false);
1158 if (hasActiveTiles)
tree.voxelizeActiveTiles();
1162 mParent->computeSweepMaskLeafOrigins();
1167 SweepMaskAccT sweepMaskAcc(
mParent->mSweepMask);
1169 const SdfValueT isoValue =
mIsoValue, above =
mAboveSign*std::numeric_limits<SdfValueT>::max();
1171 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1172 SdfValueT* sdf = leafIter.buffer(1).data();
1173 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1174 const SdfValueT value = *voxelIter;
1175 const bool isAbove = value > isoValue;
1176 if (!voxelIter.isValueOn()) {
1177 sdf[voxelIter.pos()] = isAbove ? above : -above;
1179 const Coord ijk = voxelIter.getCoord();
1180 stencil.
moveTo(ijk, value);
1183 sdf[voxelIter.pos()] = isAbove ? above : -above;
1187 const SdfValueT delta = value - isoValue;
1189 sdf[voxelIter.pos()] = 0;
1192 for (
int i=0; i<6;) {
1193 SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
1195 if (mask.test(i++)) {
1199 if (d < std::numeric_limits<SdfValueT>::max()) sum += 1/(d*d);
1209 template<
typename RootOrInternalNodeT>
1212 const SdfValueT isoValue =
mIsoValue, above =
mAboveSign*std::numeric_limits<SdfValueT>::max();
1213 for (
auto it = node.cbeginValueAll(); it; ++it) {
1214 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1215 v = v > isoValue ? above : -above;
1228template <
typename SdfGr
idT,
typename ExtValueT>
1229template <
typename OpT>
1233 using OpPoolT = tbb::enumerable_thread_specific<OpT>;
1235 mOpPool(
nullptr), mSdfGrid(parent.mSdfGrid.get()),
1236 mExtGrid(parent.mExtGrid.get()), mIsoValue(0), mAboveSign(0) {}
1237 InitExt(
const InitExt&) =
default;
1238 InitExt&
operator=(
const InitExt&) =
delete;
1239 void run(SdfValueT isoValue,
const OpT &opPrototype)
1241 static_assert(std::is_convertible<
decltype(opPrototype(
Vec3d(0))),ExtValueT>::value,
"Invalid return type of functor");
1246 mAboveSign = mParent->mIsInputSdf ? SdfValueT(1) : SdfValueT(-1);
1247 mIsoValue = isoValue;
1248 auto &tree1 = mSdfGrid->tree();
1249 auto &tree2 = mExtGrid->tree();
1250 const bool hasActiveTiles = tree1.hasActiveTiles();
1252 if (mParent->mIsInputSdf && hasActiveTiles) {
1253 OPENVDB_THROW(RuntimeError,
"FastSweeping: A SDF should not have active tiles!");
1256#ifdef BENCHMARK_FAST_SWEEPING
1260 mParent->mSweepMask.clear();
1261 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1265 OpPoolT opPool(opPrototype);
1268 tree::LeafManager<SdfTreeT> mgr(tree1, 1);
1269 tbb::parallel_for(mgr.leafRange(32), *this);
1270 mgr.swapLeafBuffer(1);
1273#ifdef BENCHMARK_FAST_SWEEPING
1274 timer.
restart(
"Initialize tiles");
1277 tree::NodeManager<SdfTreeT, SdfTreeT::RootNodeType::LEVEL-1> mgr(tree1);
1278 mgr.foreachBottomUp(*this);
1279 tree1.root().setBackground(std::numeric_limits<SdfValueT>::max(), false);
1280 if (hasActiveTiles) {
1281#ifdef BENCHMARK_FAST_SWEEPING
1282 timer.restart(
"Voxelizing active tiles");
1284 tree1.voxelizeActiveTiles();
1285 tree2.voxelizeActiveTiles();
1291 mParent->computeSweepMaskLeafOrigins();
1293#ifdef BENCHMARK_FAST_SWEEPING
1299 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1300 void sumHelper(ExtT& sum2, ExtT ext,
bool update,
const SdfT& )
const {
if (update) sum2 = ext; }
1303 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1304 void sumHelper(ExtT& sum2, ExtT ext,
bool ,
const SdfT& d2)
const { sum2 +=
static_cast<ExtValueT
>(d2 * ext); }
1306 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1307 ExtT extValHelper(ExtT extSum,
const SdfT& )
const {
return extSum; }
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& sdfSum)
const {
return ExtT((SdfT(1) / sdfSum) * extSum); }
1312 void operator()(
const LeafRange& r)
const
1314 ExtAccT acc(mExtGrid->tree());
1315 SweepMaskAccT sweepMaskAcc(mParent->mSweepMask);
1316 math::GradStencil<SdfGridT, false> stencil(*mSdfGrid);
1317 const math::Transform& xform = mExtGrid->transform();
1318 typename OpPoolT::reference op = mOpPool->local();
1319 const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
1320 const SdfValueT h = mAboveSign*
static_cast<SdfValueT
>(mSdfGrid->voxelSize()[0]);
1321 for (
auto leafIter = r.begin(); leafIter; ++leafIter) {
1322 SdfValueT *sdf = leafIter.buffer(1).data();
1323 ExtValueT *ext = acc.probeLeaf(leafIter->origin())->buffer().data();
1324 for (
auto voxelIter = leafIter->beginValueAll(); voxelIter; ++voxelIter) {
1325 const SdfValueT value = *voxelIter;
1326 const bool isAbove = value > isoValue;
1327 if (!voxelIter.isValueOn()) {
1328 sdf[voxelIter.pos()] = isAbove ? above : -above;
1330 const Coord ijk = voxelIter.getCoord();
1331 stencil.moveTo(ijk, value);
1332 const auto mask = stencil.intersectionMask( isoValue );
1334 sdf[voxelIter.pos()] = isAbove ? above : -above;
1338 sweepMaskAcc.setValueOff(ijk);
1339 const SdfValueT delta = value - isoValue;
1341 sdf[voxelIter.pos()] = 0;
1342 ext[voxelIter.pos()] = ExtValueT(op(xform.indexToWorld(ijk)));
1350 SdfValueT minD = std::numeric_limits<SdfValueT>::max();
1351 for (
int n=0, i=0; i<6;) {
1352 SdfValueT d = std::numeric_limits<SdfValueT>::max(), d2;
1353 if (mask.test(i++)) {
1354 d =
math::Abs(delta/(value-stencil.getValue(i)));
1357 if (mask.test(i++)) {
1358 d2 =
math::Abs(delta/(value-stencil.getValue(i)));
1364 if (d < std::numeric_limits<SdfValueT>::max()) {
1367 const Vec3R xyz(
static_cast<SdfValueT
>(ijk[0])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][0]),
1368 static_cast<SdfValueT
>(ijk[1])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][1]),
1369 static_cast<SdfValueT
>(ijk[2])+d*
static_cast<SdfValueT
>(FastSweeping::mOffset[n][2]));
1371 sumHelper(sum2, ExtValueT(op(xform.indexToWorld(xyz))), d < minD, d2);
1372 if (d < minD) minD = d;
1375 ext[voxelIter.pos()] = extValHelper(sum2, sum1);
1376 sdf[voxelIter.pos()] = isAbove ? h /
math::Sqrt(sum1) : -h / math::
Sqrt(sum1);
1384 template<
typename RootOrInternalNodeT>
1385 void operator()(
const RootOrInternalNodeT& node)
const
1387 const SdfValueT isoValue = mIsoValue, above = mAboveSign*std::numeric_limits<SdfValueT>::max();
1388 for (
auto it = node.cbeginValueAll(); it; ++it) {
1389 SdfValueT& v =
const_cast<SdfValueT&
>(*it);
1390 v = v > isoValue ? above : -above;
1398 SdfValueT mIsoValue;
1399 SdfValueT mAboveSign;
1403template <
typename SdfGr
idT,
typename ExtValueT>
1404template <
typename MaskTreeT>
1405struct FastSweeping<SdfGridT, ExtValueT>::MaskKernel
1407 using LeafRange =
typename tree::LeafManager<const MaskTreeT>::LeafRange;
1408 MaskKernel(FastSweeping &parent) : mParent(&parent),
1409 mSdfGrid(parent.mSdfGrid.get()) {}
1410 MaskKernel(
const MaskKernel &parent) =
default;
1411 MaskKernel& operator=(
const MaskKernel&) =
delete;
1413 void run(
const MaskTreeT &mask)
1415#ifdef BENCHMARK_FAST_SWEEPING
1416 util::CpuTimer timer;
1418 auto &lsTree = mSdfGrid->tree();
1420 static const SdfValueT
Unknown = std::numeric_limits<SdfValueT>::max();
1422#ifdef BENCHMARK_FAST_SWEEPING
1423 timer.restart(
"Changing background value");
1427#ifdef BENCHMARK_FAST_SWEEPING
1428 timer.restart(
"Union with mask");
1430 lsTree.topologyUnion(mask);
1433 tree::LeafManager<const MaskTreeT> mgr(mask);
1435#ifdef BENCHMARK_FAST_SWEEPING
1436 timer.restart(
"Initializing grid and sweep mask");
1439 mParent->mSweepMask.clear();
1440 mParent->mSweepMask.topologyUnion(mParent->mSdfGrid->constTree());
1442 using LeafManagerT = tree::LeafManager<SweepMaskTreeT>;
1443 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1444 LeafManagerT leafManager(mParent->mSweepMask);
1446 auto kernel = [&](LeafT& leaf,
size_t ) {
1447 static const SdfValueT
Unknown = std::numeric_limits<SdfValueT>::max();
1448 SdfAccT acc(mSdfGrid->tree());
1451 SdfValueT *data = acc.probeLeaf(leaf.origin())->buffer().data();
1452 for (
auto voxelIter = leaf.beginValueOn(); voxelIter; ++voxelIter) {
1453 if (math::Abs( data[voxelIter.pos()] ) < Unknown ) {
1455 voxelIter.setValue(
false);
1459 leafManager.foreach( kernel );
1462 mParent->computeSweepMaskLeafOrigins();
1464#ifdef BENCHMARK_FAST_SWEEPING
1470 FastSweeping *mParent;
1475template <
typename SdfGr
idT,
typename ExtValueT>
1483 template<
typename HashOp>
1486#ifdef BENCHMARK_FAST_SWEEPING
1491 const SweepMaskTreeT& maskTree = mParent->mSweepMask;
1494 using LeafT =
typename SweepMaskTreeT::LeafNodeType;
1495 LeafManagerT leafManager(maskTree);
1502 constexpr int maskOffset = LeafT::DIM * 3;
1503 constexpr int maskRange = maskOffset * 2;
1506 std::vector<int8_t> leafSliceMasks(leafManager.leafCount()*maskRange);
1507 auto kernel1 = [&](
const LeafT& leaf,
size_t leafIdx) {
1508 const size_t leafOffset = leafIdx * maskRange;
1509 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1510 const Coord ijk = LeafT::offsetToLocalCoord(voxelIter.pos());
1511 leafSliceMasks[leafOffset +
hash(ijk) + maskOffset] = uint8_t(1);
1514 leafManager.foreach( kernel1 );
1519 using ThreadLocalMap = std::unordered_map<int64_t, std::deque<size_t>>;
1520 tbb::enumerable_thread_specific<ThreadLocalMap> pool;
1521 auto kernel2 = [&](
const LeafT& leaf,
size_t leafIdx) {
1522 ThreadLocalMap& map = pool.local();
1523 const Coord& origin = leaf.origin();
1524 const int64_t leafKey =
hash(origin);
1525 const size_t leafOffset = leafIdx * maskRange;
1526 for (
int sliceIdx = 0; sliceIdx < maskRange; sliceIdx++) {
1527 if (leafSliceMasks[leafOffset + sliceIdx] == uint8_t(1)) {
1528 const int64_t voxelSliceKey = leafKey+sliceIdx-maskOffset;
1529 map[voxelSliceKey].emplace_back(leafIdx);
1533 leafManager.foreach( kernel2 );
1538 for (
auto poolIt = pool.begin(); poolIt != pool.end(); ++poolIt) {
1539 const ThreadLocalMap& map = *poolIt;
1540 for (
const auto& it : map) {
1541 for (
const size_t leafIdx : it.second) {
1542 mVoxelSliceMap[it.first].emplace_back(leafIdx, NodeMaskPtrT());
1548 mVoxelSliceKeys.reserve(mVoxelSliceMap.size());
1549 for (
const auto& it : mVoxelSliceMap) {
1550 mVoxelSliceKeys.push_back(it.first);
1554 auto kernel3 = [&](tbb::blocked_range<size_t>& range) {
1555 for (
size_t i = range.begin(); i < range.end(); i++) {
1556 const int64_t key = mVoxelSliceKeys[i];
1557 for (
auto& it : mVoxelSliceMap[key]) {
1558 it.second = std::make_unique<NodeMaskT>();
1562 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel3);
1569 auto kernel4 = [&](tbb::blocked_range<size_t>& range) {
1570 for (
size_t i = range.begin(); i < range.end(); i++) {
1571 const int64_t voxelSliceKey = mVoxelSliceKeys[i];
1572 LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceKey];
1573 for (LeafSlice& leafSlice : leafSliceArray) {
1574 const size_t leafIdx = leafSlice.first;
1575 NodeMaskPtrT& nodeMask = leafSlice.second;
1576 const LeafT& leaf = leafManager.leaf(leafIdx);
1577 const Coord& origin = leaf.origin();
1578 const int64_t leafKey =
hash(origin);
1579 for (
auto voxelIter = leaf.cbeginValueOn(); voxelIter; ++voxelIter) {
1580 const Index voxelIdx = voxelIter.pos();
1581 const Coord ijk = LeafT::offsetToLocalCoord(voxelIdx);
1582 const int64_t key = leafKey +
hash(ijk);
1583 if (key == voxelSliceKey) {
1584 nodeMask->setOn(voxelIdx);
1590 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceKeys.size()), kernel4);
1597 inline static Coord ijk(
const Coord &p,
int i) {
return p + FastSweeping::mOffset[i]; }
1602 inline operator bool()
const {
return v < SdfValueT(1000); }
1606 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1607 ExtT
twoNghbr(
const NN& d1,
const NN& d2,
const SdfT& ,
const ExtT& v1,
const ExtT& v2)
const {
return d1.
v < d2.
v ? v1 : v2; }
1610 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1611 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)); }
1614 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<std::is_same<ExtT, int>::value,
int>::type = 0>
1615 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& ,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1622 template<typename ExtT = ExtValueT, typename SdfT = SdfValueT, typename std::enable_if<!std::is_same<ExtT, int>::value,
int>::type = 0>
1623 ExtT
threeNghbr(
const NN& d1,
const NN& d2,
const NN& d3,
const SdfT& w,
const ExtT& v1,
const ExtT& v2,
const ExtT& v3)
const {
1624 return ExtT(w*(d1.
v*v1 + d2.
v*v2 + d3.
v*v3));
1629 typename ExtGridT::TreeType *tree2 = mParent->mExtGrid ? &mParent->mExtGrid->tree() :
nullptr;
1630 typename ExtGridT::TreeType *tree3 = mParent->mExtGridInput ? &mParent->mExtGridInput->tree() :
nullptr;
1632 const SdfValueT h =
static_cast<SdfValueT
>(mParent->mSdfGrid->voxelSize()[0]);
1633 const SdfValueT sqrt2h =
math::Sqrt(SdfValueT(2))*h;
1635 const bool isInputSdf = mParent->mIsInputSdf;
1642 const std::vector<Coord>& leafNodeOrigins = mParent->mSweepMaskLeafOrigins;
1644 int64_t voxelSliceIndex(0);
1646 auto kernel = [&](
const tbb::blocked_range<size_t>& range) {
1647 using LeafT =
typename SdfGridT::TreeType::LeafNodeType;
1649 SdfAccT acc1(mParent->mSdfGrid->tree());
1650 auto acc2 = std::unique_ptr<ExtAccT>(tree2 ?
new ExtAccT(*tree2) :
nullptr);
1651 auto acc3 = std::unique_ptr<ExtAccT>(tree3 ?
new ExtAccT(*tree3) :
nullptr);
1652 SdfValueT absV, sign, update, D;
1655 const LeafSliceArray& leafSliceArray = mVoxelSliceMap[voxelSliceIndex];
1659 for (
size_t i = range.begin(); i < range.end(); ++i) {
1664 const LeafSlice& leafSlice = leafSliceArray[i];
1665 const size_t leafIdx = leafSlice.first;
1666 const NodeMaskPtrT& nodeMask = leafSlice.second;
1668 const Coord& origin = leafNodeOrigins[leafIdx];
1671 for (
auto indexIter = nodeMask->beginOn(); indexIter; ++indexIter) {
1674 ijk = origin + LeafT::offsetToLocalCoord(indexIter.pos());
1677 d1 = std::min(
NN(acc1, ijk, 0),
NN(acc1, ijk, 1));
1678 d2 = std::min(
NN(acc1, ijk, 2),
NN(acc1, ijk, 3));
1679 d3 = std::min(
NN(acc1, ijk, 4),
NN(acc1, ijk, 5));
1681 if (!(d1 || d2 || d3))
continue;
1686 SdfValueT &value =
const_cast<SdfValueT&
>(acc1.
getValue(ijk));
1689 sign = value >= SdfValueT(0) ? SdfValueT(1) : SdfValueT(-1);
1695 if (d2 < d1) std::swap(d1, d2);
1696 if (d3 < d2) std::swap(d2, d3);
1697 if (d2 < d1) std::swap(d1, d2);
1703 if (update <= d2.
v) {
1704 if (update < absV) {
1705 value = sign * update;
1708 ExtValueT updateExt = acc2->getValue(d1(ijk));
1710 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1711 else updateExt = (value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1714 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1715 else updateExt = (value >= SdfValueT(0)) ? acc2->getValue(d1(ijk)) : acc3->getValue(ijk);
1717 acc2->setValue(ijk, updateExt);
1727 if (d2.
v <= sqrt2h + d1.
v) {
1729 update = SdfValueT(0.5) * (d1.
v + d2.
v + std::sqrt(D));
1730 if (update > d2.
v && update <= d3.
v) {
1731 if (update < absV) {
1732 value = sign * update;
1737 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v);
1738 const ExtValueT v1 = acc2->getValue(d1(ijk));
1739 const ExtValueT v2 = acc2->getValue(d2(ijk));
1740 const ExtValueT extVal =
twoNghbr(d1, d2, w, v1, v2);
1742 ExtValueT updateExt = extVal;
1744 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1745 else updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1748 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1749 else updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1751 acc2->setValue(ijk, updateExt);
1762 const SdfValueT d123 = d1.
v + d2.
v + d3.
v;
1763 D = d123*d123 - SdfValueT(3)*(d1.
v*d1.
v + d2.
v*d2.
v + d3.
v*d3.
v - h * h);
1764 if (D >= SdfValueT(0)) {
1765 update = SdfValueT(1.0/3.0) * (d123 + std::sqrt(D));
1767 if (update < absV) {
1768 value = sign * update;
1774 const SdfValueT w = SdfValueT(1)/(d1.
v+d2.
v+d3.
v);
1775 const ExtValueT v1 = acc2->getValue(d1(ijk));
1776 const ExtValueT v2 = acc2->getValue(d2(ijk));
1777 const ExtValueT v3 = acc2->getValue(d3(ijk));
1778 const ExtValueT extVal =
threeNghbr(d1, d2, d3, w, v1, v2, v3);
1780 ExtValueT updateExt = extVal;
1782 if (
isInputSdf) updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1783 else updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1786 if (
isInputSdf) updateExt = (value <= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1787 else updateExt = (value >= SdfValueT(0)) ? extVal : acc3->getValue(ijk);
1789 acc2->setValue(ijk, updateExt);
1797#ifdef BENCHMARK_FAST_SWEEPING
1801 for (
size_t i = 0; i < mVoxelSliceKeys.size(); i++) {
1802 voxelSliceIndex = mVoxelSliceKeys[i];
1803 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1806#ifdef BENCHMARK_FAST_SWEEPING
1807 timer.
restart(
"Backward sweeps");
1809 for (
size_t i = mVoxelSliceKeys.size(); i > 0; i--) {
1810 voxelSliceIndex = mVoxelSliceKeys[i-1];
1811 tbb::parallel_for(tbb::blocked_range<size_t>(0, mVoxelSliceMap[voxelSliceIndex].size()), kernel);
1814#ifdef BENCHMARK_FAST_SWEEPING
1820 using NodeMaskT =
typename SweepMaskTreeT::LeafNodeType::NodeMaskType;
1821 using NodeMaskPtrT = std::unique_ptr<NodeMaskT>;
1824 using LeafSlice = std::pair<size_t, NodeMaskPtrT>;
1825 using LeafSliceArray = std::deque<LeafSlice>;
1826 using VoxelSliceMap = std::map<int64_t, LeafSliceArray>;
1830 VoxelSliceMap mVoxelSliceMap;
1831 std::vector<int64_t> mVoxelSliceKeys;
1836template<
typename Gr
idT>
1839 typename GridT::ValueType isoValue,
1843 if (fs.initSdf(fogGrid, isoValue,
false)) fs.sweep(nIter);
1844 return fs.sdfGrid();
1847template<
typename Gr
idT>
1850 typename GridT::ValueType isoValue,
1854 if (fs.initSdf(sdfGrid, isoValue,
true)) fs.sweep(nIter);
1855 return fs.sdfGrid();
1858template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1859typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr
1862 const ExtValueT& background,
1863 typename FogGridT::ValueType isoValue,
1866 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1869 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1870 fs.sweep(nIter,
true);
1871 return fs.extGrid();
1874template<
typename SdfGr
idT,
typename OpT,
typename ExtValueT>
1875typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr
1878 const ExtValueT &background,
1879 typename SdfGridT::ValueType isoValue,
1882 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1885 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1886 fs.sweep(nIter,
true);
1887 return fs.extGrid();
1890template<
typename FogGr
idT,
typename ExtOpT,
typename ExtValueT>
1891std::pair<typename FogGridT::Ptr, typename FogGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1894 const ExtValueT &background,
1895 typename FogGridT::ValueType isoValue,
1898 const typename FogGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1901 if (fs.initExt(fogGrid, op, background, isoValue,
false, mode, extGrid))
1902 fs.sweep(nIter,
true);
1903 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1906template<
typename SdfGr
idT,
typename ExtOpT,
typename ExtValueT>
1907std::pair<typename SdfGridT::Ptr, typename SdfGridT::template ValueConverter<ExtValueT>::Type::Ptr>
1910 const ExtValueT &background,
1911 typename SdfGridT::ValueType isoValue,
1914 const typename SdfGridT::template ValueConverter<ExtValueT>::Type::ConstPtr extGrid)
1917 if (fs.initExt(sdfGrid, op, background, isoValue,
true, mode, extGrid))
1918 fs.sweep(nIter,
true);
1919 return std::make_pair(fs.sdfGrid(), fs.extGrid());
1922template<
typename Gr
idT>
1931 if (fs.initDilate(sdfGrid, dilation, nn, mode)) fs.sweep(nIter);
1932 return fs.sdfGrid();
1935template<
typename Gr
idT,
typename MaskTreeT>
1939 bool ignoreActiveTiles,
1943 if (fs.initMask(sdfGrid, mask, ignoreActiveTiles)) fs.sweep(nIter);
1944 return fs.sdfGrid();
1953#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
1955#ifdef OPENVDB_INSTANTIATE_FASTSWEEPING
1959#define _FUNCTION(TreeT) \
1960 Grid<TreeT>::Ptr fogToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1964#define _FUNCTION(TreeT) \
1965 Grid<TreeT>::Ptr sdfToSdf(const Grid<TreeT>&, TreeT::ValueType, int)
1969#define _FUNCTION(TreeT) \
1970 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:411
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:219
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:170
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:1757
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:291
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition version.h.in:235