Performs fast BVH construction using LBVH building approach. Algorithm uses spatial Morton codes to reduce the BVH construction problem to a sorting problem (radix sort -- O(N) complexity). This Linear Bounding Volume Hierarchy (LBVH) builder produces BVH trees of lower quality compared to SAH-based BVH builders but it is over an order of magnitude faster (up to 4M triangles per second).
#include <BVH_Geometry.hxx>
#include <BVH_Triangulation.hxx>
+#include <BVH_LinearBuilder.hxx>
#include <BVH_BinnedBuilder.hxx>
#include <BVH_SweepPlaneBuilder.hxx>
#include <BVH_SpatialMedianBuilder.hxx>
template class BVH_BinnedBuilder<Standard_ShortReal, 3>;
template class BVH_BinnedBuilder<Standard_ShortReal, 4>;
+template class BVH_LinearBuilder<Standard_Real, 3>;
+template class BVH_LinearBuilder<Standard_Real, 4>;
+
+template class BVH_LinearBuilder<Standard_ShortReal, 3>;
+template class BVH_LinearBuilder<Standard_ShortReal, 4>;
+
template class BVH_SweepPlaneBuilder<Standard_Real, 2>;
template class BVH_SweepPlaneBuilder<Standard_Real, 3>;
template class BVH_SweepPlaneBuilder<Standard_Real, 4>;
#ifndef _BVH_BinnedBuilder_Header
#define _BVH_BinnedBuilder_Header
-#include <BVH_Builder.hxx>
+#include <BVH_QueueBuilder.hxx>
#include <algorithm>
//! Performs building of BVH tree using binned SAH algorithm.
//! Number of Bins controls tree's quality (greater - better) in cost of construction time.
template<class T, int N, int Bins = 32>
-class BVH_BinnedBuilder : public BVH_Builder<T, N>
+class BVH_BinnedBuilder : public BVH_QueueBuilder<T, N>
{
public:
template<class T, int N, int Bins>
BVH_BinnedBuilder<T, N, Bins>::BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize,
const Standard_Integer theMaxTreeDepth)
-: BVH_Builder<T, N> (theLeafNodeSize,
- theMaxTreeDepth)
+: BVH_QueueBuilder<T, N> (theLeafNodeSize,
+ theMaxTreeDepth)
{
//
}
//
}
-namespace BVH
-{
- template<class T>
- static inline Standard_Integer IntFloor (const T theValue)
- {
- const Standard_Integer aRes = static_cast<Standard_Integer> (theValue);
-
- return aRes - static_cast<Standard_Integer> (aRes > theValue);
- }
-}
-
// =======================================================================
// function : GetSubVolumes
// purpose :
if (!isLeaf)
{
- BVH_Builder<T, N>::myTasksQueue.Append (aChildIndex);
+ BVH_QueueBuilder<T, N>::myTasksQueue.Append (aChildIndex);
}
BVH_Builder<T, N>::UpdateDepth (theBVH, theBVH->Level (aChildIndex));
#include <BVH_Set.hxx>
#include <BVH_Tree.hxx>
-#include <NCollection_Vector.hxx>
-
namespace
{
//! Minimum node size to split.
const Standard_Integer theMaxTreeDepth);
//! Releases resources of BVH builder.
- virtual ~BVH_Builder() = 0;
+ virtual ~BVH_Builder();
public:
//! Builds BVH using specified algorithm.
- void Build (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const BVH_Box<T, N>& theBox);
-
-protected:
-
- //! Builds BVH node for specified task info.
- virtual void BuildNode (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const Standard_Integer theTask);
+ virtual void Build (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const BVH_Box<T, N>& theBox) = 0;
//! Updates depth of constructed BVH tree.
void UpdateDepth (BVH_Tree<T, N>* theBVH,
Standard_Integer myMaxTreeDepth; //!< Maximum depth of constructed BVH
Standard_Integer myLeafNodeSize; //!< Maximum number of primitives per leaf
- NCollection_Vector<Standard_Integer> myTasksQueue; //!< Queue to manage BVH node building tasks
};
// =======================================================================
// function : BVH_Builder
-// purpose :
+// purpose : Creates abstract BVH builder
// =======================================================================
template<class T, int N>
BVH_Builder<T, N>::BVH_Builder (const Standard_Integer theLeafNodeSize,
// =======================================================================
// function : ~BVH_Builder
-// purpose :
+// purpose : Releases resources of BVH builder
// =======================================================================
template<class T, int N>
BVH_Builder<T, N>::~BVH_Builder()
{
//
}
-
-// =======================================================================
-// function : Build
-// purpose :
-// =======================================================================
-template<class T, int N>
-void BVH_Builder<T, N>::Build (BVH_Set<T, N>* theSet,
- BVH_Tree<T, N>* theBVH,
- const BVH_Box<T, N>& theBox)
-{
- if (theBVH == NULL)
- {
- return;
- }
-
- theBVH->Clear();
- if (theSet->Size() == 0)
- {
- return;
- }
-
- const Standard_Integer aRoot = theBVH->AddLeafNode (theBox, 0, theSet->Size() - 1);
- if (theSet->Size() == 1)
- {
- return;
- }
-
- myTasksQueue.Append (aRoot);
- for (Standard_Integer aTask = 0; aTask < myTasksQueue.Size(); ++aTask)
- {
- BuildNode (theSet, theBVH, myTasksQueue.Value (aTask));
- }
-
- myTasksQueue.Clear();
-}
-
-// =======================================================================
-// function : BuildNode
-// purpose :
-// =======================================================================
-template<class T, int N>
-void BVH_Builder<T, N>::BuildNode (BVH_Set<T, N>* ,
- BVH_Tree<T, N>* ,
- const Standard_Integer )
-{
- // need to disable compile warnings
-}
--- /dev/null
+// Created on: 2014-09-11
+// Created by: Danila ULYANOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _BVH_LinearBuilder_Header
+#define _BVH_LinearBuilder_Header
+
+#include <BVH_Builder.hxx>
+
+typedef std::pair<Standard_Integer, Standard_Integer> BVH_EncodedLink;
+
+//! Performs fast BVH construction using LBVH building approach.
+//! Algorithm uses spatial Morton codes to reduce the BVH construction
+//! problem to a sorting problem (radix sort -- O(N) complexity). This
+//! Linear Bounding Volume Hierarchy (LBVH) builder produces BVH trees
+//! of lower quality compared to SAH-based BVH builders but it is over
+//! an order of magnitude faster (up to 3M triangles per second).
+//!
+//! For more details see:
+//! C. Lauterbach, M. Garland, S. Sengupta, D. Luebke, and D. Manocha.
+//! Fast BVH construction on GPUs. Eurographics, 2009.
+template<class T, int N>
+class BVH_LinearBuilder : public BVH_Builder<T, N>
+{
+public:
+
+ typedef typename BVH::VectorType<T, N>::Type BVH_VecNt;
+
+public:
+
+ //! Creates binned LBVH builder.
+ BVH_LinearBuilder (const Standard_Integer theLeafNodeSize = 5,
+ const Standard_Integer theMaxTreeDepth = 32);
+
+ //! Releases resources of LBVH builder.
+ virtual ~BVH_LinearBuilder();
+
+ //! Builds BVH.
+ void Build (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const BVH_Box<T, N>& theBox);
+
+protected:
+
+ //! Emits hierarchy from sorted Morton codes.
+ Standard_Integer EmitHierachy (BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theBit,
+ const Standard_Integer theShift,
+ std::vector<BVH_EncodedLink>::iterator theStart,
+ std::vector<BVH_EncodedLink>::iterator theFinal);
+
+};
+
+#include <BVH_LinearBuilder.lxx>
+
+#endif // _BVH_LinearBuilder_Header
--- /dev/null
+// Created on: 2014-09-11
+// Created by: Danila ULYANOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <algorithm>
+
+#include <Standard_Assert.hxx>
+
+#ifdef HAVE_TBB
+ // On Windows, function TryEnterCriticalSection has appeared in Windows NT
+ // and is surrounded by #ifdef in MS VC++ 7.1 headers.
+ // Thus to use it we need to define appropriate macro saying that we will
+ // run on Windows NT 4.0 at least
+ #if defined(_WIN32) && !defined(_WIN32_WINNT)
+ #define _WIN32_WINNT 0x0501
+ #endif
+
+ #include <tbb/task.h>
+#endif
+
+// =======================================================================
+// function : BVH_LinearBuilder
+// purpose :
+// =======================================================================
+template<class T, int N>
+BVH_LinearBuilder<T, N>::BVH_LinearBuilder (const Standard_Integer theLeafNodeSize,
+ const Standard_Integer theMaxTreeDepth)
+: BVH_Builder<T, N> (theLeafNodeSize,
+ theMaxTreeDepth)
+{
+ //
+}
+
+// =======================================================================
+// function : ~BVH_LinearBuilder
+// purpose :
+// =======================================================================
+template<class T, int N>
+BVH_LinearBuilder<T, N>::~BVH_LinearBuilder()
+{
+ //
+}
+
+namespace BVH
+{
+ // Radix sort STL predicate for 32-bit integer.
+ class BitPredicate
+ {
+ Standard_Integer myBit;
+
+ public:
+
+ //! Creates new radix sort predicate.
+ BitPredicate (const Standard_Integer theBit) : myBit (theBit)
+ {
+ //
+ }
+
+ //! Returns predicate value.
+ bool operator() (const BVH_EncodedLink theLink) const
+ {
+ const Standard_Integer aMask = 1 << myBit;
+
+ return !(theLink.first & aMask); // 0-bit to the left side
+ }
+ };
+
+ //! STL compare tool used in binary search algorithm.
+ class BitComparator
+ {
+ Standard_Integer myBit;
+
+ public:
+
+ //! Creates new STL comparator.
+ BitComparator (const Standard_Integer theBit) : myBit (theBit)
+ {
+ //
+ }
+
+ //! Checks left value for the given bit.
+ bool operator() (BVH_EncodedLink theLink1, BVH_EncodedLink /*theLink2*/)
+ {
+ return !(theLink1.first & (1 << myBit));
+ }
+ };
+
+ //! Tool object for sorting link array using radix sort algorithm.
+ struct RadixSorter
+ {
+ typedef std::vector<BVH_EncodedLink>::iterator LinkIterator;
+
+ // Performs MSD (most significant digit) radix sort.
+ static void Perform (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theBit = 29)
+ {
+ while (theStart != theFinal && theBit >= 0)
+ {
+ LinkIterator anOffset = std::partition (theStart, theFinal, BitPredicate (theBit--));
+
+ Perform (theStart, anOffset, theBit);
+
+ theStart = anOffset;
+ }
+ }
+ };
+
+ //! Calculates bounding boxes (AABBs) for the given BVH tree.
+ template<class T, int N>
+ Standard_Integer UpdateBounds (BVH_Set<T, N>* theSet, BVH_Tree<T, N>* theTree, const Standard_Integer theNode = 0)
+ {
+ const BVH_Vec4i aData = theTree->NodeInfoBuffer()[theNode];
+
+ if (aData.x() == 0)
+ {
+ const Standard_Integer aLftChild = theTree->NodeInfoBuffer()[theNode].y();
+ const Standard_Integer aRghChild = theTree->NodeInfoBuffer()[theNode].z();
+
+ const Standard_Integer aLftDepth = UpdateBounds (theSet, theTree, aLftChild);
+ const Standard_Integer aRghDepth = UpdateBounds (theSet, theTree, aRghChild);
+
+ typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = theTree->MinPointBuffer()[aLftChild];
+ typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = theTree->MaxPointBuffer()[aLftChild];
+ typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = theTree->MinPointBuffer()[aRghChild];
+ typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = theTree->MaxPointBuffer()[aRghChild];
+
+ BVH::BoxMinMax<T, N>::CwiseMin (aLftMinPoint, aRghMinPoint);
+ BVH::BoxMinMax<T, N>::CwiseMax (aLftMaxPoint, aRghMaxPoint);
+
+ theTree->MinPointBuffer()[theNode] = aLftMinPoint;
+ theTree->MaxPointBuffer()[theNode] = aLftMaxPoint;
+
+ return Max (aLftDepth, aRghDepth) + 1;
+ }
+ else
+ {
+ typename BVH_Box<T, N>::BVH_VecNt& aMinPoint = theTree->MinPointBuffer()[theNode];
+ typename BVH_Box<T, N>::BVH_VecNt& aMaxPoint = theTree->MaxPointBuffer()[theNode];
+
+ for (Standard_Integer aPrimIdx = aData.y(); aPrimIdx <= aData.z(); ++aPrimIdx)
+ {
+ const typename BVH_Box<T, N> aBox = theSet->Box (aPrimIdx);
+
+ if (aPrimIdx == aData.y())
+ {
+ aMinPoint = aBox.CornerMin();
+ aMaxPoint = aBox.CornerMax();
+ }
+ else
+ {
+ BVH::BoxMinMax<T, N>::CwiseMin (aMinPoint, aBox.CornerMin());
+ BVH::BoxMinMax<T, N>::CwiseMax (aMaxPoint, aBox.CornerMax());
+ }
+ }
+ }
+
+ return 0;
+ }
+}
+
+// =======================================================================
+// function : EmitHierachy
+// purpose : Emits hierarchy from sorted Morton codes
+// =======================================================================
+template<class T, int N>
+Standard_Integer BVH_LinearBuilder<T, N>::EmitHierachy (BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theBit,
+ const Standard_Integer theShift,
+ std::vector<BVH_EncodedLink>::iterator theStart,
+ std::vector<BVH_EncodedLink>::iterator theFinal)
+{
+ if (theFinal - theStart > myLeafNodeSize && theBit >= 0)
+ {
+ std::vector<BVH_EncodedLink>::iterator aPosition = std::lower_bound (
+ theStart, theFinal, BVH_EncodedLink(), BVH::BitComparator (theBit));
+
+ if (aPosition == theStart || aPosition == theFinal)
+ {
+ return EmitHierachy (theBVH, theBit - 1, theShift, theStart, theFinal);
+ }
+
+ // Build inner node
+ const Standard_Integer aNode = theBVH->AddInnerNode (0, 0);
+
+ const Standard_Integer aRghNode = theShift + static_cast<Standard_Integer> (aPosition - theStart);
+
+ const Standard_Integer aLftChild = EmitHierachy (theBVH, theBit - 1, theShift, theStart, aPosition);
+ const Standard_Integer aRghChild = EmitHierachy (theBVH, theBit - 1, aRghNode, aPosition, theFinal);
+
+ theBVH->NodeInfoBuffer()[aNode].y() = aLftChild;
+ theBVH->NodeInfoBuffer()[aNode].z() = aRghChild;
+
+ return aNode;
+ }
+ else
+ {
+ // Build leaf node
+ return theBVH->AddLeafNode (theShift, theShift + static_cast<Standard_Integer> (theFinal - theStart) - 1);
+ }
+}
+
+#ifdef HAVE_TBB
+
+namespace BVH
+{
+ //! TBB task for parallel radix sort.
+ class RadixSortTask : public tbb::task
+ {
+ typedef std::vector<BVH_EncodedLink>::iterator LinkIterator;
+
+ private:
+
+ //! Start range element.
+ LinkIterator myStart;
+
+ //! Final range element.
+ LinkIterator myFinal;
+
+ //! Bit position for range partition.
+ Standard_Integer myDigit;
+
+ public:
+
+ //! Creates new TBB radix sort task.
+ RadixSortTask (LinkIterator theStart, LinkIterator theFinal, Standard_Integer theDigit)
+ : myStart (theStart),
+ myFinal (theFinal),
+ myDigit (theDigit)
+ {
+ //
+ }
+
+ //! Executes the task.
+ tbb::task* execute()
+ {
+ if (myDigit < 28)
+ {
+ BVH::RadixSorter::Perform (myStart, myFinal, myDigit);
+ }
+ else
+ {
+ LinkIterator anOffset = std::partition (myStart, myFinal, BitPredicate (myDigit));
+
+ tbb::task_list aList;
+
+ aList.push_back (*new ( allocate_child() )
+ RadixSortTask (myStart, anOffset, myDigit - 1));
+
+ aList.push_back (*new ( allocate_child() )
+ RadixSortTask (anOffset, myFinal, myDigit - 1));
+
+ set_ref_count (3); // count + 1
+ spawn_and_wait_for_all (aList);
+ }
+
+ return NULL;
+ }
+ };
+
+ //! TBB task for parallel bounds updating.
+ template<class T, int N>
+ class UpdateBoundTask: public tbb::task
+ {
+ //! Set of geometric objects.
+ BVH_Set<T, N>* mySet;
+
+ //! BVH tree built over the set.
+ BVH_Tree<T, N>* myBVH;
+
+ //! BVH node to update bounding box.
+ Standard_Integer myNode;
+
+ //! Level of the processed BVH node.
+ Standard_Integer myLevel;
+
+ //! Height of the processed BVH node.
+ Standard_Integer* myHeight;
+
+ public:
+
+ //! Creates new TBB parallel bound update task.
+ UpdateBoundTask (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ Standard_Integer theNode,
+ Standard_Integer theLevel,
+ Standard_Integer* theHeight)
+ : mySet (theSet),
+ myBVH (theBVH),
+ myNode (theNode),
+ myLevel (theLevel),
+ myHeight (theHeight)
+ {
+ //
+ }
+
+ //! Executes the task.
+ tbb::task* execute()
+ {
+ if (myBVH->IsOuter (myNode) || myLevel > 2)
+ {
+ *myHeight = BVH::UpdateBounds (mySet, myBVH, myNode);
+ }
+ else
+ {
+ Standard_Integer aLftHeight = 0;
+ Standard_Integer aRghHeight = 0;
+
+ tbb::task_list aList;
+
+ const Standard_Integer aLftChild = myBVH->NodeInfoBuffer()[myNode].y();
+ const Standard_Integer aRghChild = myBVH->NodeInfoBuffer()[myNode].z();
+
+ Standard_Integer aCount = 1;
+
+ if (!myBVH->IsOuter (aLftChild))
+ {
+ ++aCount;
+ aList.push_back (*new ( allocate_child() )
+ UpdateBoundTask (mySet, myBVH, aLftChild, myLevel + 1, &aLftHeight));
+ }
+ else
+ {
+ aLftHeight = BVH::UpdateBounds (mySet, myBVH, aLftChild);
+ }
+
+ if (!myBVH->IsOuter (aRghChild))
+ {
+ ++aCount;
+ aList.push_back (*new( allocate_child() )
+ UpdateBoundTask (mySet, myBVH, aRghChild, myLevel + 1, &aRghHeight));
+ }
+ else
+ {
+ aRghHeight = BVH::UpdateBounds (mySet, myBVH, aRghChild);
+ }
+
+ if (aCount > 1)
+ {
+ set_ref_count (aCount);
+ spawn_and_wait_for_all (aList);
+ }
+
+ typename BVH_Box<T, N>::BVH_VecNt aLftMinPoint = myBVH->MinPointBuffer()[aLftChild];
+ typename BVH_Box<T, N>::BVH_VecNt aLftMaxPoint = myBVH->MaxPointBuffer()[aLftChild];
+ typename BVH_Box<T, N>::BVH_VecNt aRghMinPoint = myBVH->MinPointBuffer()[aRghChild];
+ typename BVH_Box<T, N>::BVH_VecNt aRghMaxPoint = myBVH->MaxPointBuffer()[aRghChild];
+
+ BVH::BoxMinMax<T, N>::CwiseMin (aLftMinPoint, aRghMinPoint);
+ BVH::BoxMinMax<T, N>::CwiseMax (aLftMaxPoint, aRghMaxPoint);
+
+ myBVH->MinPointBuffer()[myNode] = aLftMinPoint;
+ myBVH->MaxPointBuffer()[myNode] = aLftMaxPoint;
+
+ *myHeight = Max (aLftHeight, aRghHeight) + 1;
+ }
+
+ return NULL;
+ }
+ };
+}
+
+#endif
+
+// =======================================================================
+// function : Build
+// purpose :
+// =======================================================================
+template<class T, int N>
+void BVH_LinearBuilder<T, N>::Build (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const BVH_Box<T, N>& theBox)
+{
+ Standard_STATIC_ASSERT (N == 3 || N == 4);
+
+ if (theBVH == NULL || theSet->Size() == 0)
+ {
+ return;
+ }
+
+ theBVH->Clear();
+
+ const Standard_Integer aDimensionX = 1024;
+ const Standard_Integer aDimensionY = 1024;
+ const Standard_Integer aDimensionZ = 1024;
+
+ const BVH_VecNt aSceneMin = theBox.CornerMin();
+ const BVH_VecNt aSceneMax = theBox.CornerMax();
+
+ const BVH_VecNt aSceneSize = aSceneMax - aSceneMin;
+
+ const T aReverseSizeX = static_cast<T> (aDimensionX) / (aSceneMax.x() - aSceneMin.x());
+ const T aReverseSizeY = static_cast<T> (aDimensionY) / (aSceneMax.y() - aSceneMin.y());
+ const T aReverseSizeZ = static_cast<T> (aDimensionZ) / (aSceneMax.z() - aSceneMin.z());
+
+ std::vector<BVH_EncodedLink> anEncodedLinks (theSet->Size(), BVH_EncodedLink());
+
+ // Step 1 -- Assign Morton code to each primitive
+ for (Standard_Integer aPrimIdx = 0; aPrimIdx < theSet->Size(); ++aPrimIdx)
+ {
+ const BVH_VecNt aCenter = theSet->Box (aPrimIdx).Center();
+
+ Standard_Integer aVoxelX = BVH::IntFloor ((aCenter.x() - aSceneMin.x()) * aReverseSizeX);
+ Standard_Integer aVoxelY = BVH::IntFloor ((aCenter.y() - aSceneMin.y()) * aReverseSizeY);
+ Standard_Integer aVoxelZ = BVH::IntFloor ((aCenter.z() - aSceneMin.z()) * aReverseSizeZ);
+
+ aVoxelX = Max (0, Min (aVoxelX, aDimensionX - 1));
+ aVoxelY = Max (0, Min (aVoxelY, aDimensionY - 1));
+ aVoxelZ = Max (0, Min (aVoxelZ, aDimensionZ - 1));
+
+ aVoxelX = (aVoxelX | (aVoxelX << 16)) & 0x030000FF;
+ aVoxelX = (aVoxelX | (aVoxelX << 8)) & 0x0300F00F;
+ aVoxelX = (aVoxelX | (aVoxelX << 4)) & 0x030C30C3;
+ aVoxelX = (aVoxelX | (aVoxelX << 2)) & 0x09249249;
+
+ aVoxelY = (aVoxelY | (aVoxelY << 16)) & 0x030000FF;
+ aVoxelY = (aVoxelY | (aVoxelY << 8)) & 0x0300F00F;
+ aVoxelY = (aVoxelY | (aVoxelY << 4)) & 0x030C30C3;
+ aVoxelY = (aVoxelY | (aVoxelY << 2)) & 0x09249249;
+
+ aVoxelZ = (aVoxelZ | (aVoxelZ << 16)) & 0x030000FF;
+ aVoxelZ = (aVoxelZ | (aVoxelZ << 8)) & 0x0300F00F;
+ aVoxelZ = (aVoxelZ | (aVoxelZ << 4)) & 0x030C30C3;
+ aVoxelZ = (aVoxelZ | (aVoxelZ << 2)) & 0x09249249;
+
+ anEncodedLinks[aPrimIdx] = BVH_EncodedLink (
+ aVoxelX | (aVoxelY << 1) | (aVoxelZ << 2), aPrimIdx);
+ }
+
+ // Step 2 -- Sort primitives by their Morton codes using radix sort
+#ifdef HAVE_TBB
+
+ BVH::RadixSortTask& aSortTask = *new ( tbb::task::allocate_root() )
+ BVH::RadixSortTask (anEncodedLinks.begin(), anEncodedLinks.end(), 29);
+
+ tbb::task::spawn_root_and_wait (aSortTask);
+
+#else
+
+ BVH::RadixSorter::Perform (anEncodedLinks.begin(), anEncodedLinks.end());
+
+#endif
+
+ // Step 3 -- Emitting BVH hierarchy from sorted Morton codes
+ EmitHierachy (theBVH, 29, 0, anEncodedLinks.begin(), anEncodedLinks.end());
+
+ Standard_Integer* aLinkMap = new Standard_Integer[theSet->Size()];
+
+ for (Standard_Integer aLinkIdx = 0; aLinkIdx < theSet->Size(); ++aLinkIdx)
+ {
+ aLinkMap[anEncodedLinks[aLinkIdx].second] = aLinkIdx;
+ }
+
+ // Step 4 -- Rearranging primitive list according to Morton codes (in place)
+ Standard_Integer aPrimIdx = 0;
+
+ while (aPrimIdx < theSet->Size())
+ {
+ const Standard_Integer aSortIdx = aLinkMap[aPrimIdx];
+
+ if (aPrimIdx != aSortIdx)
+ {
+ theSet->Swap (aPrimIdx, aSortIdx);
+
+ std::swap (aLinkMap[aPrimIdx],
+ aLinkMap[aSortIdx]);
+ }
+ else
+ {
+ ++aPrimIdx;
+ }
+ }
+
+ // Step 5 -- Compute bounding boxes of BVH nodes
+ theBVH->MinPointBuffer().resize (theBVH->NodeInfoBuffer().size());
+ theBVH->MaxPointBuffer().resize (theBVH->NodeInfoBuffer().size());
+
+ Standard_Integer aDepth = 0;
+
+#ifdef HAVE_TBB
+
+ BVH::UpdateBoundTask<T, N>& aRootTask = *new ( tbb::task::allocate_root() )
+ BVH::UpdateBoundTask<T, N> (theSet, theBVH, 0, 0, &aDepth);
+
+ tbb::task::spawn_root_and_wait (aRootTask);
+
+#else
+
+ aDepth = BVH::UpdateBounds (theSet, theBVH, 0);
+
+#endif
+
+ BVH_Builder<T, N>::UpdateDepth (theBVH, aDepth);
+}
--- /dev/null
+// Created on: 2014-09-15
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _BVH_QueueBuilder_Header
+#define _BVH_QueueBuilder_Header
+
+#include <BVH_Builder.hxx>
+
+#include <NCollection_Vector.hxx>
+
+//! Abstract BVH builder based on the concept of work queue.
+template<class T, int N>
+class BVH_QueueBuilder : public BVH_Builder<T, N>
+{
+public:
+
+ //! Creates new BVH queue based builder.
+ BVH_QueueBuilder (const Standard_Integer theLeafNodeSize,
+ const Standard_Integer theMaxTreeDepth);
+
+ //! Releases resources of BVH queue based builder.
+ virtual ~BVH_QueueBuilder() = 0;
+
+public:
+
+ //! Builds BVH using specific algorithm.
+ virtual void Build (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const BVH_Box<T, N>& theBox);
+
+protected:
+
+ //! Builds BVH node for the given task info.
+ virtual void BuildNode (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const Standard_Integer theTask);
+
+protected:
+
+ NCollection_Vector<Standard_Integer> myTasksQueue; //!< Queue to manage BVH node building tasks
+
+};
+
+#include <BVH_QueueBuilder.lxx>
+
+#endif // _BVH_QueueBuilder_Header
--- /dev/null
+// Created on: 2014-09-15
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+// =======================================================================
+// function : BVH_QueueBuilder
+// purpose : Creates new BVH queue based builder
+// =======================================================================
+template<class T, int N>
+BVH_QueueBuilder<T, N>::BVH_QueueBuilder (const Standard_Integer theLeafNodeSize,
+ const Standard_Integer theMaxTreeDepth)
+: BVH_Builder<T, N> (theLeafNodeSize,
+ theMaxTreeDepth)
+{
+ //
+}
+
+// =======================================================================
+// function : ~BVH_QueueBuilder
+// purpose : Releases resources of BVH queue based builder
+// =======================================================================
+template<class T, int N>
+BVH_QueueBuilder<T, N>::~BVH_QueueBuilder()
+{
+ //
+}
+
+// =======================================================================
+// function : Build
+// purpose : Builds BVH using specific algorithm
+// =======================================================================
+template<class T, int N>
+void BVH_QueueBuilder<T, N>::Build (BVH_Set<T, N>* theSet,
+ BVH_Tree<T, N>* theBVH,
+ const BVH_Box<T, N>& theBox)
+{
+ if (theBVH == NULL)
+ {
+ return;
+ }
+
+ theBVH->Clear();
+ if (theSet->Size() == 0)
+ {
+ return;
+ }
+
+ const Standard_Integer aRoot = theBVH->AddLeafNode (theBox, 0, theSet->Size() - 1);
+ if (theSet->Size() == 1)
+ {
+ return;
+ }
+
+ myTasksQueue.Append (aRoot);
+ for (Standard_Integer aTask = 0; aTask < myTasksQueue.Size(); ++aTask)
+ {
+ BuildNode (theSet, theBVH, myTasksQueue.Value (aTask));
+ }
+
+ myTasksQueue.Clear();
+}
+
+// =======================================================================
+// function : BuildNode
+// purpose : Builds BVH node for the given task info
+// =======================================================================
+template<class T, int N>
+void BVH_QueueBuilder<T, N>::BuildNode (BVH_Set<T, N>* /* theSet */,
+ BVH_Tree<T, N>* /* theBVH */,
+ const Standard_Integer /* theTask */)
+{
+ // needed to disable compile warnings
+}
#ifndef _BVH_SweepPlaneBuilder_Header
#define _BVH_SweepPlaneBuilder_Header
-#include <BVH_Builder.hxx>
+#include <BVH_QueueBuilder.hxx>
//! Performs building of BVH tree using sweep plane SAH algorithm.
template<class T, int N>
-class BVH_SweepPlaneBuilder : public BVH_Builder<T, N>
+class BVH_SweepPlaneBuilder : public BVH_QueueBuilder<T, N>
{
public:
template<class T, int N>
BVH_SweepPlaneBuilder<T, N>::BVH_SweepPlaneBuilder (const Standard_Integer theLeafNodeSize,
const Standard_Integer theMaxTreeDepth)
-: BVH_Builder<T, N> (theLeafNodeSize,
- theMaxTreeDepth)
+: BVH_QueueBuilder<T, N> (theLeafNodeSize,
+ theMaxTreeDepth)
{
//
}
if (!isLeaf)
{
- BVH_Builder<T, N>::myTasksQueue.Append (aChildIndex);
+ BVH_QueueBuilder<T, N>::myTasksQueue.Append (aChildIndex);
}
BVH_Builder<T, N>::UpdateDepth (theBVH, theBVH->Level (aChildIndex));
const Standard_Integer theLftChild,
const Standard_Integer theRghChild);
+ //! Adds new leaf node to the BVH with UNINITIALIZED bounds.
+ Standard_Integer AddLeafNode (const Standard_Integer theBegElem,
+ const Standard_Integer theEndElem);
+
+ //! Adds new inner node to the BVH with UNINITIALIZED bounds.
+ Standard_Integer AddInnerNode (const Standard_Integer theLftChild,
+ const Standard_Integer theRghChild);
+
//! Returns value of SAH (surface area heuristic).
//! Allows to compare the quality of BVH trees constructed for
//! the same sets of geometric objects with different methods.
BVH::ArrayOp<Standard_Integer, 4>::Clear (myNodeInfoBuffer);
}
+// =======================================================================
+// function : AddLeafNode
+// purpose :
+// =======================================================================
+template<class T, int N>
+Standard_Integer BVH_Tree<T, N>::AddLeafNode (const Standard_Integer theBegElem,
+ const Standard_Integer theEndElem)
+{
+ BVH::ArrayOp<Standard_Integer, 4>::Append (myNodeInfoBuffer, BVH_Vec4i (1, theBegElem, theEndElem, 0));
+
+ return static_cast<Standard_Integer> (BVH::ArrayOp<Standard_Integer, 4>::Size (myNodeInfoBuffer) - 1);
+}
+
+// =======================================================================
+// function : AddInnerNode
+// purpose :
+// =======================================================================
+template<class T, int N>
+Standard_Integer BVH_Tree<T, N>::AddInnerNode (const Standard_Integer theLftChild,
+ const Standard_Integer theRghChild)
+{
+ BVH::ArrayOp<Standard_Integer, 4>::Append (myNodeInfoBuffer, BVH_Vec4i (0, theLftChild, theRghChild, 0));
+
+ return static_cast<Standard_Integer> (BVH::ArrayOp<Standard_Integer, 4>::Size (myNodeInfoBuffer) - 1);
+}
+
// =======================================================================
// function : AddLeafNode
// purpose :
void BVH_Triangulation<T, N>::Swap (const Standard_Integer theIndex1,
const Standard_Integer theIndex2)
{
- BVH_Vec4i anIndices1 = BVH::ArrayOp<Standard_Integer, 4>::Value (Elements, theIndex1);
- BVH_Vec4i anIndices2 = BVH::ArrayOp<Standard_Integer, 4>::Value (Elements, theIndex2);
+ BVH_Vec4i& anIndices1 = BVH::ArrayOp<Standard_Integer, 4>::ChangeValue (Elements, theIndex1);
+ BVH_Vec4i& anIndices2 = BVH::ArrayOp<Standard_Integer, 4>::ChangeValue (Elements, theIndex2);
- BVH::ArrayOp<Standard_Integer, 4>::ChangeValue (Elements, theIndex1) = anIndices2;
- BVH::ArrayOp<Standard_Integer, 4>::ChangeValue (Elements, theIndex2) = anIndices1;
+ std::swap (anIndices1, anIndices2);
}
{
typedef NCollection_Mat4<T> Type;
};
+
+ template<class T>
+ static inline Standard_Integer IntFloor (const T theValue)
+ {
+ const Standard_Integer aRes = static_cast<Standard_Integer> (theValue);
+
+ return aRes - static_cast<Standard_Integer> (aRes > theValue);
+ }
}
//! 2D vector of integers.
const Standard_Integer theIndex)
{
#ifdef _BVH_USE_STD_VECTOR_
- return theArray.at (theIndex);
+ return theArray[theIndex];
#else
return theArray.Value (theIndex);
#endif
const Standard_Integer theIndex)
{
#ifdef _BVH_USE_STD_VECTOR_
- return theArray.at (theIndex);
+ return theArray[theIndex];
#else
return theArray.ChangeValue (theIndex);
#endif
BVH_Builder.lxx
BVH_Geometry.hxx
BVH_Geometry.lxx
+BVH_LinearBuilder.hxx
+BVH_LinearBuilder.lxx
BVH_Object.hxx
BVH_Object.lxx
BVH_ObjectSet.hxx
BVH_Triangulation.lxx
BVH_Types.hxx
BVH_Types.lxx
+BVH_QueueBuilder.hxx
+BVH_QueueBuilder.lxx