14 #ifndef OPENVDB_TOOLS_CONVEXVOXELIZER_HAS_BEEN_INCLUDED
15 #define OPENVDB_TOOLS_CONVEXVOXELIZER_HAS_BEEN_INCLUDED
24 #include <tbb/enumerable_thread_specific.h>
25 #include <tbb/parallel_for.h>
26 #include <tbb/parallel_reduce.h>
27 #include <tbb/blocked_range.h>
29 #include <type_traits>
40 template<
typename VectorType>
54 inline size_t size()
const {
return mVec.size(); };
56 inline void getPos(
size_t n, VectorType& xyz)
const { xyz = mVec[
n]; }
60 const std::vector<VectorType>& mVec;
169 template <
typename Gr
idType,
typename Derived,
typename InterruptType = util::NullInterrupter>
172 using GridPtr =
typename GridType::Ptr;
174 using TreeT =
typename GridType::TreeType;
175 using RootT =
typename TreeT::RootNodeType;
176 using LeafT =
typename TreeT::LeafNodeType;
178 using NodeChainT =
typename RootT::NodeChainType;
180 using AccessorT =
typename GridType::Accessor;
205 , mBg(grid->background())
206 , mNegBg(-(grid->background()))
208 , mInterrupter(interrupter)
222 class CacheLastLeafAccessor;
238 static const Index LEAFDIM = LeafT::DIM;
241 if (!invokeTileCanFit(LEAFDIM)) {
247 using ChainT =
typename NodeChainT::PopBack;
252 iterateTile<ChainT>();
256 if (!checkInterrupter())
317 std::function<bool(ValueT&, ValueT&, const ValueT&, const ValueT&)>
bottomTop =
333 : step * static_cast<ValueT>(
math::Ceil(perturbDown((x - offset)/step))) + offset;
341 template <
typename T>
363 : step * static_cast<ValueT>(
math::Floor(perturbUp((x - offset)/step))) + offset;
371 template <
typename T>
483 const Index i = worldToIndex(x);
485 if (std::isfinite(ymin) && ymin < mYMins[i])
496 const Index i = worldToIndex(x);
498 if (std::isfinite(ymax) && ymax > mYMaxs[i])
509 if (std::isfinite(y)) {
510 const Index i = worldToIndex(x);
527 const Index i = worldToIndex(x);
539 const Index i = worldToIndex(x);
549 const Index i = worldToIndex(x);
551 mYMins[i] = MAXVALUE;
552 mYMaxs[i] = MINVALUE;
567 mYMins.assign(mSize, MAXVALUE);
568 mYMaxs.assign(mSize, MINVALUE);
587 mSize = 1 + indexDistance(mXEnd, mXStart);
589 mYMins.assign(mSize, MAXVALUE);
590 mYMaxs.assign(mSize, MINVALUE);
655 for (
Index i = 0; i < mSize; ++i) {
656 if (mYMins[i] <= mYMaxs[i])
669 assert(mStep == xydata.
step());
673 const std::vector<ValueT>& ymins = xydata.mYMins;
674 const std::vector<ValueT>& ymaxs = xydata.mYMaxs;
676 if (start < mXStart) {
677 const Index n = indexDistance(mXStart, start);
678 mYMins.insert(mYMins.begin(),
n, MAXVALUE);
679 mYMaxs.insert(mYMaxs.begin(),
n, MINVALUE);
684 const Index m = indexDistance(
end, mXEnd);
685 mYMins.insert(mYMins.end(), m, MAXVALUE);
686 mYMaxs.insert(mYMaxs.end(), m, MINVALUE);
690 mSize = 1 + indexDistance(mXEnd, mXStart);
692 const Index offset = start < mXStart ? 0 : indexDistance(start, mXStart);
693 for (
Index i = 0,
j = offset; i < ymins.size(); ++i, ++
j) {
694 if (mYMins[
j] > ymins[i]) { mYMins[
j] = ymins[i]; }
695 if (mYMaxs[
j] < ymaxs[i]) { mYMaxs[
j] = ymaxs[i]; }
706 if (mYMins[i] > mYMaxs[i]) i++;
712 mYMins.clear(); mYMaxs.clear();
718 const Index k = mSize - (j + 1);
719 if (mYMins[k] > mYMaxs[k]) j++;
723 if (i == 0 && j == 0)
727 mXStart +=
ValueT(i * mStep);
728 mXEnd -=
ValueT(j * mStep);
731 mYMins.erase(mYMins.begin(), mYMins.begin() + i);
732 mYMaxs.erase(mYMaxs.begin(), mYMaxs.begin() + i);
736 mYMins.erase(mYMins.end() -
j, mYMins.end());
737 mYMaxs.erase(mYMaxs.end() -
j, mYMaxs.end());
743 inline static const ValueT
744 MINVALUE = std::numeric_limits<ValueT>::lowest(),
754 worldToIndex(
const ValueT&
x)
const
763 indexToWorld(
const Index i)
const
767 return mXStart +
ValueT(i * mStep);
772 ValueT mStepInv, mXStart, mXEnd;
774 std::vector<ValueT> mYMins, mYMaxs;
790 voxelCeil(
const ValueT& x)
796 voxelFloor(
const ValueT& x)
802 inline void thinIterate()
804 invokeSetXYRangeData();
810 template <
typename ChainT>
811 inline void iterateTile()
813 using NodeT =
typename ChainT::Back;
814 using PoppedChainT =
typename ChainT::PopBack;
816 static const Index DIM = NodeT::DIM;
819 if (invokeTileCanFit(DIM)) {
820 invokeSetXYRangeData(DIM);
822 tileIterateXYZ<NodeT>();
825 if constexpr (!std::is_same_v<PoppedChainT, openvdb::TypeList<>>) {
826 iterateTile<PoppedChainT>();
833 invokeSetXYRangeData();
839 template <
bool LeapFrog = false>
851 CacheLastLeafAccessor acc(getTree());
852 for (Index i = 0; i <
n; ++i) {
853 if (mInterrupter && !(i & ((1 << 7) - 1)) && !checkInterrupter())
856 iterateYZ<LeapFrog>(i, acc);
859 tbb::enumerable_thread_specific<TreeT>
pool(getTree());
861 auto kernel = [&](
const tbb::blocked_range<Index>& rng) {
862 TreeT &tree =
pool.local();
863 CacheLastLeafAccessor acc(tree);
865 if (!checkInterrupter())
868 for (Index i = rng.begin(); i != rng.end(); ++i) {
869 if constexpr (LeapFrog)
870 iterateNoTilesYZ(i, acc);
872 iterateYZ<false>(i, acc);
876 tbb::
parallel_for(tbb::blocked_range<Index>(Index(0), n, Index(128)), kernel);
877 using RangeT = tbb::blocked_range<typename tbb::enumerable_thread_specific<TreeT>::iterator>;
881 Op(TreeT &tree) : mDelete(false), mTree(&tree) {}
882 Op(
const Op& other,
tbb::split) : mDelete(true), mTree(new TreeT(other.mTree->background())) {}
883 ~Op() {
if (mDelete)
delete mTree; }
884 void operator()(
const RangeT &
r) {
for (
auto i=r.begin(); i!=r.end(); ++i) this->
merge(*i);}
885 void join(Op &other) { this->
merge(*(other.mTree)); }
888 tbb::parallel_reduce(RangeT(
pool.begin(),
pool.end(), 4),
op);
898 template <
bool LeapFrog = false>
900 iterateYZ(
const Index& i, CacheLastLeafAccessor& acc)
906 if (!std::isfinite(yb) || !std::isfinite(yt))
911 for (
ValueT y = voxelCeil(yb);
y <= perturbUp(yt); ++
y) {
918 ijk[2] =
Int32(voxelCeil(zb))-1;
921 for (
ValueT z = voxelCeil(zb);
z <= perturbUp(zt); ++
z) {
923 const ValueT val = acc.template getValue<1>(ijk);
926 if constexpr (LeapFrog) acc.template leapUp<false>(ijk,
z);
931 const
ValueT dist = mVox * invokeSignedDistance(p);
934 acc.template setValueOff<1,false>(ijk, mNegBg);
935 }
else if (
dist < val) {
936 acc.template setValueOn<1,false>(ijk,
dist);
938 acc.template checkReset<1>(ijk);
948 iterateNoTilesYZ(
const Index& i, CacheLastLeafAccessor& acc)
954 if (!std::isfinite(yb) || !std::isfinite(yt))
959 for (
ValueT y = voxelCeil(yb);
y <= perturbUp(yt); ++
y) {
966 bool early_break =
false;
969 ijk[2] =
Int32(voxelCeil(zb))-1;
971 for (
ValueT z = voxelCeil(zb);
z <= perturbUp(zt); ++
z) {
974 const ValueT dist = mVox * invokeSignedDistance(p);
976 if (dist <= mNegBg) {
980 }
else if (dist < mBg) {
981 acc.template setValueOn<1>(ijk,
dist);
983 acc.template checkReset<1>(ijk);
987 ijk[2] =
Int32(voxelFloor(zt))+1;
989 for (
ValueT z = voxelFloor(zt);
z > z_stop; --
z) {
992 const ValueT dist = mVox * invokeSignedDistance(p);
994 if (dist <= mNegBg) {
996 }
else if (dist < mBg) {
997 acc.template setValueOn<-1>(ijk,
dist);
999 acc.template checkReset<-1>(ijk);
1006 template <
typename NodeT>
1013 AccessorT acc(getTree());
1015 if (mInterrupter && !(i & ((1 << 7) - 1)) && !checkInterrupter())
1018 tileIterateYZ<NodeT>(i, acc);
1022 template <
typename NodeT>
1024 tileIterateYZ(
const Index& i, AccessorT& acc)
1030 if (!std::isfinite(yb) || !std::isfinite(yt))
1033 static const Index TILESIZE = NodeT::DIM;
1044 bool tiles_added =
false;
1046 while (z <=
tileFloor(zt, TILESIZE) + TILESIZE) {
1050 if (leapFrogToNextTile<NodeT, 1>(ijk, z, acc))
1053 if (addTile<NodeT>(p, ijk, acc)) tiles_added =
true;
1054 else if (tiles_added)
break;
1059 template <
typename NodeT,
int dir>
1061 leapFrogToNextTile(
const Coord& ijk,
ValueT& z, AccessorT& acc)
const
1063 static const int offset = NodeT::DIM;
1064 static const int nodeDepth =
int(TreeT::DEPTH - NodeT::LEVEL - 1);
1067 if (acc.getValue(ijk) != mNegBg) {
1072 const int depth = acc.getValueDepth(ijk);
1075 if (depth >= nodeDepth) {
1090 template<
typename NodeT>
1092 addTile(
const Vec3T& p,
const Coord& ijk, AccessorT& acc)
1094 static const Index LEVEL = NodeT::LEVEL + 1;
1096 if (tileFits<NodeT>(p)) {
1097 acc.addTile(LEVEL, ijk, mNegBg,
false);
1104 template <
typename NodeT>
1106 tileFits(
const Vec3T& p)
const
1108 static const Index TILESIZE = NodeT::DIM;
1113 const ValueT dist = invokeTilePointSignedDistance(p);
1116 if (dist <= -
R2-mHw)
1120 else if (dist >= -R1-mHw)
1124 return invokeTilePointSignedDistance(p +
Vec3T(-R1, -R1, -R1)) < -mHw
1125 && invokeTilePointSignedDistance(p +
Vec3T(-R1, -R1, R1)) < -mHw
1126 && invokeTilePointSignedDistance(p +
Vec3T(-R1, R1, -R1)) < -mHw
1127 && invokeTilePointSignedDistance(p +
Vec3T(-R1, R1, R1)) < -mHw
1128 && invokeTilePointSignedDistance(p +
Vec3T(R1, -R1, -R1)) < -mHw
1129 && invokeTilePointSignedDistance(p +
Vec3T(R1, -R1, R1)) < -mHw
1130 && invokeTilePointSignedDistance(p +
Vec3T(R1, R1, -R1)) < -mHw
1131 && invokeTilePointSignedDistance(p +
Vec3T(R1, R1, R1)) < -mHw;
1135 invokeSetXYRangeData(
const Index& step = 1)
1142 invokeTileCanFit(
const Index& dim)
const
1144 return static_cast<const Derived*
>(
this)->
tileCanFit(dim);
1148 invokeSignedDistance(
const Vec3T& p)
const
1154 invokeTilePointSignedDistance(
const Vec3T& p)
const
1161 static inline std::vector<int>
1165 using ChainT =
typename NodeChainT::PopBack;
1167 std::vector<int>
sizes;
1168 doTreeTileSizes<ChainT>(
sizes);
1173 template <
typename ChainT>
1175 doTreeTileSizes(std::vector<int>&
sizes)
1177 using NodeT =
typename ChainT::Back;
1178 using PoppedChainT =
typename ChainT::PopBack;
1180 sizes.push_back(NodeT::DIM);
1182 if constexpr (!std::is_same_v<PoppedChainT, openvdb::TypeList<>>) {
1183 doTreeTileSizes<PoppedChainT>(
sizes);
1191 openvdb::thread::cancelGroupExecution();
1197 inline TreeT& getTree() {
return mGrid->tree(); }
1205 class CacheLastLeafAccessor
1207 using NodeMaskType = util::NodeMask<LeafT::LOG2DIM>;
1214 CacheLastLeafAccessor(TreeT& tree)
1215 : mAcc(tree), mTileSizes(treeTileSizes())
1221 inline void reset(
const Coord& ijk) { cacheNewLeafData(ijk); }
1227 template<
int ZDir = 0>
1228 inline void checkReset(
const Coord& ijk)
1230 if (atNewLeafPos<ZDir>(ijk))
1231 cacheNewLeafData(ijk);
1240 template<
int ZDir = 0,
bool Check = true>
1243 if (Check && atNewLeafPos<ZDir>(ijk))
1244 cacheNewLeafData(ijk);
1247 ? mLeafData[coordToOffset(ijk)]
1248 : mAcc.getValue(ijk);
1257 template<
int ZDir = 0,
bool Check = true>
1258 inline void setValueOn(
const Coord& ijk,
const ValueT& val)
1260 if (Check && atNewLeafPos<ZDir>(ijk))
1261 cacheNewLeafData(ijk);
1264 const Index n = coordToOffset(ijk);
1268 mAcc.setValueOn(ijk, val);
1269 cacheNewLeafData(ijk);
1279 template<
int ZDir = 0,
bool Check = true>
1280 inline void setValueOff(
const Coord& ijk,
const ValueT& val)
1282 if (Check && atNewLeafPos<ZDir>(ijk))
1283 cacheNewLeafData(ijk);
1286 const Index n = coordToOffset(ijk);
1290 mAcc.setValueOff(ijk, val);
1291 cacheNewLeafData(ijk);
1301 template<
int ZDir = 0,
bool Check = true>
1302 inline bool isVoxel(
const Coord& ijk)
1304 return Check && atNewLeafPos<ZDir>(ijk) ? mLeaf !=
nullptr : mAcc.isVoxel(ijk);
1312 template<
bool Check = true>
1313 inline void leapUp(
const Coord& ijk,
ValueT& z)
1315 if (isVoxel<1,Check>(ijk))
1318 const int depth = mAcc.getValueDepth(ijk);
1328 LOG2DIM = LeafT::LOG2DIM;
1331 bool atNewLeafPos(
const Coord& ijk)
const
1333 if constexpr (ZDir == -1) {
1335 return (ijk[2] & (DIM-1u)) == DIM-1u;
1336 }
else if constexpr (ZDir == 1) {
1338 return (ijk[2] & (DIM-1u)) == 0;
1340 return Coord::lessThan(ijk, mOrigin)
1341 || Coord::lessThan(mOrigin.offsetBy(DIM-1u), ijk);
1345 inline void cacheNewLeafData(
const Coord& ijk)
1347 mLeaf = mAcc.probeLeaf(ijk);
1348 mOrigin = ijk & (~(DIM - 1));
1351 mLeafData = mLeaf->buffer().data();
1354 mLeafData =
nullptr;
1358 inline static Index coordToOffset(
const Coord& ijk)
1360 return ((ijk[0] & (DIM-1u)) << 2*LOG2DIM)
1361 + ((ijk[1] & (DIM-1u)) << LOG2DIM)
1362 + (ijk[2] & (DIM-1u));
1372 const std::vector<int> mTileSizes;
1380 const std::vector<int> mTileSizes = treeTileSizes();
1382 const ValueT mVox, mHw, mBg, mNegBg;
1388 InterruptType* mInterrupter;
1397 #endif // OPENVDB_TOOLS_CONVEXVOXELIZER_HAS_BEEN_INCLUDED
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
GA_API const UT_StringHolder dist
int Ceil(float x)
Return the ceiling of x.
Type Pow2(Type x)
Return x2.
GLsizei const GLfloat * value
GLdouble GLdouble GLdouble z
GLboolean GLboolean GLboolean GLboolean a
#define OPENVDB_USE_VERSION_NAMESPACE
__hostdev__ float getValue(uint32_t i) const
Coord Abs(const Coord &xyz)
float Round(float x)
Return x rounded to the nearest integer.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
OIIO_UTIL_API void parallel_for(int32_t begin, int32_t end, function_view< void(int32_t)> task, paropt opt=0)
float Sqrt(float x)
Return the square root of a floating-point value.
GLboolean GLboolean GLboolean b
MaskT< LOG2DIM > mValueMask
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
GLint GLint GLsizei GLsizei GLsizei depth
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
int Floor(float x)
Return the floor of x.
Functions to efficiently merge grids.
void OIIO_UTIL_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
bool wasInterrupted(T *i, int percent=-1)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
**Note that the tasks the is the thread number *for the pool