// Created on: 2014-01-09 // 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_SweepPlaneBuilder_HeaderFile #define BVH_SweepPlaneBuilder_HeaderFile #include "BVH_QueueBuilder.hxx" #include "BVH_QuickSorter.hxx" #include "NCollection_Array1.hxx" //! Performs building of BVH tree using sweep plane SAH algorithm. template class BVH_SweepPlaneBuilder : public BVH_QueueBuilder { public: //! Creates sweep plane SAH BVH builder. BVH_SweepPlaneBuilder(const int theLeafNodeSize = BVH_Constants_LeafNodeSizeDefault, const int theMaxTreeDepth = BVH_Constants_MaxTreeDepth, const int theNumOfThreads = 1) : BVH_QueueBuilder(theLeafNodeSize, theMaxTreeDepth, theNumOfThreads) { } //! Releases resources of sweep plane SAH BVH builder. ~BVH_SweepPlaneBuilder() override = default; protected: //! Performs splitting of the given BVH node. typename BVH_QueueBuilder::BVH_ChildNodes buildNode(BVH_Set* theSet, BVH_Tree* theBVH, const int theNode) const override { const int aNodeBegPrimitive = theBVH->BegPrimitive(theNode); const int aNodeEndPrimitive = theBVH->EndPrimitive(theNode); const int aNodeNbPrimitives = theBVH->NbPrimitives(theNode); if (aNodeNbPrimitives <= BVH_Builder::myLeafNodeSize) { // clang-format off return typename BVH_QueueBuilder::BVH_ChildNodes(); // node does not require partitioning // clang-format on } // Parameters for storing best split int aMinSplitAxis = -1; int aMinSplitIndex = 0; NCollection_Array1 aLftSet(1, aNodeNbPrimitives - 1); NCollection_Array1 aRghSet(1, aNodeNbPrimitives - 1); double aMinSplitCost = std::numeric_limits::max(); // Find best split for (int anAxis = 0; anAxis < (N < 4 ? N : 3); ++anAxis) { const T aNodeSize = BVH::VecComp::Get(theBVH->MaxPoint(theNode), anAxis) - BVH::VecComp::Get(theBVH->MinPoint(theNode), anAxis); if (aNodeSize <= BVH::THE_NODE_MIN_SIZE) { continue; } BVH_QuickSorter(anAxis).Perform(theSet, aNodeBegPrimitive, aNodeEndPrimitive); BVH_Box aLftBox; BVH_Box aRghBox; // Sweep from left for (int anIndex = 1; anIndex < aNodeNbPrimitives; ++anIndex) { aLftBox.Combine(theSet->Box(anIndex + aNodeBegPrimitive - 1)); aLftSet(anIndex) = static_cast(aLftBox.Area()); } // Sweep from right for (int anIndex = 1; anIndex < aNodeNbPrimitives; ++anIndex) { aRghBox.Combine(theSet->Box(aNodeEndPrimitive - anIndex + 1)); aRghSet(anIndex) = static_cast(aRghBox.Area()); } // Find best split using simplified SAH for (int aNbLft = 1, aNbRgh = aNodeNbPrimitives - 1; aNbLft < aNodeNbPrimitives; ++aNbLft, --aNbRgh) { double aCost = (aLftSet(aNbLft) /* / aNodeArea */) * aNbLft + (aRghSet(aNbRgh) /* / aNodeArea */) * aNbRgh; if (aCost < aMinSplitCost) { aMinSplitCost = aCost; aMinSplitAxis = anAxis; aMinSplitIndex = aNbLft; } } } if (aMinSplitAxis == -1) { return typename BVH_QueueBuilder::BVH_ChildNodes(); // failed to find split axis } theBVH->SetInner(theNode); if (aMinSplitAxis != (N < 4 ? N - 1 : 2)) { BVH_QuickSorter(aMinSplitAxis).Perform(theSet, aNodeBegPrimitive, aNodeEndPrimitive); } BVH_Box aMinSplitBoxLft; BVH_Box aMinSplitBoxRgh; // Compute bounding boxes for selected split plane for (int anIndex = aNodeBegPrimitive; anIndex < aMinSplitIndex + aNodeBegPrimitive; ++anIndex) { aMinSplitBoxLft.Combine(theSet->Box(anIndex)); } for (int anIndex = aNodeEndPrimitive; anIndex >= aMinSplitIndex + aNodeBegPrimitive; --anIndex) { aMinSplitBoxRgh.Combine(theSet->Box(anIndex)); } const int aMiddle = aNodeBegPrimitive + aMinSplitIndex; typedef typename BVH_QueueBuilder::BVH_PrimitiveRange Range; return typename BVH_QueueBuilder::BVH_ChildNodes(aMinSplitBoxLft, aMinSplitBoxRgh, Range(aNodeBegPrimitive, aMiddle - 1), Range(aMiddle, aNodeEndPrimitive)); } }; #endif // _BVH_SweepPlaneBuilder_Header