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