Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:03:18

0001 // Created on: 2013-12-20
0002 // Created by: Denis BOGOLEPOV
0003 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #ifndef BVH_BinnedBuilder_HeaderFile
0017 #define BVH_BinnedBuilder_HeaderFile
0018 
0019 #include <BVH_QueueBuilder.hxx>
0020 
0021 #include <algorithm>
0022 
0023 #if defined (_WIN32) && defined (max)
0024   #undef max
0025 #endif
0026 
0027 #include <limits>
0028 
0029 //! Stores parameters of single bin (slice of AABB).
0030 template<class T, int N>
0031 struct BVH_Bin
0032 {
0033   //! Creates new node bin.
0034   BVH_Bin() : Count (0) {}
0035 
0036   Standard_Integer Count; //!< Number of primitives in the bin
0037   BVH_Box<T, N>    Box;   //!< AABB of primitives in the bin
0038 };
0039 
0040 //! Performs construction of BVH tree using binned SAH algorithm. Number
0041 //! of bins controls BVH quality in cost of construction time (greater -
0042 //! better). For optimal results, use 32 - 48 bins. However, reasonable
0043 //! performance is provided even for 4 - 8 bins (it is only 10-20% lower
0044 //! in comparison with optimal settings). Note that multiple threads can
0045 //! be used only with thread safe BVH primitive sets.
0046 template<class T, int N, int Bins = BVH_Constants_NbBinsOptimal>
0047 class BVH_BinnedBuilder : public BVH_QueueBuilder<T, N>
0048 {
0049 public:
0050 
0051   //! Type of the array of bins of BVH tree node.
0052   typedef BVH_Bin<T, N> BVH_BinVector[Bins];
0053 
0054   //! Describes split plane candidate.
0055   struct BVH_SplitPlane
0056   {
0057     BVH_Bin<T, N> LftVoxel;
0058     BVH_Bin<T, N> RghVoxel;
0059   };
0060 
0061   //! Type of the array of split plane candidates.
0062   typedef BVH_SplitPlane BVH_SplitPlanes[Bins + 1];
0063 
0064 public:
0065 
0066   //! Creates binned SAH BVH builder.
0067   BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize = BVH_Constants_LeafNodeSizeDefault,
0068                      const Standard_Integer theMaxTreeDepth = BVH_Constants_MaxTreeDepth,
0069                      const Standard_Boolean theDoMainSplits = Standard_False,
0070                      const Standard_Integer theNumOfThreads = 1)
0071   : BVH_QueueBuilder<T, N> (theLeafNodeSize, theMaxTreeDepth, theNumOfThreads),
0072     myUseMainAxis (theDoMainSplits)
0073   {
0074     //
0075   }
0076 
0077   //! Releases resources of binned SAH BVH builder.
0078   virtual ~BVH_BinnedBuilder() {}
0079 
0080 protected:
0081 
0082   //! Performs splitting of the given BVH node.
0083   virtual typename BVH_QueueBuilder<T, N>::BVH_ChildNodes buildNode (BVH_Set<T, N>*         theSet,
0084                                                                      BVH_Tree<T, N>*        theBVH,
0085                                                                      const Standard_Integer theNode) const Standard_OVERRIDE;
0086 
0087   //! Arranges node primitives into bins.
0088   virtual void getSubVolumes (BVH_Set<T, N>*         theSet,
0089                               BVH_Tree<T, N>*        theBVH,
0090                               const Standard_Integer theNode,
0091                               BVH_BinVector&         theBins,
0092                               const Standard_Integer theAxis) const;
0093 
0094 private:
0095 
0096   Standard_Boolean myUseMainAxis; //!< Defines whether to search for the best split or use the widest axis
0097 
0098 };
0099 
0100 // =======================================================================
0101 // function : getSubVolumes
0102 // purpose  :
0103 // =======================================================================
0104 template<class T, int N, int Bins>
0105 void BVH_BinnedBuilder<T, N, Bins>::getSubVolumes (BVH_Set<T, N>*         theSet,
0106                                                    BVH_Tree<T, N>*        theBVH,
0107                                                    const Standard_Integer theNode,
0108                                                    BVH_BinVector&         theBins,
0109                                                    const Standard_Integer theAxis) const
0110 {
0111   const T aMin = BVH::VecComp<T, N>::Get (theBVH->MinPoint (theNode), theAxis);
0112   const T aMax = BVH::VecComp<T, N>::Get (theBVH->MaxPoint (theNode), theAxis);
0113   const T anInverseStep = static_cast<T> (Bins) / (aMax - aMin);
0114   for (Standard_Integer anIdx = theBVH->BegPrimitive (theNode); anIdx <= theBVH->EndPrimitive (theNode); ++anIdx)
0115   {
0116     typename BVH_Set<T, N>::BVH_BoxNt aBox = theSet->Box (anIdx);
0117     Standard_Integer aBinIndex = BVH::IntFloor<T> ((theSet->Center (anIdx, theAxis) - aMin) * anInverseStep);
0118     if (aBinIndex < 0)
0119     {
0120       aBinIndex = 0;
0121     }
0122     else if (aBinIndex >= Bins)
0123     {
0124       aBinIndex = Bins - 1;
0125     }
0126 
0127     theBins[aBinIndex].Count++;
0128     theBins[aBinIndex].Box.Combine (aBox);
0129   }
0130 }
0131 
0132 namespace BVH
0133 {
0134   template<class T, int N>
0135   Standard_Integer SplitPrimitives (BVH_Set<T, N>*         theSet,
0136                                     const BVH_Box<T, N>&   theBox,
0137                                     const Standard_Integer theBeg,
0138                                     const Standard_Integer theEnd,
0139                                     const Standard_Integer theBin,
0140                                     const Standard_Integer theAxis,
0141                                     const Standard_Integer theBins)
0142   {
0143     const T aMin = BVH::VecComp<T, N>::Get (theBox.CornerMin(), theAxis);
0144     const T aMax = BVH::VecComp<T, N>::Get (theBox.CornerMax(), theAxis);
0145 
0146     const T anInverseStep = static_cast<T> (theBins) / (aMax - aMin);
0147 
0148     Standard_Integer aLftIdx (theBeg);
0149     Standard_Integer aRghIdx (theEnd);
0150 
0151     do
0152     {
0153       while (BVH::IntFloor<T> ((theSet->Center (aLftIdx, theAxis) - aMin) * anInverseStep) <= theBin && aLftIdx < theEnd)
0154       {
0155         ++aLftIdx;
0156       }
0157       while (BVH::IntFloor<T> ((theSet->Center (aRghIdx, theAxis) - aMin) * anInverseStep) > theBin && aRghIdx > theBeg)
0158       {
0159         --aRghIdx;
0160       }
0161 
0162       if (aLftIdx <= aRghIdx)
0163       {
0164         if (aLftIdx != aRghIdx)
0165         {
0166           theSet->Swap (aLftIdx, aRghIdx);
0167         }
0168 
0169         ++aLftIdx;
0170         --aRghIdx;
0171       }
0172     } while (aLftIdx <= aRghIdx);
0173 
0174     return aLftIdx;
0175   }
0176 
0177   template<class T, int N>
0178   struct BVH_AxisSelector
0179   {
0180     typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
0181     static Standard_Integer MainAxis (const BVH_VecNt& theSize)
0182     {
0183       if (theSize.y() > theSize.x())
0184       {
0185         return theSize.y() > theSize.z() ? 1 : 2;
0186       }
0187       else
0188       {
0189         return theSize.z() > theSize.x() ? 2 : 0;
0190       }
0191     }
0192   };
0193 
0194   template<class T>
0195   struct BVH_AxisSelector<T, 2>
0196   {
0197     typedef typename BVH::VectorType<T, 2>::Type BVH_VecNt;
0198     static Standard_Integer MainAxis (const BVH_VecNt& theSize)
0199     {
0200       return theSize.x() > theSize.y() ? 0 : 1;
0201     }
0202   };
0203 }
0204 
0205 // =======================================================================
0206 // function : buildNode
0207 // purpose  :
0208 // =======================================================================
0209 template<class T, int N, int Bins>
0210 typename BVH_QueueBuilder<T, N>::BVH_ChildNodes BVH_BinnedBuilder<T, N, Bins>::buildNode (BVH_Set<T, N>*         theSet,
0211                                                                                           BVH_Tree<T, N>*        theBVH,
0212                                                                                           const Standard_Integer theNode) const
0213 {
0214   const Standard_Integer aNodeBegPrimitive = theBVH->BegPrimitive (theNode);
0215   const Standard_Integer aNodeEndPrimitive = theBVH->EndPrimitive (theNode);
0216   if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder<T, N>::myLeafNodeSize)
0217   {
0218     return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes(); // node does not require partitioning
0219   }
0220 
0221   const BVH_Box<T, N> anAABB (theBVH->MinPoint (theNode),
0222                               theBVH->MaxPoint (theNode));
0223   const typename BVH_Box<T, N>::BVH_VecNt aSize = anAABB.Size();
0224 
0225   // Parameters for storing best split
0226   Standard_Integer aMinSplitAxis   = -1;
0227   Standard_Integer aMinSplitIndex  =  0;
0228   Standard_Integer aMinSplitNumLft =  0;
0229   Standard_Integer aMinSplitNumRgh =  0;
0230 
0231   BVH_Box<T, N> aMinSplitBoxLft;
0232   BVH_Box<T, N> aMinSplitBoxRgh;
0233 
0234   Standard_Real aMinSplitCost = std::numeric_limits<Standard_Real>::max();
0235   const Standard_Integer aMainAxis = BVH::BVH_AxisSelector<T, N>::MainAxis (aSize);
0236 
0237   // Find best split
0238   for (Standard_Integer anAxis = myUseMainAxis ? aMainAxis : 0; anAxis <= (myUseMainAxis ? aMainAxis : Min (N - 1, 2)); ++anAxis)
0239   {
0240     if (BVH::VecComp<T, N>::Get (aSize, anAxis) <= BVH::THE_NODE_MIN_SIZE)
0241     {
0242       continue;
0243     }
0244 
0245     BVH_BinVector aBinVector;
0246     getSubVolumes (theSet, theBVH, theNode, aBinVector, anAxis);
0247 
0248     BVH_SplitPlanes aSplitPlanes;
0249     for (Standard_Integer aLftSplit = 1, aRghSplit = Bins - 1; aLftSplit < Bins; ++aLftSplit, --aRghSplit)
0250     {
0251       aSplitPlanes[aLftSplit].LftVoxel.Count = aSplitPlanes[aLftSplit - 1].LftVoxel.Count + aBinVector[aLftSplit - 1].Count;
0252       aSplitPlanes[aRghSplit].RghVoxel.Count = aSplitPlanes[aRghSplit + 1].RghVoxel.Count + aBinVector[aRghSplit + 0].Count;
0253 
0254       aSplitPlanes[aLftSplit].LftVoxel.Box = aSplitPlanes[aLftSplit - 1].LftVoxel.Box;
0255       aSplitPlanes[aRghSplit].RghVoxel.Box = aSplitPlanes[aRghSplit + 1].RghVoxel.Box;
0256 
0257       aSplitPlanes[aLftSplit].LftVoxel.Box.Combine (aBinVector[aLftSplit - 1].Box);
0258       aSplitPlanes[aRghSplit].RghVoxel.Box.Combine (aBinVector[aRghSplit + 0].Box);
0259     }
0260 
0261     // Choose the best split (with minimum SAH cost)
0262     for (Standard_Integer aSplit = 1; aSplit < Bins; ++aSplit)
0263     {
0264       // Simple SAH evaluation
0265       Standard_Real aCost =
0266         (static_cast<Standard_Real> (aSplitPlanes[aSplit].LftVoxel.Box.Area()) /* / S(N) */) * aSplitPlanes[aSplit].LftVoxel.Count
0267       + (static_cast<Standard_Real> (aSplitPlanes[aSplit].RghVoxel.Box.Area()) /* / S(N) */) * aSplitPlanes[aSplit].RghVoxel.Count;
0268 
0269       if (aCost <= aMinSplitCost)
0270       {
0271         aMinSplitCost   = aCost;
0272         aMinSplitAxis   = anAxis;
0273         aMinSplitIndex  = aSplit;
0274         aMinSplitBoxLft = aSplitPlanes[aSplit].LftVoxel.Box;
0275         aMinSplitBoxRgh = aSplitPlanes[aSplit].RghVoxel.Box;
0276         aMinSplitNumLft = aSplitPlanes[aSplit].LftVoxel.Count;
0277         aMinSplitNumRgh = aSplitPlanes[aSplit].RghVoxel.Count;
0278       }
0279     }
0280   }
0281 
0282   theBVH->SetInner (theNode);
0283   Standard_Integer aMiddle = -1;
0284   if (aMinSplitNumLft == 0 || aMinSplitNumRgh == 0 || aMinSplitAxis == -1) // case of objects with the same center
0285   {
0286     aMinSplitBoxLft.Clear();
0287     aMinSplitBoxRgh.Clear();
0288 
0289     aMiddle = std::max (aNodeBegPrimitive + 1,
0290       static_cast<Standard_Integer> ((aNodeBegPrimitive + aNodeEndPrimitive) / 2.f));
0291 
0292     aMinSplitNumLft = aMiddle - aNodeBegPrimitive;
0293     for (Standard_Integer anIndex = aNodeBegPrimitive; anIndex < aMiddle; ++anIndex)
0294     {
0295       aMinSplitBoxLft.Combine (theSet->Box (anIndex));
0296     }
0297 
0298     aMinSplitNumRgh = aNodeEndPrimitive - aMiddle + 1;
0299     for (Standard_Integer anIndex = aNodeEndPrimitive; anIndex >= aMiddle; --anIndex)
0300     {
0301       aMinSplitBoxRgh.Combine (theSet->Box (anIndex));
0302     }
0303   }
0304   else
0305   {
0306     aMiddle = BVH::SplitPrimitives<T, N> (theSet,
0307                                           anAABB,
0308                                           aNodeBegPrimitive,
0309                                           aNodeEndPrimitive,
0310                                           aMinSplitIndex - 1,
0311                                           aMinSplitAxis,
0312                                           Bins);
0313   }
0314 
0315   typedef typename BVH_QueueBuilder<T, N>::BVH_PrimitiveRange Range;
0316   return typename BVH_QueueBuilder<T, N>::BVH_ChildNodes (aMinSplitBoxLft,
0317                                                           aMinSplitBoxRgh,
0318                                                           Range (aNodeBegPrimitive, aMiddle - 1),
0319                                                           Range (aMiddle,     aNodeEndPrimitive));
0320 }
0321 
0322 #endif // _BVH_BinnedBuilder_Header