diff --git a/include/reactphysics3d/collision/narrowphase/NarrowPhaseInfoBatch.h b/include/reactphysics3d/collision/narrowphase/NarrowPhaseInfoBatch.h index bcad2c5b..73b44cb3 100644 --- a/include/reactphysics3d/collision/narrowphase/NarrowPhaseInfoBatch.h +++ b/include/reactphysics3d/collision/narrowphase/NarrowPhaseInfoBatch.h @@ -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); diff --git a/include/reactphysics3d/collision/narrowphase/NarrowPhaseInput.h b/include/reactphysics3d/collision/narrowphase/NarrowPhaseInput.h index 639117a7..9f64574a 100644 --- a/include/reactphysics3d/collision/narrowphase/NarrowPhaseInput.h +++ b/include/reactphysics3d/collision/narrowphase/NarrowPhaseInput.h @@ -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 diff --git a/include/reactphysics3d/engine/OverlappingPairs.h b/include/reactphysics3d/engine/OverlappingPairs.h index 206d43bc..e00dcd54 100644 --- a/include/reactphysics3d/engine/OverlappingPairs.h +++ b/include/reactphysics3d/engine/OverlappingPairs.h @@ -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 diff --git a/include/reactphysics3d/systems/CollisionDetectionSystem.h b/include/reactphysics3d/systems/CollisionDetectionSystem.h index 683df3cc..5cb28461 100644 --- a/include/reactphysics3d/systems/CollisionDetectionSystem.h +++ b/include/reactphysics3d/systems/CollisionDetectionSystem.h @@ -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 diff --git a/src/collision/broadphase/DynamicAABBTree.cpp b/src/collision/broadphase/DynamicAABBTree.cpp index a5a7ad21..655e3a1e 100644 --- a/src/collision/broadphase/DynamicAABBTree.cpp +++ b/src/collision/broadphase/DynamicAABBTree.cpp @@ -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; diff --git a/src/collision/narrowphase/NarrowPhaseInfoBatch.cpp b/src/collision/narrowphase/NarrowPhaseInfoBatch.cpp index d0266741..dcde890e 100644 --- a/src/collision/narrowphase/NarrowPhaseInfoBatch.cpp +++ b/src/collision/narrowphase/NarrowPhaseInfoBatch.cpp @@ -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) { diff --git a/src/collision/shapes/ConcaveMeshShape.cpp b/src/collision/shapes/ConcaveMeshShape.cpp index c395b0ec..f977b752 100644 --- a/src/collision/shapes/ConcaveMeshShape.cpp +++ b/src/collision/shapes/ConcaveMeshShape.cpp @@ -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(); diff --git a/src/collision/shapes/HeightFieldShape.cpp b/src/collision/shapes/HeightFieldShape.cpp index 7c2e99cd..dd056ca3 100644 --- a/src/collision/shapes/HeightFieldShape.cpp +++ b/src/collision/shapes/HeightFieldShape.cpp @@ -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()); diff --git a/src/engine/OverlappingPairs.cpp b/src/engine/OverlappingPairs.cpp index 543a32ef..c0ad16ef 100644 --- a/src/engine/OverlappingPairs.cpp +++ b/src/engine/OverlappingPairs.cpp @@ -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; } } diff --git a/src/systems/BroadPhaseSystem.cpp b/src/systems/BroadPhaseSystem.cpp index 53a2993e..8c1326a6 100644 --- a/src/systems/BroadPhaseSystem.cpp +++ b/src/systems/BroadPhaseSystem.cpp @@ -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); diff --git a/src/systems/CollisionDetectionSystem.cpp b/src/systems/CollisionDetectionSystem.cpp index 4315cdb5..ab706182 100644 --- a/src/systems/CollisionDetectionSystem.cpp +++ b/src/systems/CollisionDetectionSystem.cpp @@ -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); } } }