Refactor OverlappingPairs

This commit is contained in:
Daniel Chappuis 2020-08-11 18:14:32 +02:00
parent 5dd48c195c
commit a1e0e0aa94
11 changed files with 542 additions and 686 deletions

View File

@ -59,7 +59,6 @@ struct NarrowPhaseInfoBatch {
Entity colliderEntity2;
/// Collision info of the previous frame
// TODO OPTI : Do we really need to use a pointer here ? why not flat object instead ?
LastFrameCollisionInfo* lastFrameCollisionInfo;
/// Memory allocator for the collision shape (Used to release TriangleShape memory in destructor)
@ -124,9 +123,9 @@ struct NarrowPhaseInfoBatch {
~NarrowPhaseInfoBatch();
/// Add shapes to be tested during narrow-phase collision detection into the batch
void addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
void addNarrowPhaseInfo(uint64 pairId, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform, const Transform& shape2Transform,
bool needToReportContacts, MemoryAllocator& shapeAllocator);
bool needToReportContacts, LastFrameCollisionInfo* lastFrameInfo, MemoryAllocator& shapeAllocator);
/// Return the number of objects in the batch
uint getNbObjects() const;
@ -151,13 +150,9 @@ RP3D_FORCE_INLINE uint NarrowPhaseInfoBatch::getNbObjects() const {
}
// Add shapes to be tested during narrow-phase collision detection into the batch
RP3D_FORCE_INLINE void NarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
RP3D_FORCE_INLINE void NarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform, const Transform& shape2Transform,
bool needToReportContacts, MemoryAllocator& shapeAllocator) {
// Add a collision info for the two collision shapes into the overlapping pair (if not present yet)
// TODO OPTI : Can we better manage this
LastFrameCollisionInfo* lastFrameInfo = mOverlappingPairs.addLastFrameInfoIfNecessary(pairIndex, shape1->getId(), shape2->getId());
bool needToReportContacts, LastFrameCollisionInfo* lastFrameInfo, MemoryAllocator& shapeAllocator) {
// Create a meta data object
narrowPhaseInfos.emplace(pairId, collider1, collider2, lastFrameInfo, shapeAllocator, shape1Transform, shape2Transform, shape1, shape2, needToReportContacts);

View File

@ -66,10 +66,10 @@ class NarrowPhaseInput {
NarrowPhaseInput(MemoryAllocator& allocator, OverlappingPairs& overlappingPairs);
/// Add shapes to be tested during narrow-phase collision detection into the batch
void addNarrowPhaseTest(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
void addNarrowPhaseTest(uint64 pairId, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform, NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, bool reportContacts,
MemoryAllocator& shapeAllocator);
LastFrameCollisionInfo* lastFrameInfo, MemoryAllocator& shapeAllocator);
/// Get a reference to the sphere vs sphere batch
NarrowPhaseInfoBatch& getSphereVsSphereBatch();
@ -128,28 +128,29 @@ RP3D_FORCE_INLINE NarrowPhaseInfoBatch &NarrowPhaseInput::getConvexPolyhedronVsC
}
// Add shapes to be tested during narrow-phase collision detection into the batch
RP3D_FORCE_INLINE void NarrowPhaseInput::addNarrowPhaseTest(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
RP3D_FORCE_INLINE void NarrowPhaseInput::addNarrowPhaseTest(uint64 pairId, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform,
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, bool reportContacts, MemoryAllocator& shapeAllocator) {
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, bool reportContacts, LastFrameCollisionInfo* lastFrameInfo,
MemoryAllocator& shapeAllocator) {
switch (narrowPhaseAlgorithmType) {
case NarrowPhaseAlgorithmType::SphereVsSphere:
mSphereVsSphereBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mSphereVsSphereBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::SphereVsCapsule:
mSphereVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mSphereVsCapsuleBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::CapsuleVsCapsule:
mCapsuleVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mCapsuleVsCapsuleBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::SphereVsConvexPolyhedron:
mSphereVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mSphereVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::CapsuleVsConvexPolyhedron:
mCapsuleVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mCapsuleVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::ConvexPolyhedronVsConvexPolyhedron:
mConvexPolyhedronVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
mConvexPolyhedronVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, lastFrameInfo, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::None:
// Must never happen

View File

@ -106,77 +106,199 @@ struct LastFrameCollisionInfo {
*/
class OverlappingPairs {
public:
struct OverlappingPair {
/// Ids of the convex vs convex pairs
uint64 pairID;
/// Broad-phase Id of the first shape
// TODO OPTI : Is this used ?
int32 broadPhaseId1;
/// Broad-phase Id of the second shape
// TODO OPTI : Is this used ?
int32 broadPhaseId2;
/// Entity of the first collider of the convex vs convex pairs
Entity collider1;
/// Entity of the second collider of the convex vs convex pairs
Entity collider2;
/// True if we need to test if the convex vs convex overlapping pairs of shapes still overlap
bool needToTestOverlap;
/// Pointer to the narrow-phase algorithm
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType;
/// True if the colliders of the overlapping pair were colliding in the previous frame
bool collidingInPreviousFrame;
/// True if the colliders of the overlapping pair are colliding in the current frame
bool collidingInCurrentFrame;
/// Constructor
OverlappingPair(uint64 pairId, int32 broadPhaseId1, int32 broadPhaseId2, Entity collider1, Entity collider2,
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType)
: pairID(pairId), broadPhaseId1(broadPhaseId1), broadPhaseId2(broadPhaseId2), collider1(collider1) , collider2(collider2),
needToTestOverlap(false), narrowPhaseAlgorithmType(narrowPhaseAlgorithmType), collidingInPreviousFrame(false),
collidingInCurrentFrame(false) {
}
/// Destructor
virtual ~OverlappingPair() = default;
};
// Overlapping pair between two convex colliders
struct ConvexOverlappingPair : public OverlappingPair {
/// Temporal coherence collision data for each overlapping collision shapes of this pair.
/// Temporal coherence data store collision information about the last frame.
/// If two convex shapes overlap, we have a single collision data but if one shape is concave,
/// we might have collision data for several overlapping triangles.
LastFrameCollisionInfo lastFrameCollisionInfo;
/// Constructor
ConvexOverlappingPair(uint64 pairId, int32 broadPhaseId1, int32 broadPhaseId2, Entity collider1, Entity collider2,
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType)
: OverlappingPair(pairId, broadPhaseId1, broadPhaseId2, collider1, collider2, narrowPhaseAlgorithmType) {
}
};
// Overlapping pair between two a convex collider and a concave collider
struct ConcaveOverlappingPair : public OverlappingPair {
private:
MemoryAllocator& mPoolAllocator;
public:
/// True if the first shape of the pair is convex
bool isShape1Convex;
/// Temporal coherence collision data for each overlapping collision shapes of this pair.
/// Temporal coherence data store collision information about the last frame.
/// If two convex shapes overlap, we have a single collision data but if one shape is concave,
/// we might have collision data for several overlapping triangles. The key in the map is the
/// shape Ids of the two collision shapes.
Map<uint64, LastFrameCollisionInfo*> lastFrameCollisionInfos;
/// Constructor
ConcaveOverlappingPair(uint64 pairId, int32 broadPhaseId1, int32 broadPhaseId2, Entity collider1, Entity collider2,
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType,
bool isShape1Convex, MemoryAllocator& poolAllocator, MemoryAllocator& heapAllocator)
: OverlappingPair(pairId, broadPhaseId1, broadPhaseId2, collider1, collider2, narrowPhaseAlgorithmType), mPoolAllocator(poolAllocator),
isShape1Convex(isShape1Convex), lastFrameCollisionInfos(heapAllocator, 16) {
}
// Destroy all the LastFrameCollisionInfo objects
void destroyLastFrameCollisionInfos() {
for (auto it = lastFrameCollisionInfos.begin(); it != lastFrameCollisionInfos.end(); ++it) {
// Call the destructor
it->second->LastFrameCollisionInfo::~LastFrameCollisionInfo();
// Release memory
mPoolAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
}
lastFrameCollisionInfos.clear();
}
// Add a new last frame collision info if it does not exist for the given shapes already
LastFrameCollisionInfo* addLastFrameInfoIfNecessary(uint32 shapeId1, uint32 shapeId2) {
uint32 maxShapeId = shapeId1;
uint32 minShapeId = shapeId2;
if (shapeId1 < shapeId2) {
maxShapeId = shapeId2;
minShapeId = shapeId1;
}
// Try to get the corresponding last frame collision info
const uint64 shapesId = pairNumbers(maxShapeId, minShapeId);
// If there is no collision info for those two shapes already
auto it = lastFrameCollisionInfos.find(shapesId);
if (it == lastFrameCollisionInfos.end()) {
LastFrameCollisionInfo* lastFrameInfo = new (mPoolAllocator.allocate(sizeof(LastFrameCollisionInfo))) LastFrameCollisionInfo();
// Add it into the map of collision infos
lastFrameCollisionInfos.add(Pair<uint64, LastFrameCollisionInfo*>(shapesId, lastFrameInfo));
return lastFrameInfo;
}
else {
// The existing collision info is not obsolete
it->second->isObsolete = false;
return it->second;
}
}
/// Clear the obsolete LastFrameCollisionInfo objects
void clearObsoleteLastFrameInfos() {
// For each last frame collision info
for (auto it = lastFrameCollisionInfos.begin(); it != lastFrameCollisionInfos.end(); ) {
// If the collision info is obsolete
if (it->second->isObsolete) {
// Call the destructor
it->second->LastFrameCollisionInfo::~LastFrameCollisionInfo();
// Release memory
mPoolAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
it = lastFrameCollisionInfos.remove(it);
}
else { // If the collision info is not obsolete
// Do not delete it but mark it as obsolete
it->second->isObsolete = true;
++it;
}
}
}
/// Destructor
virtual ~ConcaveOverlappingPair() {
}
};
private:
// -------------------- Constants -------------------- //
/// Number of pairs to allocated at the beginning
const uint32 INIT_NB_ALLOCATED_PAIRS = 10;
// -------------------- Attributes -------------------- //
/// Persistent memory allocator
MemoryAllocator& mPersistentAllocator;
/// Pool memory allocator
MemoryAllocator& mPoolAllocator;
/// Memory allocator used to allocated memory for the ContactManifoldInfo and ContactPointInfo
// TODO OPTI : Do we need to keep this ?
MemoryAllocator& mTempMemoryAllocator;
/// Heap memory allocator
MemoryAllocator& mHeapAllocator;
/// Current number of components
uint64 mNbPairs;
/// List of convex vs convex overlapping pairs
List<ConvexOverlappingPair> mConvexPairs;
/// Index in the array of the first convex vs concave pair
uint64 mConcavePairsStartIndex;
/// Size (in bytes) of a single pair
size_t mPairDataSize;
/// Number of allocated pairs
uint64 mNbAllocatedPairs;
/// Allocated memory for all the data of the pairs
void* mBuffer;
/// List of convex vs concave overlapping pairs
List<ConcaveOverlappingPair> mConcavePairs;
/// Map a pair id to the internal array index
Map<uint64, uint64> mMapPairIdToPairIndex;
Map<uint64, uint64> mMapConvexPairIdToPairIndex;
/// Ids of the convex vs convex pairs
uint64* mPairIds;
/// Array with the broad-phase Ids of the first shape
int32* mPairBroadPhaseId1;
/// Array with the broad-phase Ids of the second shape
int32* mPairBroadPhaseId2;
/// Array of Entity of the first collider of the convex vs convex pairs
Entity* mColliders1;
/// Array of Entity of the second collider of the convex vs convex pairs
Entity* mColliders2;
/// Temporal coherence collision data for each overlapping collision shapes of this pair.
/// Temporal coherence data store collision information about the last frame.
/// If two convex shapes overlap, we have a single collision data but if one shape is concave,
/// we might have collision data for several overlapping triangles. The key in the map is the
/// shape Ids of the two collision shapes.
Map<uint64, LastFrameCollisionInfo*>* mLastFrameCollisionInfos;
/// True if we need to test if the convex vs convex overlapping pairs of shapes still overlap
bool* mNeedToTestOverlap;
/// Array with the pointer to the narrow-phase algorithm for each overlapping pair
NarrowPhaseAlgorithmType* mNarrowPhaseAlgorithmType;
/// True if the first shape of the pair is convex
bool* mIsShape1Convex;
/// True if the colliders of the overlapping pair were colliding in the previous frame
bool* mCollidingInPreviousFrame;
/// True if the colliders of the overlapping pair are colliding in the current frame
bool* mCollidingInCurrentFrame;
/// Map a pair id to the internal array index
Map<uint64, uint64> mMapConcavePairIdToPairIndex;
/// Reference to the colliders components
ColliderComponents& mColliderComponents;
@ -202,15 +324,6 @@ class OverlappingPairs {
// -------------------- Methods -------------------- //
/// Allocate memory for a given number of pairs
void allocate(uint64 nbPairsToAllocate);
/// Compute the index where we need to insert the new pair
uint64 prepareAddPair(bool isConvexVsConvex);
/// Destroy a pair at a given index
void destroyPair(uint64 index);
// Move a pair from a source to a destination index in the pairs array
void movePairToIndex(uint64 srcIndex, uint64 destIndex);
@ -222,8 +335,8 @@ class OverlappingPairs {
// -------------------- Methods -------------------- //
/// Constructor
OverlappingPairs(MemoryAllocator& persistentMemoryAllocator, MemoryAllocator& temporaryMemoryAllocator,
ColliderComponents& colliderComponents, CollisionBodyComponents& collisionBodyComponents,
OverlappingPairs(MemoryManager& memoryManager, ColliderComponents& colliderComponents,
CollisionBodyComponents& collisionBodyComponents,
RigidBodyComponents& rigidBodyComponents, Set<bodypair>& noCollisionPairs,
CollisionDispatch& collisionDispatch);
@ -237,40 +350,13 @@ class OverlappingPairs {
OverlappingPairs& operator=(const OverlappingPairs& pair) = delete;
/// Add an overlapping pair
uint64 addPair(Collider* shape1, Collider* shape2);
uint64 addPair(uint32 collider1Index, uint32 collider2Index, bool isConvexVsConvex);
/// Remove a component at a given index
void removePair(uint64 pairId);
/// Return the number of pairs
uint64 getNbPairs() const;
/// Return the number of convex vs convex pairs
uint64 getNbConvexVsConvexPairs() const;
/// Return the number of convex vs concave pairs
uint64 getNbConvexVsConcavePairs() const;
/// Return the starting index of the convex vs concave pairs
uint64 getConvexVsConcavePairsStartIndex() const;
/// Return the entity of the first collider
Entity getCollider1(uint64 pairId) const;
/// Return the entity of the second collider
Entity getCollider2(uint64 pairId) const;
/// Return the index of a given overlapping pair in the internal array
uint64 getPairIndex(uint64 pairId) const;
/// Return the last frame collision info
LastFrameCollisionInfo* getLastFrameCollisionInfo(uint64, uint64 shapesId);
/// Return a reference to the temporary memory allocator
MemoryAllocator& getTemporaryAllocator();
/// Add a new last frame collision info if it does not exist for the given shapes already
LastFrameCollisionInfo* addLastFrameInfoIfNecessary(uint64 pairIndex, uint32 shapeId1, uint32 shapeId2);
/// Remove a pair
void removePair(uint64 pairIndex, bool isConvexVsConvex);
/// Delete all the obsolete last frame collision info
void clearObsoleteLastFrameCollisionInfos();
@ -284,11 +370,8 @@ class OverlappingPairs {
/// Set if we need to test a given pair for overlap
void setNeedToTestOverlap(uint64 pairId, bool needToTestOverlap);
/// Return true if the two colliders of the pair were already colliding the previous frame
bool getCollidingInPreviousFrame(uint64 pairId) const;
/// Set to true if the two colliders of the pair were already colliding the previous frame
void setCollidingInPreviousFrame(uint64 pairId, bool wereCollidingInPreviousFrame);
/// Return a reference to an overlapping pair
OverlappingPair* getOverlappingPair(uint64 pairId);
#ifdef IS_RP3D_PROFILING_ENABLED
@ -303,41 +386,6 @@ class OverlappingPairs {
friend class CollisionDetectionSystem;
};
// Return the entity of the first collider
RP3D_FORCE_INLINE Entity OverlappingPairs::getCollider1(uint64 pairId) const {
assert(mMapPairIdToPairIndex.containsKey(pairId));
assert(mMapPairIdToPairIndex[pairId] < mNbPairs);
return mColliders1[mMapPairIdToPairIndex[pairId]];
}
// Return the entity of the second collider
RP3D_FORCE_INLINE Entity OverlappingPairs::getCollider2(uint64 pairId) const {
assert(mMapPairIdToPairIndex.containsKey(pairId));
assert(mMapPairIdToPairIndex[pairId] < mNbPairs);
return mColliders2[mMapPairIdToPairIndex[pairId]];
}
// Return the index of a given overlapping pair in the internal array
RP3D_FORCE_INLINE uint64 OverlappingPairs::getPairIndex(uint64 pairId) const {
assert(mMapPairIdToPairIndex.containsKey(pairId));
return mMapPairIdToPairIndex[pairId];
}
// Return the last frame collision info for a given shape id or nullptr if none is found
RP3D_FORCE_INLINE LastFrameCollisionInfo* OverlappingPairs::getLastFrameCollisionInfo(uint64 pairId, uint64 shapesId) {
assert(mMapPairIdToPairIndex.containsKey(pairId));
const uint64 index = mMapPairIdToPairIndex[pairId];
assert(index < mNbPairs);
Map<uint64, LastFrameCollisionInfo*>::Iterator it = mLastFrameCollisionInfos[index].find(shapesId);
if (it != mLastFrameCollisionInfos[index].end()) {
return it->second;
}
return nullptr;
}
// Return the pair of bodies index
RP3D_FORCE_INLINE bodypair OverlappingPairs::computeBodiesIndexPair(Entity body1Entity, Entity body2Entity) {
@ -349,47 +397,33 @@ RP3D_FORCE_INLINE bodypair OverlappingPairs::computeBodiesIndexPair(Entity body1
return indexPair;
}
// Return the number of pairs
RP3D_FORCE_INLINE uint64 OverlappingPairs::getNbPairs() const {
return mNbPairs;
}
// Return the number of convex vs convex pairs
RP3D_FORCE_INLINE uint64 OverlappingPairs::getNbConvexVsConvexPairs() const {
return mConcavePairsStartIndex;
}
// Return the number of convex vs concave pairs
RP3D_FORCE_INLINE uint64 OverlappingPairs::getNbConvexVsConcavePairs() const {
return mNbPairs - mConcavePairsStartIndex;
}
// Return the starting index of the convex vs concave pairs
RP3D_FORCE_INLINE uint64 OverlappingPairs::getConvexVsConcavePairsStartIndex() const {
return mConcavePairsStartIndex;
}
// Return a reference to the temporary memory allocator
RP3D_FORCE_INLINE MemoryAllocator& OverlappingPairs::getTemporaryAllocator() {
return mTempMemoryAllocator;
}
// Set if we need to test a given pair for overlap
RP3D_FORCE_INLINE void OverlappingPairs::setNeedToTestOverlap(uint64 pairId, bool needToTestOverlap) {
assert(mMapPairIdToPairIndex.containsKey(pairId));
mNeedToTestOverlap[mMapPairIdToPairIndex[pairId]] = needToTestOverlap;
assert(mMapConvexPairIdToPairIndex.containsKey(pairId) || mMapConcavePairIdToPairIndex.containsKey(pairId));
auto it = mMapConvexPairIdToPairIndex.find(pairId);
if (it != mMapConvexPairIdToPairIndex.end()) {
mConvexPairs[it->second].needToTestOverlap = needToTestOverlap;
}
else {
mConcavePairs[mMapConcavePairIdToPairIndex[pairId]].needToTestOverlap = needToTestOverlap;
}
}
// Return true if the two colliders of the pair were already colliding the previous frame
RP3D_FORCE_INLINE bool OverlappingPairs::getCollidingInPreviousFrame(uint64 pairId) const {
assert(mMapPairIdToPairIndex.containsKey(pairId));
return mCollidingInPreviousFrame[mMapPairIdToPairIndex[pairId]];
}
// Return a reference to an overlapping pair
RP3D_FORCE_INLINE OverlappingPairs::OverlappingPair* OverlappingPairs::getOverlappingPair(uint64 pairId) {
// Set to true if the two colliders of the pair were already colliding the previous frame
RP3D_FORCE_INLINE void OverlappingPairs::setCollidingInPreviousFrame(uint64 pairId, bool wereCollidingInPreviousFrame) {
assert(mMapPairIdToPairIndex.containsKey(pairId));
mCollidingInPreviousFrame[mMapPairIdToPairIndex[pairId]] = wereCollidingInPreviousFrame;
auto it = mMapConvexPairIdToPairIndex.find(pairId);
if (it != mMapConvexPairIdToPairIndex.end()) {
return &(mConvexPairs[it->second]);
}
it = mMapConcavePairIdToPairIndex.find(pairId);
if (it != mMapConcavePairIdToPairIndex.end()) {
return &(mConcavePairs[it->second]);
}
return nullptr;
}
#ifdef IS_RP3D_PROFILING_ENABLED

View File

@ -198,13 +198,13 @@ class CollisionDetectionSystem {
void removeNonOverlappingPairs();
/// Add a lost contact pair (pair of colliders that are not in contact anymore)
void addLostContactPair(uint64 overlappingPairIndex);
void addLostContactPair(OverlappingPairs::OverlappingPair& overlappingPair);
/// Execute the narrow-phase collision detection algorithm on batches
bool testNarrowPhaseCollision(NarrowPhaseInput& narrowPhaseInput, bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& allocator);
/// Compute the concave vs convex middle-phase algorithm for a given pair of bodies
void computeConvexVsConcaveMiddlePhase(uint64 pairIndex, MemoryAllocator& allocator,
void computeConvexVsConcaveMiddlePhase(OverlappingPairs::ConcaveOverlappingPair& overlappingPair, MemoryAllocator& allocator,
NarrowPhaseInput& narrowPhaseInput);
/// Swap the previous and current contacts lists

View File

@ -640,6 +640,9 @@ void DynamicAABBTree::reportAllShapesOverlappingWithAABB(const AABB& aabb, List<
// Get the next node ID to visit
const int32 nodeIDToVisit = stack.pop();
assert(nodeIDToVisit >= 0);
assert(nodeIDToVisit < mNbAllocatedNodes);
// Skip it if it is a null node
if (nodeIDToVisit == TreeNode::NULL_TREE_NODE) continue;

View File

@ -52,11 +52,12 @@ void NarrowPhaseInfoBatch::reserveMemory() {
// Clear all the objects in the batch
void NarrowPhaseInfoBatch::clear() {
// TODO OPTI : Better manage this
for (uint i=0; i < narrowPhaseInfos.size(); i++) {
assert(narrowPhaseInfos[i].nbContactPoints == 0);
// TODO OPTI : Better manage this
// Release the memory of the TriangleShape (this memory was allocated in the
// MiddlePhaseTriangleCallback::testTriangle() method)
if (narrowPhaseInfos[i].collisionShape1->getName() == CollisionShapeName::TRIANGLE) {

View File

@ -139,7 +139,7 @@ void ConcaveMeshShape::computeOverlappingTriangles(const AABB& localAABB, List<V
aabb.applyScale(Vector3(decimal(1.0) / mScale.x, decimal(1.0) / mScale.y, decimal(1.0) / mScale.z));
// Compute the nodes of the internal AABB tree that are overlapping with the AABB
List<int> overlappingNodes(allocator);
List<int> overlappingNodes(allocator, 64);
mDynamicAABBTree.reportAllShapesOverlappingWithAABB(aabb, overlappingNodes);
const uint nbOverlappingNodes = overlappingNodes.size();

View File

@ -236,9 +236,9 @@ bool HeightFieldShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, Collide
const AABB rayAABB(Vector3::min(ray.point1, rayEnd), Vector3::max(ray.point1, rayEnd));
// Compute the triangles overlapping with the ray AABB
List<Vector3> triangleVertices(allocator);
List<Vector3> triangleVerticesNormals(allocator);
List<uint> shapeIds(allocator);
List<Vector3> triangleVertices(allocator, 64);
List<Vector3> triangleVerticesNormals(allocator, 64);
List<uint> shapeIds(allocator, 64);
computeOverlappingTriangles(rayAABB, triangleVertices, triangleVerticesNormals, shapeIds, allocator);
assert(triangleVertices.size() == triangleVerticesNormals.size());

View File

@ -30,459 +30,194 @@
#include <reactphysics3d/collision/ContactPointInfo.h>
#include <reactphysics3d/collision/narrowphase/NarrowPhaseAlgorithm.h>
#include <reactphysics3d/collision/narrowphase/CollisionDispatch.h>
#include <reactphysics3d/memory/MemoryManager.h>
using namespace reactphysics3d;
// Constructor
OverlappingPairs::OverlappingPairs(MemoryAllocator& persistentMemoryAllocator, MemoryAllocator& temporaryMemoryAllocator, ColliderComponents &colliderComponents,
OverlappingPairs::OverlappingPairs(MemoryManager& memoryManager, ColliderComponents& colliderComponents,
CollisionBodyComponents& collisionBodyComponents, RigidBodyComponents& rigidBodyComponents, Set<bodypair> &noCollisionPairs, CollisionDispatch &collisionDispatch)
: mPersistentAllocator(persistentMemoryAllocator), mTempMemoryAllocator(temporaryMemoryAllocator),
mNbPairs(0), mConcavePairsStartIndex(0), mPairDataSize(sizeof(uint64) + sizeof(int32) + sizeof(int32) + sizeof(Entity) +
sizeof(Entity) + sizeof(Map<uint64, LastFrameCollisionInfo*>) +
sizeof(bool) + sizeof(NarrowPhaseAlgorithmType) +
sizeof(bool) + sizeof(bool) + sizeof(bool)),
mNbAllocatedPairs(0), mBuffer(nullptr),
mMapPairIdToPairIndex(persistentMemoryAllocator),
: mPoolAllocator(memoryManager.getPoolAllocator()), mHeapAllocator(memoryManager.getHeapAllocator()), mConvexPairs(memoryManager.getHeapAllocator()),
mConcavePairs(memoryManager.getHeapAllocator()), mMapConvexPairIdToPairIndex(memoryManager.getHeapAllocator()), mMapConcavePairIdToPairIndex(memoryManager.getHeapAllocator()),
mColliderComponents(colliderComponents), mCollisionBodyComponents(collisionBodyComponents),
mRigidBodyComponents(rigidBodyComponents), mNoCollisionPairs(noCollisionPairs), mCollisionDispatch(collisionDispatch) {
// Allocate memory for the components data
allocate(INIT_NB_ALLOCATED_PAIRS);
}
// Destructor
OverlappingPairs::~OverlappingPairs() {
// If there are allocated pairs
if (mNbAllocatedPairs > 0) {
// Destroy the convex pairs
while (mConvexPairs.size() > 0) {
// Destroy all the remaining pairs
for (uint32 i = 0; i < mNbPairs; i++) {
// Remove all the remaining last frame collision info
for (auto it = mLastFrameCollisionInfos[i].begin(); it != mLastFrameCollisionInfos[i].end(); ++it) {
// Call the constructor
it->second->~LastFrameCollisionInfo();
// Release memory
mPersistentAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
}
// Remove the involved overlapping pair to the two colliders
assert(mColliderComponents.getOverlappingPairs(mColliders1[i]).find(mPairIds[i]) != mColliderComponents.getOverlappingPairs(mColliders1[i]).end());
assert(mColliderComponents.getOverlappingPairs(mColliders2[i]).find(mPairIds[i]) != mColliderComponents.getOverlappingPairs(mColliders2[i]).end());
mColliderComponents.getOverlappingPairs(mColliders1[i]).remove(mPairIds[i]);
mColliderComponents.getOverlappingPairs(mColliders2[i]).remove(mPairIds[i]);
destroyPair(i);
}
// Size for the data of a single pair (in bytes)
const size_t totalSizeBytes = mNbAllocatedPairs * mPairDataSize;
// Release the allocated memory
mPersistentAllocator.release(mBuffer, totalSizeBytes);
}
}
// Compute the index where we need to insert the new pair
uint64 OverlappingPairs::prepareAddPair(bool isConvexVsConvex) {
// If we need to allocate more components
if (mNbPairs == mNbAllocatedPairs) {
allocate(mNbAllocatedPairs * 2);
removePair(mConvexPairs.size() - 1, true);
}
uint64 index;
// Destroy the concave pairs
while (mConcavePairs.size() > 0) {
// If the pair to add is not convex vs convex or there are no concave pairs yet
if (!isConvexVsConvex) {
// Add the component at the end of the array
index = mNbPairs;
removePair(mConcavePairs.size() - 1, false);
}
// If the pair to add is convex vs convex
else {
// If there already are convex vs concave pairs
if (mConcavePairsStartIndex != mNbPairs) {
// Move the first convex vs concave pair to the end of the array
movePairToIndex(mConcavePairsStartIndex, mNbPairs);
}
index = mConcavePairsStartIndex;
mConcavePairsStartIndex++;
}
return index;
}
// Remove a component at a given index
void OverlappingPairs::removePair(uint64 pairId) {
RP3D_PROFILE("OverlappingPairs::removePair()", mProfiler);
assert(mMapConvexPairIdToPairIndex.containsKey(pairId) || mMapConcavePairIdToPairIndex.containsKey(pairId));
assert(mMapPairIdToPairIndex.containsKey(pairId));
uint64 index = mMapPairIdToPairIndex[pairId];
assert(index < mNbPairs);
// We want to keep the arrays tightly packed. Therefore, when a pair is removed,
// we replace it with the last element of the array. But we need to make sure that convex
// and concave pairs stay grouped together.
// Remove all the remaining last frame collision info
for (auto it = mLastFrameCollisionInfos[index].begin(); it != mLastFrameCollisionInfos[index].end(); ++it) {
// Call the constructor
it->second->~LastFrameCollisionInfo();
// Release memory
mPersistentAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
auto it = mMapConvexPairIdToPairIndex.find(pairId);
if (it != mMapConvexPairIdToPairIndex.end()) {
removePair(it->second, true);
}
// Remove the involved overlapping pair to the two colliders
assert(mColliderComponents.getOverlappingPairs(mColliders1[index]).find(pairId) != mColliderComponents.getOverlappingPairs(mColliders1[index]).end());
assert(mColliderComponents.getOverlappingPairs(mColliders2[index]).find(pairId) != mColliderComponents.getOverlappingPairs(mColliders2[index]).end());
mColliderComponents.getOverlappingPairs(mColliders1[index]).remove(pairId);
mColliderComponents.getOverlappingPairs(mColliders2[index]).remove(pairId);
// Destroy the pair
destroyPair(index);
// If the pair to remove is convex vs concave
if (index >= mConcavePairsStartIndex) {
// If the pair is not the last one
if (index != mNbPairs - 1) {
// We replace it by the last convex vs concave pair
movePairToIndex(mNbPairs - 1, index);
}
else {
removePair(mMapConcavePairIdToPairIndex[pairId], false);
}
else { // If the pair to remove is convex vs convex
// If it not the last convex vs convex pair
if (index != mConcavePairsStartIndex - 1) {
// We replace it by the last convex vs convex pair
movePairToIndex(mConcavePairsStartIndex - 1, index);
}
// If there are convex vs concave pairs at the end
if (mConcavePairsStartIndex != mNbPairs) {
// We replace the last convex vs convex pair by the last convex vs concave pair
movePairToIndex(mNbPairs - 1, mConcavePairsStartIndex - 1);
}
mConcavePairsStartIndex--;
}
mNbPairs--;
assert(mConcavePairsStartIndex <= mNbPairs);
assert(mNbPairs == static_cast<uint32>(mMapPairIdToPairIndex.size()));
}
// Allocate memory for a given number of pairs
void OverlappingPairs::allocate(uint64 nbPairsToAllocate) {
// Remove a component at a given index
void OverlappingPairs::removePair(uint64 pairIndex, bool isConvexVsConvex) {
assert(nbPairsToAllocate > mNbAllocatedPairs);
RP3D_PROFILE("OverlappingPairs::removePair()", mProfiler);
// Size for the data of a single component (in bytes)
const size_t totalSizeBytes = nbPairsToAllocate * mPairDataSize;
if (isConvexVsConvex) {
// Allocate memory
void* newBuffer = mPersistentAllocator.allocate(totalSizeBytes);
assert(newBuffer != nullptr);
const uint nbConvexPairs = mConvexPairs.size();
// New pointers to components data
uint64* newPairIds = static_cast<uint64*>(newBuffer);
int32* newPairBroadPhaseId1 = reinterpret_cast<int32*>(newPairIds + nbPairsToAllocate);
int32* newPairBroadPhaseId2 = reinterpret_cast<int32*>(newPairBroadPhaseId1 + nbPairsToAllocate);
Entity* newColliders1 = reinterpret_cast<Entity*>(newPairBroadPhaseId2 + nbPairsToAllocate);
Entity* newColliders2 = reinterpret_cast<Entity*>(newColliders1 + nbPairsToAllocate);
Map<uint64, LastFrameCollisionInfo*>* newLastFrameCollisionInfos = reinterpret_cast<Map<uint64, LastFrameCollisionInfo*>*>(newColliders2 + nbPairsToAllocate);
bool* newNeedToTestOverlap = reinterpret_cast<bool*>(newLastFrameCollisionInfos + nbPairsToAllocate);
NarrowPhaseAlgorithmType* newNarrowPhaseAlgorithmType = reinterpret_cast<NarrowPhaseAlgorithmType*>(newNeedToTestOverlap + nbPairsToAllocate);
bool* newIsShape1Convex = reinterpret_cast<bool*>(newNarrowPhaseAlgorithmType + nbPairsToAllocate);
bool* wereCollidingInPreviousFrame = reinterpret_cast<bool*>(newIsShape1Convex + nbPairsToAllocate);
bool* areCollidingInCurrentFrame = reinterpret_cast<bool*>(wereCollidingInPreviousFrame + nbPairsToAllocate);
assert(pairIndex < nbConvexPairs);
// If there was already pairs before
if (mNbPairs > 0) {
// Remove the involved overlapping pair from the two colliders
assert(mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider1).find(mConvexPairs[pairIndex].pairID) != mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider1).end());
assert(mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider2).find(mConvexPairs[pairIndex].pairID) != mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider2).end());
mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider1).remove(mConvexPairs[pairIndex].pairID);
mColliderComponents.getOverlappingPairs(mConvexPairs[pairIndex].collider2).remove(mConvexPairs[pairIndex].pairID);
// Copy component data from the previous buffer to the new one
memcpy(newPairIds, mPairIds, mNbPairs * sizeof(uint64));
memcpy(newPairBroadPhaseId1, mPairBroadPhaseId1, mNbPairs * sizeof(int32));
memcpy(newPairBroadPhaseId2, mPairBroadPhaseId2, mNbPairs * sizeof(int32));
memcpy(newColliders1, mColliders1, mNbPairs * sizeof(Entity));
memcpy(newColliders2, mColliders2, mNbPairs * sizeof(Entity));
memcpy(newLastFrameCollisionInfos, mLastFrameCollisionInfos, mNbPairs * sizeof(Map<uint64, LastFrameCollisionInfo*>));
memcpy(newNeedToTestOverlap, mNeedToTestOverlap, mNbPairs * sizeof(bool));
memcpy(newNarrowPhaseAlgorithmType, mNarrowPhaseAlgorithmType, mNbPairs * sizeof(NarrowPhaseAlgorithmType));
memcpy(newIsShape1Convex, mIsShape1Convex, mNbPairs * sizeof(bool));
memcpy(wereCollidingInPreviousFrame, mCollidingInPreviousFrame, mNbPairs * sizeof(bool));
memcpy(areCollidingInCurrentFrame, mCollidingInCurrentFrame, mNbPairs * sizeof(bool));
assert(mMapConvexPairIdToPairIndex[mConvexPairs[pairIndex].pairID] == pairIndex);
mMapConvexPairIdToPairIndex.remove(mConvexPairs[pairIndex].pairID);
// Deallocate previous memory
mPersistentAllocator.release(mBuffer, mNbAllocatedPairs * mPairDataSize);
// Change the mapping between the pairId and the index in the convex pairs array if we swap the last item with the one to remove
if (mConvexPairs.size() > 1 && pairIndex < (nbConvexPairs - 1)) {
mMapConvexPairIdToPairIndex[mConvexPairs[nbConvexPairs - 1].pairID] = pairIndex;
}
// We want to keep the arrays tightly packed. Therefore, when a pair is removed,
// we replace it with the last element of the array.
mConvexPairs.removeAtAndReplaceByLast(pairIndex);
}
else {
mBuffer = newBuffer;
mPairIds = newPairIds;
mPairBroadPhaseId1 = newPairBroadPhaseId1;
mPairBroadPhaseId2 = newPairBroadPhaseId2;
mColliders1 = newColliders1;
mColliders2 = newColliders2;
mLastFrameCollisionInfos = newLastFrameCollisionInfos;
mNeedToTestOverlap = newNeedToTestOverlap;
mNarrowPhaseAlgorithmType = newNarrowPhaseAlgorithmType;
mIsShape1Convex = newIsShape1Convex;
mCollidingInPreviousFrame = wereCollidingInPreviousFrame;
mCollidingInCurrentFrame = areCollidingInCurrentFrame;
const uint nbConcavePairs = mConcavePairs.size();
mNbAllocatedPairs = nbPairsToAllocate;
assert(pairIndex < nbConcavePairs);
// Remove the involved overlapping pair to the two colliders
assert(mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider1).find(mConcavePairs[pairIndex].pairID) != mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider1).end());
assert(mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider2).find(mConcavePairs[pairIndex].pairID) != mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider2).end());
mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider1).remove(mConcavePairs[pairIndex].pairID);
mColliderComponents.getOverlappingPairs(mConcavePairs[pairIndex].collider2).remove(mConcavePairs[pairIndex].pairID);
assert(mMapConcavePairIdToPairIndex[mConcavePairs[pairIndex].pairID] == pairIndex);
mMapConcavePairIdToPairIndex.remove(mConcavePairs[pairIndex].pairID);
// Destroy all the LastFrameCollisionInfo objects
mConcavePairs[pairIndex].destroyLastFrameCollisionInfos();
// Change the mapping between the pairId and the index in the convex pairs array if we swap the last item with the one to remove
if (mConcavePairs.size() > 1 && pairIndex < (nbConcavePairs - 1)) {
mMapConcavePairIdToPairIndex[mConcavePairs[nbConcavePairs - 1].pairID] = pairIndex;
}
// We want to keep the arrays tightly packed. Therefore, when a pair is removed,
// we replace it with the last element of the array.
mConcavePairs.removeAtAndReplaceByLast(pairIndex);
}
}
// Add an overlapping pair
uint64 OverlappingPairs::addPair(Collider* shape1, Collider* shape2) {
uint64 OverlappingPairs::addPair(uint32 collider1Index, uint32 collider2Index, bool isConvexVsConvex) {
RP3D_PROFILE("OverlappingPairs::addPair()", mProfiler);
const Entity collider1 = shape1->getEntity();
const Entity collider2 = shape2->getEntity();
const uint collider1Index = mColliderComponents.getEntityIndex(collider1);
const uint collider2Index = mColliderComponents.getEntityIndex(collider2);
assert(mColliderComponents.mBroadPhaseIds[collider1Index] >= 0 && mColliderComponents.mBroadPhaseIds[collider2Index] >= 0);
const CollisionShape* collisionShape1 = mColliderComponents.mCollisionShapes[collider1Index];
const CollisionShape* collisionShape2 = mColliderComponents.mCollisionShapes[collider2Index];
const bool isShape1Convex = collisionShape1->isConvex();
const bool isShape2Convex = collisionShape2->isConvex();
const bool isConvexVsConvex = isShape1Convex && isShape2Convex;
const Entity collider1Entity = mColliderComponents.mCollidersEntities[collider1Index];
const Entity collider2Entity = mColliderComponents.mCollidersEntities[collider2Index];
// Prepare to add new pair (allocate memory if necessary and compute insertion index)
uint64 index = prepareAddPair(isConvexVsConvex);
const uint32 broadPhase1Id = static_cast<uint32>(shape1->getBroadPhaseId());
const uint32 broadPhase2Id = static_cast<uint32>(shape2->getBroadPhaseId());
const uint32 broadPhase1Id = static_cast<uint32>(mColliderComponents.mBroadPhaseIds[collider1Index]);
const uint32 broadPhase2Id = static_cast<uint32>(mColliderComponents.mBroadPhaseIds[collider2Index]);
// Compute a unique id for the overlapping pair
const uint64 pairId = pairNumbers(std::max(broadPhase1Id, broadPhase2Id), std::min(broadPhase1Id, broadPhase2Id));
assert(!mMapPairIdToPairIndex.containsKey(pairId));
// Select the narrow phase algorithm to use according to the two collision shapes
NarrowPhaseAlgorithmType algorithmType;
if (isConvexVsConvex) {
algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(), collisionShape2->getType());
assert(!mMapConvexPairIdToPairIndex.containsKey(pairId));
NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(collisionShape1->getType(), collisionShape2->getType());
// Map the entity with the new component lookup index
mMapConvexPairIdToPairIndex.add(Pair<uint64, uint64>(pairId, mConvexPairs.size()));
// Create and add a new convex pair
mConvexPairs.emplace(pairId, broadPhase1Id, broadPhase2Id, collider1Entity, collider2Entity, algorithmType);
}
else {
algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(isShape1Convex ? collisionShape1->getType() : collisionShape2->getType(),
const bool isShape1Convex = collisionShape1->isConvex();
assert(!mMapConcavePairIdToPairIndex.containsKey(pairId));
NarrowPhaseAlgorithmType algorithmType = mCollisionDispatch.selectNarrowPhaseAlgorithm(isShape1Convex ? collisionShape1->getType() : collisionShape2->getType(),
CollisionShapeType::CONVEX_POLYHEDRON);
// Map the entity with the new component lookup index
mMapConcavePairIdToPairIndex.add(Pair<uint64, uint64>(pairId, mConcavePairs.size()));
// Create and add a new concave pair
mConcavePairs.emplace(pairId, broadPhase1Id, broadPhase2Id, collider1Entity, collider2Entity, algorithmType,
isShape1Convex, mPoolAllocator, mHeapAllocator);
}
// Insert the new component data
new (mPairIds + index) uint64(pairId);
new (mPairBroadPhaseId1 + index) int32(shape1->getBroadPhaseId());
new (mPairBroadPhaseId2 + index) int32(shape2->getBroadPhaseId());
new (mColliders1 + index) Entity(shape1->getEntity());
new (mColliders2 + index) Entity(shape2->getEntity());
new (mLastFrameCollisionInfos + index) Map<uint64, LastFrameCollisionInfo*>(mPersistentAllocator);
new (mNeedToTestOverlap + index) bool(false);
new (mNarrowPhaseAlgorithmType + index) NarrowPhaseAlgorithmType(algorithmType);
new (mIsShape1Convex + index) bool(isShape1Convex);
new (mCollidingInPreviousFrame + index) bool(false);
new (mCollidingInCurrentFrame + index) bool(false);
// Map the entity with the new component lookup index
mMapPairIdToPairIndex.add(Pair<uint64, uint64>(pairId, index));
// Add the involved overlapping pair to the two colliders
assert(mColliderComponents.mOverlappingPairs[collider1Index].find(pairId) == mColliderComponents.mOverlappingPairs[collider1Index].end());
assert(mColliderComponents.mOverlappingPairs[collider2Index].find(pairId) == mColliderComponents.mOverlappingPairs[collider2Index].end());
mColliderComponents.mOverlappingPairs[collider1Index].add(pairId);
mColliderComponents.mOverlappingPairs[collider2Index].add(pairId);
mNbPairs++;
assert(mConcavePairsStartIndex <= mNbPairs);
assert(mNbPairs == static_cast<uint64>(mMapPairIdToPairIndex.size()));
return pairId;
}
// Move a pair from a source to a destination index in the pairs array
// The destination location must contain a constructed object
void OverlappingPairs::movePairToIndex(uint64 srcIndex, uint64 destIndex) {
const uint64 pairId = mPairIds[srcIndex];
// Copy the data of the source pair to the destination location
mPairIds[destIndex] = mPairIds[srcIndex];
mPairBroadPhaseId1[destIndex] = mPairBroadPhaseId1[srcIndex];
mPairBroadPhaseId2[destIndex] = mPairBroadPhaseId2[srcIndex];
new (mColliders1 + destIndex) Entity(mColliders1[srcIndex]);
new (mColliders2 + destIndex) Entity(mColliders2[srcIndex]);
new (mLastFrameCollisionInfos + destIndex) Map<uint64, LastFrameCollisionInfo*>(mLastFrameCollisionInfos[srcIndex]);
mNeedToTestOverlap[destIndex] = mNeedToTestOverlap[srcIndex];
new (mNarrowPhaseAlgorithmType + destIndex) NarrowPhaseAlgorithmType(mNarrowPhaseAlgorithmType[srcIndex]);
mIsShape1Convex[destIndex] = mIsShape1Convex[srcIndex];
mCollidingInPreviousFrame[destIndex] = mCollidingInPreviousFrame[srcIndex];
mCollidingInCurrentFrame[destIndex] = mCollidingInCurrentFrame[srcIndex];
// Destroy the source pair
destroyPair(srcIndex);
assert(!mMapPairIdToPairIndex.containsKey(pairId));
// Update the pairId to pair index mapping
mMapPairIdToPairIndex.add(Pair<uint64, uint64>(pairId, destIndex));
assert(mMapPairIdToPairIndex[mPairIds[destIndex]] == destIndex);
}
// Swap two pairs in the array
void OverlappingPairs::swapPairs(uint64 index1, uint64 index2) {
// Copy pair 1 data
uint64 pairId = mPairIds[index1];
int32 pairBroadPhaseId1 = mPairBroadPhaseId1[index1];
int32 pairBroadPhaseId2 = mPairBroadPhaseId2[index1];
Entity collider1 = mColliders1[index1];
Entity collider2 = mColliders2[index1];
Map<uint64, LastFrameCollisionInfo*> lastFrameCollisionInfo(mLastFrameCollisionInfos[index1]);
bool needTestOverlap = mNeedToTestOverlap[index1];
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType = mNarrowPhaseAlgorithmType[index1];
bool isShape1Convex = mIsShape1Convex[index1];
bool wereCollidingInPreviousFrame = mCollidingInPreviousFrame[index1];
bool areCollidingInCurrentFrame = mCollidingInCurrentFrame[index1];
// Destroy pair 1
destroyPair(index1);
movePairToIndex(index2, index1);
// Reconstruct pair 1 at pair 2 location
mPairIds[index2] = pairId;
mPairBroadPhaseId1[index2] = pairBroadPhaseId1;
mPairBroadPhaseId2[index2] = pairBroadPhaseId2;
new (mColliders1 + index2) Entity(collider1);
new (mColliders2 + index2) Entity(collider2);
new (mLastFrameCollisionInfos + index2) Map<uint64, LastFrameCollisionInfo*>(lastFrameCollisionInfo);
mNeedToTestOverlap[index2] = needTestOverlap;
new (mNarrowPhaseAlgorithmType + index2) NarrowPhaseAlgorithmType(narrowPhaseAlgorithmType);
mIsShape1Convex[index2] = isShape1Convex;
mCollidingInPreviousFrame[index2] = wereCollidingInPreviousFrame;
mCollidingInCurrentFrame[index2] = areCollidingInCurrentFrame;
// Update the pairID to pair index mapping
mMapPairIdToPairIndex.add(Pair<uint64, uint64>(pairId, index2));
assert(mMapPairIdToPairIndex[mPairIds[index1]] == index1);
assert(mMapPairIdToPairIndex[mPairIds[index2]] == index2);
assert(mNbPairs == static_cast<uint64>(mMapPairIdToPairIndex.size()));
}
// Destroy a pair at a given index
void OverlappingPairs::destroyPair(uint64 index) {
assert(index < mNbPairs);
assert(mMapPairIdToPairIndex[mPairIds[index]] == index);
mMapPairIdToPairIndex.remove(mPairIds[index]);
mColliders1[index].~Entity();
mColliders2[index].~Entity();
mLastFrameCollisionInfos[index].~Map<uint64, LastFrameCollisionInfo*>();
mNarrowPhaseAlgorithmType[index].~NarrowPhaseAlgorithmType();
}
// Add a new last frame collision info if it does not exist for the given shapes already
LastFrameCollisionInfo* OverlappingPairs::addLastFrameInfoIfNecessary(uint64 pairIndex, uint32 shapeId1, uint32 shapeId2) {
RP3D_PROFILE("OverlappingPairs::addLastFrameInfoIfNecessary()", mProfiler);
assert(pairIndex < mNbPairs);
uint32 maxShapeId = shapeId1;
uint32 minShapeId = shapeId2;
if (shapeId1 < shapeId2) {
maxShapeId = shapeId2;
minShapeId = shapeId1;
}
// Try to get the corresponding last frame collision info
const uint64 shapesId = pairNumbers(maxShapeId, minShapeId);
// If there is no collision info for those two shapes already
auto it = mLastFrameCollisionInfos[pairIndex].find(shapesId);
if (it == mLastFrameCollisionInfos[pairIndex].end()) {
// Create a new collision info
LastFrameCollisionInfo* collisionInfo = new (mPersistentAllocator.allocate(sizeof(LastFrameCollisionInfo)))
LastFrameCollisionInfo();
// Add it into the map of collision infos
mLastFrameCollisionInfos[pairIndex].add(Pair<uint64, LastFrameCollisionInfo*>(shapesId, collisionInfo));
return collisionInfo;
}
else {
// The existing collision info is not obsolete
it->second->isObsolete = false;
return it->second;
}
}
// Delete all the obsolete last frame collision info
void OverlappingPairs::clearObsoleteLastFrameCollisionInfos() {
RP3D_PROFILE("OverlappingPairs::clearObsoleteLastFrameCollisionInfos()", mProfiler);
// For each overlapping pair
for (uint64 i=0; i < mNbPairs; i++) {
// For each concave overlapping pair
const uint64 nbConcavePairs = mConcavePairs.size();
for (uint64 i=0; i < nbConcavePairs; i++) {
// For each collision info
for (auto it = mLastFrameCollisionInfos[i].begin(); it != mLastFrameCollisionInfos[i].end(); ) {
// If the collision info is obsolete
if (it->second->isObsolete) {
// Delete it
it->second->~LastFrameCollisionInfo();
mPersistentAllocator.release(it->second, sizeof(LastFrameCollisionInfo));
it = mLastFrameCollisionInfos[i].remove(it);
}
else { // If the collision info is not obsolete
// Do not delete it but mark it as obsolete
it->second->isObsolete = true;
++it;
}
}
mConcavePairs[i].clearObsoleteLastFrameInfos();
}
}
// Set the collidingInPreviousFrame value with the collidinginCurrentFrame value for each pair
void OverlappingPairs::updateCollidingInPreviousFrame() {
// For each overlapping pair
for (uint64 i=0; i < mNbPairs; i++) {
RP3D_PROFILE("OverlappingPairs::updateCollidingInPreviousFrame()", mProfiler);
mCollidingInPreviousFrame[i] = mCollidingInCurrentFrame[i];
// For each convex overlapping pair
const uint64 nbConvexPairs = mConvexPairs.size();
for (uint64 i=0; i < nbConvexPairs; i++) {
mConvexPairs[i].collidingInPreviousFrame = mConvexPairs[i].collidingInCurrentFrame;
}
// For each concave overlapping pair
const uint64 nbConcavePairs = mConcavePairs.size();
for (uint64 i=0; i < nbConcavePairs; i++) {
mConcavePairs[i].collidingInPreviousFrame = mConcavePairs[i].collidingInCurrentFrame;
}
}

View File

@ -37,9 +37,9 @@ using namespace reactphysics3d;
// Constructor
BroadPhaseSystem::BroadPhaseSystem(CollisionDetectionSystem& collisionDetection, ColliderComponents& collidersComponents,
TransformComponents& transformComponents, RigidBodyComponents& rigidBodyComponents)
:mDynamicAABBTree(collisionDetection.getMemoryManager().getPoolAllocator(), DYNAMIC_TREE_FAT_AABB_INFLATE_PERCENTAGE),
:mDynamicAABBTree(collisionDetection.getMemoryManager().getHeapAllocator(), DYNAMIC_TREE_FAT_AABB_INFLATE_PERCENTAGE),
mCollidersComponents(collidersComponents), mTransformsComponents(transformComponents),
mRigidBodyComponents(rigidBodyComponents), mMovedShapes(collisionDetection.getMemoryManager().getPoolAllocator()),
mRigidBodyComponents(rigidBodyComponents), mMovedShapes(collisionDetection.getMemoryManager().getHeapAllocator()),
mCollisionDetection(collisionDetection) {
#ifdef IS_RP3D_PROFILING_ENABLED
@ -211,7 +211,7 @@ void BroadPhaseSystem::computeOverlappingPairs(MemoryManager& memoryManager, Lis
RP3D_PROFILE("BroadPhaseSystem::computeOverlappingPairs()", mProfiler);
// Get the list of the colliders that have moved or have been created in the last frame
List<int> shapesToTest = mMovedShapes.toList(memoryManager.getPoolAllocator());
List<int> shapesToTest = mMovedShapes.toList(memoryManager.getHeapAllocator());
// Ask the dynamic AABB tree to report all collision shapes that overlap with the shapes to test
mDynamicAABBTree.reportAllShapesOverlappingWithShapes(shapesToTest, 0, shapesToTest.size(), overlappingNodes);

View File

@ -55,8 +55,8 @@ CollisionDetectionSystem::CollisionDetectionSystem(PhysicsWorld* world, Collider
: mMemoryManager(memoryManager), mCollidersComponents(collidersComponents), mRigidBodyComponents(rigidBodyComponents),
mCollisionDispatch(mMemoryManager.getPoolAllocator()), mWorld(world),
mNoCollisionPairs(mMemoryManager.getPoolAllocator()),
mOverlappingPairs(mMemoryManager.getPoolAllocator(), mMemoryManager.getSingleFrameAllocator(), mCollidersComponents,
collisionBodyComponents, rigidBodyComponents, mNoCollisionPairs, mCollisionDispatch),
mOverlappingPairs(mMemoryManager, mCollidersComponents, collisionBodyComponents, rigidBodyComponents,
mNoCollisionPairs, mCollisionDispatch),
mBroadPhaseSystem(*this, mCollidersComponents, transformComponents, rigidBodyComponents),
mMapBroadPhaseIdToColliderEntity(memoryManager.getPoolAllocator()),
mNarrowPhaseInput(mMemoryManager.getSingleFrameAllocator(), mOverlappingPairs), mPotentialContactPoints(mMemoryManager.getSingleFrameAllocator()),
@ -102,7 +102,7 @@ void CollisionDetectionSystem::computeBroadPhase() {
// Ask the broad-phase to compute all the shapes overlapping with 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.
List<Pair<int32, int32>> overlappingNodes(mMemoryManager.getPoolAllocator(), 32);
List<Pair<int32, int32>> overlappingNodes(mMemoryManager.getHeapAllocator(), 32);
mBroadPhaseSystem.computeOverlappingPairs(mMemoryManager, overlappingNodes);
// Create new overlapping pairs if necessary
@ -117,25 +117,55 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() {
RP3D_PROFILE("CollisionDetectionSystem::removeNonOverlappingPairs()", mProfiler);
for (uint64 i=0; i < mOverlappingPairs.getNbPairs(); i++) {
// For each convex pairs
for (uint64 i=0; i < mOverlappingPairs.mConvexPairs.size(); i++) {
OverlappingPairs::ConvexOverlappingPair& overlappingPair = mOverlappingPairs.mConvexPairs[i];
// Check if we need to test overlap. If so, test if the two shapes are still overlapping.
// Otherwise, we destroy the overlapping pair
if (mOverlappingPairs.mNeedToTestOverlap[i]) {
if (overlappingPair.needToTestOverlap) {
if(mBroadPhaseSystem.testOverlappingShapes(mOverlappingPairs.mPairBroadPhaseId1[i], mOverlappingPairs.mPairBroadPhaseId2[i])) {
mOverlappingPairs.mNeedToTestOverlap[i] = false;
if(mBroadPhaseSystem.testOverlappingShapes(overlappingPair.broadPhaseId1, overlappingPair.broadPhaseId2)) {
overlappingPair.needToTestOverlap = false;
}
else {
// If the two colliders of the pair were colliding in the previous frame
if (mOverlappingPairs.mCollidingInPreviousFrame[i]) {
if (overlappingPair.collidingInPreviousFrame) {
// Create a new lost contact pair
addLostContactPair(i);
addLostContactPair(overlappingPair);
}
mOverlappingPairs.removePair(mOverlappingPairs.mPairIds[i]);
mOverlappingPairs.removePair(i, true);
i--;
}
}
}
// For each concave pairs
for (uint64 i=0; i < mOverlappingPairs.mConcavePairs.size(); i++) {
OverlappingPairs::ConcaveOverlappingPair& overlappingPair = mOverlappingPairs.mConcavePairs[i];
// Check if we need to test overlap. If so, test if the two shapes are still overlapping.
// Otherwise, we destroy the overlapping pair
if (overlappingPair.needToTestOverlap) {
if(mBroadPhaseSystem.testOverlappingShapes(overlappingPair.broadPhaseId1, overlappingPair.broadPhaseId2)) {
overlappingPair.needToTestOverlap = false;
}
else {
// If the two colliders of the pair were colliding in the previous frame
if (overlappingPair.collidingInPreviousFrame) {
// Create a new lost contact pair
addLostContactPair(overlappingPair);
}
mOverlappingPairs.removePair(i, false);
i--;
}
}
@ -143,20 +173,20 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() {
}
// Add a lost contact pair (pair of colliders that are not in contact anymore)
void CollisionDetectionSystem::addLostContactPair(uint64 overlappingPairIndex) {
void CollisionDetectionSystem::addLostContactPair(OverlappingPairs::OverlappingPair& overlappingPair) {
const Entity collider1Entity = mOverlappingPairs.mColliders1[overlappingPairIndex];
const Entity collider2Entity = mOverlappingPairs.mColliders2[overlappingPairIndex];
const uint32 collider1Index = mCollidersComponents.getEntityIndex(overlappingPair.collider1);
const uint32 collider2Index = mCollidersComponents.getEntityIndex(overlappingPair.collider2);
const Entity body1Entity = mCollidersComponents.getBody(collider1Entity);
const Entity body2Entity = mCollidersComponents.getBody(collider2Entity);
const Entity body1Entity = mCollidersComponents.mBodiesEntities[collider1Index];
const Entity body2Entity = mCollidersComponents.mBodiesEntities[collider2Index];
const bool isCollider1Trigger = mCollidersComponents.getIsTrigger(collider1Entity);
const bool isCollider2Trigger = mCollidersComponents.getIsTrigger(collider2Entity);
const bool isCollider1Trigger = mCollidersComponents.mIsTrigger[collider1Index];
const bool isCollider2Trigger = mCollidersComponents.mIsTrigger[collider2Index];
const bool isTrigger = isCollider1Trigger || isCollider2Trigger;
// Create a lost contact pair
ContactPair lostContactPair(mOverlappingPairs.mPairIds[overlappingPairIndex], body1Entity, body2Entity, collider1Entity, collider2Entity, mLostContactPairs.size(),
ContactPair lostContactPair(overlappingPair.pairID, body1Entity, body2Entity, overlappingPair.collider1, overlappingPair.collider2, mLostContactPairs.size(),
true, isTrigger);
mLostContactPairs.add(lostContactPair);
}
@ -219,8 +249,8 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int32, int
const uint64 pairId = pairNumbers(std::max(nodePair.first, nodePair.second), std::min(nodePair.first, nodePair.second));
// Check if the overlapping pair already exists
auto it = mOverlappingPairs.mMapPairIdToPairIndex.find(pairId);
if (it == mOverlappingPairs.mMapPairIdToPairIndex.end()) {
OverlappingPairs::OverlappingPair* overlappingPair = mOverlappingPairs.getOverlappingPair(pairId);
if (overlappingPair == nullptr) {
const unsigned short shape1CollideWithMaskBits = mCollidersComponents.mCollideWithMaskBits[collider1Index];
const unsigned short shape2CollideWithMaskBits = mCollidersComponents.mCollideWithMaskBits[collider2Index];
@ -236,17 +266,19 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int32, int
Collider* shape2 = mCollidersComponents.mColliders[collider2Index];
// Check that at least one collision shape is convex
if (shape1->getCollisionShape()->isConvex() || shape2->getCollisionShape()->isConvex()) {
const bool isShape1Convex = shape1->getCollisionShape()->isConvex();
const bool isShape2Convex = shape2->getCollisionShape()->isConvex();
if (isShape1Convex || isShape2Convex) {
// Add the new overlapping pair
mOverlappingPairs.addPair(shape1, shape2);
mOverlappingPairs.addPair(collider1Index, collider2Index, isShape1Convex && isShape2Convex);
}
}
}
else {
// We do not need to test the pair for overlap because it has just been reported that they still overlap
mOverlappingPairs.mNeedToTestOverlap[it->second] = false;
overlappingPair->needToTestOverlap = false;
}
}
}
@ -267,16 +299,18 @@ void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseI
mOverlappingPairs.clearObsoleteLastFrameCollisionInfos();
// For each possible convex vs convex pair of bodies
const uint64 nbConvexVsConvexPairs = mOverlappingPairs.getNbConvexVsConvexPairs();
const uint64 nbConvexVsConvexPairs = mOverlappingPairs.mConvexPairs.size();
for (uint64 i=0; i < nbConvexVsConvexPairs; i++) {
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[i]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[i]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[i]) != mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[i]));
OverlappingPairs::ConvexOverlappingPair& overlappingPair = mOverlappingPairs.mConvexPairs[i];
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider1) != -1);
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider2) != -1);
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider1) != mCollidersComponents.getBroadPhaseId(overlappingPair.collider2));
const Entity collider1Entity = mOverlappingPairs.mColliders1[i];
const Entity collider2Entity = mOverlappingPairs.mColliders2[i];
const Entity collider1Entity = overlappingPair.collider1;
const Entity collider2Entity = overlappingPair.collider2;
const uint collider1Index = mCollidersComponents.getEntityIndex(collider1Entity);
const uint collider2Index = mCollidersComponents.getEntityIndex(collider2Entity);
@ -284,7 +318,7 @@ void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseI
CollisionShape* collisionShape1 = mCollidersComponents.mCollisionShapes[collider1Index];
CollisionShape* collisionShape2 = mCollidersComponents.mCollisionShapes[collider2Index];
NarrowPhaseAlgorithmType algorithmType = mOverlappingPairs.mNarrowPhaseAlgorithmType[i];
NarrowPhaseAlgorithmType algorithmType = overlappingPair.narrowPhaseAlgorithmType;
const bool isCollider1Trigger = mCollidersComponents.mIsTrigger[collider1Index];
const bool isCollider2Trigger = mCollidersComponents.mIsTrigger[collider2Index];
@ -292,32 +326,34 @@ void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseI
// No middle-phase is necessary, simply create a narrow phase info
// for the narrow-phase collision detection
narrowPhaseInput.addNarrowPhaseTest(mOverlappingPairs.mPairIds[i], i, collider1Entity, collider2Entity, collisionShape1, collisionShape2,
mCollidersComponents.mLocalToWorldTransforms[collider1Index],
mCollidersComponents.mLocalToWorldTransforms[collider2Index],
algorithmType, reportContacts, mMemoryManager.getSingleFrameAllocator());
narrowPhaseInput.addNarrowPhaseTest(overlappingPair.pairID, collider1Entity, collider2Entity, collisionShape1, collisionShape2,
mCollidersComponents.mLocalToWorldTransforms[collider1Index],
mCollidersComponents.mLocalToWorldTransforms[collider2Index],
algorithmType, reportContacts, &overlappingPair.lastFrameCollisionInfo,
mMemoryManager.getSingleFrameAllocator());
mOverlappingPairs.mCollidingInCurrentFrame[i] = false;
overlappingPair.collidingInCurrentFrame = false;
}
// For each possible convex vs concave pair of bodies
const uint64 convexVsConcaveStartIndex = mOverlappingPairs.getConvexVsConcavePairsStartIndex();
const uint64 nbConvexVsConcavePairs = mOverlappingPairs.getNbConvexVsConcavePairs();
for (uint64 i=convexVsConcaveStartIndex; i < convexVsConcaveStartIndex + nbConvexVsConcavePairs; i++) {
const uint64 nbConcavePairs = mOverlappingPairs.mConcavePairs.size();
for (uint64 i=0; i < nbConcavePairs; i++) {
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[i]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[i]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[i]) != mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[i]));
OverlappingPairs::ConcaveOverlappingPair& overlappingPair = mOverlappingPairs.mConcavePairs[i];
computeConvexVsConcaveMiddlePhase(i, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider1) != -1);
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider2) != -1);
assert(mCollidersComponents.getBroadPhaseId(overlappingPair.collider1) != mCollidersComponents.getBroadPhaseId(overlappingPair.collider2));
mOverlappingPairs.mCollidingInCurrentFrame[i] = false;
computeConvexVsConcaveMiddlePhase(overlappingPair, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
overlappingPair.collidingInCurrentFrame = false;
}
}
// Compute the middle-phase collision detection
void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs, NarrowPhaseInput& narrowPhaseInput,
bool reportContacts) {
void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs,
NarrowPhaseInput& narrowPhaseInput, bool reportContacts) {
RP3D_PROFILE("CollisionDetectionSystem::computeMiddlePhase()", mProfiler);
@ -333,11 +369,11 @@ void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>&
const uint64 pairId = convexPairs[p];
const uint64 pairIndex = mOverlappingPairs.mMapPairIdToPairIndex[pairId];
assert(pairIndex < mOverlappingPairs.getNbPairs());
const uint64 pairIndex = mOverlappingPairs.mMapConvexPairIdToPairIndex[pairId];
assert(pairIndex < mOverlappingPairs.mConvexPairs.size());
const Entity collider1Entity = mOverlappingPairs.mColliders1[pairIndex];
const Entity collider2Entity = mOverlappingPairs.mColliders2[pairIndex];
const Entity collider1Entity = mOverlappingPairs.mConvexPairs[pairIndex].collider1;
const Entity collider2Entity = mOverlappingPairs.mConvexPairs[pairIndex].collider2;
const uint collider1Index = mCollidersComponents.getEntityIndex(collider1Entity);
const uint collider2Index = mCollidersComponents.getEntityIndex(collider2Entity);
@ -349,14 +385,14 @@ void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>&
CollisionShape* collisionShape1 = mCollidersComponents.mCollisionShapes[collider1Index];
CollisionShape* collisionShape2 = mCollidersComponents.mCollisionShapes[collider2Index];
NarrowPhaseAlgorithmType algorithmType = mOverlappingPairs.mNarrowPhaseAlgorithmType[pairIndex];
NarrowPhaseAlgorithmType algorithmType = mOverlappingPairs.mConvexPairs[pairIndex].narrowPhaseAlgorithmType;
// No middle-phase is necessary, simply create a narrow phase info
// for the narrow-phase collision detection
narrowPhaseInput.addNarrowPhaseTest(pairId, pairIndex, collider1Entity, collider2Entity, collisionShape1, collisionShape2,
narrowPhaseInput.addNarrowPhaseTest(pairId, collider1Entity, collider2Entity, collisionShape1, collisionShape2,
mCollidersComponents.mLocalToWorldTransforms[collider1Index],
mCollidersComponents.mLocalToWorldTransforms[collider2Index],
algorithmType, reportContacts, mMemoryManager.getSingleFrameAllocator());
algorithmType, reportContacts, &mOverlappingPairs.mConvexPairs[pairIndex].lastFrameCollisionInfo, mMemoryManager.getSingleFrameAllocator());
}
@ -365,23 +401,23 @@ void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>&
for (uint p=0; p < nbConcavePairs; p++) {
const uint64 pairId = concavePairs[p];
const uint64 pairIndex = mOverlappingPairs.mMapPairIdToPairIndex[pairId];
const uint64 pairIndex = mOverlappingPairs.mMapConcavePairIdToPairIndex[pairId];
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[pairIndex]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[pairIndex]) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders1[pairIndex]) != mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mColliders2[pairIndex]));
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mConcavePairs[pairIndex].collider1) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mConcavePairs[pairIndex].collider2) != -1);
assert(mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mConcavePairs[pairIndex].collider1) != mCollidersComponents.getBroadPhaseId(mOverlappingPairs.mConcavePairs[pairIndex].collider2));
computeConvexVsConcaveMiddlePhase(pairIndex, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
computeConvexVsConcaveMiddlePhase(mOverlappingPairs.mConcavePairs[pairIndex], mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
}
}
// Compute the concave vs convex middle-phase algorithm for a given pair of bodies
void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairIndex, MemoryAllocator& allocator, NarrowPhaseInput& narrowPhaseInput) {
void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(OverlappingPairs::ConcaveOverlappingPair& overlappingPair, MemoryAllocator& allocator, NarrowPhaseInput& narrowPhaseInput) {
RP3D_PROFILE("CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase()", mProfiler);
const Entity collider1 = mOverlappingPairs.mColliders1[pairIndex];
const Entity collider2 = mOverlappingPairs.mColliders2[pairIndex];
const Entity collider1 = overlappingPair.collider1;
const Entity collider2 = overlappingPair.collider2;
const uint collider1Index = mCollidersComponents.getEntityIndex(collider1);
const uint collider2Index = mCollidersComponents.getEntityIndex(collider2);
@ -394,8 +430,7 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
// Collision shape 1 is convex, collision shape 2 is concave
ConvexShape* convexShape;
ConcaveShape* concaveShape;
const bool isShape1Convex = mOverlappingPairs.mIsShape1Convex[pairIndex];
if (isShape1Convex) {
if (overlappingPair.isShape1Convex) {
convexShape = static_cast<ConvexShape*>(mCollidersComponents.mCollisionShapes[collider1Index]);
concaveShape = static_cast<ConcaveShape*>(mCollidersComponents.mCollisionShapes[collider2Index]);
convexToConcaveTransform = shape2LocalToWorldTransform.getInverse() * shape1LocalToWorldTransform;
@ -408,16 +443,16 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
assert(convexShape->isConvex());
assert(!concaveShape->isConvex());
assert(mOverlappingPairs.mNarrowPhaseAlgorithmType[pairIndex] != NarrowPhaseAlgorithmType::None);
assert(overlappingPair.narrowPhaseAlgorithmType != NarrowPhaseAlgorithmType::None);
// Compute the convex shape AABB in the local-space of the convex shape
AABB aabb;
convexShape->computeAABB(aabb, convexToConcaveTransform);
// Compute the concave shape triangles that are overlapping with the convex mesh AABB
List<Vector3> triangleVertices(allocator);
List<Vector3> triangleVerticesNormals(allocator);
List<uint> shapeIds(allocator);
List<Vector3> triangleVertices(allocator, 64);
List<Vector3> triangleVerticesNormals(allocator, 64);
List<uint> shapeIds(allocator, 64);
concaveShape->computeOverlappingTriangles(aabb, triangleVertices, triangleVerticesNormals, shapeIds, allocator);
assert(triangleVertices.size() == triangleVerticesNormals.size());
@ -429,10 +464,20 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
const bool isCollider2Trigger = mCollidersComponents.mIsTrigger[collider2Index];
const bool reportContacts = !isCollider1Trigger && !isCollider2Trigger;
CollisionShape* shape1;
CollisionShape* shape2;
if (overlappingPair.isShape1Convex) {
shape1 = convexShape;
}
else {
shape2 = convexShape;
}
// For each overlapping triangle
const uint nbShapeIds = shapeIds.size();
for (uint i=0; i < nbShapeIds; i++)
{
for (uint i=0; i < nbShapeIds; i++) {
// Create a triangle collision shape (the allocated memory for the TriangleShape will be released in the
// destructor of the corresponding NarrowPhaseInfo.
TriangleShape* triangleShape = new (allocator.allocate(sizeof(TriangleShape)))
@ -446,11 +491,20 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
#endif
if (overlappingPair.isShape1Convex) {
shape2 = triangleShape;
}
else {
shape1 = triangleShape;
}
// Add a collision info for the two collision shapes into the overlapping pair (if not present yet)
LastFrameCollisionInfo* lastFrameInfo = overlappingPair.addLastFrameInfoIfNecessary(shape1->getId(), shape2->getId());
// Create a narrow phase info for the narrow-phase collision detection
narrowPhaseInput.addNarrowPhaseTest(mOverlappingPairs.mPairIds[pairIndex], pairIndex, collider1, collider2, isShape1Convex ? convexShape : triangleShape,
isShape1Convex ? triangleShape : convexShape,
shape1LocalToWorldTransform, shape2LocalToWorldTransform,
mOverlappingPairs.mNarrowPhaseAlgorithmType[pairIndex], reportContacts, allocator);
narrowPhaseInput.addNarrowPhaseTest(overlappingPair.pairID, collider1, collider2, shape1, shape2,
shape1LocalToWorldTransform, shape2LocalToWorldTransform,
overlappingPair.narrowPhaseAlgorithmType, reportContacts, lastFrameInfo, allocator);
}
}
@ -624,7 +678,8 @@ void CollisionDetectionSystem::notifyOverlappingPairsToTestOverlap(Collider* col
// Get the overlapping pairs involved with this collider
List<uint64>& overlappingPairs = mCollidersComponents.getOverlappingPairs(collider->getEntity());
for (uint i=0; i < overlappingPairs.size(); i++) {
const uint nbPairs = overlappingPairs.size();
for (uint i=0; i < nbPairs; i++) {
// Notify that the overlapping pair needs to be testbed for overlap
mOverlappingPairs.setNeedToTestOverlap(overlappingPairs[i], true);
@ -802,17 +857,34 @@ void CollisionDetectionSystem::createContacts() {
// Compute the lost contact pairs (contact pairs in contact in the previous frame but not in the current one)
void CollisionDetectionSystem::computeLostContactPairs() {
// For each overlapping pair
for (uint i=0; i < mOverlappingPairs.getNbPairs(); i++) {
// For each convex pair
const uint nbConvexPairs = mOverlappingPairs.mConvexPairs.size();
for (uint i=0; i < nbConvexPairs; i++) {
// If the two colliders of the pair were colliding in the previous frame but not in the current one
if (mOverlappingPairs.mCollidingInPreviousFrame[i] && !mOverlappingPairs.mCollidingInCurrentFrame[i]) {
if (mOverlappingPairs.mConvexPairs[i].collidingInPreviousFrame && !mOverlappingPairs.mConvexPairs[i].collidingInCurrentFrame) {
// If both bodies still exist
if (mCollidersComponents.hasComponent(mOverlappingPairs.mColliders1[i]) && mCollidersComponents.hasComponent(mOverlappingPairs.mColliders2[i])) {
if (mCollidersComponents.hasComponent(mOverlappingPairs.mConvexPairs[i].collider1) && mCollidersComponents.hasComponent(mOverlappingPairs.mConvexPairs[i].collider2)) {
// Create a lost contact pair
addLostContactPair(i);
addLostContactPair(mOverlappingPairs.mConvexPairs[i]);
}
}
}
// For each convex pair
const uint nbConcavePairs = mOverlappingPairs.mConcavePairs.size();
for (uint i=0; i < nbConcavePairs; i++) {
// If the two colliders of the pair were colliding in the previous frame but not in the current one
if (mOverlappingPairs.mConcavePairs[i].collidingInPreviousFrame && !mOverlappingPairs.mConcavePairs[i].collidingInCurrentFrame) {
// If both bodies still exist
if (mCollidersComponents.hasComponent(mOverlappingPairs.mConcavePairs[i].collider1) && mCollidersComponents.hasComponent(mOverlappingPairs.mConcavePairs[i].collider2)) {
// Create a lost contact pair
addLostContactPair(mOverlappingPairs.mConcavePairs[i]);
}
}
}
@ -1025,13 +1097,14 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
// For each narrow phase info object
for(uint i=0; i < nbObjects; i++) {
const uint64 pairId = narrowPhaseInfoBatch.narrowPhaseInfos[i].overlappingPairId;
const uint64 pairIndex = mOverlappingPairs.mMapPairIdToPairIndex[pairId];
// If the two colliders are colliding
if (narrowPhaseInfoBatch.narrowPhaseInfos[i].isColliding) {
mOverlappingPairs.mCollidingInCurrentFrame[pairIndex] = true;
const uint64 pairId = narrowPhaseInfoBatch.narrowPhaseInfos[i].overlappingPairId;
OverlappingPairs::OverlappingPair* overlappingPair = mOverlappingPairs.getOverlappingPair(pairId);
assert(overlappingPair != nullptr);
overlappingPair->collidingInCurrentFrame = true;
const Entity collider1Entity = narrowPhaseInfoBatch.narrowPhaseInfos[i].colliderEntity1;
const Entity collider2Entity = narrowPhaseInfoBatch.narrowPhaseInfos[i].colliderEntity2;
@ -1043,8 +1116,7 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
const Entity body2Entity = mCollidersComponents.mBodiesEntities[collider2Index];
// If we have a convex vs convex collision (if we consider the base collision shapes of the colliders)
if (mCollidersComponents.mCollisionShapes[collider1Index]->isConvex() &&
mCollidersComponents.mCollisionShapes[collider2Index]->isConvex()) {
if (mCollidersComponents.mCollisionShapes[collider1Index]->isConvex() && mCollidersComponents.mCollisionShapes[collider2Index]->isConvex()) {
// Create a new ContactPair
@ -1055,7 +1127,7 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
const uint newContactPairIndex = contactPairs->size();
contactPairs->emplace(pairId, body1Entity, body2Entity, collider1Entity, collider2Entity,
newContactPairIndex, mOverlappingPairs.getCollidingInPreviousFrame(pairId), isTrigger);
newContactPairIndex, overlappingPair->collidingInPreviousFrame, isTrigger);
ContactPair* pairContact = &((*contactPairs)[newContactPairIndex]);
@ -1102,7 +1174,7 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
const uint newContactPairIndex = contactPairs->size();
contactPairs->emplace(pairId, body1Entity, body2Entity, collider1Entity, collider2Entity,
newContactPairIndex, mOverlappingPairs.getCollidingInPreviousFrame(pairId), isTrigger);
newContactPairIndex, overlappingPair->collidingInPreviousFrame , isTrigger);
pairContact = &((*contactPairs)[newContactPairIndex]);
mapPairIdToContactPairIndex.add(Pair<uint64, uint>(pairId, newContactPairIndex));
@ -1236,9 +1308,7 @@ void CollisionDetectionSystem::reducePotentialContactManifolds(List<ContactPair>
// If there are two many contact points in the manifold
if (manifold.nbPotentialContactPoints > MAX_CONTACT_POINTS_IN_MANIFOLD) {
Entity collider1 = mOverlappingPairs.mColliders1[mOverlappingPairs.mMapPairIdToPairIndex[manifold.pairId]];
Transform shape1LocalToWorldTransoform = mCollidersComponents.getLocalToWorldTransform(collider1);
Transform shape1LocalToWorldTransoform = mCollidersComponents.getLocalToWorldTransform(pairContact.collider1Entity);
// Reduce the number of contact points in the manifold
reduceContactPoints(manifold, shape1LocalToWorldTransoform, potentialContactPoints);
@ -1655,18 +1725,25 @@ void CollisionDetectionSystem::testCollision(CollisionCallback& callback) {
// Filter the overlapping pairs to keep only the pairs where a given body is involved
void CollisionDetectionSystem::filterOverlappingPairs(Entity bodyEntity, List<uint64>& convexPairs, List<uint64>& concavePairs) const {
// For each possible collision pair of bodies
for (uint i=0; i < mOverlappingPairs.getNbPairs(); i++) {
// For each convex pairs
const uint nbConvexPairs = mOverlappingPairs.mConvexPairs.size();
for (uint i=0; i < nbConvexPairs; i++) {
if (mCollidersComponents.getBody(mOverlappingPairs.mColliders1[i]) == bodyEntity ||
mCollidersComponents.getBody(mOverlappingPairs.mColliders2[i]) == bodyEntity) {
if (mCollidersComponents.getBody(mOverlappingPairs.mConvexPairs[i].collider1) == bodyEntity ||
mCollidersComponents.getBody(mOverlappingPairs.mConvexPairs[i].collider2) == bodyEntity) {
if (i < mOverlappingPairs.getNbConvexVsConvexPairs()) {
convexPairs.add(mOverlappingPairs.mPairIds[i]);
}
else {
concavePairs.add(mOverlappingPairs.mPairIds[i]);
}
convexPairs.add(mOverlappingPairs.mConvexPairs[i].pairID);
}
}
// For each concave pairs
const uint nbConcavePairs = mOverlappingPairs.mConcavePairs.size();
for (uint i=0; i < nbConcavePairs; i++) {
if (mCollidersComponents.getBody(mOverlappingPairs.mConcavePairs[i].collider1) == bodyEntity ||
mCollidersComponents.getBody(mOverlappingPairs.mConcavePairs[i].collider2) == bodyEntity) {
concavePairs.add(mOverlappingPairs.mConcavePairs[i].pairID);
}
}
}
@ -1674,21 +1751,31 @@ void CollisionDetectionSystem::filterOverlappingPairs(Entity bodyEntity, List<ui
// Filter the overlapping pairs to keep only the pairs where two given bodies are involved
void CollisionDetectionSystem::filterOverlappingPairs(Entity body1Entity, Entity body2Entity, List<uint64>& convexPairs, List<uint64>& concavePairs) const {
// For each possible collision pair of bodies
for (uint i=0; i < mOverlappingPairs.getNbPairs(); i++) {
// For each convex pair
const uint nbConvexPairs = mOverlappingPairs.mConvexPairs.size();
for (uint i=0; i < nbConvexPairs; i++) {
const Entity collider1Body = mCollidersComponents.getBody(mOverlappingPairs.mColliders1[i]);
const Entity collider2Body = mCollidersComponents.getBody(mOverlappingPairs.mColliders2[i]);
const Entity collider1Body = mCollidersComponents.getBody(mOverlappingPairs.mConvexPairs[i].collider1);
const Entity collider2Body = mCollidersComponents.getBody(mOverlappingPairs.mConvexPairs[i].collider2);
if ((collider1Body == body1Entity && collider2Body == body2Entity) ||
(collider1Body == body2Entity && collider2Body == body1Entity)) {
if (i < mOverlappingPairs.getNbConvexVsConvexPairs()) {
convexPairs.add(mOverlappingPairs.mPairIds[i]);
}
else {
concavePairs.add(mOverlappingPairs.mPairIds[i]);
}
convexPairs.add(mOverlappingPairs.mConvexPairs[i].pairID);
}
}
// For each concave pair
const uint nbConcavePairs = mOverlappingPairs.mConcavePairs.size();
for (uint i=0; i < nbConcavePairs; i++) {
const Entity collider1Body = mCollidersComponents.getBody(mOverlappingPairs.mConcavePairs[i].collider1);
const Entity collider2Body = mCollidersComponents.getBody(mOverlappingPairs.mConcavePairs[i].collider2);
if ((collider1Body == body1Entity && collider2Body == body2Entity) ||
(collider1Body == body2Entity && collider2Body == body1Entity)) {
concavePairs.add(mOverlappingPairs.mConcavePairs[i].pairID);
}
}
}