Skip to content

Commit ec63347

Browse files
committed
CollisionDetection() (between different trees) performance improvements
1 parent ee6a0ff commit ec63347

File tree

1 file changed

+57
-22
lines changed

1 file changed

+57
-22
lines changed

octree.h

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3194,7 +3194,11 @@ namespace OrthoTree
31943194

31953195
private: // K Nearest Neighbor helpers
31963196
static inline void CreateEntityDistance(
3197-
std::vector<TEntityID> const& entities, TVector const& searchPoint, TContainer const& points, std::vector<EntityDistance>& neighborEntities, TGeometry maxDistance) noexcept
3197+
std::vector<TEntityID> const& entities,
3198+
TVector const& searchPoint,
3199+
TContainer const& points,
3200+
std::vector<EntityDistance>& neighborEntities,
3201+
TGeometry maxDistance) noexcept
31983202
{
31993203
for (auto const entityID : entities)
32003204
{
@@ -3992,7 +3996,24 @@ namespace OrthoTree
39923996
return this->FrustumCullingBase(boundaryPlanes, tolerance, boxes);
39933997
}
39943998

3999+
private:
4000+
struct SweepAndPruneDatabase
4001+
{
4002+
inline constexpr SweepAndPruneDatabase(TContainer const& boxes, std::vector<TEntityID> const& entityIDs) noexcept
4003+
: m_sortedEntityIDs(entityIDs)
4004+
{
4005+
std::sort(m_sortedEntityIDs.begin(), m_sortedEntityIDs.end(), [&](auto const entityIDL, auto const entityIDR) {
4006+
return AD::GetBoxMinC(detail::at(boxes, entityIDL), 0) < AD::GetBoxMinC(detail::at(boxes, entityIDR), 0);
4007+
});
4008+
}
4009+
4010+
inline constexpr std::vector<TEntityID> const& GetEntities() const noexcept { return m_sortedEntityIDs; }
4011+
4012+
private:
4013+
std::vector<TEntityID> m_sortedEntityIDs;
4014+
};
39954015

4016+
public:
39964017
// Client-defined Collision detector based on indices. AABB intersection is executed independently from this checker.
39974018
using FCollisionDetector = std::function<bool(TEntityID, TEntityID)>;
39984019

@@ -4020,6 +4041,18 @@ namespace OrthoTree
40204041
auto constexpr rootKey = SI::GetRootKey();
40214042
auto const trees = std::array{ &leftTree, &rightTree };
40224043

4044+
auto entitiesInOrderCache = std::array<std::unordered_map<MortonNodeID, SweepAndPruneDatabase>, 2>{};
4045+
auto const getOrCreateEntitiesInOrder = [&](bool side, NodeIterator const& it, TContainer const& boxes) -> std::vector<TEntityID> const& {
4046+
auto itKeyAndSPD = entitiesInOrderCache[side].find(it->first);
4047+
if (itKeyAndSPD == entitiesInOrderCache[side].end())
4048+
{
4049+
bool isInserted = false;
4050+
std::tie(itKeyAndSPD, isInserted) = entitiesInOrderCache[side].emplace(it->first, SweepAndPruneDatabase(boxes, it->second.Entities));
4051+
}
4052+
4053+
return itKeyAndSPD->second.GetEntities();
4054+
};
4055+
40234056
[[maybe_unused]] auto const pLeftTree = &leftTree;
40244057
[[maybe_unused]] auto const pRightTree = &rightTree;
40254058
auto nodePairToProceed = std::queue<ParentIteratorArray>{};
@@ -4032,11 +4065,28 @@ namespace OrthoTree
40324065
auto const& parentNodePair = nodePairToProceed.front();
40334066

40344067
// Check the current ascendant content
4068+
4069+
auto const& leftEntitiesInOrder = getOrCreateEntitiesInOrder(Left, parentNodePair[Left].Iterator, leftBoxes);
4070+
auto const& rightEntitiesInOrder = getOrCreateEntitiesInOrder(Right, parentNodePair[Right].Iterator, rightBoxes);
4071+
4072+
auto const rightEntityNo = rightEntitiesInOrder.size();
4073+
std::size_t iRightEntityBegin = 0;
4074+
for (auto const leftEntityID : leftEntitiesInOrder)
40354075
{
4036-
for (auto const leftEntityID : parentNodePair[Left].Iterator->second.Entities)
4037-
for (auto const rightEntityID : parentNodePair[Right].Iterator->second.Entities)
4038-
if (AD::AreBoxesOverlapped(detail::at(leftBoxes, leftEntityID), detail::at(rightBoxes, rightEntityID), false))
4039-
results.emplace_back(leftEntityID, rightEntityID);
4076+
for (; iRightEntityBegin < rightEntityNo; ++iRightEntityBegin)
4077+
if (AD::GetBoxMaxC(detail::at(rightBoxes, rightEntitiesInOrder[iRightEntityBegin]), 0) >= AD::GetBoxMinC(detail::at(leftBoxes, leftEntityID), 0))
4078+
break; // sweep and prune optimization
4079+
4080+
for (std::size_t iRightEntity = iRightEntityBegin; iRightEntity < rightEntityNo; ++iRightEntity)
4081+
{
4082+
auto const rightEntityID = rightEntitiesInOrder[iRightEntity];
4083+
4084+
if (AD::GetBoxMaxC(detail::at(leftBoxes, leftEntityID), 0) < AD::GetBoxMinC(detail::at(rightBoxes, rightEntityID), 0))
4085+
break; // sweep and prune optimization
4086+
4087+
if (AD::AreBoxesOverlapped(detail::at(leftBoxes, leftEntityID), detail::at(rightBoxes, rightEntityID), false))
4088+
results.emplace_back(leftEntityID, rightEntityID);
4089+
}
40404090
}
40414091

40424092
// Collect children
@@ -4091,22 +4141,6 @@ namespace OrthoTree
40914141
}
40924142

