OpenVDB  1.1.0
LevelSetUtil.h
Go to the documentation of this file.
1 
2 //
3 // Copyright (c) 2012-2013 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 //
35 
36 #ifndef OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED
37 #define OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED
38 
39 #include <openvdb/Grid.h>
40 #include <openvdb/tree/LeafManager.h>
41 #include <tbb/blocked_range.h>
42 #include <tbb/parallel_for.h>
43 #include <tbb/parallel_reduce.h>
44 #include <limits>
45 
46 
47 namespace openvdb {
49 namespace OPENVDB_VERSION_NAME {
50 namespace tools {
51 
52 // MS Visual C++ requires this extra level of indirection in order to compile
53 // THIS MUST EXIST IN AN UNNAMED NAMESPACE IN ORDER TO COMPILE ON WINDOWS
54 namespace {
55 
56 template<typename GridType>
57 inline typename GridType::ValueType lsutilGridMax()
58 {
60 }
61 
62 template<typename GridType>
63 inline typename GridType::ValueType lsutilGridZero()
64 {
65  return zeroVal<typename GridType::ValueType>();
66 }
67 
68 } // unnamed namespace
69 
70 
72 
73 
88 template<class GridType>
89 inline void
91  GridType& grid,
92  typename GridType::ValueType cutoffDistance = lsutilGridMax<GridType>());
93 
94 
96 
97 
107 template<class GridType>
108 inline typename Grid<typename GridType::TreeType::template ValueConverter<bool>::Type>::Ptr
110  const GridType& grid,
111  typename GridType::ValueType iso = lsutilGridZero<GridType>());
112 
113 
115 
116 
121 template<class TreeType>
123 {
124 public:
126  typedef typename TreeType::ValueType ValueType;
127 
128  // LeafArray = openvdb::tree::LeafManager<TreeType> leafs(myTree)
130 
131  void runParallel();
132  void runSerial();
133 
134  const ValueType& minVoxel() const { return mMin; }
135  const ValueType& maxVoxel() const { return mMax; }
136 
137  inline MinMaxVoxel(const MinMaxVoxel<TreeType>&, tbb::split);
138  inline void operator()(const tbb::blocked_range<size_t>&);
139  inline void join(const MinMaxVoxel<TreeType>&);
140 
141 private:
142  LeafArray& mLeafArray;
143  ValueType mMin, mMax;
144 };
145 
146 
148 
149 
152 template<class TreeType, class LeafOp>
154 {
155 public:
157  typedef typename TreeType::ValueType ValueType;
158 
159  // LeafArray = openvdb::tree::LeafManager<TreeType> leafs(myTree)
160  LeafTransformer(LeafArray&, LeafOp&);
161 
162  void runParallel();
163  void runSerial();
164 
165 
166  inline void operator()(const tbb::blocked_range<size_t>&) const;
168 
169 private:
170  LeafArray& mLeafArray;
171  LeafOp& mLeafOp;
172 };
173 
174 
176 
177 
178 // Internal utility objects and implementation details
179 namespace internal {
180 
181 template<typename ValueType>
183 {
184 public:
185  FogVolumeOp(ValueType cutoffDistance)
186  : mWeight(ValueType(1.0) / cutoffDistance)
187  {
188  }
189 
190  // cutoff has to be < 0.0
191  template <typename LeafNodeType>
192  void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const
193  {
194  const ValueType zero = zeroVal<ValueType>();
195 
196  for (typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll(); iter; ++iter) {
197  ValueType& value = const_cast<ValueType&>(iter.getValue());
198  if (value > zero) {
199  value = zero;
200  iter.setValueOff();
201  } else {
202  value = std::min(ValueType(1.0), value * mWeight);
203  iter.setValueOn(value > zero);
204  }
205  }
206  }
207 
208 private:
209  ValueType mWeight;
210 }; // class FogVolumeOp
211 
212 
213 template<typename TreeType>
215 {
216 public:
217  InteriorMaskOp(const TreeType& tree, typename TreeType::ValueType iso)
218  : mTree(tree)
219  , mIso(iso)
220  {
221  }
222 
223  template <typename LeafNodeType>
224  void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const
225  {
226  const Coord origin = leaf.getOrigin();
227  const typename TreeType::LeafNodeType* refLeafPt = mTree.probeConstLeaf(origin);
228 
229  if (refLeafPt != NULL) {
230 
231  const typename TreeType::LeafNodeType& refLeaf = *refLeafPt;
232  typename LeafNodeType::ValueAllIter iter = leaf.beginValueAll();
233 
234  for (; iter; ++iter) {
235  if (refLeaf.getValue(iter.pos()) < mIso) {
236  iter.setValueOn();
237  } else {
238  iter.setValueOff();
239  }
240  }
241  }
242  }
243 
244 private:
245  const TreeType& mTree;
246  typename TreeType::ValueType mIso;
247 }; // class InteriorMaskOp
248 
249 } // namespace internal
250 
251 
253 
254 
255 template <class TreeType>
257  : mLeafArray(leafs)
258  , mMin(std::numeric_limits<ValueType>::max())
259  , mMax(-mMin)
260 {
261 }
262 
263 
264 template <class TreeType>
265 inline
267  : mLeafArray(rhs.mLeafArray)
268  , mMin(rhs.mMin)
269  , mMax(rhs.mMax)
270 {
271 }
272 
273 
274 template <class TreeType>
275 void
277 {
278  tbb::parallel_reduce(mLeafArray.getRange(), *this);
279 }
280 
281 
282 template <class TreeType>
283 void
285 {
286  (*this)(mLeafArray.getRange());
287 }
288 
289 
290 template <class TreeType>
291 inline void
292 MinMaxVoxel<TreeType>::operator()(const tbb::blocked_range<size_t>& range)
293 {
294  typename TreeType::LeafNodeType::ValueOnCIter iter;
295 
296  for (size_t n = range.begin(); n < range.end(); ++n) {
297  iter = mLeafArray.leaf(n).cbeginValueOn();
298  for (; iter; ++iter) {
299  const ValueType value = iter.getValue();
300  mMin = std::min(mMin, value);
301  mMax = std::max(mMax, value);
302  }
303  }
304 }
305 
306 
307 template <class TreeType>
308 inline void
310 {
311  mMin = std::min(mMin, rhs.mMin);
312  mMax = std::max(mMax, rhs.mMax);
313 }
314 
315 
317 
318 
319 template <class TreeType, class LeafOp>
321  : mLeafArray(leafs)
322  , mLeafOp(leafOp)
323 {
324 }
325 
326 
327 template <class TreeType, class LeafOp>
328 inline
331  : mLeafArray(rhs.mLeafArray)
332  , mLeafOp(rhs.mLeafOp)
333 {
334 }
335 
336 
337 template <class TreeType, class LeafOp>
338 void
340 {
341  tbb::parallel_for(mLeafArray.getRange(), *this);
342 }
343 
344 
345 template <class TreeType, class LeafOp>
346 void
348 {
349  (*this)(mLeafArray.getRange());
350 }
351 
352 
353 template <class TreeType, class LeafOp>
354 inline void
355 LeafTransformer<TreeType, LeafOp>::operator()(const tbb::blocked_range<size_t>& range) const
356 {
357  for (size_t n = range.begin(); n < range.end(); ++n) {
358  mLeafOp(mLeafArray.leaf(n), n);
359  }
360 }
361 
362 
364 
365 
366 template <class GridType>
367 inline void
368 sdfToFogVolume(GridType& grid, typename GridType::ValueType cutoffDistance)
369 {
370  typedef typename GridType::TreeType TreeType;
371  typedef typename GridType::ValueType ValueType;
372 
373  cutoffDistance = -std::abs(cutoffDistance);
374 
375  TreeType& tree = const_cast<TreeType&>(grid.tree());
376 
377  { // Transform all voxels (parallel, over leaf nodes)
378  tree::LeafManager<TreeType> leafs(tree);
379 
380  MinMaxVoxel<TreeType> minmax(leafs);
381  minmax.runParallel();
382 
383  // Clamp to the interior band width.
384  if (minmax.minVoxel() > cutoffDistance) {
385  cutoffDistance = minmax.minVoxel();
386  }
387 
388  internal::FogVolumeOp<ValueType> op(cutoffDistance);
390  transform.runParallel();
391  }
392 
393  // Transform all tile values (serial, but the iteration
394  // is constrained from descending into leaf nodes)
395  const ValueType zero = zeroVal<ValueType>();
396  typename TreeType::ValueAllIter iter(tree);
397  iter.setMaxDepth(TreeType::ValueAllIter::LEAF_DEPTH - 1);
398 
399  for ( ; iter; ++iter) {
400  ValueType& value = const_cast<ValueType&>(iter.getValue());
401 
402  if (value > zero) {
403  value = zero;
404  iter.setValueOff();
405  } else {
406  value = ValueType(1.0);
407  iter.setActiveState(true);
408  }
409  }
410 
411  // Update the tree background value.
412 
413  typename TreeType::Ptr newTree(new TreeType(/*background=*/zero));
414  newTree->merge(tree);
415  // This is faster than calling Tree::setBackground, since we only need
416  // to update the value that is returned for coordinates that don't fall
417  // inside an allocated node. All inactive tiles and voxels have already
418  // been updated in the previous step so the Tree::setBackground method
419  // will in this case do a redundant traversal of the tree to update the
420  // inactive values once more.
421 
422  //newTree->pruneInactive();
423  grid.setTree(newTree);
424 
425  grid.setGridClass(GRID_FOG_VOLUME);
426 }
427 
428 
430 
431 
432 template <class GridType>
434 sdfInteriorMask(const GridType& grid, typename GridType::ValueType iso)
435 {
436  typedef typename GridType::TreeType::template ValueConverter<bool>::Type BoolTreeType;
437  typedef Grid<BoolTreeType> BoolGridType;
438 
439  typename BoolGridType::Ptr maskGrid(BoolGridType::create(false));
440  maskGrid->setTransform(grid.transform().copy());
441  BoolTreeType& maskTree = maskGrid->tree();
442 
443  maskTree.topologyUnion(grid.tree());
444 
445  { // Evaluate voxels (parallel, over leaf nodes)
446 
447  tree::LeafManager<BoolTreeType> leafs(maskTree);
448 
450  InteriorMaskOp op(grid.tree(), iso);
451 
453  transform.runParallel();
454  }
455 
456  // Evaluate tile values (serial, but the iteration
457  // is constrained from descending into leaf nodes)
458 
460  typename BoolTreeType::ValueAllIter iter(maskTree);
461  iter.setMaxDepth(BoolTreeType::ValueAllIter::LEAF_DEPTH - 1);
462 
463  for ( ; iter; ++iter) {
464  iter.setActiveState(acc.getValue(iter.getCoord()) < iso);
465  }
466 
467  maskTree.pruneInactive();
468 
469  return maskGrid;
470 }
471 
472 } // namespace tools
473 } // namespace OPENVDB_VERSION_NAME
474 } // namespace openvdb
475 
476 #endif // OPENVDB_TOOLS_LEVELSETUTIL_HAS_BEEN_INCLUDED
477 
478 // Copyright (c) 2012-2013 DreamWorks Animation LLC
479 // All rights reserved. This software is distributed under the
480 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )