// Created on: 2013-12-20 // 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_BinnedBuilder // purpose : // ======================================================================= template BVH_BinnedBuilder::BVH_BinnedBuilder (const Standard_Integer theLeafNodeSize, const Standard_Integer theMaxTreeDepth, const Standard_Boolean theDoMainSplits, const Standard_Integer theNumOfThreads) : BVH_QueueBuilder (theLeafNodeSize, theMaxTreeDepth, theNumOfThreads), myUseMainAxis (theDoMainSplits) { // } // ======================================================================= // function : ~BVH_BinnedBuilder // purpose : // ======================================================================= template BVH_BinnedBuilder::~BVH_BinnedBuilder() { // } // ======================================================================= // function : GetSubVolumes // purpose : // ======================================================================= template void BVH_BinnedBuilder::GetSubVolumes (BVH_Set* theSet, BVH_Tree* theBVH, const Standard_Integer theNode, BVH_BinVector& theBins, const Standard_Integer theAxis) { const T aMin = BVH::VecComp::Get (theBVH->MinPoint (theNode), theAxis); const T aMax = BVH::VecComp::Get (theBVH->MaxPoint (theNode), theAxis); const T anInverseStep = static_cast (Bins) / (aMax - aMin); for (Standard_Integer anIdx = theBVH->BegPrimitive (theNode); anIdx <= theBVH->EndPrimitive (theNode); ++anIdx) { typename BVH_Set::BVH_BoxNt aBox = theSet->Box (anIdx); Standard_Integer aBinIndex = BVH::IntFloor ( (theSet->Center (anIdx, theAxis) - aMin) * anInverseStep); if (aBinIndex < 0) { aBinIndex = 0; } else if (aBinIndex >= Bins) { aBinIndex = Bins - 1; } theBins[aBinIndex].Count++; theBins[aBinIndex].Box.Combine (aBox); } } namespace BVH { // ======================================================================= // function : SplitPrimitives // purpose : // ======================================================================= template Standard_Integer SplitPrimitives (BVH_Set* theSet, const BVH_Box& theBox, const Standard_Integer theBeg, const Standard_Integer theEnd, const Standard_Integer theBin, const Standard_Integer theAxis, const Standard_Integer theBins) { const T aMin = BVH::VecComp::Get (theBox.CornerMin(), theAxis); const T aMax = BVH::VecComp::Get (theBox.CornerMax(), theAxis); const T anInverseStep = static_cast (theBins) / (aMax - aMin); Standard_Integer aLftIdx (theBeg); Standard_Integer aRghIdx (theEnd); do { while (BVH::IntFloor ((theSet->Center (aLftIdx, theAxis) - aMin) * anInverseStep) <= theBin && aLftIdx < theEnd) { ++aLftIdx; } while (BVH::IntFloor ((theSet->Center (aRghIdx, theAxis) - aMin) * anInverseStep) > theBin && aRghIdx > theBeg) { --aRghIdx; } if (aLftIdx <= aRghIdx) { if (aLftIdx != aRghIdx) { theSet->Swap (aLftIdx, aRghIdx); } ++aLftIdx; --aRghIdx; } } while (aLftIdx <= aRghIdx); return aLftIdx; } } #if defined (_WIN32) && defined (max) #undef max #endif #include namespace BVH { template struct BVH_AxisSelector { typedef typename BVH::VectorType::Type BVH_VecNt; // ======================================================================= // function : MainAxis // purpose : // ======================================================================= static Standard_Integer MainAxis (const BVH_VecNt& theSize) { if (theSize.y() > theSize.x()) { return theSize.y() > theSize.z() ? 1 : 2; } else { return theSize.z() > theSize.x() ? 2 : 0; } } }; template struct BVH_AxisSelector { typedef typename BVH::VectorType::Type BVH_VecNt; // ======================================================================= // function : MainAxis // purpose : // ======================================================================= static Standard_Integer MainAxis (const BVH_VecNt& theSize) { return theSize.x() > theSize.y() ? 0 : 1; } }; } // ======================================================================= // function : BuildNode // purpose : // ======================================================================= template typename BVH_QueueBuilder::BVH_ChildNodes BVH_BinnedBuilder::BuildNode (BVH_Set* theSet, BVH_Tree* theBVH, const Standard_Integer theNode) { const Standard_Integer aNodeBegPrimitive = theBVH->BegPrimitive (theNode); const Standard_Integer aNodeEndPrimitive = theBVH->EndPrimitive (theNode); if (aNodeEndPrimitive - aNodeBegPrimitive < BVH_Builder::myLeafNodeSize) { return typename BVH_QueueBuilder::BVH_ChildNodes(); // node does not require partitioning } const BVH_Box anAABB (theBVH->MinPoint (theNode), theBVH->MaxPoint (theNode)); const typename BVH_Box::BVH_VecNt aSize = anAABB.Size(); // Parameters for storing best split Standard_Integer aMinSplitAxis = -1; Standard_Integer aMinSplitIndex = 0; Standard_Integer aMinSplitNumLft = 0; Standard_Integer aMinSplitNumRgh = 0; BVH_Box aMinSplitBoxLft; BVH_Box aMinSplitBoxRgh; Standard_Real aMinSplitCost = std::numeric_limits::max(); const Standard_Integer aMainAxis = BVH::BVH_AxisSelector::MainAxis (aSize); // Find best split for (Standard_Integer anAxis = myUseMainAxis ? aMainAxis : 0; anAxis <= (myUseMainAxis ? aMainAxis : Min (N - 1, 2)); ++anAxis) { if (BVH::VecComp::Get (aSize, anAxis) <= BVH::THE_NODE_MIN_SIZE) { continue; } BVH_BinVector aBinVector; GetSubVolumes (theSet, theBVH, theNode, aBinVector, anAxis); BVH_SplitPlanes aSplitPlanes; for (Standard_Integer aLftSplit = 1, aRghSplit = Bins - 1; aLftSplit < Bins; ++aLftSplit, --aRghSplit) { aSplitPlanes[aLftSplit].LftVoxel.Count = aSplitPlanes[aLftSplit - 1].LftVoxel.Count + aBinVector[aLftSplit - 1].Count; aSplitPlanes[aRghSplit].RghVoxel.Count = aSplitPlanes[aRghSplit + 1].RghVoxel.Count + aBinVector[aRghSplit + 0].Count; aSplitPlanes[aLftSplit].LftVoxel.Box = aSplitPlanes[aLftSplit - 1].LftVoxel.Box; aSplitPlanes[aRghSplit].RghVoxel.Box = aSplitPlanes[aRghSplit + 1].RghVoxel.Box; aSplitPlanes[aLftSplit].LftVoxel.Box.Combine (aBinVector[aLftSplit - 1].Box); aSplitPlanes[aRghSplit].RghVoxel.Box.Combine (aBinVector[aRghSplit + 0].Box); } // Choose the best split (with minimum SAH cost) for (Standard_Integer aSplit = 1; aSplit < Bins; ++aSplit) { // Simple SAH evaluation Standard_Real aCost = (static_cast (aSplitPlanes[aSplit].LftVoxel.Box.Area()) /* / S(N) */) * aSplitPlanes[aSplit].LftVoxel.Count + (static_cast (aSplitPlanes[aSplit].RghVoxel.Box.Area()) /* / S(N) */) * aSplitPlanes[aSplit].RghVoxel.Count; if (aCost <= aMinSplitCost) { aMinSplitCost = aCost; aMinSplitAxis = anAxis; aMinSplitIndex = aSplit; aMinSplitBoxLft = aSplitPlanes[aSplit].LftVoxel.Box; aMinSplitBoxRgh = aSplitPlanes[aSplit].RghVoxel.Box; aMinSplitNumLft = aSplitPlanes[aSplit].LftVoxel.Count; aMinSplitNumRgh = aSplitPlanes[aSplit].RghVoxel.Count; } } } theBVH->SetInner (theNode); Standard_Integer aMiddle = -1; if (aMinSplitNumLft == 0 || aMinSplitNumRgh == 0 || aMinSplitAxis == -1) // case of objects with the same center { aMinSplitBoxLft.Clear(); aMinSplitBoxRgh.Clear(); aMiddle = std::max (aNodeBegPrimitive + 1, static_cast ((aNodeBegPrimitive + aNodeEndPrimitive) / 2.f)); aMinSplitNumLft = aMiddle - aNodeBegPrimitive; for (Standard_Integer anIndex = aNodeBegPrimitive; anIndex < aMiddle; ++anIndex) { aMinSplitBoxLft.Combine (theSet->Box (anIndex)); } aMinSplitNumRgh = aNodeEndPrimitive - aMiddle + 1; for (Standard_Integer anIndex = aNodeEndPrimitive; anIndex >= aMiddle; --anIndex) { aMinSplitBoxRgh.Combine (theSet->Box (anIndex)); } } else { aMiddle = BVH::SplitPrimitives (theSet, anAABB, aNodeBegPrimitive, aNodeEndPrimitive, aMinSplitIndex - 1, aMinSplitAxis, Bins); } typedef typename BVH_QueueBuilder::BVH_PrimitiveRange Range; return typename BVH_QueueBuilder::BVH_ChildNodes (aMinSplitBoxLft, aMinSplitBoxRgh, Range (aNodeBegPrimitive, aMiddle - 1), Range (aMiddle, aNodeEndPrimitive)); }