40934143
private:
4094-
struct SweepAndPruneDatabase
4095-
{
4096-
inline constexpr SweepAndPruneDatabase(TContainer const& boxes, std::vector<TEntityID> const& entityIDs) noexcept
4097-
: m_sortedEntityIDs(entityIDs)
4098-
{
4099-
std::sort(m_sortedEntityIDs.begin(), m_sortedEntityIDs.end(), [&](auto const entityIDL, auto const entityIDR) {
4100-
return AD::GetBoxMinC(detail::at(boxes, entityIDL), 0) < AD::GetBoxMinC(detail::at(boxes, entityIDR), 0);
4101-
});
4102-
}
4103-
4104-
inline constexpr std::vector<TEntityID> const& GetEntities() const noexcept { return m_sortedEntityIDs; }
4105-
4106-
private:
4107-
std::vector<TEntityID> m_sortedEntityIDs;
4108-
};
4109-
41104144
template<typename TCollisionDetectionContainer>
41114145
void InsertCollidedEntities(
41124146
TContainer const& boxes, std::pair<MortonNodeID, Node> const& pairKeyNode, TCollisionDetectionContainer& collidedEntityPairsInsideNode) const noexcept
@@ -4369,7 +4403,8 @@ namespace OrthoTree
43694403
TVector const& rayBasePoint, TVector const& rayHeading, TContainer const& boxes, TGeometry tolerance = {}) const noexcept
43704404
{
43714405
auto const& rootNode = this->GetNode(SI::GetRootKey());
4372-
auto const distance = IGM::GetRayBoxDistanceAD(GetNodeCenterMacro(this, SI::GetRootKey(), rootNode), this->GetNodeSize(1), rayBasePoint, rayHeading, tolerance);
4406+
auto const distance =
4407+
IGM::GetRayBoxDistanceAD(GetNodeCenterMacro(this, SI::GetRootKey(), rootNode), this->GetNodeSize(1), rayBasePoint, rayHeading, tolerance);
43734408
if (!distance)
43744409
return std::nullopt;
43754410

0 commit comments

Comments
 (0)