Optimizations

This commit is contained in:
Daniel Chappuis 2019-10-22 07:10:57 +02:00
parent 130eb00136
commit f991717cc1
5 changed files with 129 additions and 49 deletions

View File

@ -37,13 +37,15 @@ OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
const WorldSettings& worldSettings) const WorldSettings& worldSettings)
: mPairID(computeID(shape1->getBroadPhaseId(), shape2->getBroadPhaseId())), mProxyShape1(shape1->getEntity()), mProxyShape2(shape2->getEntity()), : mPairID(computeID(shape1->getBroadPhaseId(), shape2->getBroadPhaseId())), mProxyShape1(shape1->getEntity()), mProxyShape2(shape2->getEntity()),
mPersistentAllocator(persistentMemoryAllocator), mTempMemoryAllocator(temporaryMemoryAllocator), mPersistentAllocator(persistentMemoryAllocator), mTempMemoryAllocator(temporaryMemoryAllocator),
mLastFrameCollisionInfos(mPersistentAllocator), mWorldSettings(worldSettings) { mLastFrameCollisionInfos(mPersistentAllocator), mWorldSettings(worldSettings), mNeedToTestOverlap(false) {
} }
// Destructor // Destructor
OverlappingPair::~OverlappingPair() { OverlappingPair::~OverlappingPair() {
RP3D_PROFILE("OverlappingPair::~OverlappingPair()", mProfiler);
// Remove all the remaining last frame collision info // Remove all the remaining last frame collision info
for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ++it) { 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 // Add a new last frame collision info if it does not exist for the given shapes already
LastFrameCollisionInfo* OverlappingPair::addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2) { LastFrameCollisionInfo* OverlappingPair::addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2) {
RP3D_PROFILE("OverlappingPair::addLastFrameInfoIfNecessary()", mProfiler);
// Try to get the corresponding last frame collision info // Try to get the corresponding last frame collision info
const ShapeIdPair shapeIdPair(shapeId1, shapeId2); const ShapeIdPair shapeIdPair(shapeId1, shapeId2);
auto it = mLastFrameCollisionInfos.find(shapeIdPair); auto it = mLastFrameCollisionInfos.find(shapeIdPair);
@ -83,10 +87,11 @@ LastFrameCollisionInfo* OverlappingPair::addLastFrameInfoIfNecessary(uint shapeI
} }
} }
// Delete all the obsolete last frame collision info // Delete all the obsolete last frame collision info
void OverlappingPair::clearObsoleteLastFrameCollisionInfos() { void OverlappingPair::clearObsoleteLastFrameCollisionInfos() {
RP3D_PROFILE("OverlappingPair::clearObsoleteLastFrameCollisionInfos()", mProfiler);
// For each collision info // For each collision info
for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ) { for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ) {

View File

@ -31,6 +31,7 @@
#include "containers/Map.h" #include "containers/Map.h"
#include "containers/Pair.h" #include "containers/Pair.h"
#include "containers/containers_common.h" #include "containers/containers_common.h"
#include "utils/Profiler.h"
#include <cstddef> #include <cstddef>
/// ReactPhysics3D namespace /// ReactPhysics3D namespace
@ -131,6 +132,16 @@ class OverlappingPair {
/// World settings /// World settings
const WorldSettings& mWorldSettings; 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: public:
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
@ -163,6 +174,12 @@ class OverlappingPair {
/// Return a reference to the temporary memory allocator /// Return a reference to the temporary memory allocator
MemoryAllocator& getTemporaryAllocator(); 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 /// Add a new last frame collision info if it does not exist for the given shapes already
LastFrameCollisionInfo* addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2); LastFrameCollisionInfo* addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2);
@ -178,6 +195,13 @@ class OverlappingPair {
/// Return the pair of bodies index of the pair /// Return the pair of bodies index of the pair
static bodypair computeBodiesIndexPair(Entity body1Entity, Entity body2Entity); static bodypair computeBodiesIndexPair(Entity body1Entity, Entity body2Entity);
#ifdef IS_PROFILING_ACTIVE
/// Set the profiler
void setProfiler(Profiler* profiler);
#endif
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class DynamicsWorld; friend class DynamicsWorld;
@ -236,11 +260,29 @@ inline MemoryAllocator& OverlappingPair::getTemporaryAllocator() {
return mTempMemoryAllocator; 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 // Return the last frame collision info for a given pair of shape ids
inline LastFrameCollisionInfo* OverlappingPair::getLastFrameCollisionInfo(uint shapeId1, uint shapeId2) const { inline LastFrameCollisionInfo* OverlappingPair::getLastFrameCollisionInfo(uint shapeId1, uint shapeId2) const {
return mLastFrameCollisionInfos[ShapeIdPair(shapeId1, shapeId2)]; return mLastFrameCollisionInfos[ShapeIdPair(shapeId1, shapeId2)];
} }
#ifdef IS_PROFILING_ACTIVE
// Set the profiler
inline void OverlappingPair::setProfiler(Profiler* profiler) {
mProfiler = profiler;
}
#endif
} }
#endif #endif

View File

@ -53,10 +53,12 @@ BroadPhaseSystem::BroadPhaseSystem(CollisionDetectionSystem& collisionDetection,
// Return true if the two broad-phase collision shapes are overlapping // Return true if the two broad-phase collision shapes are overlapping
bool BroadPhaseSystem::testOverlappingShapes(Entity proxyShape1Entity, Entity proxyShape2Entity) const { bool BroadPhaseSystem::testOverlappingShapes(Entity proxyShape1Entity, Entity proxyShape2Entity) const {
RP3D_PROFILE("CollisionDetectionSystem::testOverlappingShapes()", mProfiler);
const int32 shape1BroadPhaseId = mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity); const int32 shape1BroadPhaseId = mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity);
const int32 shape2BroadPhaseId = mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity); 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 // Get the two AABBs of the collision shapes
const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1BroadPhaseId); 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 // Update the broad-phase state of all the enabled proxy-shapes
void BroadPhaseSystem::updateProxyShapes(decimal timeStep) { void BroadPhaseSystem::updateProxyShapes(decimal timeStep) {
RP3D_PROFILE("BroadPhaseSystem::updateProxyShapes()", mProfiler);
// Update all the enabled proxy-shape components // Update all the enabled proxy-shape components
updateProxyShapesComponents(0, mProxyShapesComponents.getNbEnabledComponents(), timeStep); updateProxyShapesComponents(0, mProxyShapesComponents.getNbEnabledComponents(), timeStep);
} }
@ -176,7 +180,6 @@ void BroadPhaseSystem::updateProxyShapesComponents(uint32 startIndex, uint32 nbI
// Get the linear velocity from the dynamics component // Get the linear velocity from the dynamics component
const Vector3& linearVelocity = mRigidBodyComponents.getLinearVelocity(bodyEntity); const Vector3& linearVelocity = mRigidBodyComponents.getLinearVelocity(bodyEntity);
// TODO : Use body linear velocity and compute displacement
displacement = timeStep * linearVelocity; displacement = timeStep * linearVelocity;
} }
@ -193,6 +196,8 @@ void BroadPhaseSystem::updateProxyShapesComponents(uint32 startIndex, uint32 nbI
// Compute all the overlapping pairs of collision shapes // Compute all the overlapping pairs of collision shapes
void BroadPhaseSystem::computeOverlappingPairs(MemoryManager& memoryManager, List<Pair<int, int>>& overlappingNodes) { void BroadPhaseSystem::computeOverlappingPairs(MemoryManager& memoryManager, List<Pair<int, int>>& overlappingNodes) {
RP3D_PROFILE("CollisionDetectionSystem::computeOverlappingPairs()", mProfiler);
// Get the list of the proxy-shapes that have moved or have been created in the last frame // Get the list of the proxy-shapes that have moved or have been created in the last frame
List<int> shapesToTest = mMovedShapes.toList(memoryManager.getPoolAllocator()); List<int> shapesToTest = mMovedShapes.toList(memoryManager.getPoolAllocator());

View File

@ -99,6 +99,8 @@ void CollisionDetectionSystem::computeBroadPhase() {
RP3D_PROFILE("CollisionDetectionSystem::computeBroadPhase()", mProfiler); RP3D_PROFILE("CollisionDetectionSystem::computeBroadPhase()", mProfiler);
resetNeedToTestOverlap();
// Ask the broad-phase to compute all the shapes overlapping the shapes that // 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 // have moved or have been added in the last frame. This call can only add new
// overlapping pairs in the collision detection. // overlapping pairs in the collision detection.
@ -112,16 +114,31 @@ void CollisionDetectionSystem::computeBroadPhase() {
removeNonOverlappingPairs(); 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 // Remove pairs that are not overlapping anymore
void CollisionDetectionSystem::removeNonOverlappingPairs() { void CollisionDetectionSystem::removeNonOverlappingPairs() {
RP3D_PROFILE("CollisionDetectionSystem::removeNonOverlappingPairs()", mProfiler);
// For each possible collision pair of bodies // For each possible collision pair of bodies
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
OverlappingPair* pair = it->second; OverlappingPair* pair = it->second;
// Check if the two shapes are still overlapping. Otherwise, we destroy the overlapping pair // Check if we need to test overlap. If so, test if the two shapes are still overlapping.
if (!mBroadPhaseSystem.testOverlappingShapes(pair->getProxyShape1(), pair->getProxyShape2())) { // Otherwise, we destroy the overlapping pair
if (pair->needToTestOverlap() &&
!mBroadPhaseSystem.testOverlappingShapes(pair->getProxyShape1(), pair->getProxyShape2())) {
// Destroy the overlapping pair // Destroy the overlapping pair
pair->~OverlappingPair(); 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 // Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary
void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int, int>>& overlappingNodes) { void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int, int>>& overlappingNodes) {
RP3D_PROFILE("CollisionDetectionSystem::updateOverlappingPairs()", mProfiler);
// For each overlapping pair of nodes // For each overlapping pair of nodes
for (uint i=0; i < overlappingNodes.size(); i++) { for (uint i=0; i < overlappingNodes.size(); i++) {
@ -165,7 +184,8 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int, int>>
Pair<uint, uint> pairID = OverlappingPair::computeID(nodePair.first, nodePair.second); Pair<uint, uint> pairID = OverlappingPair::computeID(nodePair.first, nodePair.second);
// Check if the overlapping pair already exists // 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 shape1CollideWithMaskBits = mProxyShapesComponents.getCollideWithMaskBits(proxyShape1Entity);
unsigned short shape2CollideWithMaskBits = mProxyShapesComponents.getCollideWithMaskBits(proxyShape2Entity); unsigned short shape2CollideWithMaskBits = mProxyShapesComponents.getCollideWithMaskBits(proxyShape2Entity);
@ -189,8 +209,18 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int, int>>
// Add the new overlapping pair // Add the new overlapping pair
mOverlappingPairs.add(Pair<Pair<uint, uint>, OverlappingPair*>(pairID, newPair)); mOverlappingPairs.add(Pair<Pair<uint, uint>, 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(proxyShape2Entity) != -1);
assert(mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity) != mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity)); assert(mProxyShapesComponents.getBroadPhaseId(proxyShape1Entity) != mProxyShapesComponents.getBroadPhaseId(proxyShape2Entity));
// Check if the collision filtering allows collision between the two shapes const Entity body1Entity = mProxyShapesComponents.getBody(proxyShape1Entity);
if ((mProxyShapesComponents.getCollideWithMaskBits(proxyShape1Entity) & mProxyShapesComponents.getCollisionCategoryBits(proxyShape2Entity)) != 0 && const Entity body2Entity = mProxyShapesComponents.getBody(proxyShape2Entity);
(mProxyShapesComponents.getCollisionCategoryBits(proxyShape1Entity) & mProxyShapesComponents.getCollideWithMaskBits(proxyShape2Entity)) != 0) {
const Entity body1Entity = mProxyShapesComponents.getBody(proxyShape1Entity); const bool isStaticRigidBody1 = mWorld->mRigidBodyComponents.hasComponent(body1Entity) &&
const Entity body2Entity = mProxyShapesComponents.getBody(proxyShape2Entity); 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) && // Check that at least one body is enabled (active and awake) and not static
mWorld->mRigidBodyComponents.getBodyType(body1Entity) == BodyType::STATIC; bool isBody1Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) && !isStaticRigidBody1;
const bool isStaticRigidBody2 = mWorld->mRigidBodyComponents.hasComponent(body2Entity) && bool isBody2Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity) && !isStaticRigidBody2;
mWorld->mRigidBodyComponents.getBodyType(body2Entity) == BodyType::STATIC; if (!isBody1Active && !isBody2Active) continue;
// Check that at least one body is enabled (active and awake) and not static // Check if the bodies are in the set of bodies that cannot collide between each other
bool isBody1Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) && !isStaticRigidBody1; bodypair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1Entity, body2Entity);
bool isBody2Active = !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity) && !isStaticRigidBody2; if (mNoCollisionPairs.contains(bodiesIndex) > 0) continue;
if (!isBody1Active && !isBody2Active) continue;
// Check if the bodies are in the set of bodies that cannot collide between each other CollisionShape* collisionShape1 = mProxyShapesComponents.getCollisionShape(proxyShape1Entity);
bodypair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1Entity, body2Entity); CollisionShape* collisionShape2 = mProxyShapesComponents.getCollisionShape(proxyShape2Entity);
if (mNoCollisionPairs.contains(bodiesIndex) > 0) continue;
CollisionShape* collisionShape1 = mProxyShapesComponents.getCollisionShape(proxyShape1Entity); const bool isShape1Convex = collisionShape1->isConvex();
CollisionShape* collisionShape2 = mProxyShapesComponents.getCollisionShape(proxyShape2Entity); const bool isShape2Convex = collisionShape2->isConvex();
const bool isShape1Convex = collisionShape1->isConvex(); // If both shapes are convex
const bool isShape2Convex = collisionShape2->isConvex(); if (isShape1Convex && isShape2Convex) {
// If both shapes are convex // Select the narrow phase algorithm to use according to the two collision shapes
if (isShape1Convex && isShape2Convex) { NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(),
collisionShape2->getType());
// Select the narrow phase algorithm to use according to the two collision shapes // No middle-phase is necessary, simply create a narrow phase info
NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(), // for the narrow-phase collision detection
collisionShape2->getType()); 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 // Concave vs Convex algorithm
narrowPhaseInput.addNarrowPhaseTest(pair, collisionShape1, collisionShape2, else if ((!isShape1Convex && isShape2Convex) || (!isShape2Convex && isShape1Convex)) {
mProxyShapesComponents.getLocalToWorldTransform(proxyShape1Entity),
mProxyShapesComponents.getLocalToWorldTransform(proxyShape2Entity),
algorithmType, mMemoryManager.getSingleFrameAllocator());
} computeConvexVsConcaveMiddlePhase(pair, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
// Concave vs Convex algorithm }
else if ((!isShape1Convex && isShape2Convex) || (!isShape2Convex && isShape1Convex)) { // Concave vs Concave shape
else {
computeConvexVsConcaveMiddlePhase(pair, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput); // Not handled
} continue;
// Concave vs Concave shape
else {
// Not handled
continue;
}
} }
} }
} }

View File

@ -195,6 +195,9 @@ class CollisionDetectionSystem {
/// Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary /// Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary
void updateOverlappingPairs(const List<Pair<int, int>>& overlappingNodes); void updateOverlappingPairs(const List<Pair<int, int>>& overlappingNodes);
/// Set the needToTestOverlap value of each overlapping pair to true
void resetNeedToTestOverlap();
/// Remove pairs that are not overlapping anymore /// Remove pairs that are not overlapping anymore
void removeNonOverlappingPairs(); void removeNonOverlappingPairs();