OpenVDB: LevelSetFracture.h Source File

OpenVDB 6.1.0

LevelSetFracture.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2019 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30 //
36
37 #ifndef OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
38 #define OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
39
40 #include <openvdb/Grid.h>
41 #include <openvdb/math/Quat.h>
42 #include <openvdb/util/NullInterrupter.h>
43
44 #include "Composite.h" // for csgIntersectionCopy() and csgDifferenceCopy()
45 #include "GridTransformer.h" // for resampleToMatch()
46 #include "LevelSetUtil.h" // for sdfSegmentation()
47
48 #include <algorithm> // for std::max(), std::min()
49 #include <limits>
50 #include <list>
51 #include <vector>
52
53 #include <tbb/blocked_range.h>
54 #include <tbb/parallel_reduce.h>
55
56
57 namespace openvdb {
58 OPENVDB_USE_VERSION_NAMESPACE
59 namespace OPENVDB_VERSION_NAME {
60 namespace tools {
61
63 template<class GridType, class InterruptType = util::NullInterrupter>
64 class LevelSetFracture
65 {
66 public:
67 using Vec3sList = std::vector<Vec3s>;
68 using QuatsList = std::vector<math::Quats>;
69 using GridPtrList = std::list<typename GridType::Ptr>;
70 using GridPtrListIter = typename GridPtrList::iterator;
71
72
76 explicit LevelSetFracture(InterruptType* interrupter = nullptr);
77
96 void fracture(GridPtrList& grids, const GridType& cutter, bool segment = false,
97 const Vec3sList* points = nullptr, const QuatsList* rotations = nullptr,
98 bool cutterOverlap = true);
99
101 GridPtrList& fragments() { return mFragments; }
102
104 void clear() { mFragments.clear(); }
105
106 private:
107 // disallow copy by assignment
108 void operator=(const LevelSetFracture&) {}
109
110 bool wasInterrupted(int percent = -1) const {
111 return mInterrupter && mInterrupter->wasInterrupted(percent);
112 }
113
114 bool isValidFragment(GridType&) const;
115 void segmentFragments(GridPtrList&) const;
116 void process(GridPtrList&, const GridType& cutter);
117
118 InterruptType* mInterrupter;
119 GridPtrList mFragments;
120 };
121
122
124
125
126 // Internal utility objects and implementation details
127
128 namespace level_set_fracture_internal {
129
130
131 template<typename LeafNodeType>
132 struct FindMinMaxVoxelValue {
133
134 using ValueType = typename LeafNodeType::ValueType;
135
136 FindMinMaxVoxelValue(const std::vector<const LeafNodeType*>& nodes)
137 : minValue(std::numeric_limits<ValueType>::max())
138 , maxValue(-minValue)
139 , mNodes(nodes.empty() ? nullptr : &nodes.front())
140 {
141 }
142
143 FindMinMaxVoxelValue(FindMinMaxVoxelValue& rhs, tbb::split)
144 : minValue(std::numeric_limits<ValueType>::max())
145 , maxValue(-minValue)
146 , mNodes(rhs.mNodes)
147 {
148 }
149
150 void operator()(const tbb::blocked_range<size_t>& range) {
151 for (size_t n = range.begin(), N = range.end(); n < N; ++n) {
152 const ValueType* data = mNodes[n]->buffer().data();
153 for (Index i = 0; i < LeafNodeType::SIZE; ++i) {
154 minValue = std::min(minValue, data[i]);
155 maxValue = std::max(maxValue, data[i]);
156 }
157 }
158 }
159
160 void join(FindMinMaxVoxelValue& rhs) {
161 minValue = std::min(minValue, rhs.minValue);
162 maxValue = std::max(maxValue, rhs.maxValue);
163 }
164
165 ValueType minValue, maxValue;
166
167 LeafNodeType const * const * const mNodes;
168 }; // struct FindMinMaxVoxelValue
169
170
171 } // namespace level_set_fracture_internal
172
173
175
176
177 template<class GridType, class InterruptType>
178 LevelSetFracture<GridType, InterruptType>::LevelSetFracture(InterruptType* interrupter)
179 : mInterrupter(interrupter)
180 , mFragments()
181 {
182 }
183
184
185 template<class GridType, class InterruptType>
186 void
187 LevelSetFracture<GridType, InterruptType>::fracture(GridPtrList& grids, const GridType& cutter,
188 bool segmentation, const Vec3sList* points, const QuatsList* rotations, bool cutterOverlap)
189 {
190 // We can process all incoming grids with the same cutter instance,
191 // this optimization is enabled by the requirement of having matching
192 // transforms between all incoming grids and the cutter object.
193 if (points && points->size() != 0) {
194
195
196 math::Transform::Ptr originalCutterTransform = cutter.transform().copy();
197 GridType cutterGrid(*const_cast<GridType*>(&cutter), ShallowCopy());
198
199 const bool hasInstanceRotations =
200 points && rotations && points->size() == rotations->size();
201
202 // for each instance point..
203 for (size_t p = 0, P = points->size(); p < P; ++p) {
204 int percent = int((float(p) / float(P)) * 100.0);
205 if (wasInterrupted(percent)) break;
206
207 GridType instCutterGrid;
208 instCutterGrid.setTransform(originalCutterTransform->copy());
209 math::Transform::Ptr xform = originalCutterTransform->copy();
210
211 if (hasInstanceRotations) {
212 const Vec3s& rot = (*rotations)[p].eulerAngles(math::XYZ_ROTATION);
213 xform->preRotate(rot[0], math::X_AXIS);
214 xform->preRotate(rot[1], math::Y_AXIS);
215 xform->preRotate(rot[2], math::Z_AXIS);
216 xform->postTranslate((*points)[p]);
217 } else {
218 xform->postTranslate((*points)[p]);
219 }
220
221 cutterGrid.setTransform(xform);
222
223 // Since there is no scaling, use the generic resampler instead of
224 // the more expensive level set rebuild tool.
225 if (mInterrupter != nullptr) {
226
227 if (hasInstanceRotations) {
228 doResampleToMatch<BoxSampler>(cutterGrid, instCutterGrid, *mInterrupter);
229 } else {
230 doResampleToMatch<PointSampler>(cutterGrid, instCutterGrid, *mInterrupter);
231 }
232 } else {
233 util::NullInterrupter interrupter;
234 if (hasInstanceRotations) {
235 doResampleToMatch<BoxSampler>(cutterGrid, instCutterGrid, interrupter);
236 } else {
237 doResampleToMatch<PointSampler>(cutterGrid, instCutterGrid, interrupter);
238 }
239 }
240
241 if (wasInterrupted(percent)) break;
242
243 if (cutterOverlap && !mFragments.empty()) process(mFragments, instCutterGrid);
244 process(grids, instCutterGrid);
245 }
246
247 } else {
248 // use cutter in place
249 if (cutterOverlap && !mFragments.empty()) process(mFragments, cutter);
250 process(grids, cutter);
251 }
252
253 if (segmentation) {
254 segmentFragments(mFragments);
255 segmentFragments(grids);
256 }
257 }
258
259
260 template<class GridType, class InterruptType>
261 bool
262 LevelSetFracture<GridType, InterruptType>::isValidFragment(GridType& grid) const
263 {
264 using LeafNodeType = typename GridType::TreeType::LeafNodeType;
265
266 if (grid.tree().leafCount() < 9) {
267
268 std::vector<const LeafNodeType*> nodes;
269 grid.tree().getNodes(nodes);
270
271 Index64 activeVoxelCount = 0;
272
273 for (size_t n = 0, N = nodes.size(); n < N; ++n) {
274 activeVoxelCount += nodes[n]->onVoxelCount();
275 }
276
277 if (activeVoxelCount < 27) return false;
278
279 level_set_fracture_internal::FindMinMaxVoxelValue<LeafNodeType> op(nodes);
280 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, nodes.size()), op);
281
282 if ((op.minValue < 0) == (op.maxValue < 0)) return false;
283 }
284
285 return true;
286 }
287
288
289 template<class GridType, class InterruptType>
290 void
291 LevelSetFracture<GridType, InterruptType>::segmentFragments(GridPtrList& grids) const
292 {
293 GridPtrList newFragments;
294
295 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
296
297 std::vector<typename GridType::Ptr> segments;
298 segmentSDF(*(*it), segments);
299
300 for (size_t n = 0, N = segments.size(); n < N; ++n) {
301 newFragments.push_back(segments[n]);
302 }
303 }
304
305 grids.swap(newFragments);
306 }
307
308
309 template<class GridType, class InterruptType>
310 void
311 LevelSetFracture<GridType, InterruptType>::process(
312 GridPtrList& grids, const GridType& cutter)
313 {
314 using GridPtr = typename GridType::Ptr;
315 GridPtrList newFragments;
316
317 for (GridPtrListIter it = grids.begin(); it != grids.end(); ++it) {
318
319 if (wasInterrupted()) break;
320
321 GridPtr& grid = *it;
322
323 GridPtr fragment = csgIntersectionCopy(*grid, cutter);
324 if (!isValidFragment(*fragment)) continue;
325
326 GridPtr residual = csgDifferenceCopy(*grid, cutter);
327 if (!isValidFragment(*residual)) continue;
328
329 newFragments.push_back(fragment);
330
331 grid->tree().clear();
332 grid->tree().merge(residual->tree());
333 }
334
335 if (!newFragments.empty()) {
336 mFragments.splice(mFragments.end(), newFragments);
337 }
338 }
339
340 } // namespace tools
341 } // namespace OPENVDB_VERSION_NAME
342 } // namespace openvdb
343
344 #endif // OPENVDB_TOOLS_LEVELSETFRACTURE_HAS_BEEN_INCLUDED
345
346 // Copyright (c) 2012-2019 DreamWorks Animation LLC
347 // All rights reserved. This software is distributed under the
348 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v6_1::tools::LevelSetFracture::Vec3sList
std::vector< Vec3s > Vec3sList
Definition: LevelSetFracture.h:67
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: LevelSetFracture.h:150
openvdb::v6_1::math::X_AXIS
Definition: Math.h:857
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::FindMinMaxVoxelValue
FindMinMaxVoxelValue(const std::vector< const LeafNodeType * > &nodes)
Definition: LevelSetFracture.h:136
NullInterrupter.h
openvdb::v6_1::tools::LevelSetFracture::fragments
GridPtrList & fragments()
Return a list of new fragments, not including the residuals from the input grids.
Definition: LevelSetFracture.h:101
Composite.h
Functions to efficiently perform various compositing operations on grids.
openvdb::v6_1::tools::csgIntersectionCopy
GridOrTreeT::Ptr csgIntersectionCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG intersection operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1205
openvdb::v6_1::tools::LevelSetFracture::GridPtrListIter
typename GridPtrList::iterator GridPtrListIter
Definition: LevelSetFracture.h:70
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::minValue
ValueType minValue
Definition: LevelSetFracture.h:165
std
Definition: Coord.h:608
openvdb::v6_1::ShallowCopy
Tag dispatch class that distinguishes shallow copy constructors from deep copy constructors.
Definition: Types.h:747
GridTransformer.h
openvdb::v6_1::tools::LevelSetFracture::GridPtrList
std::list< typename GridType::Ptr > GridPtrList
Definition: LevelSetFracture.h:69
openvdb::v6_1::tools::LevelSetFracture::clear
void clear()
Remove all elements from the fragment list.
Definition: LevelSetFracture.h:104
openvdb::v6_1::tools::segmentSDF
void segmentSDF(const GridOrTreeType &volume, std::vector< typename GridOrTreeType::Ptr > &segments)
Separates disjoint SDF surfaces into distinct grids or trees.
Definition: LevelSetUtil.h:2576
openvdb::v6_1::math::Y_AXIS
Definition: Math.h:858
Quat.h
openvdb::v6_1::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition: NullInterrupter.h:76
openvdb::v6_1::math::XYZ_ROTATION
Definition: Math.h:864
openvdb::v6_1::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
openvdb::v6_1::tools::LevelSetFracture::QuatsList
std::vector< math::Quats > QuatsList
Definition: LevelSetFracture.h:68
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:125
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::ValueType
typename LeafNodeType::ValueType ValueType
Definition: LevelSetFracture.h:134
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::mNodes
LeafNodeType const *const *const mNodes
Definition: LevelSetFracture.h:167
openvdb::v6_1::Index
Index32 Index
Definition: Types.h:61
openvdb::v6_1::Index64
uint64_t Index64
Definition: Types.h:60
openvdb
Definition: Exceptions.h:40
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::FindMinMaxVoxelValue
FindMinMaxVoxelValue(FindMinMaxVoxelValue &rhs, tbb::split)
Definition: LevelSetFracture.h:143
openvdb::v6_1::util::NullInterrupter
Dummy NOOP interrupter class defining interface.
Definition: NullInterrupter.h:52
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::maxValue
ValueType maxValue
Definition: LevelSetFracture.h:165
openvdb::v6_1::math::Vec3s
Vec3< float > Vec3s
Definition: Vec3.h:688
openvdb::v6_1::math::Transform::Ptr
SharedPtr< Transform > Ptr
Definition: Transform.h:69
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue::join
void join(FindMinMaxVoxelValue &rhs)
Definition: LevelSetFracture.h:160
openvdb::v6_1::tools::level_set_fracture_internal::FindMinMaxVoxelValue
Definition: LevelSetFracture.h:132
openvdb::v6_1::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
openvdb::v6_1::tools::LevelSetFracture
Level set fracturing.
Definition: LevelSetFracture.h:64
openvdb::v6_1::math::Z_AXIS
Definition: Math.h:859
Grid.h
LevelSetUtil.h
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
openvdb::v6_1::tools::LevelSetFracture::fracture
void fracture(GridPtrList &grids, const GridType &cutter, bool segment=false, const Vec3sList *points=nullptr, const QuatsList *rotations=nullptr, bool cutterOverlap=true)
Divide volumes represented by level set grids into multiple, disjoint pieces by intersecting them wit...
Definition: LevelSetFracture.h:187
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:177
openvdb::v6_1::tools::csgDifferenceCopy
GridOrTreeT::Ptr csgDifferenceCopy(const GridOrTreeT &a, const GridOrTreeT &b)
Threaded CSG difference operation that produces a new grid or tree from immutable inputs.
Definition: Composite.h:1219