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)
: 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(); ) {

View File

@ -31,6 +31,7 @@
#include "containers/Map.h"
#include "containers/Pair.h"
#include "containers/containers_common.h"
#include "utils/Profiler.h"
#include <cstddef>
/// 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

View File

@ -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<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
List<int> shapesToTest = mMovedShapes.toList(memoryManager.getPoolAllocator());

View File

@ -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<Pair<int, int>>& 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<int, int>>
Pair<uint, uint> 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<Pair<int, int>>
// Add the new overlapping pair
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(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;
}
}
}

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
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
void removeNonOverlappingPairs();