From f991717cc1e9b8564a65dee4b48ddc0e9daa1973 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Tue, 22 Oct 2019 07:10:57 +0200 Subject: [PATCH] Optimizations --- src/engine/OverlappingPair.cpp | 9 +- src/engine/OverlappingPair.h | 42 +++++++++ src/systems/BroadPhaseSystem.cpp | 9 +- src/systems/CollisionDetectionSystem.cpp | 115 ++++++++++++++--------- src/systems/CollisionDetectionSystem.h | 3 + 5 files changed, 129 insertions(+), 49 deletions(-) diff --git a/src/engine/OverlappingPair.cpp b/src/engine/OverlappingPair.cpp index d3779d27..ca86ce40 100644 --- a/src/engine/OverlappingPair.cpp +++ b/src/engine/OverlappingPair.cpp @@ -37,13 +37,15 @@ OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2, const WorldSettings& worldSettings) : mPairID(computeID(shape1->getBroadPhaseId(), shape2->getBroadPhaseId())), mProxyShape1(shape1->getEntity()), mProxyShape2(shape2->getEntity()), mPersistentAllocator(persistentMemoryAllocator), mTempMemoryAllocator(temporaryMemoryAllocator), - mLastFrameCollisionInfos(mPersistentAllocator), mWorldSettings(worldSettings) { + mLastFrameCollisionInfos(mPersistentAllocator), mWorldSettings(worldSettings), mNeedToTestOverlap(false) { } // Destructor OverlappingPair::~OverlappingPair() { + RP3D_PROFILE("OverlappingPair::~OverlappingPair()", mProfiler); + // Remove all the remaining last frame collision info for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ++it) { @@ -58,6 +60,8 @@ OverlappingPair::~OverlappingPair() { // Add a new last frame collision info if it does not exist for the given shapes already LastFrameCollisionInfo* OverlappingPair::addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2) { + RP3D_PROFILE("OverlappingPair::addLastFrameInfoIfNecessary()", mProfiler); + // Try to get the corresponding last frame collision info const ShapeIdPair shapeIdPair(shapeId1, shapeId2); auto it = mLastFrameCollisionInfos.find(shapeIdPair); @@ -83,10 +87,11 @@ LastFrameCollisionInfo* OverlappingPair::addLastFrameInfoIfNecessary(uint shapeI } } - // Delete all the obsolete last frame collision info void OverlappingPair::clearObsoleteLastFrameCollisionInfos() { + RP3D_PROFILE("OverlappingPair::clearObsoleteLastFrameCollisionInfos()", mProfiler); + // For each collision info for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ) { diff --git a/src/engine/OverlappingPair.h b/src/engine/OverlappingPair.h index b2567535..bf46290c 100644 --- a/src/engine/OverlappingPair.h +++ b/src/engine/OverlappingPair.h @@ -31,6 +31,7 @@ #include "containers/Map.h" #include "containers/Pair.h" #include "containers/containers_common.h" +#include "utils/Profiler.h" #include /// ReactPhysics3D namespace @@ -131,6 +132,16 @@ class OverlappingPair { /// World settings const WorldSettings& mWorldSettings; + /// True if we need to test if the overlapping pair of shapes still overlap + bool mNeedToTestOverlap; + +#ifdef IS_PROFILING_ACTIVE + + /// Pointer to the profiler + Profiler* mProfiler; + +#endif + public: // -------------------- Methods -------------------- // @@ -163,6 +174,12 @@ class OverlappingPair { /// Return a reference to the temporary memory allocator MemoryAllocator& getTemporaryAllocator(); + /// Return true if we need to test if the overlapping pair of shapes still overlap + bool needToTestOverlap() const; + + /// Set to true if we need to test if the overlapping pair of shapes still overlap + void setNeedToTestOverlap(bool needToTestOverlap); + /// Add a new last frame collision info if it does not exist for the given shapes already LastFrameCollisionInfo* addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2); @@ -178,6 +195,13 @@ class OverlappingPair { /// Return the pair of bodies index of the pair static bodypair computeBodiesIndexPair(Entity body1Entity, Entity body2Entity); +#ifdef IS_PROFILING_ACTIVE + + /// Set the profiler + void setProfiler(Profiler* profiler); + +#endif + // -------------------- Friendship -------------------- // friend class DynamicsWorld; @@ -236,11 +260,29 @@ inline MemoryAllocator& OverlappingPair::getTemporaryAllocator() { return mTempMemoryAllocator; } +// Return true if we need to test if the overlapping pair of shapes still overlap +inline bool OverlappingPair::needToTestOverlap() const { + return mNeedToTestOverlap; +} + +// Set to true if we need to test if the overlapping pair of shapes still overlap +inline void OverlappingPair::setNeedToTestOverlap(bool needToTestOverlap) { + mNeedToTestOverlap = needToTestOverlap; +} + // Return the last frame collision info for a given pair of shape ids inline LastFrameCollisionInfo* OverlappingPair::getLastFrameCollisionInfo(uint shapeId1, uint shapeId2) const { return mLastFrameCollisionInfos[ShapeIdPair(shapeId1, shapeId2)]; } +#ifdef IS_PROFILING_ACTIVE + +// Set the profiler +inline void OverlappingPair::setProfiler(Profiler* profiler) { + mProfiler = profiler; +} + +#endif } #endif diff --git a/src/systems/BroadPhaseSystem.cpp b/src/systems/BroadPhaseSystem.cpp index 120eba23..1d3b9968 100644 --- a/src/systems/BroadPhaseSystem.cpp +++ b/src/systems/BroadPhaseSystem.cpp @@ -53,10 +53,12 @@ BroadPhaseSystem::BroadPhaseSystem(CollisionDetectionSystem& collisionDetection, // Return true if the two broad-phase collision shapes are overlapping bool BroadPhaseSystem::testOverlappingShapes(Entity proxyShape1Entity, Entity proxyShape2Entity) const { + RP3D_PROFILE("CollisionDetectionSystem::testOverlappingShapes()", mProfiler); + const int32 shape1BroadPhaseId = mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity); const int32 shape2BroadPhaseId = mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity); - if (shape1BroadPhaseId == -1 || shape2BroadPhaseId == -1) return false; + assert(shape1BroadPhaseId != -1 && shape2BroadPhaseId != -1); // Get the two AABBs of the collision shapes const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1BroadPhaseId); @@ -125,6 +127,8 @@ void BroadPhaseSystem::updateProxyShape(Entity proxyShapeEntity, decimal timeSte // Update the broad-phase state of all the enabled proxy-shapes void BroadPhaseSystem::updateProxyShapes(decimal timeStep) { + RP3D_PROFILE("BroadPhaseSystem::updateProxyShapes()", mProfiler); + // Update all the enabled proxy-shape components updateProxyShapesComponents(0, mProxyShapesComponents.getNbEnabledComponents(), timeStep); } @@ -176,7 +180,6 @@ void BroadPhaseSystem::updateProxyShapesComponents(uint32 startIndex, uint32 nbI // Get the linear velocity from the dynamics component const Vector3& linearVelocity = mRigidBodyComponents.getLinearVelocity(bodyEntity); - // TODO : Use body linear velocity and compute displacement displacement = timeStep * linearVelocity; } @@ -193,6 +196,8 @@ void BroadPhaseSystem::updateProxyShapesComponents(uint32 startIndex, uint32 nbI // Compute all the overlapping pairs of collision shapes void BroadPhaseSystem::computeOverlappingPairs(MemoryManager& memoryManager, List>& overlappingNodes) { + RP3D_PROFILE("CollisionDetectionSystem::computeOverlappingPairs()", mProfiler); + // Get the list of the proxy-shapes that have moved or have been created in the last frame List shapesToTest = mMovedShapes.toList(memoryManager.getPoolAllocator()); diff --git a/src/systems/CollisionDetectionSystem.cpp b/src/systems/CollisionDetectionSystem.cpp index 9ac8c70a..a2f2447b 100644 --- a/src/systems/CollisionDetectionSystem.cpp +++ b/src/systems/CollisionDetectionSystem.cpp @@ -99,6 +99,8 @@ void CollisionDetectionSystem::computeBroadPhase() { RP3D_PROFILE("CollisionDetectionSystem::computeBroadPhase()", mProfiler); + resetNeedToTestOverlap(); + // Ask the broad-phase to compute all the shapes overlapping the shapes that // have moved or have been added in the last frame. This call can only add new // overlapping pairs in the collision detection. @@ -112,16 +114,31 @@ void CollisionDetectionSystem::computeBroadPhase() { removeNonOverlappingPairs(); } +// Set the needToTestOverlap value of each overlapping pair to true +void CollisionDetectionSystem::resetNeedToTestOverlap() { + + RP3D_PROFILE("CollisionDetectionSystem::resetNeedToTestOverlap()", mProfiler); + + // For each possible collision pair of bodies + for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) { + it->second->setNeedToTestOverlap(true); + } +} + // Remove pairs that are not overlapping anymore void CollisionDetectionSystem::removeNonOverlappingPairs() { + RP3D_PROFILE("CollisionDetectionSystem::removeNonOverlappingPairs()", mProfiler); + // For each possible collision pair of bodies for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { OverlappingPair* pair = it->second; - // Check if the two shapes are still overlapping. Otherwise, we destroy the overlapping pair - if (!mBroadPhaseSystem.testOverlappingShapes(pair->getProxyShape1(), pair->getProxyShape2())) { + // Check if we need to test overlap. If so, test if the two shapes are still overlapping. + // Otherwise, we destroy the overlapping pair + if (pair->needToTestOverlap() && + !mBroadPhaseSystem.testOverlappingShapes(pair->getProxyShape1(), pair->getProxyShape2())) { // Destroy the overlapping pair pair->~OverlappingPair(); @@ -139,6 +156,8 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() { // Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary void CollisionDetectionSystem::updateOverlappingPairs(const List>& overlappingNodes) { + RP3D_PROFILE("CollisionDetectionSystem::updateOverlappingPairs()", mProfiler); + // For each overlapping pair of nodes for (uint i=0; i < overlappingNodes.size(); i++) { @@ -165,7 +184,8 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List> Pair pairID = OverlappingPair::computeID(nodePair.first, nodePair.second); // Check if the overlapping pair already exists - if (!mOverlappingPairs.containsKey(pairID)) { + auto itPair = mOverlappingPairs.find(pairID); + if (itPair == mOverlappingPairs.end()) { unsigned short shape1CollideWithMaskBits = mProxyShapesComponents.getCollideWithMaskBits(proxyShape1Entity); unsigned short shape2CollideWithMaskBits = mProxyShapesComponents.getCollideWithMaskBits(proxyShape2Entity); @@ -189,8 +209,18 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List> // Add the new overlapping pair mOverlappingPairs.add(Pair, OverlappingPair*>(pairID, newPair)); + +#ifdef IS_PROFILING_ACTIVE + newPair->setProfiler(mProfiler); +#endif + } } + else { + + // We do not need to test the pair for overlap because it has just been reported that they still overlap + itPair->second->setNeedToTestOverlap(false); + } } } } @@ -219,58 +249,53 @@ void CollisionDetectionSystem::computeMiddlePhase(OverlappingPairMap& overlappin assert(mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity) != -1); assert(mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity) != mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity)); - // Check if the collision filtering allows collision between the two shapes - if ((mProxyShapesComponents.getCollideWithMaskBits(proxyShape1Entity) & mProxyShapesComponents.getCollisionCategoryBits(proxyShape2Entity)) != 0 && - (mProxyShapesComponents.getCollisionCategoryBits(proxyShape1Entity) & mProxyShapesComponents.getCollideWithMaskBits(proxyShape2Entity)) != 0) { + const Entity body1Entity = mProxyShapesComponents.getBody(proxyShape1Entity); + const Entity body2Entity = mProxyShapesComponents.getBody(proxyShape2Entity); - const Entity body1Entity = mProxyShapesComponents.getBody(proxyShape1Entity); - const Entity body2Entity = mProxyShapesComponents.getBody(proxyShape2Entity); + const bool isStaticRigidBody1 = mWorld->mRigidBodyComponents.hasComponent(body1Entity) && + mWorld->mRigidBodyComponents.getBodyType(body1Entity) == BodyType::STATIC; + const bool isStaticRigidBody2 = mWorld->mRigidBodyComponents.hasComponent(body2Entity) && + mWorld->mRigidBodyComponents.getBodyType(body2Entity) == BodyType::STATIC; - const bool isStaticRigidBody1 = mWorld->mRigidBodyComponents.hasComponent(body1Entity) && - mWorld->mRigidBodyComponents.getBodyType(body1Entity) == BodyType::STATIC; - const bool isStaticRigidBody2 = mWorld->mRigidBodyComponents.hasComponent(body2Entity) && - mWorld->mRigidBodyComponents.getBodyType(body2Entity) == BodyType::STATIC; + // Check that at least one body is enabled (active and awake) and not static + bool isBody1Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) && !isStaticRigidBody1; + bool isBody2Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity) && !isStaticRigidBody2; + if (!isBody1Active && !isBody2Active) continue; - // Check that at least one body is enabled (active and awake) and not static - bool isBody1Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) && !isStaticRigidBody1; - bool isBody2Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity) && !isStaticRigidBody2; - if (!isBody1Active && !isBody2Active) continue; + // Check if the bodies are in the set of bodies that cannot collide between each other + bodypair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1Entity, body2Entity); + if (mNoCollisionPairs.contains(bodiesIndex) > 0) continue; - // Check if the bodies are in the set of bodies that cannot collide between each other - bodypair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1Entity, body2Entity); - if (mNoCollisionPairs.contains(bodiesIndex) > 0) continue; + CollisionShape* collisionShape1 = mProxyShapesComponents.getCollisionShape(proxyShape1Entity); + CollisionShape* collisionShape2 = mProxyShapesComponents.getCollisionShape(proxyShape2Entity); - CollisionShape* collisionShape1 = mProxyShapesComponents.getCollisionShape(proxyShape1Entity); - CollisionShape* collisionShape2 = mProxyShapesComponents.getCollisionShape(proxyShape2Entity); + const bool isShape1Convex = collisionShape1->isConvex(); + const bool isShape2Convex = collisionShape2->isConvex(); - const bool isShape1Convex = collisionShape1->isConvex(); - const bool isShape2Convex = collisionShape2->isConvex(); + // If both shapes are convex + if (isShape1Convex && isShape2Convex) { - // If both shapes are convex - if (isShape1Convex && isShape2Convex) { + // Select the narrow phase algorithm to use according to the two collision shapes + NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(), + collisionShape2->getType()); - // Select the narrow phase algorithm to use according to the two collision shapes - NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(), - collisionShape2->getType()); + // No middle-phase is necessary, simply create a narrow phase info + // for the narrow-phase collision detection + narrowPhaseInput.addNarrowPhaseTest(pair, collisionShape1, collisionShape2, + mProxyShapesComponents.getLocalToWorldTransform(proxyShape1Entity), + mProxyShapesComponents.getLocalToWorldTransform(proxyShape2Entity), + algorithmType, mMemoryManager.getSingleFrameAllocator()); - // No middle-phase is necessary, simply create a narrow phase info - // for the narrow-phase collision detection - narrowPhaseInput.addNarrowPhaseTest(pair, collisionShape1, collisionShape2, - mProxyShapesComponents.getLocalToWorldTransform(proxyShape1Entity), - mProxyShapesComponents.getLocalToWorldTransform(proxyShape2Entity), - algorithmType, mMemoryManager.getSingleFrameAllocator()); + } + // Concave vs Convex algorithm + else if ((!isShape1Convex && isShape2Convex) || (!isShape2Convex && isShape1Convex)) { - } - // Concave vs Convex algorithm - else if ((!isShape1Convex && isShape2Convex) || (!isShape2Convex && isShape1Convex)) { - - computeConvexVsConcaveMiddlePhase(pair, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput); - } - // Concave vs Concave shape - else { - // Not handled - continue; - } + computeConvexVsConcaveMiddlePhase(pair, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput); + } + // Concave vs Concave shape + else { + // Not handled + continue; } } } diff --git a/src/systems/CollisionDetectionSystem.h b/src/systems/CollisionDetectionSystem.h index 525525ce..f5264245 100644 --- a/src/systems/CollisionDetectionSystem.h +++ b/src/systems/CollisionDetectionSystem.h @@ -195,6 +195,9 @@ class CollisionDetectionSystem { /// Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary void updateOverlappingPairs(const List>& overlappingNodes); + /// Set the needToTestOverlap value of each overlapping pair to true + void resetNeedToTestOverlap(); + /// Remove pairs that are not overlapping anymore void removeNonOverlappingPairs();