OpenVDB 9.0.0
LevelSetRebuild.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3
4#ifndef OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
5#define OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
6
7#include <openvdb/Grid.h>
9#include <openvdb/math/Math.h>
14#include <openvdb/util/Util.h>
15#include <openvdb/openvdb.h>
16#include <tbb/blocked_range.h>
17#include <tbb/parallel_for.h>
18#include <type_traits>
19
20
21namespace openvdb {
23namespace OPENVDB_VERSION_NAME {
24namespace tools {
25
26
27/// @brief Return a new grid of type @c GridType that contains a narrow-band level set
28/// representation of an isosurface of a given grid.
29///
30/// @param grid a scalar, floating-point grid with one or more disjoint,
31/// closed isosurfaces at the given @a isovalue
32/// @param isovalue the isovalue that defines the implicit surface (defaults to zero,
33/// which is typical if the input grid is already a level set or a SDF).
34/// @param halfWidth half the width of the narrow band, in voxel units
35/// (defaults to 3 voxels, which is required for some level set operations)
36/// @param xform optional transform for the output grid
37/// (if not provided, the transform of the input @a grid will be matched)
38///
39/// @throw TypeError if @a grid is not scalar or not floating-point
40///
41/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
42template<class GridType>
43typename GridType::Ptr
44levelSetRebuild(const GridType& grid, float isovalue = 0,
45 float halfWidth = float(LEVEL_SET_HALF_WIDTH), const math::Transform* xform = nullptr);
46
47
48/// @brief Return a new grid of type @c GridType that contains a narrow-band level set
49/// representation of an isosurface of a given grid.
50///
51/// @param grid a scalar, floating-point grid with one or more disjoint,
52/// closed isosurfaces at the given @a isovalue
53/// @param isovalue the isovalue that defines the implicit surface
54/// @param exBandWidth the exterior narrow-band width in voxel units
55/// @param inBandWidth the interior narrow-band width in voxel units
56/// @param xform optional transform for the output grid
57/// (if not provided, the transform of the input @a grid will be matched)
58///
59/// @throw TypeError if @a grid is not scalar or not floating-point
60///
61/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
62template<class GridType>
63typename GridType::Ptr
64levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth,
65 const math::Transform* xform = nullptr);
66
67
68/// @brief Return a new grid of type @c GridType that contains a narrow-band level set
69/// representation of an isosurface of a given grid.
70///
71/// @param grid a scalar, floating-point grid with one or more disjoint,
72/// closed isosurfaces at the given @a isovalue
73/// @param isovalue the isovalue that defines the implicit surface
74/// @param exBandWidth the exterior narrow-band width in voxel units
75/// @param inBandWidth the interior narrow-band width in voxel units
76/// @param xform optional transform for the output grid
77/// (if not provided, the transform of the input @a grid will be matched)
78/// @param interrupter optional interrupter object
79///
80/// @throw TypeError if @a grid is not scalar or not floating-point
81///
82/// @note If the input grid contains overlapping isosurfaces, interior edges will be lost.
83template<class GridType, typename InterruptT>
84typename GridType::Ptr
85levelSetRebuild(const GridType& grid, float isovalue, float exBandWidth, float inBandWidth,
86 const math::Transform* xform = nullptr, InterruptT* interrupter = nullptr);
87
88
89////////////////////////////////////////
90
91/// @cond OPENVDB_DOCS_INTERNAL
92
93// Internal utility objects and implementation details
94
95namespace internal {
96
97class PointListTransform
98{
99public:
100 PointListTransform(const PointList& pointsIn, std::vector<Vec3s>& pointsOut,
101 const math::Transform& xform)
102 : mPointsIn(pointsIn)
103 , mPointsOut(&pointsOut)
104 , mXform(xform)
105 {
106 }
107
108 void runParallel()
109 {
110 tbb::parallel_for(tbb::blocked_range<size_t>(0, mPointsOut->size()), *this);
111 }
112
113 void runSerial()
114 {
115 (*this)(tbb::blocked_range<size_t>(0, mPointsOut->size()));
116 }
117
118 inline void operator()(const tbb::blocked_range<size_t>& range) const
119 {
120 for (size_t n = range.begin(); n < range.end(); ++n) {
121 (*mPointsOut)[n] = Vec3s(mXform.worldToIndex(mPointsIn[n]));
122 }
123 }
124
125private:
126 const PointList& mPointsIn;
127 std::vector<Vec3s> * const mPointsOut;
128 const math::Transform& mXform;
129};
130
131
132class PrimCpy
133{
134public:
135 PrimCpy(const PolygonPoolList& primsIn, const std::vector<size_t>& indexList,
136 std::vector<Vec4I>& primsOut)
137 : mPrimsIn(primsIn)
138 , mIndexList(indexList)
139 , mPrimsOut(&primsOut)
140 {
141 }
142
143 void runParallel()
144 {
145 tbb::parallel_for(tbb::blocked_range<size_t>(0, mIndexList.size()), *this);
146 }
147
148 void runSerial()
149 {
150 (*this)(tbb::blocked_range<size_t>(0, mIndexList.size()));
151 }
152
153 inline void operator()(const tbb::blocked_range<size_t>& range) const
154 {
155 openvdb::Vec4I quad;
157 std::vector<Vec4I>& primsOut = *mPrimsOut;
158
159 for (size_t n = range.begin(); n < range.end(); ++n) {
160 size_t index = mIndexList[n];
161 PolygonPool& polygons = mPrimsIn[n];
162
163 // Copy quads
164 for (size_t i = 0, I = polygons.numQuads(); i < I; ++i) {
165 primsOut[index++] = polygons.quad(i);
166 }
167 polygons.clearQuads();
168
169 // Copy triangles (adaptive mesh)
170 for (size_t i = 0, I = polygons.numTriangles(); i < I; ++i) {
171 const openvdb::Vec3I& triangle = polygons.triangle(i);
172 quad[0] = triangle[0];
173 quad[1] = triangle[1];
174 quad[2] = triangle[2];
175 primsOut[index++] = quad;
176 }
177
178 polygons.clearTriangles();
179 }
180 }
181
182private:
183 const PolygonPoolList& mPrimsIn;
184 const std::vector<size_t>& mIndexList;
185 std::vector<Vec4I> * const mPrimsOut;
186};
187
188} // namespace internal
189
190/// @endcond
191
192////////////////////////////////////////
193
194
195//{
196/// @cond OPENVDB_DOCS_INTERNAL
197
198/// The normal entry points for level set rebuild are the levelSetRebuild() functions.
199/// doLevelSetRebuild() is mainly for internal use, but when the isovalue and half band
200/// widths are given in ValueType units (for example, if they are queried from
201/// a grid), it might be more convenient to call this function directly.
202///
203/// @internal This overload is enabled only for grids with a scalar, floating-point ValueType.
204template<class GridType, typename InterruptT>
205inline typename std::enable_if<
207doLevelSetRebuild(const GridType& grid, typename GridType::ValueType iso,
208 typename GridType::ValueType exWidth, typename GridType::ValueType inWidth,
209 const math::Transform* xform, InterruptT* interrupter)
210{
211 const float
212 isovalue = float(iso),
213 exBandWidth = float(exWidth),
214 inBandWidth = float(inWidth);
215
216 tools::VolumeToMesh mesher(isovalue);
217 mesher(grid);
218
219 math::Transform::Ptr transform = (xform != nullptr) ? xform->copy() : grid.transform().copy();
220
221 std::vector<Vec3s> points(mesher.pointListSize());
222
223 { // Copy and transform (required for MeshToVolume) points to grid space.
224 internal::PointListTransform ptnXForm(mesher.pointList(), points, *transform);
225 ptnXForm.runParallel();
226 mesher.pointList().reset(nullptr);
227 }
228
229 std::vector<Vec4I> primitives;
230
231 { // Copy primitives.
232 PolygonPoolList& polygonPoolList = mesher.polygonPoolList();
233
234 size_t numPrimitives = 0;
235 std::vector<size_t> indexlist(mesher.polygonPoolListSize());
236
237 for (size_t n = 0, N = mesher.polygonPoolListSize(); n < N; ++n) {
238 const openvdb::tools::PolygonPool& polygons = polygonPoolList[n];
239 indexlist[n] = numPrimitives;
240 numPrimitives += polygons.numQuads();
241 numPrimitives += polygons.numTriangles();
242 }
243
244 primitives.resize(numPrimitives);
245 internal::PrimCpy primCpy(polygonPoolList, indexlist, primitives);
246 primCpy.runParallel();
247 }
248
249 QuadAndTriangleDataAdapter<Vec3s, Vec4I> mesh(points, primitives);
250
251 if (interrupter) {
252 return meshToVolume<GridType>(*interrupter, mesh, *transform, exBandWidth, inBandWidth,
253 DISABLE_RENORMALIZATION, nullptr);
254 }
255
256 return meshToVolume<GridType>(mesh, *transform, exBandWidth, inBandWidth,
257 DISABLE_RENORMALIZATION, nullptr);
258}
259
260
261/// @internal This overload is enabled only for grids that do not have a scalar,
262/// floating-point ValueType.
263template<class GridType, typename InterruptT>
264inline typename std::enable_if<
266doLevelSetRebuild(const GridType&, typename GridType::ValueType /*isovalue*/,
267 typename GridType::ValueType /*exWidth*/, typename GridType::ValueType /*inWidth*/,
268 const math::Transform*, InterruptT*)
269{
270 OPENVDB_THROW(TypeError,
271 "level set rebuild is supported only for scalar, floating-point grids");
272}
273
274/// @endcond
275//}
276
277
278////////////////////////////////////////
279
280
281template<class GridType, typename InterruptT>
282typename GridType::Ptr
283levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth,
284 const math::Transform* xform, InterruptT* interrupter)
285{
286 using ValueT = typename GridType::ValueType;
287 ValueT
288 isovalue(zeroVal<ValueT>() + ValueT(iso)),
289 exBandWidth(zeroVal<ValueT>() + ValueT(exWidth)),
290 inBandWidth(zeroVal<ValueT>() + ValueT(inWidth));
291
292 return doLevelSetRebuild(grid, isovalue, exBandWidth, inBandWidth, xform, interrupter);
293}
294
295
296template<class GridType>
297typename GridType::Ptr
298levelSetRebuild(const GridType& grid, float iso, float exWidth, float inWidth,
299 const math::Transform* xform)
300{
301 using ValueT = typename GridType::ValueType;
302 ValueT
303 isovalue(zeroVal<ValueT>() + ValueT(iso)),
304 exBandWidth(zeroVal<ValueT>() + ValueT(exWidth)),
305 inBandWidth(zeroVal<ValueT>() + ValueT(inWidth));
306
307 return doLevelSetRebuild<GridType, util::NullInterrupter>(
308 grid, isovalue, exBandWidth, inBandWidth, xform, nullptr);
309}
310
311
312template<class GridType>
313typename GridType::Ptr
314levelSetRebuild(const GridType& grid, float iso, float halfVal, const math::Transform* xform)
315{
316 using ValueT = typename GridType::ValueType;
317 ValueT
318 isovalue(zeroVal<ValueT>() + ValueT(iso)),
319 halfWidth(zeroVal<ValueT>() + ValueT(halfVal));
320
321 return doLevelSetRebuild<GridType, util::NullInterrupter>(
322 grid, isovalue, halfWidth, halfWidth, xform, nullptr);
323}
324
325
326////////////////////////////////////////
327
328
329// Explicit Template Instantiation
330
331#ifdef OPENVDB_USE_EXPLICIT_INSTANTIATION
332
333#ifdef OPENVDB_INSTANTIATE_LEVELSETREBUILD
335#endif
336
337#define _FUNCTION(TreeT) \
338 Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, const math::Transform*)
340#undef _FUNCTION
341
342#define _FUNCTION(TreeT) \
343 Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, float, const math::Transform*)
345#undef _FUNCTION
346
347#define _FUNCTION(TreeT) \
348 Grid<TreeT>::Ptr levelSetRebuild(const Grid<TreeT>&, float, float, float, const math::Transform*, \
349 util::NullInterrupter*)
351#undef _FUNCTION
352
353#endif // OPENVDB_USE_EXPLICIT_INSTANTIATION
354
355
356} // namespace tools
357} // namespace OPENVDB_VERSION_NAME
358} // namespace openvdb
359
360#endif // OPENVDB_TOOLS_LEVELSETREBUILD_HAS_BEEN_INCLUDED
ValueT value
Definition: GridBuilder.h:1287
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Convert polygonal meshes that consist of quads and/or triangles into signed or unsigned distance fiel...
Extract polygonal surfaces from scalar volumes.
Definition: Transform.h:40
Definition: Vec3.h:24
Definition: Vec4.h:25
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
Vec3< float > Vec3s
Definition: Vec3.h:667
@ DISABLE_RENORMALIZATION
Definition: MeshToVolume.h:73
std::unique_ptr< openvdb::Vec3s[]> PointList
Point and primitive list types.
Definition: VolumeToMesh.h:151
GridType::Ptr levelSetRebuild(const GridType &grid, float isovalue, float exBandWidth, float inBandWidth, const math::Transform *xform=nullptr, InterruptT *interrupter=nullptr)
Return a new grid of type GridType that contains a narrow-band level set representation of an isosurf...
Definition: LevelSetRebuild.h:283
std::unique_ptr< PolygonPool[]> PolygonPoolList
Point and primitive list types.
Definition: VolumeToMesh.h:152
OPENVDB_API const Index32 INVALID_IDX
static const Real LEVEL_SET_HALF_WIDTH
Definition: Types.h:343
Definition: Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202
#define OPENVDB_REAL_TREE_INSTANTIATE(Function)
Definition: version.h.in:147