OpenVDB  6.1.0
MultiResGrid.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2018 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 
51 
52 #ifndef OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
53 #define OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
54 
55 #include <openvdb/Grid.h>
57 #include <openvdb/math/Math.h>
58 #include <openvdb/math/Operators.h>
59 #include <openvdb/math/Stencils.h>
60 #include <openvdb/Metadata.h>
63 #include "Interpolation.h"
64 #include "Morphology.h"
65 #include "Prune.h"
66 #include "SignedFloodFill.h"
67 #include "ValueTransformer.h"
68 
69 #include <tbb/blocked_range.h>
70 #include <tbb/enumerable_thread_specific.h>
71 #include <tbb/parallel_for.h>
72 
73 #include <iostream>
74 #include <sstream>
75 #include <string>
76 #include <vector>
77 
78 
79 namespace openvdb {
81 namespace OPENVDB_VERSION_NAME {
82 namespace tools {
83 
84 template<typename TreeType>
85 class MultiResGrid: public MetaMap
86 {
87 public:
90 
91  using ValueType = typename TreeType::ValueType;
92  using ValueOnCIter = typename TreeType::ValueOnCIter;
93  using ValueOnIter = typename TreeType::ValueOnIter;
94  using TreePtr = typename TreeType::Ptr;
95  using ConstTreePtr = typename TreeType::ConstPtr;
96  using GridPtr = typename Grid<TreeType>::Ptr;
98 
100 
106  MultiResGrid(size_t levels, ValueType background, double voxelSize = 1.0);
107 
116  MultiResGrid(size_t levels, const Grid<TreeType> &grid, bool useInjection = false);
117 
126  MultiResGrid(size_t levels, GridPtr grid, bool useInjection = false);
127 
129 
133  size_t numLevels() const { return mTrees.size(); }
134 
136  static size_t finestLevel() { return 0; }
137 
139  size_t coarsestLevel() const { return mTrees.size()-1; }
140 
142 
146  TreeType& tree(size_t level);
147 
151  const TreeType& constTree(size_t level) const;
152 
156  TreePtr treePtr(size_t level);
157 
161  ConstTreePtr constTreePtr(size_t level) const;
162 
164  TreeType& finestTree() { return *mTrees.front(); }
165 
167  const TreeType& finestConstTree() const { return *mTrees.front(); }
168 
170  TreePtr finestTreePtr() { return mTrees.front(); }
171 
173  ConstTreePtr finestConstTreePtr() const { return mTrees.front(); }
174 
176  TreeType& coarsestTree() { return *mTrees.back(); }
177 
179  const TreeType& coarsestConstTree() const { return *mTrees.back(); }
180 
182  TreePtr coarsestTreePtr() { return mTrees.back(); }
183 
185  ConstTreePtr coarsestConstTreePtr() const { return mTrees.back(); }
186 
188 
192  GridPtr grid(size_t level);
193 
197  ConstGridPtr grid(size_t level) const;
198 
206  template<Index Order>
207  GridPtr createGrid(float level, size_t grainSize = 1) const;
208 
212  GridPtrVecPtr grids();
213 
217  GridCPtrVecPtr grids() const;
218 
220 
222  math::Transform& transform() { return *mTransform; }
228  const math::Transform& transform() const { return *mTransform; }
229  const math::Transform& constTransform() const { return *mTransform; }
231 
233 
235  static Vec3R xyz(const Coord& in_ijk, size_t in_level, size_t out_level);
238  static Vec3R xyz(const Vec3R& in_xyz, size_t in_level, size_t out_level);
239  static Vec3R xyz(const Vec3R& in_xyz, double in_level, double out_level);
241 
243 
244 
245 
247  template<Index Order>
257  ValueType sampleValue(const Coord& in_ijk, size_t in_level, size_t out_level) const;
258  template<Index Order>
259  ValueType sampleValue(const Vec3R& in_ijk, size_t in_level, size_t out_level) const;
261 
268  template<Index Order>
269  ValueType sampleValue(const Coord& ijk, double level) const;
270 
278  template<Index Order>
279  ValueType sampleValue(const Vec3R& xyz, double level) const;
280 
282 
289  ValueType prolongateVoxel(const Coord& coords, const size_t level) const;
290 
291 
295  void prolongateActiveVoxels(size_t destlevel, size_t grainSize = 1);
296 
298 
303  ValueType restrictVoxel(Coord ijk, const size_t level, bool useInjection = false) const;
304 
311  void restrictActiveVoxels(size_t destlevel, size_t grainSize = 1);
312 
314  void print(std::ostream& = std::cout, int verboseLevel = 1) const;
315 
317  std::string getName() const
318  {
319  if (Metadata::ConstPtr meta = (*this)[GridBase::META_GRID_NAME]) return meta->str();
320  return "";
321  }
322 
324  void setName(const std::string& name)
325  {
326  this->removeMeta(GridBase::META_GRID_NAME);
327  this->insertMeta(GridBase::META_GRID_NAME, StringMetadata(name));
328  }
329 
332  {
333  typename StringMetadata::ConstPtr s =
334  this->getMetadata<StringMetadata>(GridBase::META_GRID_CLASS);
335  return s ? GridBase::stringToGridClass(s->value()) : GRID_UNKNOWN;
336  }
337 
340  {
342  }
343 
345  void clearGridClass() { this->removeMeta(GridBase::META_GRID_CLASS); }
346 
347 private:
348 
349  MultiResGrid(const MultiResGrid& other);//disallow copy construction
350  MultiResGrid& operator=(const MultiResGrid& other);//disallow copy assignment
351 
352  // For optimal performance we disable registration of the ValueAccessor
353  using Accessor = tree::ValueAccessor<TreeType, false>;
354  using ConstAccessor = tree::ValueAccessor<const TreeType, false>;
355 
356  void topDownRestrict(bool useInjection);
357 
358  inline void initMeta();
359 
360  // Private struct that concurrently creates a mask of active voxel
361  // in a coarse tree from the active voxels in a fine tree
362  struct MaskOp;
363 
365  struct RestrictOp;
366 
368  struct ProlongateOp;
369 
370  // Private struct that performs multi-threaded computation of grids a fraction levels
371  template<Index Order>
372  struct FractionOp;
373 
375  template<typename OpType> struct CookOp;
376 
377  // Array of shared pointer to trees, level 0 has the highest resolution.
378  std::vector<TreePtr> mTrees;
379  // Shared pointer to a transform associated with the finest level grid
380  typename math::Transform::Ptr mTransform;
381 };// MultiResGrid
382 
383 template<typename TreeType>
384 MultiResGrid<TreeType>::
385 MultiResGrid(size_t levels, ValueType background, double voxelSize)
386  : mTrees(levels)
387  , mTransform(math::Transform::createLinearTransform( voxelSize ))
388 {
389  this->initMeta();
390  for (size_t i=0; i<levels; ++i) mTrees[i] = TreePtr(new TreeType(background));
391 }
392 
393 template<typename TreeType>
395 MultiResGrid(size_t levels, const Grid<TreeType> &grid, bool useInjection)
396  : MetaMap(grid)
397  , mTrees(levels)
398  , mTransform( grid.transform().copy() )
399 {
400  this->initMeta();
401  mTrees[0].reset( new TreeType( grid.tree() ) );// deep copy input tree
402  mTrees[0]->voxelizeActiveTiles();
403  this->topDownRestrict(useInjection);
404 }
405 
406 template<typename TreeType>
408 MultiResGrid(size_t levels, GridPtr grid, bool useInjection)
409  : MetaMap(*grid)
410  , mTrees(levels)
411  , mTransform( grid->transform().copy() )
412 {
413  this->initMeta();
414  mTrees[0] = grid->treePtr();// steal tree from input grid
415  mTrees[0]->voxelizeActiveTiles();
416  grid->newTree();
417  this->topDownRestrict(useInjection);
418 }
419 
420 template<typename TreeType>
421 inline TreeType& MultiResGrid<TreeType>::
422 tree(size_t level)
423 {
424  assert( level < mTrees.size() );
425  return *mTrees[level];
426 }
427 
428 template<typename TreeType>
429 inline const TreeType& MultiResGrid<TreeType>::
430 constTree(size_t level) const
431 {
432  assert( level < mTrees.size() );
433  return *mTrees[level];
434 }
435 
436 template<typename TreeType>
437 inline typename TreeType::Ptr MultiResGrid<TreeType>::
438 treePtr(size_t level)
439 {
440  assert( level < mTrees.size() );
441  return mTrees[level];
442 }
443 
444 template<typename TreeType>
445 inline typename TreeType::ConstPtr MultiResGrid<TreeType>::
446 constTreePtr(size_t level) const
447 {
448  assert( level < mTrees.size() );
449  return mTrees[level];
450 }
451 
452 template<typename TreeType>
454 grid(size_t level)
455 {
456  typename Grid<TreeType>::Ptr grid = Grid<TreeType>::create(this->treePtr(level));
457  math::Transform::Ptr xform = mTransform->copy();
458  if (level>0) xform->preScale( Real(1 << level) );
459  grid->setTransform( xform );
460  grid->insertMeta( *this->copyMeta() );
461  grid->insertMeta( "MultiResGrid_Level", Int64Metadata(level));
462  std::stringstream ss;
463  ss << this->getName() << "_level_" << level;
464  grid->setName( ss.str() );
465  return grid;
466 }
467 
468 template<typename TreeType>
470 grid(size_t level) const
471 {
472  return const_cast<MultiResGrid*>(this)->grid(level);
473 }
474 
475 template<typename TreeType>
476 template<Index Order>
478 createGrid(float level, size_t grainSize) const
479 {
480  assert( level >= 0.0f && level <= float(mTrees.size()-1) );
481 
482  typename Grid<TreeType>::Ptr grid(new Grid<TreeType>(this->constTree(0).background()));
483  math::Transform::Ptr xform = mTransform->copy();
484  xform->preScale( math::Pow(2.0f, level) );
485  grid->setTransform( xform );
486  grid->insertMeta( *(this->copyMeta()) );
487  grid->insertMeta( "MultiResGrid_Level", FloatMetadata(level) );
488  std::stringstream ss;
489  ss << this->getName() << "_level_" << level;
490  grid->setName( ss.str() );
491 
492  if ( size_t(floorf(level)) == size_t(ceilf(level)) ) {
493  grid->setTree( this->constTree( size_t(floorf(level))).copy() );
494  } else {
495  FractionOp<Order> tmp(*this, grid->tree(), level, grainSize);
496  if ( grid->getGridClass() == GRID_LEVEL_SET ) {
497  signedFloodFill( grid->tree() );
498  pruneLevelSet( grid->tree() );//only creates inactive tiles
499  }
500  }
501 
502  return grid;
503 }
504 
505 template<typename TreeType>
508 {
509  GridPtrVecPtr grids( new GridPtrVec );
510  for (size_t level=0; level<mTrees.size(); ++level) grids->push_back(this->grid(level));
511  return grids;
512 }
513 
514 template<typename TreeType>
516 grids() const
517 {
518  GridCPtrVecPtr grids( new GridCPtrVec );
519  for (size_t level=0; level<mTrees.size(); ++level) grids->push_back(this->grid(level));
520  return grids;
521 }
522 
523 template<typename TreeType>
525 xyz(const Coord& in_ijk, size_t in_level, size_t out_level)
526 {
527  return Vec3R( in_ijk.data() ) * Real(1 << in_level) / Real(1 << out_level);
528 }
529 
530 template<typename TreeType>
532 xyz(const Vec3R& in_xyz, size_t in_level, size_t out_level)
533 {
534  return in_xyz * Real(1 << in_level) / Real(1 << out_level);
535 }
536 
537 template<typename TreeType>
539 xyz(const Vec3R& in_xyz, double in_level, double out_level)
540 {
541  return in_xyz * math::Pow(2.0, in_level - out_level);
542 
543 }
544 
545 template<typename TreeType>
546 template<Index Order>
547 typename TreeType::ValueType MultiResGrid<TreeType>::
548 sampleValue(const Coord& in_ijk, size_t in_level, size_t out_level) const
549 {
550  assert( in_level >= 0 && in_level < mTrees.size() );
551  assert( out_level >= 0 && out_level < mTrees.size() );
552  const ConstAccessor acc(*mTrees[out_level]);// has disabled registration!
553  return tools::Sampler<Order>::sample( acc, this->xyz(in_ijk, in_level, out_level) );
554 }
555 
556 template<typename TreeType>
557 template<Index Order>
558 typename TreeType::ValueType MultiResGrid<TreeType>::
559 sampleValue(const Vec3R& in_xyz, size_t in_level, size_t out_level) const
560 {
561  assert( in_level >= 0 && in_level < mTrees.size() );
562  assert( out_level >= 0 && out_level < mTrees.size() );
563  const ConstAccessor acc(*mTrees[out_level]);// has disabled registration!
564  return tools::Sampler<Order>::sample( acc, this->xyz(in_xyz, in_level, out_level) );
565 }
566 
567 template<typename TreeType>
568 template<Index Order>
569 typename TreeType::ValueType MultiResGrid<TreeType>::
570 sampleValue(const Coord& ijk, double level) const
571 {
572  assert( level >= 0.0 && level <= double(mTrees.size()-1) );
573  const size_t level0 = size_t(floor(level)), level1 = size_t(ceil(level));
574  const ValueType v0 = this->template sampleValue<Order>( ijk, 0, level0 );
575  if ( level0 == level1 ) return v0;
576  assert( level1 - level0 == 1 );
577  const ValueType v1 = this->template sampleValue<Order>( ijk, 0, level1 );
579  const ValueType a = ValueType(level1 - level);
581  return a * v0 + (ValueType(1) - a) * v1;
582 }
583 
584 template<typename TreeType>
585 template<Index Order>
586 typename TreeType::ValueType MultiResGrid<TreeType>::
587 sampleValue(const Vec3R& xyz, double level) const
588 {
589  assert( level >= 0.0 && level <= double(mTrees.size()-1) );
590  const size_t level0 = size_t(floor(level)), level1 = size_t(ceil(level));
591  const ValueType v0 = this->template sampleValue<Order>( xyz, 0, level0 );
592  if ( level0 == level1 ) return v0;
593  assert( level1 - level0 == 1 );
594  const ValueType v1 = this->template sampleValue<Order>( xyz, 0, level1 );
596  const ValueType a = ValueType(level1 - level);
598  return a * v0 + (ValueType(1) - a) * v1;
599 }
600 
601 template<typename TreeType>
602 typename TreeType::ValueType MultiResGrid<TreeType>::
603 prolongateVoxel(const Coord& ijk, const size_t level) const
604 {
605  assert( level+1 < mTrees.size() );
606  const ConstAccessor acc(*mTrees[level + 1]);// has disabled registration!
607  return ProlongateOp::run(ijk, acc);
608 }
609 
610 template<typename TreeType>
612 prolongateActiveVoxels(size_t destlevel, size_t grainSize)
613 {
614  assert( destlevel < mTrees.size()-1 );
615  TreeType &fineTree = *mTrees[ destlevel ];
616  const TreeType &coarseTree = *mTrees[ destlevel+1 ];
617  CookOp<ProlongateOp> tmp( coarseTree, fineTree, grainSize );
618 }
619 
620 template<typename TreeType>
621 typename TreeType::ValueType MultiResGrid<TreeType>::
622 restrictVoxel(Coord ijk, const size_t destlevel, bool useInjection) const
623 {
624  assert( destlevel > 0 && destlevel < mTrees.size() );
625  const TreeType &fineTree = *mTrees[ destlevel-1 ];
626  if ( useInjection ) return fineTree.getValue(ijk<<1);
627  const ConstAccessor acc( fineTree );// has disabled registration!
628  return RestrictOp::run( ijk, acc);
629 }
630 
631 template<typename TreeType>
633 restrictActiveVoxels(size_t destlevel, size_t grainSize)
634 {
635  assert( destlevel > 0 && destlevel < mTrees.size() );
636  const TreeType &fineTree = *mTrees[ destlevel-1 ];
637  TreeType &coarseTree = *mTrees[ destlevel ];
638  CookOp<RestrictOp> tmp( fineTree, coarseTree, grainSize );
639 }
640 
641 template<typename TreeType>
643 print(std::ostream& os, int verboseLevel) const
644 {
645  os << "MultiResGrid with " << mTrees.size() << " levels\n";
646  for (size_t i=0; i<mTrees.size(); ++i) {
647  os << "Level " << i << ": ";
648  mTrees[i]->print(os, verboseLevel);
649  }
650 
651  if ( MetaMap::metaCount() > 0) {
652  os << "Additional metadata:" << std::endl;
653  for (ConstMetaIterator it = beginMeta(), end = endMeta(); it != end; ++it) {
654  os << " " << it->first;
655  if (it->second) {
656  const std::string value = it->second->str();
657  if (!value.empty()) os << ": " << value;
658  }
659  os << "\n";
660  }
661  }
662 
663  os << "Transform:" << std::endl;
664  transform().print(os, /*indent=*/" ");
665  os << std::endl;
666 }
667 
668 template<typename TreeType>
670 initMeta()
671 {
672  const size_t levels = this->numLevels();
673  if (levels < 2) {
674  OPENVDB_THROW(ValueError, "MultiResGrid: at least two levels are required");
675  }
676  this->insertMeta("MultiResGrid_Levels", Int64Metadata( levels ) );
677 }
678 
679 template<typename TreeType>
680 void MultiResGrid<TreeType>::
681 topDownRestrict(bool useInjection)
682 {
683  const bool isLevelSet = this->getGridClass() == GRID_LEVEL_SET;
684  for (size_t n=1; n<mTrees.size(); ++n) {
685  const TreeType &fineTree = *mTrees[n-1];
686  mTrees[n] = TreePtr(new TreeType( fineTree.background() ) );// empty tree
687  TreeType &coarseTree = *mTrees[n];
688  if (useInjection) {// Restriction by injection
689  for (ValueOnCIter it = fineTree.cbeginValueOn(); it; ++it) {
690  const Coord ijk = it.getCoord();
691  if ( (ijk[0] & 1) || (ijk[1] & 1) || (ijk[2] & 1) ) continue;
692  coarseTree.setValue( ijk >> 1, *it );
693  }
694  } else {// Restriction by full-weighting
695  MaskOp tmp(fineTree, coarseTree, 128);
696  this->restrictActiveVoxels(n, 64);
697  }
698  if ( isLevelSet ) {
699  tools::signedFloodFill( coarseTree );
700  tools::pruneLevelSet( coarseTree );//only creates inactive tiles
701  }
702  }// loop over grid levels
703 }
704 
705 template<typename TreeType>
707 {
708  using MaskT = typename TreeType::template ValueConverter<ValueMask>::Type;
709  using PoolType = tbb::enumerable_thread_specific<TreeType>;
711  using RangeT = typename ManagerT::LeafRange;
712  using VoxelIterT = typename ManagerT::LeafNodeType::ValueOnCIter;
713 
714  MaskOp(const TreeType& fineTree, TreeType& coarseTree, size_t grainSize = 1)
715  : mPool(new PoolType( coarseTree ) )// empty coarse tree acts as examplar
716  {
717  assert( coarseTree.empty() );
718 
719  // Create Mask of restruction performed on fineTree
720  MaskT mask(fineTree, false, true, TopologyCopy() );
721 
722  // Muli-threaded dilation which also linearizes the tree to leaf nodes
724 
725  // Restriction by injection using thread-local storage of coarse tree masks
726  ManagerT leafs( mask );
727  tbb::parallel_for(leafs.leafRange( grainSize ), *this);
728 
729  // multithreaded union of thread-local coarse tree masks with the coarse tree
730  using IterT = typename PoolType::const_iterator;
731  for (IterT it=mPool->begin(); it!=mPool->end(); ++it) coarseTree.topologyUnion( *it );
732  delete mPool;
733  }
734  void operator()(const RangeT& range) const
735  {
736  Accessor coarseAcc( mPool->local() );// disabled registration
737  for (typename RangeT::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
738  for (VoxelIterT voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
739  Coord ijk = voxelIter.getCoord();
740  if ( (ijk[2] & 1) || (ijk[1] & 1) || (ijk[0] & 1) ) continue;//no overlap
741  coarseAcc.setValueOn( ijk >> 1 );//injection from fine to coarse level
742  }//loop over active voxels in the fine tree
743  }// loop over leaf nodes in the fine tree
744  }
746 };// MaskOp
747 
748 template<typename TreeType>
749 template<Index Order>
751 {
752  using MaskT = typename TreeType::template ValueConverter<ValueMask>::Type;
753  using PoolType = tbb::enumerable_thread_specific<MaskT>;
754  using PoolIterT = typename PoolType::iterator;
755  using Manager1 = tree::LeafManager<const TreeType>;
756  using Manager2 = tree::LeafManager<TreeType>;
757  using Range1 = typename Manager1::LeafRange;
758  using Range2 = typename Manager2::LeafRange;
759 
760  FractionOp(const MultiResGrid& parent,
761  TreeType& midTree,
762  float level,
763  size_t grainSize = 1)
764  : mLevel( level )
765  , mPool(nullptr)
766  , mTree0( &*(parent.mTrees[size_t(floorf(level))]) )//high-resolution
767  , mTree1( &*(parent.mTrees[size_t(ceilf(level))]) ) //low-resolution
768  {
769  assert( midTree.empty() );
770  assert( mTree0 != mTree1 );
771 
772  // Create a pool of thread-local masks
773  MaskT examplar( false );
774  mPool = new PoolType( examplar );
775 
776  {// create mask from re-mapping coarse tree to mid-level tree
777  tree::LeafManager<const TreeType> manager( *mTree1 );
778  tbb::parallel_for( manager.leafRange(grainSize), *this );
779  }
780 
781  // Multi-threaded dilation of mask
782  tbb::parallel_for(tbb::blocked_range<PoolIterT>(mPool->begin(),mPool->end(),1), *this);
783 
784  // Union thread-local coarse tree masks into the coarse tree
785  for (PoolIterT it=mPool->begin(); it!=mPool->end(); ++it) midTree.topologyUnion( *it );
786  delete mPool;
787 
788  {// Interpolate values into the static mid level tree
789  Manager2 manager( midTree );
790  tbb::parallel_for(manager.leafRange(grainSize), *this);
791  }
792  }
793  void operator()(const Range1& range) const
794  {
795  using VoxelIter = typename Manager1::LeafNodeType::ValueOnCIter;
796  // Let mLevel = level + frac, where
797  // level is integer part of mLevel and frac is the fractional part
798  // low-res voxel size in world units = dx1 = 2^(level + 1)
799  // mid-res voxel size in world units = dx = 2^(mLevel) = 2^(level + frac)
800  // low-res index -> world: ijk * dx1
801  // world -> mid-res index: world / dx
802  // low-res index -> mid-res index: (ijk * dx1) / dx = ijk * scale where
803  // scale = dx1/dx = 2^(level+1)/2^(level+frac) = 2^(1-frac)
804  const float scale = math::Pow(2.0f, 1.0f - math::FractionalPart(mLevel));
805  tree::ValueAccessor<MaskT, false> acc( mPool->local() );// disabled registration
806  for (typename Range1::Iterator leafIter = range.begin(); leafIter; ++leafIter) {
807  for (VoxelIter voxelIter = leafIter->cbeginValueOn(); voxelIter; ++voxelIter) {
808  Coord ijk = voxelIter.getCoord();
810  const auto value0 = ijk[0] * scale;
811  const auto value1 = ijk[1] * scale;
812  const auto value2 = ijk[2] * scale;
814  ijk[0] = int(math::Round(value0));
815  ijk[1] = int(math::Round(value1));
816  ijk[2] = int(math::Round(value2));
817 
818  acc.setValueOn( ijk );
819  }//loop over active voxels in the fine tree
820  }// loop over leaf nodes in the fine tree
821  }
822  void operator()(const tbb::blocked_range<PoolIterT>& range) const
823  {
824  for (PoolIterT it=range.begin(); it!=range.end(); ++it) {
826  }
827  }
828  void operator()(const Range2 &r) const
829  {
830  using VoxelIter = typename TreeType::LeafNodeType::ValueOnIter;
831  // Let mLevel = level + frac, where
832  // level is integer part of mLevel and frac is the fractional part
833  // high-res voxel size in world units = dx0 = 2^(level)
834  // low-res voxel size in world units = dx1 = 2^(level+1)
835  // mid-res voxel size in world units = dx = 2^(mLevel) = 2^(level + frac)
836  // mid-res index -> world: ijk * dx
837  // world -> high-res index: world / dx0
838  // world -> low-res index: world / dx1
839  // mid-res index -> high-res index: (ijk * dx) / dx0 = ijk * scale0 where
840  // scale0 = dx/dx0 = 2^(level+frac)/2^(level) = 2^(frac)
841  // mid-res index -> low-res index: (ijk * dx) / dx1 = ijk * scale1 where
842  // scale1 = dx/dx1 = 2^(level+frac)/2^(level+1) = 2^(frac-1)
843  const float b = math::FractionalPart(mLevel), a = 1.0f - b;
844  const float scale0 = math::Pow( 2.0f, b );
845  const float scale1 = math::Pow( 2.0f,-a );
846  ConstAccessor acc0( *mTree0 ), acc1( *mTree1 );
847  for (typename Range2::Iterator leafIter = r.begin(); leafIter; ++leafIter) {
848  for (VoxelIter voxelIter = leafIter->beginValueOn(); voxelIter; ++voxelIter) {
849  const Vec3R xyz = Vec3R( voxelIter.getCoord().data() );// mid level coord
850  const ValueType v0 = tools::Sampler<Order>::sample( acc0, xyz * scale0 );
851  const ValueType v1 = tools::Sampler<Order>::sample( acc1, xyz * scale1 );
853  const auto value0 = a*v0;
854  const auto value1 = b*v1;
856  voxelIter.setValue( ValueType(value0 + value1) );
857  }
858  }
859  }
860  const float mLevel;
861  PoolType* mPool;
862  const TreeType *mTree0, *mTree1;
863 };// FractionOp
864 
865 
866 template<typename TreeType>
867 template<typename OperatorType>
868 struct MultiResGrid<TreeType>::CookOp
869 {
870  using ManagerT = tree::LeafManager<TreeType>;
871  using RangeT = typename ManagerT::LeafRange;
872 
873  CookOp(const TreeType& srcTree, TreeType& dstTree, size_t grainSize): acc(srcTree)
874  {
875  ManagerT leafs(dstTree);
876  tbb::parallel_for(leafs.leafRange(grainSize), *this);
877  }
878  CookOp(const CookOp &other): acc(other.acc.tree()) {}
879 
880  void operator()(const RangeT& range) const
881  {
882  for (auto leafIt = range.begin(); leafIt; ++leafIt) {
883  auto& phi = leafIt.buffer(0);
884  for (auto voxelIt = leafIt->beginValueOn(); voxelIt; ++voxelIt) {
885  phi.setValue(voxelIt.pos(), OperatorType::run(voxelIt.getCoord(), acc));
886  }
887  }
888  }
889 
890  const ConstAccessor acc;
891 };// CookOp
892 
893 
894 template<typename TreeType>
896 {
900  static ValueType run(Coord ijk, const ConstAccessor &acc)
901  {
902  ijk <<= 1;
903  // Overlapping grid point
904  ValueType v = 8*acc.getValue(ijk);
905  // neighbors in one axial direction
906  v += 4*(acc.getValue(ijk.offsetBy(-1, 0, 0)) + acc.getValue(ijk.offsetBy( 1, 0, 0)) +// x
907  acc.getValue(ijk.offsetBy( 0,-1, 0)) + acc.getValue(ijk.offsetBy( 0, 1, 0)) +// y
908  acc.getValue(ijk.offsetBy( 0, 0,-1)) + acc.getValue(ijk.offsetBy( 0, 0, 1)));// z
909  // neighbors in two axial directions
910  v += 2*(acc.getValue(ijk.offsetBy(-1,-1, 0)) + acc.getValue(ijk.offsetBy(-1, 1, 0)) +// xy
911  acc.getValue(ijk.offsetBy( 1,-1, 0)) + acc.getValue(ijk.offsetBy( 1, 1, 0)) +// xy
912  acc.getValue(ijk.offsetBy(-1, 0,-1)) + acc.getValue(ijk.offsetBy(-1, 0, 1)) +// xz
913  acc.getValue(ijk.offsetBy( 1, 0,-1)) + acc.getValue(ijk.offsetBy( 1, 0, 1)) +// xz
914  acc.getValue(ijk.offsetBy( 0,-1,-1)) + acc.getValue(ijk.offsetBy( 0,-1, 1)) +// yz
915  acc.getValue(ijk.offsetBy( 0, 1,-1)) + acc.getValue(ijk.offsetBy( 0, 1, 1)));// yz
916  // neighbors in three axial directions
917  for (int i=-1; i<=1; i+=2) {
918  for (int j=-1; j<=1; j+=2) {
919  for (int k=-1; k<=1; k+=2) v += acc.getValue(ijk.offsetBy(i,j,k));// xyz
920  }
921  }
922  v *= ValueType(1.0f/64.0f);
923  return v;
924  }
925 };// RestrictOp
926 
927 template<typename TreeType>
929 {
933  static ValueType run(const Coord& ijk, const ConstAccessor &acc)
934  {
935  switch ( (ijk[0] & 1) | ((ijk[1] & 1) << 1) | ((ijk[2] & 1) << 2) ) {
936  case 0:// all even
937  return acc.getValue(ijk>>1);
938  case 1:// x is odd
939  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(-1,0,0)>>1) +
940  acc.getValue(ijk.offsetBy( 1,0,0)>>1));
941  case 2:// y is odd
942  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(0,-1,0)>>1) +
943  acc.getValue(ijk.offsetBy(0, 1,0)>>1));
944  case 3:// x&y are odd
945  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(-1,-1,0)>>1) +
946  acc.getValue(ijk.offsetBy(-1, 1,0)>>1) +
947  acc.getValue(ijk.offsetBy( 1,-1,0)>>1) +
948  acc.getValue(ijk.offsetBy( 1, 1,0)>>1));
949  case 4:// z is odd
950  return ValueType(0.5)*(acc.getValue(ijk.offsetBy(0,0,-1)>>1) +
951  acc.getValue(ijk.offsetBy(0,0, 1)>>1));
952  case 5:// x&z are odd
953  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(-1,0,-1)>>1) +
954  acc.getValue(ijk.offsetBy(-1,0, 1)>>1) +
955  acc.getValue(ijk.offsetBy( 1,0,-1)>>1) +
956  acc.getValue(ijk.offsetBy( 1,0, 1)>>1));
957  case 6:// y&z are odd
958  return ValueType(0.25)*(acc.getValue(ijk.offsetBy(0,-1,-1)>>1) +
959  acc.getValue(ijk.offsetBy(0,-1, 1)>>1) +
960  acc.getValue(ijk.offsetBy(0, 1,-1)>>1) +
961  acc.getValue(ijk.offsetBy(0, 1, 1)>>1));
962  }
963  // all are odd
964  ValueType v = zeroVal<ValueType>();
965  for (int i=-1; i<=1; i+=2) {
966  for (int j=-1; j<=1; j+=2) {
967  for (int k=-1; k<=1; k+=2) v += acc.getValue(ijk.offsetBy(i,j,k)>>1);// xyz
968  }
969  }
970  return ValueType(0.125) * v;
971  }
972 };// ProlongateOp
973 
974 } // namespace tools
975 } // namespace OPENVDB_VERSION_NAME
976 } // namespace openvdb
977 
978 #endif // OPENVDB_TOOLS_MULTIRESGRID_HAS_BEEN_INCLUDED
979 
980 // Copyright (c) 2012-2018 DreamWorks Animation LLC
981 // All rights reserved. This software is distributed under the
982 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
static Ptr create()
Return a new grid with background value zero.
Definition: Grid.h:1279
typename Grid< TreeType >::ConstPtr ConstGridPtr
Definition: MultiResGrid.h:97
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN
Bracket code with OPENVDB_NO_TYPE_CONVERSION_WARNING_BEGIN/_END, to inhibit warnings about type conve...
Definition: Platform.h:223
tbb::enumerable_thread_specific< TreeType > PoolType
Definition: MultiResGrid.h:709
Definition: MultiResGrid.h:85
static size_t finestLevel()
Return the level of the finest grid (always 0)
Definition: MultiResGrid.h:136
typename Grid< TreeType >::Ptr GridPtr
Definition: MultiResGrid.h:96
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
TypedMetadata< float > FloatMetadata
Definition: Metadata.h:410
typename TreeType::ConstPtr ConstTreePtr
Definition: MultiResGrid.h:95
void dilateVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically dilate all leaf-level active voxels in a tree using one of three nearest neighbor conne...
Definition: Morphology.h:859
Type Pow(Type x, int n)
Return xn.
Definition: Math.h:515
SharedPtr< const TypedMetadata< T > > ConstPtr
Definition: Metadata.h:175
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition: Prune.h:416
const math::Transform & transform() const
Return a reference to the finest grid's transform, which might be shared with other grids.
Definition: MultiResGrid.h:228
static const char *const META_GRID_NAME
Definition: Grid.h:369
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
NodeManager produces linear arrays of all tree nodes allowing for efficient threading and bottom-up p...
SharedPtr< GridCPtrVec > GridCPtrVecPtr
Definition: Grid.h:535
Definition: ValueAccessor.h:220
typename TreeType::ValueOnIter ValueOnIter
Definition: MultiResGrid.h:93
static ValueType run(Coord ijk, const ConstAccessor &acc)
Static method that performs restriction by full weighting.
Definition: MultiResGrid.h:900
SharedPtr< const MetaMap > ConstPtr
Definition: MetaMap.h:50
typename ManagerT::LeafRange RangeT
Definition: MultiResGrid.h:711
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) stored in this grid.
Definition: MultiResGrid.h:331
ConstTreePtr coarsestConstTreePtr() const
Return a const shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:185
SharedPtr< MetaMap > Ptr
Definition: MetaMap.h:49
static Vec3R xyz(const Coord &in_ijk, size_t in_level, size_t out_level)
Return the floating-point index coordinate at out_level given the index coordinate in_xyz at in_level...
Definition: MultiResGrid.h:525
const TreeType & coarsestConstTree() const
Return a const reference to the tree at the coarsest level.
Definition: MultiResGrid.h:179
void setName(const std::string &name)
Set the name of this MultiResGrid.
Definition: MultiResGrid.h:324
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
size_t coarsestLevel() const
Return the level of the coarsest grid, i.e. numLevels()-1.
Definition: MultiResGrid.h:139
size_t numLevels() const
Return the number of levels, i.e. trees, in this MultiResGrid.
Definition: MultiResGrid.h:133
SharedPtr< const Metadata > ConstPtr
Definition: Metadata.h:54
std::shared_ptr< T > SharedPtr
Definition: Types.h:139
typename TreeType::template ValueConverter< ValueMask >::Type MaskT
Definition: MultiResGrid.h:708
SharedPtr< GridPtrVec > GridPtrVecPtr
Definition: Grid.h:530
#define OPENVDB_NO_TYPE_CONVERSION_WARNING_END
Definition: Platform.h:224
static std::string gridClassToString(GridClass)
Return the metadata string value for the given class of volumetric data.
GridClass getGridClass() const
Return the class of volumetric data (level set, fog volume, etc.) that is stored in this grid.
size_t metaCount() const
Definition: MetaMap.h:118
Defined various multi-threaded utility functions for trees.
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
std::vector< GridBase::Ptr > GridPtrVec
Definition: Grid.h:527
static const char *const META_GRID_CLASS
Definition: Grid.h:367
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:385
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition: SignedFloodFill.h:294
math::Vec3< Real > Vec3R
Definition: Types.h:79
const Int32 * data() const
Definition: Coord.h:167
PoolType * mPool
Definition: MultiResGrid.h:745
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:125
typename TreeType::ValueType ValueType
Definition: MultiResGrid.h:91
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
TreeType & coarsestTree()
Return a reference to the tree at the coarsest level.
Definition: MultiResGrid.h:176
GridType::Ptr createGrid(const typename GridType::ValueType &background)
Create a new grid of type GridType with a given background value.
Definition: Grid.h:1677
MetadataMap::const_iterator ConstMetaIterator
Definition: MetaMap.h:55
Definition: Morphology.h:102
void dilateActiveValues(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE, TilePolicy mode=PRESERVE_TILES)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition: Morphology.h:1080
double Real
Definition: Types.h:67
Implementation of morphological dilation and erosion.
ConstTreePtr constTreePtr(size_t level) const
Return a const shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:446
Definition: Exceptions.h:40
MaskOp(const TreeType &fineTree, TreeType &coarseTree, size_t grainSize=1)
Definition: MultiResGrid.h:714
ValueType restrictVoxel(Coord ijk, const size_t level, bool useInjection=false) const
Definition: MultiResGrid.h:622
std::vector< GridBase::ConstPtr > GridCPtrVec
Definition: Grid.h:532
std::string getName() const
Return a string with the name of this MultiResGrid.
Definition: MultiResGrid.h:317
const math::Transform & constTransform() const
Return a reference to the finest grid's transform, which might be shared with other grids.
Definition: MultiResGrid.h:229
typename TreeType::ValueOnCIter ValueOnCIter
Definition: MultiResGrid.h:92
TreeType & tree(size_t level)
Return a reference to the tree at the specified level.
Definition: MultiResGrid.h:422
SharedPtr< Transform > Ptr
Definition: Transform.h:69
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:647
typename TreeType::Ptr TreePtr
Definition: MultiResGrid.h:94
Definition: LeafManager.h:126
Definition: Transform.h:66
TypedMetadata< std::string > StringMetadata
Definition: Metadata.h:413
static bool sample(const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &result)
Sample inTree at the floating-point index coordinate inCoord and store the result in result.
void setGridClass(GridClass cls)
Specify the class of volumetric data (level set, fog volume, etc.) stored in this grid.
Definition: MultiResGrid.h:339
GridPtrVecPtr grids()
Return a shared pointer to a vector of all the base grids in this instance of the MultiResGrid.
Definition: MultiResGrid.h:507
void prolongateActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:612
Signed (x, y, z) 32-bit integer coordinates.
Definition: Coord.h:52
void restrictActiveVoxels(size_t destlevel, size_t grainSize=1)
Definition: MultiResGrid.h:633
const TreeType & finestConstTree() const
Return a const reference to the tree at the finest level.
Definition: MultiResGrid.h:167
ValueType prolongateVoxel(const Coord &coords, const size_t level) const
Return the value at coordinate location in level tree from the coarser tree at level+1 using trilinea...
Definition: MultiResGrid.h:603
void setName(const std::string &)
Specify a name for this grid.
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:750
GridClass
Definition: Types.h:502
Definition: MultiResGrid.h:706
static GridClass stringToGridClass(const std::string &)
Return the class of volumetric data specified by the given string.
ConstTreePtr finestConstTreePtr() const
Return a const shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:173
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
Type FractionalPart(Type x)
Return the fractional part of x.
Definition: Math.h:797
TreeType & tree()
Return a reference to this grid's tree, which might be shared with other grids.
Definition: Grid.h:890
void setTree(TreeBase::Ptr) override
Associate the given tree with this grid, in place of its existing tree.
Definition: Grid.h:1402
void setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform.
Definition: Grid.h:1205
Definition: Exceptions.h:92
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:177
Definition: Types.h:503
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
void operator()(const RangeT &range) const
Definition: MultiResGrid.h:734
MultiResGrid(size_t levels, ValueType background, double voxelSize=1.0)
Constructor of empty grids.
Definition: MultiResGrid.h:385
SharedPtr< Grid > Ptr
Definition: Grid.h:592
TreePtr coarsestTreePtr()
Return a shared pointer to the tree at the coarsest level.
Definition: MultiResGrid.h:182
GridPtr grid(size_t level)
Return a shared pointer to the grid at the specified integer level.
Definition: MultiResGrid.h:454
void clearGridClass()
Remove the setting specifying the class of this grid's volumetric data.
Definition: MultiResGrid.h:345
TreePtr finestTreePtr()
Return a shared pointer to the tree at the finest level.
Definition: MultiResGrid.h:170
SharedPtr< const Grid > ConstPtr
Definition: Grid.h:593
Definition: Types.h:504
ValueType sampleValue(const Coord &in_ijk, size_t in_level, size_t out_level) const
Return the value at the specified coordinate position using interpolation of the specified order into...
typename ManagerT::LeafNodeType::ValueOnCIter VoxelIterT
Definition: MultiResGrid.h:712
void insertMeta(const Name &, const Metadata &value)
Insert a new metadata field or overwrite the value of an existing field.
TreePtr treePtr(size_t level)
Return a shared pointer to the tree at the specified level.
Definition: MultiResGrid.h:438
void print(std::ostream &=std::cout, int verboseLevel=1) const
Output a human-readable description of this MultiResGrid.
Definition: MultiResGrid.h:643
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:46
float Round(float x)
Return x rounded to the nearest integer.
Definition: Math.h:773
const TreeType & constTree(size_t level) const
Return a const reference to the tree at the specified level.
Definition: MultiResGrid.h:430
static ValueType run(const Coord &ijk, const ConstAccessor &acc)
Interpolate values from a coarse grid (acc) into the index space (ijk) of a fine grid.
Definition: MultiResGrid.h:933
Coord offsetBy(Int32 dx, Int32 dy, Int32 dz) const
Definition: Coord.h:119
GridPtr createGrid(float level, size_t grainSize=1) const
Return a shared pointer to a new grid at the specified floating-point level.
TreeType & finestTree()
Return a reference to the tree at the finest level.
Definition: MultiResGrid.h:164
TypedMetadata< int64_t > Int64Metadata
Definition: Metadata.h:412
OPENVDB_API uint32_t getGridClass(std::ios_base &)
Return the class (GRID_LEVEL_SET, GRID_UNKNOWN, etc.) of the grid currently being read from or writte...
const ValueType & getValue(const Coord &xyz) const
Return the value of the voxel at the given coordinates.
Definition: ValueAccessor.h:257