Improve EventListener: add onTrigger() method, add event types, add triggers, ...

This commit is contained in:
Daniel Chappuis 2020-04-18 20:43:13 +02:00
parent a190bba8c0
commit dcd71ef103
46 changed files with 758 additions and 418 deletions

View File

@ -20,6 +20,9 @@
- The RigidBody::getLocalInertiaTensor() method has been added to retrieve the local-space inertia tensor of a rigid body.
- The RigidBody::updateMassFromColliders() method has been added to compute and set the mass of a body using its colliders
- A Material nows has a mass density parameter that can be set using the Material::setMassDensity() method. The mass density is used to compute the mass of a collider when computing the mass of a rigid body
- A Collider can now be a trigger. This collider will be used to only report collisions with another collider but no collision response will be applied. You can use the Collider::setIsTrigger() method for this.
- The EventListener class now has a onTrigger() method that is called when a trigger collider is colling with another collider.
- In the EventListener, the onContact() and onTrigger() method now reports the type of event (start, stay, exit) for each contact. This way the user can know whether it's a new contact or not or when two colliders are not in contact anymore.
### Fixed

View File

@ -160,6 +160,12 @@ class Collider {
/// Set a new material for this collider
void setMaterial(const Material& material);
/// Return true if the collider is a trigger
bool getIsTrigger() const;
/// Set whether the collider is a trigger
void setIsTrigger(bool isTrigger) const;
#ifdef IS_PROFILING_ACTIVE
/// Set the profiler

View File

@ -108,6 +108,22 @@ class CollisionCallback {
*/
class ContactPair {
public:
/// Enumeration EventType that describes the type of contact event
enum class EventType {
/// This contact is a new contact between the two
/// colliders (the colliders where not touching in the previous frame)
ContactStart,
/// The two colliders were already touching in the previous frame and this is a new or updated contact
ContactStay,
/// The two colliders were in contact in the previous frame and are not in contact anymore
ContactExit
};
private:
// -------------------- Attributes -------------------- //
@ -120,11 +136,14 @@ class CollisionCallback {
/// Reference to the physics world
PhysicsWorld& mWorld;
/// True if this is a lost contact pair (contact pair colliding in previous frame but not in current one)
bool mIsLostContactPair;
// -------------------- Methods -------------------- //
/// Constructor
ContactPair(const reactphysics3d::ContactPair& contactPair, List<reactphysics3d::ContactPoint>* contactPoints,
PhysicsWorld& world);
ContactPair(const reactphysics3d::ContactPair& contactPair, List<reactphysics3d::ContactPoint>* contactPoints,
PhysicsWorld& world, bool mIsLostContactPair);
public:
@ -157,6 +176,9 @@ class CollisionCallback {
/// Return a pointer to the second collider in contact (in body 2)
Collider* getCollider2() const;
/// Return the corresponding type of event for this contact pair
EventType getEventType() const;
// -------------------- Friendship -------------------- //
friend class CollisionCallback;
@ -172,7 +194,7 @@ class CollisionCallback {
// -------------------- Attributes -------------------- //
/// Pointer to the list of contact pairs
/// Pointer to the list of contact pairs (contains contacts and triggers events)
List<reactphysics3d::ContactPair>* mContactPairs;
/// Pointer to the list of contact manifolds
@ -181,6 +203,15 @@ class CollisionCallback {
/// Pointer to the contact points
List<reactphysics3d::ContactPoint>* mContactPoints;
/// Pointer to the list of lost contact pairs (contains contacts and triggers events)
List<reactphysics3d::ContactPair>& mLostContactPairs;
/// List of indices of the mContactPairs list that are contact events (not overlap/triggers)
List<uint> mContactPairsIndices;
/// List of indices of the mLostContactPairs list that are contact events (not overlap/triggers)
List<uint> mLostContactPairsIndices;
/// Reference to the physics world
PhysicsWorld& mWorld;
@ -188,7 +219,8 @@ class CollisionCallback {
/// Constructor
CallbackData(List<reactphysics3d::ContactPair>* contactPairs, List<ContactManifold>* manifolds,
List<reactphysics3d::ContactPoint>* contactPoints, PhysicsWorld& world);
List<reactphysics3d::ContactPoint>* contactPoints, List<reactphysics3d::ContactPair>& lostContactPairs,
PhysicsWorld& world);
/// Deleted copy constructor
CallbackData(const CallbackData& callbackData) = delete;
@ -226,7 +258,7 @@ class CollisionCallback {
* @return The number of contact pairs
*/
inline uint CollisionCallback::CallbackData::getNbContactPairs() const {
return mContactPairs->size();
return mContactPairsIndices.size() + mLostContactPairsIndices.size();
}
// Return the number of contact points in the contact pair

View File

@ -80,15 +80,21 @@ struct ContactPair {
/// Total number of contact points in all the manifolds of the contact pair
uint nbToTalContactPoints;
/// True if the colliders of the pair were already colliding in the previous frame
bool collidingInPreviousFrame;
/// True if one of the two involved colliders is a trigger
bool isTrigger;
// -------------------- Methods -------------------- //
/// Constructor
ContactPair(uint64 pairId, Entity body1Entity, Entity body2Entity, Entity collider1Entity,
Entity collider2Entity, uint contactPairIndex, MemoryAllocator& allocator)
Entity collider2Entity, uint contactPairIndex, bool collidingInPreviousFrame, bool isTrigger, MemoryAllocator& allocator)
: pairId(pairId), potentialContactManifoldsIndices(allocator), body1Entity(body1Entity), body2Entity(body2Entity),
collider1Entity(collider1Entity), collider2Entity(collider2Entity),
isAlreadyInIsland(false), contactPairIndex(contactPairIndex), contactManifoldsIndex(0), nbContactManifolds(0),
contactPointsIndex(0), nbToTalContactPoints(0) {
contactPointsIndex(0), nbToTalContactPoints(0), collidingInPreviousFrame(collidingInPreviousFrame), isTrigger(isTrigger) {
}
};

View File

@ -28,6 +28,7 @@
// Libraries
#include <reactphysics3d/containers/List.h>
#include <reactphysics3d/collision/ContactPair.h>
/// ReactPhysics3D namespace
namespace reactphysics3d {
@ -53,20 +54,39 @@ class OverlapCallback {
*/
class OverlapPair {
public:
/// Enumeration EventType that describes the type of overlapping event
enum class EventType {
/// This overlap is a new overlap between the two
/// colliders (the colliders where not overlapping in the previous frame)
OverlapStart,
/// The two colliders were already overlapping in the previous frame and this is a new or updated overlap
OverlapStay,
/// The two colliders were overlapping in the previous frame and are not overlapping anymore
OverlapExit
};
private:
// -------------------- Attributes -------------------- //
/// Pair of overlapping body entities
Pair<Entity, Entity>& mOverlapPair;
/// Contact pair
ContactPair& mContactPair;
/// Reference to the physics world
PhysicsWorld& mWorld;
/// True if the pair were overlapping in the previous frame but not in the current one
bool mIsLostOverlapPair;
// -------------------- Methods -------------------- //
/// Constructor
OverlapPair(Pair<Entity, Entity>& overlapPair, reactphysics3d::PhysicsWorld& world);
OverlapPair(ContactPair& contactPair, reactphysics3d::PhysicsWorld& world, bool isLostOverlappingPair);
public:
@ -81,12 +101,21 @@ class OverlapCallback {
/// Destructor
~OverlapPair() = default;
/// Return a pointer to the first collider in contact
Collider* getCollider1() const;
/// Return a pointer to the second collider in contact
Collider* getCollider2() const;
/// Return a pointer to the first body in contact
CollisionBody* getBody1() const;
/// Return a pointer to the second body in contact
CollisionBody* getBody2() const;
/// Return the corresponding type of event for this overlapping pair
EventType getEventType() const;
// -------------------- Friendship -------------------- //
friend class OverlapCallback;
@ -102,7 +131,17 @@ class OverlapCallback {
// -------------------- Attributes -------------------- //
List<Pair<Entity, Entity>>& mOverlapBodies;
/// Reference to the list of contact pairs (contains contacts and triggers events)
List<ContactPair>& mContactPairs;
/// Reference to the list of lost contact pairs (contains contacts and triggers events)
List<ContactPair>& mLostContactPairs;
/// List of indices of the mContactPairs list that are overlap/triggers events (not contact events)
List<uint> mContactPairsIndices;
/// List of indices of the mLostContactPairs list that are overlap/triggers events (not contact events)
List<uint> mLostContactPairsIndices;
/// Reference to the physics world
PhysicsWorld& mWorld;
@ -110,7 +149,7 @@ class OverlapCallback {
// -------------------- Methods -------------------- //
/// Constructor
CallbackData(List<Pair<Entity, Entity>>& overlapColliders, PhysicsWorld& world);
CallbackData(List<ContactPair>& contactPairs, List<ContactPair>& lostContactPairs, PhysicsWorld& world);
/// Deleted copy constructor
CallbackData(const CallbackData& callbackData) = delete;
@ -147,7 +186,7 @@ class OverlapCallback {
// Return the number of overlapping pairs of bodies
inline uint OverlapCallback::CallbackData::getNbOverlappingPairs() const {
return mOverlapBodies.size();
return mContactPairsIndices.size() + mLostContactPairsIndices.size();
}
// Return a given overlapping pair of bodies
@ -158,7 +197,15 @@ inline OverlapCallback::OverlapPair OverlapCallback::CallbackData::getOverlappin
assert(index < getNbOverlappingPairs());
return OverlapPair(mOverlapBodies[index], mWorld);
if (index < mContactPairsIndices.size()) {
// Return a contact pair
return OverlapCallback::OverlapPair((mContactPairs)[mContactPairsIndices[index]], mWorld, false);
}
else {
// Return a lost contact pair
return OverlapCallback::OverlapPair(mLostContactPairs[mLostContactPairsIndices[index - mContactPairsIndices.size()]], mWorld, true);
}
}
}

View File

@ -67,7 +67,7 @@ class CapsuleVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
/// Compute the narrow-phase collision detection between two capsules
bool testCollision(CapsuleVsCapsuleNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, bool reportContacts, MemoryAllocator& memoryAllocator);
uint batchNbItems, MemoryAllocator& memoryAllocator);
};
}

View File

@ -58,18 +58,18 @@ struct CapsuleVsCapsuleNarrowPhaseInfoBatch : public NarrowPhaseInfoBatch {
CapsuleVsCapsuleNarrowPhaseInfoBatch(MemoryAllocator& allocator, OverlappingPairs& overlappingPairs);
/// Destructor
virtual ~CapsuleVsCapsuleNarrowPhaseInfoBatch() = default;
virtual ~CapsuleVsCapsuleNarrowPhaseInfoBatch() override = default;
/// Add shapes to be tested during narrow-phase collision detection into the batch
virtual void addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform);
const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator& shapeAllocator) override;
// Initialize the containers using cached capacity
virtual void reserveMemory();
virtual void reserveMemory() override;
/// Clear all the objects in the batch
virtual void clear();
virtual void clear() override;
};
}

View File

@ -70,7 +70,7 @@ class CapsuleVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm {
/// Compute the narrow-phase collision detection between a capsule and a polyhedron
bool testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, bool reportContacts, bool clipWithPreviousAxisIfStillColliding,
uint batchNbItems, bool clipWithPreviousAxisIfStillColliding,
MemoryAllocator& memoryAllocator);
};

View File

@ -64,7 +64,7 @@ class ConvexPolyhedronVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm
ConvexPolyhedronVsConvexPolyhedronAlgorithm& operator=(const ConvexPolyhedronVsConvexPolyhedronAlgorithm& algorithm) = delete;
/// Compute the narrow-phase collision detection between two convex polyhedra
bool testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems, bool reportContacts,
bool testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator);
};

View File

@ -98,7 +98,7 @@ class GJKAlgorithm {
/// Compute a contact info if the two bounding volumes collide.
void testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, List<GJKResult>& gjkResults, bool reportContacts);
uint batchNbItems, List<GJKResult>& gjkResults);
#ifdef IS_PROFILING_ACTIVE

View File

@ -81,6 +81,9 @@ struct NarrowPhaseInfoBatch {
/// List of transforms that maps from collision shape 2 local-space to world-space
List<Transform> shape2ToWorldTransforms;
/// True for each pair of objects that we need to report contacts (false for triggers for instance)
List<bool> reportContacts;
/// Result of the narrow-phase collision detection test
List<bool> isColliding;
@ -103,9 +106,9 @@ struct NarrowPhaseInfoBatch {
uint getNbObjects() const;
/// 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,
virtual void addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform, MemoryAllocator& shapeAllocator);
const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator& shapeAllocator);
/// Add a new contact point
virtual void addContactPoint(uint index, const Vector3& contactNormal, decimal penDepth,

View File

@ -61,6 +61,7 @@ class NarrowPhaseInput {
NarrowPhaseInfoBatch mSphereVsConvexPolyhedronBatch;
NarrowPhaseInfoBatch mCapsuleVsConvexPolyhedronBatch;
NarrowPhaseInfoBatch mConvexPolyhedronVsConvexPolyhedronBatch;
public:
/// Constructor
@ -69,7 +70,7 @@ class NarrowPhaseInput {
/// 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,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform, NarrowPhaseAlgorithmType narrowPhaseAlgorithmType,
const Transform& shape2Transform, NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, bool reportContacts,
MemoryAllocator& shapeAllocator);
/// Get a reference to the sphere vs sphere batch
@ -98,32 +99,32 @@ class NarrowPhaseInput {
};
// Get a reference to the sphere vs sphere batch
// Get a reference to the sphere vs sphere batch contacts
inline SphereVsSphereNarrowPhaseInfoBatch& NarrowPhaseInput::getSphereVsSphereBatch() {
return mSphereVsSphereBatch;
}
// Get a reference to the sphere vs capsule batch
// Get a reference to the sphere vs capsule batch contacts
inline SphereVsCapsuleNarrowPhaseInfoBatch& NarrowPhaseInput::getSphereVsCapsuleBatch() {
return mSphereVsCapsuleBatch;
}
// Get a reference to the capsule vs capsule batch
// Get a reference to the capsule vs capsule batch contacts
inline CapsuleVsCapsuleNarrowPhaseInfoBatch& NarrowPhaseInput::getCapsuleVsCapsuleBatch() {
return mCapsuleVsCapsuleBatch;
}
// Get a reference to the sphere vs convex polyhedron batch
// Get a reference to the sphere vs convex polyhedron batch contacts
inline NarrowPhaseInfoBatch& NarrowPhaseInput::getSphereVsConvexPolyhedronBatch() {
return mSphereVsConvexPolyhedronBatch;
}
// Get a reference to the capsule vs convex polyhedron batch
// Get a reference to the capsule vs convex polyhedron batch contacts
inline NarrowPhaseInfoBatch& NarrowPhaseInput::getCapsuleVsConvexPolyhedronBatch() {
return mCapsuleVsConvexPolyhedronBatch;
}
// Get a reference to the convex polyhedron vs convex polyhedron batch
// Get a reference to the convex polyhedron vs convex polyhedron batch contacts
inline NarrowPhaseInfoBatch& NarrowPhaseInput::getConvexPolyhedronVsConvexPolyhedronBatch() {
return mConvexPolyhedronVsConvexPolyhedronBatch;
}

View File

@ -154,11 +154,10 @@ class SATAlgorithm {
/// Test collision between a sphere and a convex mesh
bool testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch,
uint batchStartIndex, uint batchNbItems,
bool reportContacts) const;
uint batchStartIndex, uint batchNbItems) const;
/// Test collision between a capsule and a convex mesh
bool testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchIndex, bool reportContacts) const;
bool testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchIndex) const;
/// Compute the two contact points between a polyhedron and a capsule when the separating axis is a face normal of the polyhedron
bool computeCapsulePolyhedronFaceContactPoints(uint referenceFaceIndex, decimal capsuleRadius, const ConvexPolyhedronShape* polyhedron,
@ -172,8 +171,7 @@ class SATAlgorithm {
const Vector3& edgeAdjacentFace2Normal) const;
/// Test collision between two convex meshes
bool testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, bool reportContacts) const;
bool testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems) const;
#ifdef IS_PROFILING_ACTIVE

View File

@ -66,7 +66,7 @@ class SphereVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
/// Compute the narrow-phase collision detection between a sphere and a capsule
bool testCollision(SphereVsCapsuleNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, bool reportContacts, MemoryAllocator& memoryAllocator);
uint batchNbItems, MemoryAllocator& memoryAllocator);
};
}

View File

@ -58,18 +58,18 @@ struct SphereVsCapsuleNarrowPhaseInfoBatch : public NarrowPhaseInfoBatch {
SphereVsCapsuleNarrowPhaseInfoBatch(MemoryAllocator& allocator, OverlappingPairs& overlappingPairs);
/// Destructor
virtual ~SphereVsCapsuleNarrowPhaseInfoBatch() = default;
virtual ~SphereVsCapsuleNarrowPhaseInfoBatch() override = default;
/// Add shapes to be tested during narrow-phase collision detection into the batch
virtual void addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform);
const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator& shapeAllocator) override;
// Initialize the containers using cached capacity
virtual void reserveMemory();
virtual void reserveMemory() override;
/// Clear all the objects in the batch
virtual void clear();
virtual void clear() override;
};
}

View File

@ -70,7 +70,7 @@ class SphereVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm {
SphereVsConvexPolyhedronAlgorithm& operator=(const SphereVsConvexPolyhedronAlgorithm& algorithm) = delete;
/// Compute the narrow-phase collision detection between a sphere and a convex polyhedron
bool testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems, bool reportContacts,
bool testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator);
};

View File

@ -66,7 +66,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
/// Compute a contact info if the two bounding volume collide
bool testCollision(SphereVsSphereNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, bool reportContacts, MemoryAllocator& memoryAllocator);
uint batchNbItems, MemoryAllocator& memoryAllocator);
};
}

View File

@ -55,9 +55,9 @@ struct SphereVsSphereNarrowPhaseInfoBatch : public NarrowPhaseInfoBatch {
virtual ~SphereVsSphereNarrowPhaseInfoBatch() override = default;
/// Add shapes to be tested during narrow-phase collision detection into the batch
virtual void addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
virtual void addNarrowPhaseInfo(uint64 airId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1,
CollisionShape* shape2, const Transform& shape1Transform,
const Transform& shape2Transform);
const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator& shapeAllocator) override;
// Initialize the containers using cached capacity
virtual void reserveMemory() override;

View File

@ -96,6 +96,9 @@ class ColliderComponents : public Components {
/// has been changed by the user
bool* mHasCollisionShapeChangedSize;
/// True if the collider is a trigger
bool* mIsTrigger;
// -------------------- Methods -------------------- //
@ -192,9 +195,15 @@ class ColliderComponents : public Components {
/// Return true if the size of collision shape of the collider has been changed by the user
bool getHasCollisionShapeChangedSize(Entity colliderEntity) const;
/// Return true if the size of collision shape of the collider has been changed by the user
/// Set whether the size of collision shape of the collider has been changed by the user
void setHasCollisionShapeChangedSize(Entity colliderEntity, bool hasCollisionShapeChangedSize);
/// Return true if a collider is a trigger
bool getIsTrigger(Entity colliderEntity) const;
/// Set whether a collider is a trigger
void setIsTrigger(Entity colliderEntity, bool isTrigger);
// -------------------- Friendship -------------------- //
friend class BroadPhaseSystem;
@ -331,6 +340,23 @@ inline void ColliderComponents::setHasCollisionShapeChangedSize(Entity colliderE
mHasCollisionShapeChangedSize[mMapEntityToComponentIndex[colliderEntity]] = hasCollisionShapeChangedSize;
}
// Return true if a collider is a trigger
inline bool ColliderComponents::getIsTrigger(Entity colliderEntity) const {
assert(mMapEntityToComponentIndex.containsKey(colliderEntity));
return mIsTrigger[mMapEntityToComponentIndex[colliderEntity]];
}
// Set whether a collider is a trigger
inline void ColliderComponents::setIsTrigger(Entity colliderEntity, bool isTrigger) {
assert(mMapEntityToComponentIndex.containsKey(colliderEntity));
mIsTrigger[mMapEntityToComponentIndex[colliderEntity]] = isTrigger;
}
}
#endif

View File

@ -110,7 +110,6 @@ class RigidBodyComponents : public Components {
Vector3* mLocalInertiaTensors;
/// Array with the inverse of the inertia tensor of each component
// TODO : We should use a Vector3 here for the diagonal instead of a Matrix3x3
Vector3* mInverseInertiaTensorsLocal;
/// Array with the constrained linear velocity of each component

View File

@ -28,6 +28,7 @@
// Libraries
#include <reactphysics3d/collision/CollisionCallback.h>
#include <reactphysics3d/collision/OverlapCallback.h>
namespace reactphysics3d {
@ -54,6 +55,12 @@ class EventListener : public CollisionCallback {
* @param collisionInfo Information about the contacts
*/
virtual void onContact(const CollisionCallback::CallbackData& callbackData) override {}
/// Called when some trigger events occur
virtual void onTrigger(const OverlapCallback::CallbackData& callbackData) {}
/// Called to report rigid bodies that started to sleep or has woken up in the previous frame
virtual void onSleep() {}
};
}

View File

@ -173,6 +173,12 @@ class OverlappingPairs {
/// 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;
/// Reference to the colliders components
ColliderComponents& mColliderComponents;
@ -276,12 +282,21 @@ class OverlappingPairs {
/// Delete all the obsolete last frame collision info
void clearObsoleteLastFrameCollisionInfos();
/// Set the collidingInPreviousFrame value with the collidinginCurrentFrame value for each pair
void updateCollidingInPreviousFrame();
/// Return the pair of bodies index of the pair
static bodypair computeBodiesIndexPair(Entity body1Entity, Entity body2Entity);
/// 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);
#ifdef IS_PROFILING_ACTIVE
/// Set the profiler
@ -380,6 +395,18 @@ inline void OverlappingPairs::setNeedToTestOverlap(uint64 pairId, bool needToTes
mNeedToTestOverlap[mMapPairIdToPairIndex[pairId]] = needToTestOverlap;
}
// Return true if the two colliders of the pair were already colliding the previous frame
inline bool OverlappingPairs::getCollidingInPreviousFrame(uint64 pairId) const {
assert(mMapPairIdToPairIndex.containsKey(pairId));
return mCollidingInPreviousFrame[mMapPairIdToPairIndex[pairId]];
}
// Set to true if the two colliders of the pair were already colliding the previous frame
inline void OverlappingPairs::setCollidingInPreviousFrame(uint64 pairId, bool wereCollidingInPreviousFrame) {
assert(mMapPairIdToPairIndex.containsKey(pairId));
mCollidingInPreviousFrame[mMapPairIdToPairIndex[pairId]] = wereCollidingInPreviousFrame;
}
#ifdef IS_PROFILING_ACTIVE
// Set the profiler

View File

@ -481,6 +481,8 @@ class PhysicsWorld {
friend class FixedJoint;
friend class HingeJoint;
friend class SliderJoint;
friend class CollisionCallback::CallbackData;
friend class OverlapCallback::CallbackData;
};
// Set the collision dispatch configuration

View File

@ -122,6 +122,9 @@ class CollisionDetectionSystem {
/// Pointer to the list of contact pairs of the current frame (either mContactPairs1 or mContactPairs2)
List<ContactPair>* mCurrentContactPairs;
/// List of lost contact pairs (contact pairs in contact in previous frame but not in the current one)
List<ContactPair> mLostContactPairs;
/// First map of overlapping pair id to the index of the corresponding pair contact
Map<uint64, uint> mMapPairIdToContactPairIndex1;
@ -176,10 +179,11 @@ class CollisionDetectionSystem {
void computeBroadPhase();
/// Compute the middle-phase collision detection
void computeMiddlePhase(NarrowPhaseInput& narrowPhaseInput);
void computeMiddlePhase(NarrowPhaseInput& narrowPhaseInput, bool needToReportContacts);
// Compute the middle-phase collision detection
void computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs, NarrowPhaseInput& narrowPhaseInput);
void computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs, NarrowPhaseInput& narrowPhaseInput,
bool reportContacts);
/// Compute the narrow-phase collision detection
void computeNarrowPhase();
@ -191,10 +195,11 @@ class CollisionDetectionSystem {
bool computeNarrowPhaseCollisionSnapshot(NarrowPhaseInput& narrowPhaseInput, CollisionCallback& callback);
/// Process the potential contacts after narrow-phase collision detection
void computeSnapshotContactPairs(NarrowPhaseInput& narrowPhaseInput, List<Pair<Entity, Entity>>& overlapPairs) const;
void computeOverlapSnapshotContactPairs(NarrowPhaseInput& narrowPhaseInput, List<ContactPair>& contactPairs) const;
/// Convert the potential contact into actual contacts
void computeSnapshotContactPairs(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, List<Pair<Entity, Entity>>& overlapPairs) const;
void computeOverlapSnapshotContactPairs(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, List<ContactPair>& contactPairs,
Set<uint64>& setOverlapContactPairId) const;
/// Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary
void updateOverlappingPairs(const List<Pair<int32, int32> >& overlappingNodes);
@ -202,8 +207,11 @@ class CollisionDetectionSystem {
/// Remove pairs that are not overlapping anymore
void removeNonOverlappingPairs();
/// Add a lost contact pair (pair of colliders that are not in contact anymore)
void addLostContactPair(uint64 overlappingPairIndex);
/// Execute the narrow-phase collision detection algorithm on batches
bool testNarrowPhaseCollision(NarrowPhaseInput& narrowPhaseInput, bool reportContacts, bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& allocator);
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,
@ -222,7 +230,7 @@ class CollisionDetectionSystem {
/// Process the potential contacts after narrow-phase collision detection
void processAllPotentialContacts(NarrowPhaseInput& narrowPhaseInput, bool updateLastFrameInfo, List<ContactPointInfo>& potentialContactPoints,
Map<uint64, uint>* mapPairIdToContactPairIndex,
List<ContactManifoldInfo> &potentialContactManifolds, List<ContactPair>* contactPairs,
List<ContactManifoldInfo>& potentialContactManifolds, List<ContactPair>* contactPairs,
Map<Entity, List<uint>>& mapBodyToContactPairs);
/// Reduce the potential contact manifolds and contact points of the overlapping pair contacts
@ -232,6 +240,9 @@ class CollisionDetectionSystem {
/// Create the actual contact manifolds and contacts points (from potential contacts) for a given contact pair
void createContacts();
/// Compute the lost contact pairs (contact pairs in contact in the previous frame but not in the current one)
void computeLostContactPairs();
/// Create the actual contact manifolds and contacts points for testCollision() methods
void createSnapshotContacts(List<ContactPair>& contactPairs, List<ContactManifold> &contactManifolds,
List<ContactPoint>& contactPoints,
@ -247,7 +258,10 @@ class CollisionDetectionSystem {
/// Report contacts
void reportContacts(CollisionCallback& callback, List<ContactPair>* contactPairs,
List<ContactManifold>* manifolds, List<ContactPoint>* contactPoints);
List<ContactManifold>* manifolds, List<ContactPoint>* contactPoints, List<ContactPair>& lostContactPairs);
/// Report all triggers
void reportTriggers(EventListener& eventListener, List<ContactPair>* contactPairs, List<ContactPair>& lostContactPairs);
/// Return the largest depth of all the contact points of a potential manifold
decimal computePotentialManifoldLargestContactDepth(const ContactManifoldInfo& manifold,
@ -307,8 +321,8 @@ class CollisionDetectionSystem {
/// Notify that the overlapping pairs where a given collider is involved need to be tested for overlap
void notifyOverlappingPairsToTestOverlap(Collider* collider);
/// Report contacts
void reportContacts();
/// Report contacts and triggers
void reportContactsAndTriggers();
/// Compute the collision detection
void computeCollisionDetection();

View File

@ -224,6 +224,16 @@ const Transform Collider::getLocalToWorldTransform() const {
return mBody->mWorld.mCollidersComponents.getLocalToWorldTransform(mEntity);
}
// Return true if the collider is a trigger
bool Collider::getIsTrigger() const {
return mBody->mWorld.mCollidersComponents.getIsTrigger(mEntity);
}
// Set whether the collider is a trigger
void Collider::setIsTrigger(bool isTrigger) const {
mBody->mWorld.mCollidersComponents.setIsTrigger(mEntity, isTrigger);
}
#ifdef IS_PROFILING_ACTIVE
// Set the profiler

View File

@ -39,9 +39,9 @@ CollisionCallback::ContactPoint::ContactPoint(const reactphysics3d::ContactPoint
// Contact Pair Constructor
CollisionCallback::ContactPair::ContactPair(const reactphysics3d::ContactPair& contactPair,
List<reactphysics3d::ContactPoint>* contactPoints, PhysicsWorld& world)
List<reactphysics3d::ContactPoint>* contactPoints, PhysicsWorld& world, bool isLostContactPair)
:mContactPair(contactPair), mContactPoints(contactPoints),
mWorld(world) {
mWorld(world), mIsLostContactPair(isLostContactPair) {
}
@ -65,11 +65,38 @@ Collider* CollisionCallback::ContactPair::getCollider2() const {
return mWorld.mCollidersComponents.getCollider(mContactPair.collider2Entity);
}
// Return the corresponding type of event for this contact pair
CollisionCallback::ContactPair::EventType CollisionCallback::ContactPair::getEventType() const {
if (mIsLostContactPair) return EventType::ContactExit;
if (mContactPair.collidingInPreviousFrame) return EventType::ContactStay;
return EventType::ContactStart;
}
// CollisionCallbackInfo Constructor
CollisionCallback::CallbackData::CallbackData(List<reactphysics3d::ContactPair>* contactPairs, List<ContactManifold>* manifolds,
List<reactphysics3d::ContactPoint>* contactPoints, PhysicsWorld &world)
:mContactPairs(contactPairs), mContactManifolds(manifolds), mContactPoints(contactPoints), mWorld(world) {
List<reactphysics3d::ContactPoint>* contactPoints, List<reactphysics3d::ContactPair>& lostContactPairs, PhysicsWorld& world)
:mContactPairs(contactPairs), mContactManifolds(manifolds), mContactPoints(contactPoints), mLostContactPairs(lostContactPairs),
mContactPairsIndices(world.mMemoryManager.getHeapAllocator()), mLostContactPairsIndices(world.mMemoryManager.getHeapAllocator()), mWorld(world) {
// Filter the contact pairs to only keep the contact events (not the overlap/trigger events)
for (uint i=0; i < mContactPairs->size(); i++) {
// If the contact pair contains contacts (and is therefore not an overlap/trigger event)
if (!(*mContactPairs)[i].isTrigger) {
mContactPairsIndices.add(i);
}
}
// Filter the lost contact pairs to only keep the contact events (not the overlap/trigger events)
for (uint i=0; i < mLostContactPairs.size(); i++) {
// If the contact pair contains contacts (and is therefore not an overlap/trigger event)
if (!mLostContactPairs[i].isTrigger) {
mLostContactPairsIndices.add(i);
}
}
}
// Return a given contact point of the contact pair
@ -91,5 +118,13 @@ CollisionCallback::ContactPair CollisionCallback::CallbackData::getContactPair(u
assert(index < getNbContactPairs());
return CollisionCallback::ContactPair((*mContactPairs)[index], mContactPoints, mWorld);
if (index < mContactPairsIndices.size()) {
// Return a contact pair
return CollisionCallback::ContactPair((*mContactPairs)[mContactPairsIndices[index]], mContactPoints, mWorld, false);
}
else {
// Return a lost contact pair
return CollisionCallback::ContactPair(mLostContactPairs[mLostContactPairsIndices[index - mContactPairsIndices.size()]], mContactPoints, mWorld, true);
}
}

View File

@ -31,23 +31,60 @@
using namespace reactphysics3d;
// Contact Pair Constructor
OverlapCallback::OverlapPair::OverlapPair(Pair<Entity, Entity>& overlapPair, PhysicsWorld& world)
: mOverlapPair(overlapPair), mWorld(world) {
OverlapCallback::OverlapPair::OverlapPair(ContactPair& contactPair, PhysicsWorld& world, bool isLostOverlappingPair)
: mContactPair(contactPair), mWorld(world), mIsLostOverlapPair(isLostOverlappingPair) {
}
// Return a pointer to the first collider in contact
Collider* OverlapCallback::OverlapPair::getCollider1() const {
return static_cast<Collider*>(mWorld.mCollidersComponents.getCollider(mContactPair.collider1Entity));
}
// Return a pointer to the second collider in contact
Collider* OverlapCallback::OverlapPair::getCollider2() const {
return static_cast<Collider*>(mWorld.mCollidersComponents.getCollider(mContactPair.collider2Entity));
}
// Return a pointer to the first body in contact
CollisionBody* OverlapCallback::OverlapPair::getBody1() const {
return static_cast<CollisionBody*>(mWorld.mCollisionBodyComponents.getBody(mOverlapPair.first));
return static_cast<CollisionBody*>(mWorld.mCollisionBodyComponents.getBody(mContactPair.body1Entity));
}
// Return a pointer to the second body in contact
CollisionBody* OverlapCallback::OverlapPair::getBody2() const {
return static_cast<CollisionBody*>(mWorld.mCollisionBodyComponents.getBody(mOverlapPair.second));
return static_cast<CollisionBody*>(mWorld.mCollisionBodyComponents.getBody(mContactPair.body2Entity));
}
// Return the corresponding type of event for this overlapping pair
OverlapCallback::OverlapPair::EventType OverlapCallback::OverlapPair::getEventType() const {
if (mIsLostOverlapPair) return EventType::OverlapExit;
if (mContactPair.collidingInPreviousFrame) return EventType::OverlapStay;
return EventType::OverlapStart;
}
// CollisionCallbackData Constructor
OverlapCallback::CallbackData::CallbackData(List<Pair<Entity, Entity>>& overlapColliders, PhysicsWorld& world)
:mOverlapBodies(overlapColliders), mWorld(world) {
OverlapCallback::CallbackData::CallbackData(List<ContactPair>& contactPairs, List<ContactPair>& lostContactPairs, PhysicsWorld& world)
:mContactPairs(contactPairs), mLostContactPairs(lostContactPairs),
mContactPairsIndices(world.mMemoryManager.getHeapAllocator()), mLostContactPairsIndices(world.mMemoryManager.getHeapAllocator()), mWorld(world) {
// Filter the contact pairs to only keep the overlap/trigger events (not the contact events)
for (uint i=0; i < mContactPairs.size(); i++) {
// If the contact pair contains contacts (and is therefore not an overlap/trigger event)
if (mContactPairs[i].isTrigger) {
mContactPairsIndices.add(i);
}
}
// Filter the lost contact pairs to only keep the overlap/trigger events (not the contact events)
for (uint i=0; i < mLostContactPairs.size(); i++) {
// If the contact pair contains contacts (and is therefore not an overlap/trigger event)
if (mLostContactPairs[i].isTrigger) {
mLostContactPairsIndices.add(i);
}
}
}

View File

@ -35,7 +35,7 @@ using namespace reactphysics3d;
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
// by Dirk Gregorius.
bool CapsuleVsCapsuleAlgorithm::testCollision(CapsuleVsCapsuleNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool reportContacts, MemoryAllocator& memoryAllocator) {
MemoryAllocator& memoryAllocator) {
bool isCollisionFound = false;
@ -95,7 +95,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(CapsuleVsCapsuleNarrowPhaseInfoBat
// If the segments were overlapping (the clip segment is valid)
if (t1 > decimal(0.0) && t2 > decimal(0.0)) {
if (reportContacts) {
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Clip the inner segment of capsule 2
if (t1 > decimal(1.0)) t1 = decimal(1.0);
@ -171,7 +171,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(CapsuleVsCapsuleNarrowPhaseInfoBat
// If the collision shapes overlap
if (closestPointsDistanceSquare < sumRadius * sumRadius) {
if (reportContacts) {
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// If the distance between the inner segments is not zero
if (closestPointsDistanceSquare > MACHINE_EPSILON) {

View File

@ -39,7 +39,10 @@ CapsuleVsCapsuleNarrowPhaseInfoBatch::CapsuleVsCapsuleNarrowPhaseInfoBatch(Memor
// Add shapes to be tested during narrow-phase collision detection into the batch
void CapsuleVsCapsuleNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform) {
const Transform& shape1Transform, const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator &shapeAllocator) {
NarrowPhaseInfoBatch::addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform,
shape2Transform, needToReportContacts, shapeAllocator);
assert(shape1->getType() == CollisionShapeType::CAPSULE);
assert(shape2->getType() == CollisionShapeType::CAPSULE);
@ -47,34 +50,16 @@ void CapsuleVsCapsuleNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uin
const CapsuleShape* capsule1 = static_cast<const CapsuleShape*>(shape1);
const CapsuleShape* capsule2 = static_cast<const CapsuleShape*>(shape2);
colliderEntities1.add(collider1);
colliderEntities2.add(collider2);
capsule1Radiuses.add(capsule1->getRadius());
capsule2Radiuses.add(capsule2->getRadius());
capsule1Heights.add(capsule1->getHeight());
capsule2Heights.add(capsule2->getHeight());
shape1ToWorldTransforms.add(shape1Transform);
shape2ToWorldTransforms.add(shape2Transform);
overlappingPairIds.add(pairId);
contactPoints.add(List<ContactPointInfo*>(mMemoryAllocator));
isColliding.add(false);
// Add a collision info for the two collision shapes into the overlapping pair (if not present yet)
LastFrameCollisionInfo* lastFrameInfo = mOverlappingPairs.addLastFrameInfoIfNecessary(pairIndex, shape1->getId(), shape2->getId());
lastFrameCollisionInfos.add(lastFrameInfo);
}
// Initialize the containers using cached capacity
void CapsuleVsCapsuleNarrowPhaseInfoBatch::reserveMemory() {
overlappingPairIds.reserve(mCachedCapacity);
colliderEntities1.reserve(mCachedCapacity);
colliderEntities2.reserve(mCachedCapacity);
shape1ToWorldTransforms.reserve(mCachedCapacity);
shape2ToWorldTransforms.reserve(mCachedCapacity);
lastFrameCollisionInfos.reserve(mCachedCapacity);
isColliding.reserve(mCachedCapacity);
contactPoints.reserve(mCachedCapacity);
NarrowPhaseInfoBatch::reserveMemory();
capsule1Radiuses.reserve(mCachedCapacity);
capsule2Radiuses.reserve(mCachedCapacity);
@ -90,16 +75,7 @@ void CapsuleVsCapsuleNarrowPhaseInfoBatch::clear() {
// allocated in the next frame at a possibly different location in memory (remember that the
// location of the allocated memory of a single frame allocator might change between two frames)
mCachedCapacity = overlappingPairIds.size();
overlappingPairIds.clear(true);
colliderEntities1.clear(true);
colliderEntities2.clear(true);
shape1ToWorldTransforms.clear(true);
shape2ToWorldTransforms.clear(true);
lastFrameCollisionInfos.clear(true);
isColliding.clear(true);
contactPoints.clear(true);
NarrowPhaseInfoBatch::clear();
capsule1Radiuses.clear(true);
capsule2Radiuses.clear(true);

View File

@ -41,7 +41,7 @@ using namespace reactphysics3d;
// by Dirk Gregorius.
bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch,
uint batchStartIndex, uint batchNbItems,
bool reportContacts, bool clipWithPreviousAxisIfStillColliding,
bool clipWithPreviousAxisIfStillColliding,
MemoryAllocator& memoryAllocator) {
bool isCollisionFound = false;
@ -59,7 +59,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& nar
// Run the GJK algorithm
List<GJKAlgorithm::GJKResult> gjkResults(memoryAllocator);
gjkAlgorithm.testCollision(narrowPhaseInfoBatch, batchStartIndex, batchNbItems, gjkResults, reportContacts);
gjkAlgorithm.testCollision(narrowPhaseInfoBatch, batchStartIndex, batchNbItems, gjkResults);
assert(gjkResults.size() == batchNbItems);
for (uint batchIndex = batchStartIndex; batchIndex < batchStartIndex + batchNbItems; batchIndex++) {
@ -78,7 +78,8 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& nar
// If we have found a contact point inside the margins (shallow penetration)
if (gjkResults[batchIndex] == GJKAlgorithm::GJKResult::COLLIDE_IN_MARGIN) {
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
bool noContact = false;
@ -173,7 +174,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& nar
if (gjkResults[batchIndex] == GJKAlgorithm::GJKResult::INTERPENETRATE) {
// Run the SAT algorithm to find the separating axis and compute contact point
narrowPhaseInfoBatch.isColliding[batchIndex] = satAlgorithm.testCollisionCapsuleVsConvexPolyhedron(narrowPhaseInfoBatch, batchIndex, reportContacts);
narrowPhaseInfoBatch.isColliding[batchIndex] = satAlgorithm.testCollisionCapsuleVsConvexPolyhedron(narrowPhaseInfoBatch, batchIndex);
lastFrameCollisionInfo->wasUsingGJK = false;
lastFrameCollisionInfo->wasUsingSAT = true;

View File

@ -37,7 +37,7 @@ using namespace reactphysics3d;
// by Dirk Gregorius.
bool ConvexPolyhedronVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch,
uint batchStartIndex, uint batchNbItems,
bool reportContacts, bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator) {
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator) {
// Run the SAT algorithm to find the separating axis and compute contact point
SATAlgorithm satAlgorithm(clipWithPreviousAxisIfStillColliding, memoryAllocator);
@ -48,8 +48,7 @@ bool ConvexPolyhedronVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoB
#endif
bool isCollisionFound = satAlgorithm.testCollisionConvexPolyhedronVsConvexPolyhedron(narrowPhaseInfoBatch, batchStartIndex,
batchNbItems, reportContacts);
bool isCollisionFound = satAlgorithm.testCollisionConvexPolyhedronVsConvexPolyhedron(narrowPhaseInfoBatch, batchStartIndex, batchNbItems);
for (uint batchIndex = batchStartIndex; batchIndex < batchStartIndex + batchNbItems; batchIndex++) {

View File

@ -48,7 +48,7 @@ using namespace reactphysics3d;
/// origin, they we give that simplex polytope to the EPA algorithm which will compute
/// the correct penetration depth and contact points between the enlarged objects.
void GJKAlgorithm::testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex,
uint batchNbItems, List<GJKResult>& gjkResults, bool reportContacts) {
uint batchNbItems, List<GJKResult>& gjkResults) {
RP3D_PROFILE("GJKAlgorithm::testCollision()", mProfiler);
@ -214,7 +214,8 @@ void GJKAlgorithm::testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uin
continue;
}
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(shape1, shape2, pA, pB, transform1, transform2,

View File

@ -36,7 +36,7 @@ using namespace reactphysics3d;
NarrowPhaseInfoBatch::NarrowPhaseInfoBatch(MemoryAllocator& allocator, OverlappingPairs& overlappingPairs)
: mMemoryAllocator(allocator), mOverlappingPairs(overlappingPairs), overlappingPairIds(allocator),
colliderEntities1(allocator), colliderEntities2(allocator), collisionShapes1(allocator), collisionShapes2(allocator),
shape1ToWorldTransforms(allocator), shape2ToWorldTransforms(allocator),
shape1ToWorldTransforms(allocator), shape2ToWorldTransforms(allocator), reportContacts(allocator),
isColliding(allocator), contactPoints(allocator), collisionShapeAllocators(allocator),
lastFrameCollisionInfos(allocator) {
@ -49,7 +49,7 @@ NarrowPhaseInfoBatch::~NarrowPhaseInfoBatch() {
// Add shapes to be tested during narrow-phase collision detection into the batch
void NarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform,
const Transform& shape1Transform, const Transform& shape2Transform, bool needToReportContacts,
MemoryAllocator& shapeAllocator) {
overlappingPairIds.add(pairId);
@ -59,6 +59,7 @@ void NarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, E
collisionShapes2.add(shape2);
shape1ToWorldTransforms.add(shape1Transform);
shape2ToWorldTransforms.add(shape2Transform);
reportContacts.add(needToReportContacts);
collisionShapeAllocators.add(&shapeAllocator);
contactPoints.add(List<ContactPointInfo*>(mMemoryAllocator));
isColliding.add(false);
@ -72,6 +73,7 @@ void NarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, E
void NarrowPhaseInfoBatch::addContactPoint(uint index, const Vector3& contactNormal, decimal penDepth,
const Vector3& localPt1, const Vector3& localPt2) {
assert(reportContacts[index]);
assert(penDepth > decimal(0.0));
// Get the memory allocator
@ -116,6 +118,7 @@ void NarrowPhaseInfoBatch::reserveMemory() {
collisionShapes2.reserve(mCachedCapacity);
shape1ToWorldTransforms.reserve(mCachedCapacity);
shape2ToWorldTransforms.reserve(mCachedCapacity);
reportContacts.reserve(mCachedCapacity);
collisionShapeAllocators.reserve(mCachedCapacity);
lastFrameCollisionInfos.reserve(mCachedCapacity);
isColliding.reserve(mCachedCapacity);
@ -155,6 +158,7 @@ void NarrowPhaseInfoBatch::clear() {
collisionShapes2.clear(true);
shape1ToWorldTransforms.clear(true);
shape2ToWorldTransforms.clear(true);
reportContacts.clear(true);
collisionShapeAllocators.clear(true);
lastFrameCollisionInfos.clear(true);
isColliding.clear(true);

View File

@ -41,26 +41,26 @@ NarrowPhaseInput::NarrowPhaseInput(MemoryAllocator& allocator, OverlappingPairs&
// Add shapes to be tested during narrow-phase collision detection into the batch
void NarrowPhaseInput::addNarrowPhaseTest(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform,
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, MemoryAllocator& shapeAllocator) {
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType, bool reportContacts, MemoryAllocator& shapeAllocator) {
switch (narrowPhaseAlgorithmType) {
case NarrowPhaseAlgorithmType::SphereVsSphere:
mSphereVsSphereBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform);
mSphereVsSphereBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::SphereVsCapsule:
mSphereVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform);
mSphereVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::CapsuleVsCapsule:
mCapsuleVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform);
mCapsuleVsCapsuleBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::SphereVsConvexPolyhedron:
mSphereVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, shapeAllocator);
mSphereVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::CapsuleVsConvexPolyhedron:
mCapsuleVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, shapeAllocator);
mCapsuleVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::ConvexPolyhedronVsConvexPolyhedron:
mConvexPolyhedronVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, shapeAllocator);
mConvexPolyhedronVsConvexPolyhedronBatch.addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform, shape2Transform, reportContacts, shapeAllocator);
break;
case NarrowPhaseAlgorithmType::None:
// Must never happen

View File

@ -55,8 +55,7 @@ SATAlgorithm::SATAlgorithm(bool clipWithPreviousAxisIfStillColliding, MemoryAllo
// Test collision between a sphere and a convex mesh
bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch,
uint batchStartIndex, uint batchNbItems,
bool reportContacts) const {
uint batchStartIndex, uint batchNbItems) const {
bool isCollisionFound = false;
@ -114,7 +113,8 @@ bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfoBatch& n
continue;
}
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
const Vector3 minFaceNormal = polyhedron->getFaceNormal(minFaceIndex);
Vector3 minFaceNormalWorld = polyhedronToWorldTransform.getOrientation() * minFaceNormal;
@ -162,7 +162,7 @@ decimal SATAlgorithm::computePolyhedronFaceVsSpherePenetrationDepth(uint faceInd
}
// Test collision between a capsule and a convex mesh
bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchIndex, bool reportContacts) const {
bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchIndex) const {
RP3D_PROFILE("SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron()", mProfiler);
@ -277,7 +277,8 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch&
// We need to clip the inner capsule segment with the adjacent faces of the separating face
if (isMinPenetrationFaceNormal) {
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
return computeCapsulePolyhedronFaceContactPoints(minFaceIndex, capsuleRadius, polyhedron, minPenetrationDepth,
polyhedronToCapsuleTransform, normalWorld, separatingAxisCapsuleSpace,
@ -287,7 +288,8 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfoBatch&
}
else { // The separating axis is the cross product of a polyhedron edge and the inner capsule segment
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Compute the closest points between the inner capsule segment and the
// edge of the polyhedron in polyhedron local-space
@ -475,7 +477,7 @@ bool SATAlgorithm::isMinkowskiFaceCapsuleVsEdge(const Vector3& capsuleSegment, c
}
// Test collision between two convex polyhedrons
bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems, bool reportContacts) const {
bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems) const {
RP3D_PROFILE("SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron()", mProfiler);
@ -485,6 +487,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
assert(narrowPhaseInfoBatch.collisionShapes1[batchIndex]->getType() == CollisionShapeType::CONVEX_POLYHEDRON);
assert(narrowPhaseInfoBatch.collisionShapes2[batchIndex]->getType() == CollisionShapeType::CONVEX_POLYHEDRON);
assert(narrowPhaseInfoBatch.contactPoints[batchIndex].size() == 0);
const ConvexPolyhedronShape* polyhedron1 = static_cast<const ConvexPolyhedronShape*>(narrowPhaseInfoBatch.collisionShapes1[batchIndex]);
const ConvexPolyhedronShape* polyhedron2 = static_cast<const ConvexPolyhedronShape*>(narrowPhaseInfoBatch.collisionShapes2[batchIndex]);
@ -646,32 +649,37 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
decimal t2 = vec2.dot(edge1Direction) / edge1LengthSquare;
if (t1 >= decimal(0.0) && t1 <= decimal(1) && t2 >= decimal(0.0) && t2 <= decimal(1.0)) {
// Compute the contact point on polyhedron 1 edge in the local-space of polyhedron 1
Vector3 closestPointPolyhedron1EdgeLocalSpace = polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge;
// If we need to report contact points
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Compute the contact point on polyhedron 1 edge in the local-space of polyhedron 1
Vector3 closestPointPolyhedron1EdgeLocalSpace = polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge;
// Compute the world normal
// We use the direction from the centroid to the edge of the shape that is not a triangle
// to avoid possible degeneracies when axis direction is orthogonal to triangle normal
Vector3 normal;
if (isShape1Triangle) {
normal = polyhedron2->getCentroid() - closestPointPolyhedron2Edge;
}
else {
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
}
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * normal.getUnit();
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge,
narrowPhaseInfoBatch.shape1ToWorldTransforms[batchIndex], narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex],
penetrationDepth, normalWorld);
// Create the contact point
narrowPhaseInfoBatch.addContactPoint(batchIndex, normalWorld, penetrationDepth,
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
// Compute the world normal
// We use the direction from the centroid to the edge of the shape that is not a triangle
// to avoid possible degeneracies when axis direction is orthogonal to triangle normal
Vector3 normal;
if (isShape1Triangle) {
normal = polyhedron2->getCentroid() - closestPointPolyhedron2Edge;
}
else {
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
}
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * normal.getUnit();
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge,
narrowPhaseInfoBatch.shape1ToWorldTransforms[batchIndex], narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex],
penetrationDepth, normalWorld);
// Create the contact point
narrowPhaseInfoBatch.addContactPoint(batchIndex, normalWorld, penetrationDepth,
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
// The shapes are overlapping on the previous axis (the contact manifold is not empty). Therefore
// we return without running the whole SAT algorithm
@ -819,24 +827,21 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
// If the minimum separating axis is a face normal
if (isMinPenetrationFaceNormal) {
if (reportContacts) {
// Compute the contact points between two faces of two convex polyhedra.
bool contactsFound = computePolyhedronVsPolyhedronFaceContactPoints(isMinPenetrationFaceNormalPolyhedron1, polyhedron1,
polyhedron2, polyhedron1ToPolyhedron2, polyhedron2ToPolyhedron1,
minFaceIndex, narrowPhaseInfoBatch, batchIndex);
// Compute the contact points between two faces of two convex polyhedra.
bool contactsFound = computePolyhedronVsPolyhedronFaceContactPoints(isMinPenetrationFaceNormalPolyhedron1, polyhedron1,
polyhedron2, polyhedron1ToPolyhedron2, polyhedron2ToPolyhedron1,
minFaceIndex, narrowPhaseInfoBatch, batchIndex);
// There should be clipping points here. If it is not the case, it might be
// because of a numerical issue
if (!contactsFound) {
// There should be clipping points here. If it is not the case, it might be
// because of a numerical issue
if (!contactsFound) {
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = isMinPenetrationFaceNormalPolyhedron1;
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = !isMinPenetrationFaceNormalPolyhedron1;
lastFrameCollisionInfo->satMinAxisFaceIndex = minFaceIndex;
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = isMinPenetrationFaceNormalPolyhedron1;
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = !isMinPenetrationFaceNormalPolyhedron1;
lastFrameCollisionInfo->satMinAxisFaceIndex = minFaceIndex;
// Return no collision
continue;
}
// Return no collision
continue;
}
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = isMinPenetrationFaceNormalPolyhedron1;
@ -845,7 +850,8 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
}
else { // If we have an edge vs edge contact
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Compute the closest points between the two edges (in the local-space of poylhedron 2)
Vector3 closestPointPolyhedron1Edge, closestPointPolyhedron2Edge;
@ -981,25 +987,29 @@ bool SATAlgorithm::computePolyhedronVsPolyhedronFaceContactPoints(bool isMinPene
contactPointsFound = true;
Vector3 outWorldNormal = normalWorld;
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// Convert the clip incident polyhedron vertex into the incident polyhedron local-space
Vector3 contactPointIncidentPolyhedron = referenceToIncidentTransform * clipPolygonVertices[i];
Vector3 outWorldNormal = normalWorld;
// Project the contact point onto the reference face
Vector3 contactPointReferencePolyhedron = projectPointOntoPlane(clipPolygonVertices[i], axisReferenceSpace, referenceFaceVertex);
// Convert the clip incident polyhedron vertex into the incident polyhedron local-space
Vector3 contactPointIncidentPolyhedron = referenceToIncidentTransform * clipPolygonVertices[i];
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron,
narrowPhaseInfoBatch.shape1ToWorldTransforms[batchIndex], narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex],
penetrationDepth, outWorldNormal);
// Project the contact point onto the reference face
Vector3 contactPointReferencePolyhedron = projectPointOntoPlane(clipPolygonVertices[i], axisReferenceSpace, referenceFaceVertex);
// Create a new contact point
narrowPhaseInfoBatch.addContactPoint(batchIndex, outWorldNormal, penetrationDepth,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron);
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron,
narrowPhaseInfoBatch.shape1ToWorldTransforms[batchIndex], narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex],
penetrationDepth, outWorldNormal);
// Create a new contact point
narrowPhaseInfoBatch.addContactPoint(batchIndex, outWorldNormal, penetrationDepth,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron);
}
}
}

View File

@ -36,7 +36,7 @@ using namespace reactphysics3d;
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
// by Dirk Gregorius.
bool SphereVsCapsuleAlgorithm::testCollision(SphereVsCapsuleNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool reportContacts, MemoryAllocator& memoryAllocator) {
MemoryAllocator& memoryAllocator) {
bool isCollisionFound = false;
@ -79,7 +79,8 @@ bool SphereVsCapsuleAlgorithm::testCollision(SphereVsCapsuleNarrowPhaseInfoBatch
Vector3 contactPointSphereLocal;
Vector3 contactPointCapsuleLocal;
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
// If the sphere center is not on the capsule inner segment
if (sphereSegmentDistanceSquare > MACHINE_EPSILON) {

View File

@ -40,7 +40,11 @@ SphereVsCapsuleNarrowPhaseInfoBatch::SphereVsCapsuleNarrowPhaseInfoBatch(MemoryA
// Add shapes to be tested during narrow-phase collision detection into the batch
void SphereVsCapsuleNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform) {
const Transform& shape1Transform, const Transform& shape2Transform,
bool needToReportContacts, MemoryAllocator& shapeAllocator) {
NarrowPhaseInfoBatch::addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform,
shape2Transform, needToReportContacts, shapeAllocator);
bool isSphereShape1 = shape1->getType() == CollisionShapeType::SPHERE;
isSpheresShape1.add(isSphereShape1);
@ -54,30 +58,12 @@ void SphereVsCapsuleNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint
sphereRadiuses.add(sphereShape->getRadius());
capsuleRadiuses.add(capsuleShape->getRadius());
capsuleHeights.add(capsuleShape->getHeight());
shape1ToWorldTransforms.add(shape1Transform);
shape2ToWorldTransforms.add(shape2Transform);
overlappingPairIds.add(pairId);
colliderEntities1.add(collider1);
colliderEntities2.add(collider2);
contactPoints.add(List<ContactPointInfo*>(mMemoryAllocator));
isColliding.add(false);
// Add a collision info for the two collision shapes into the overlapping pair (if not present yet)
LastFrameCollisionInfo* lastFrameInfo = mOverlappingPairs.addLastFrameInfoIfNecessary(pairIndex, shape1->getId(), shape2->getId());
lastFrameCollisionInfos.add(lastFrameInfo);
}
// Initialize the containers using cached capacity
void SphereVsCapsuleNarrowPhaseInfoBatch::reserveMemory() {
overlappingPairIds.reserve(mCachedCapacity);
colliderEntities1.reserve(mCachedCapacity);
colliderEntities2.reserve(mCachedCapacity);
shape1ToWorldTransforms.reserve(mCachedCapacity);
shape2ToWorldTransforms.reserve(mCachedCapacity);
lastFrameCollisionInfos.reserve(mCachedCapacity);
isColliding.reserve(mCachedCapacity);
contactPoints.reserve(mCachedCapacity);
NarrowPhaseInfoBatch::reserveMemory();
isSpheresShape1.reserve(mCachedCapacity);
sphereRadiuses.reserve(mCachedCapacity);
@ -93,16 +79,7 @@ void SphereVsCapsuleNarrowPhaseInfoBatch::clear() {
// allocated in the next frame at a possibly different location in memory (remember that the
// location of the allocated memory of a single frame allocator might change between two frames)
mCachedCapacity = overlappingPairIds.size();
overlappingPairIds.clear(true);
colliderEntities1.clear(true);
colliderEntities2.clear(true);
shape1ToWorldTransforms.clear(true);
shape2ToWorldTransforms.clear(true);
lastFrameCollisionInfos.clear(true);
isColliding.clear(true);
contactPoints.clear(true);
NarrowPhaseInfoBatch::clear();
isSpheresShape1.clear(true);
sphereRadiuses.clear(true);

View File

@ -36,7 +36,7 @@ using namespace reactphysics3d;
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
// by Dirk Gregorius.
bool SphereVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool reportContacts, bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator) {
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& memoryAllocator) {
// First, we run the GJK algorithm
GJKAlgorithm gjkAlgorithm;
@ -50,7 +50,7 @@ bool SphereVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& narr
#endif
List<GJKAlgorithm::GJKResult> gjkResults(memoryAllocator);
gjkAlgorithm.testCollision(narrowPhaseInfoBatch, batchStartIndex, batchNbItems, gjkResults, reportContacts);
gjkAlgorithm.testCollision(narrowPhaseInfoBatch, batchStartIndex, batchNbItems, gjkResults);
assert(gjkResults.size() == batchNbItems);
// For each item in the batch
@ -88,7 +88,7 @@ bool SphereVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfoBatch& narr
#endif
isCollisionFound |= satAlgorithm.testCollisionSphereVsConvexPolyhedron(narrowPhaseInfoBatch, batchIndex, 1, reportContacts);
isCollisionFound |= satAlgorithm.testCollisionSphereVsConvexPolyhedron(narrowPhaseInfoBatch, batchIndex, 1);
lastFrameCollisionInfo->wasUsingGJK = false;
lastFrameCollisionInfo->wasUsingSAT = true;

View File

@ -31,8 +31,7 @@
// We want to use the ReactPhysics3D namespace
using namespace reactphysics3d;
bool SphereVsSphereAlgorithm::testCollision(SphereVsSphereNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems,
bool reportContacts, MemoryAllocator& memoryAllocator) {
bool SphereVsSphereAlgorithm::testCollision(SphereVsSphereNarrowPhaseInfoBatch& narrowPhaseInfoBatch, uint batchStartIndex, uint batchNbItems, MemoryAllocator& memoryAllocator) {
bool isCollisionFound = false;
@ -59,10 +58,11 @@ bool SphereVsSphereAlgorithm::testCollision(SphereVsSphereNarrowPhaseInfoBatch&
// If the sphere collision shapes intersect
if (squaredDistanceBetweenCenters < sumRadiusesProducts) {
if (reportContacts) {
// If we need to report contacts
if (narrowPhaseInfoBatch.reportContacts[batchIndex]) {
Transform transform1Inverse = transform1.getInverse();
Transform transform2Inverse = transform2.getInverse();
const Transform transform1Inverse = transform1.getInverse();
const Transform transform2Inverse = transform2.getInverse();
decimal penetrationDepth = sumRadiuses - std::sqrt(squaredDistanceBetweenCenters);
Vector3 intersectionOnBody1;

View File

@ -37,7 +37,10 @@ SphereVsSphereNarrowPhaseInfoBatch::SphereVsSphereNarrowPhaseInfoBatch(MemoryAll
// Add shapes to be tested during narrow-phase collision detection into the batch
void SphereVsSphereNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint64 pairIndex, Entity collider1, Entity collider2, CollisionShape* shape1, CollisionShape* shape2,
const Transform& shape1Transform, const Transform& shape2Transform) {
const Transform& shape1Transform, const Transform& shape2Transform, bool needToReportContacts, MemoryAllocator &shapeAllocator) {
NarrowPhaseInfoBatch::addNarrowPhaseInfo(pairId, pairIndex, collider1, collider2, shape1, shape2, shape1Transform,
shape2Transform, needToReportContacts, shapeAllocator);
assert(shape1->getType() == CollisionShapeType::SPHERE);
assert(shape2->getType() == CollisionShapeType::SPHERE);
@ -47,30 +50,12 @@ void SphereVsSphereNarrowPhaseInfoBatch::addNarrowPhaseInfo(uint64 pairId, uint6
sphere1Radiuses.add(sphere1->getRadius());
sphere2Radiuses.add(sphere2->getRadius());
colliderEntities1.add(collider1);
colliderEntities2.add(collider2);
shape1ToWorldTransforms.add(shape1Transform);
shape2ToWorldTransforms.add(shape2Transform);
overlappingPairIds.add(pairId);
contactPoints.add(List<ContactPointInfo*>(mMemoryAllocator));
isColliding.add(false);
// Add a collision info for the two collision shapes into the overlapping pair (if not present yet)
LastFrameCollisionInfo* lastFrameInfo = mOverlappingPairs.addLastFrameInfoIfNecessary(pairIndex, shape1->getId(), shape2->getId());
lastFrameCollisionInfos.add(lastFrameInfo);
}
// Initialize the containers using cached capacity
void SphereVsSphereNarrowPhaseInfoBatch::reserveMemory() {
overlappingPairIds.reserve(mCachedCapacity);
colliderEntities1.reserve(mCachedCapacity);
colliderEntities2.reserve(mCachedCapacity);
shape1ToWorldTransforms.reserve(mCachedCapacity);
shape2ToWorldTransforms.reserve(mCachedCapacity);
lastFrameCollisionInfos.reserve(mCachedCapacity);
isColliding.reserve(mCachedCapacity);
contactPoints.reserve(mCachedCapacity);
NarrowPhaseInfoBatch::reserveMemory();
sphere1Radiuses.reserve(mCachedCapacity);
sphere2Radiuses.reserve(mCachedCapacity);
@ -84,16 +69,7 @@ void SphereVsSphereNarrowPhaseInfoBatch::clear() {
// allocated in the next frame at a possibly different location in memory (remember that the
// location of the allocated memory of a single frame allocator might change between two frames)
mCachedCapacity = overlappingPairIds.size();
overlappingPairIds.clear(true);
colliderEntities1.clear(true);
colliderEntities2.clear(true);
shape1ToWorldTransforms.clear(true);
shape2ToWorldTransforms.clear(true);
lastFrameCollisionInfos.clear(true);
isColliding.clear(true);
contactPoints.clear(true);
NarrowPhaseInfoBatch::clear();
sphere1Radiuses.clear(true);
sphere2Radiuses.clear(true);

View File

@ -37,7 +37,8 @@ using namespace reactphysics3d;
ColliderComponents::ColliderComponents(MemoryAllocator& allocator)
:Components(allocator, sizeof(Entity) + sizeof(Entity) + sizeof(Collider*) + sizeof(int32) +
sizeof(Transform) + sizeof(CollisionShape*) + sizeof(unsigned short) +
sizeof(unsigned short) + sizeof(Transform) + sizeof(List<uint64>) + sizeof(bool)) {
sizeof(unsigned short) + sizeof(Transform) + sizeof(List<uint64>) + sizeof(bool) +
sizeof(bool)) {
// Allocate memory for the components data
allocate(INIT_NB_ALLOCATED_COMPONENTS);
@ -67,6 +68,7 @@ void ColliderComponents::allocate(uint32 nbComponentsToAllocate) {
Transform* newLocalToWorldTransforms = reinterpret_cast<Transform*>(newCollideWithMaskBits + nbComponentsToAllocate);
List<uint64>* newOverlappingPairs = reinterpret_cast<List<uint64>*>(newLocalToWorldTransforms + nbComponentsToAllocate);
bool* hasCollisionShapeChangedSize = reinterpret_cast<bool*>(newOverlappingPairs + nbComponentsToAllocate);
bool* isTrigger = reinterpret_cast<bool*>(hasCollisionShapeChangedSize + nbComponentsToAllocate);
// If there was already components before
if (mNbComponents > 0) {
@ -83,6 +85,7 @@ void ColliderComponents::allocate(uint32 nbComponentsToAllocate) {
memcpy(newLocalToWorldTransforms, mLocalToWorldTransforms, mNbComponents * sizeof(Transform));
memcpy(newOverlappingPairs, mOverlappingPairs, mNbComponents * sizeof(List<uint64>));
memcpy(hasCollisionShapeChangedSize, mHasCollisionShapeChangedSize, mNbComponents * sizeof(bool));
memcpy(isTrigger, mIsTrigger, mNbComponents * sizeof(bool));
// Deallocate previous memory
mMemoryAllocator.release(mBuffer, mNbAllocatedComponents * mComponentDataSize);
@ -101,6 +104,7 @@ void ColliderComponents::allocate(uint32 nbComponentsToAllocate) {
mLocalToWorldTransforms = newLocalToWorldTransforms;
mOverlappingPairs = newOverlappingPairs;
mHasCollisionShapeChangedSize = hasCollisionShapeChangedSize;
mIsTrigger = isTrigger;
mNbAllocatedComponents = nbComponentsToAllocate;
}
@ -123,6 +127,7 @@ void ColliderComponents::addComponent(Entity colliderEntity, bool isSleeping, co
new (mLocalToWorldTransforms + index) Transform(component.localToWorldTransform);
new (mOverlappingPairs + index) List<uint64>(mMemoryAllocator);
mHasCollisionShapeChangedSize[index] = false;
mIsTrigger[index] = false;
// Map the entity with the new component lookup index
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(colliderEntity, index));
@ -150,6 +155,7 @@ void ColliderComponents::moveComponentToIndex(uint32 srcIndex, uint32 destIndex)
new (mLocalToWorldTransforms + destIndex) Transform(mLocalToWorldTransforms[srcIndex]);
new (mOverlappingPairs + destIndex) List<uint64>(mOverlappingPairs[srcIndex]);
mHasCollisionShapeChangedSize[destIndex] = mHasCollisionShapeChangedSize[srcIndex];
mIsTrigger[destIndex] = mIsTrigger[srcIndex];
// Destroy the source component
destroyComponent(srcIndex);
@ -177,6 +183,7 @@ void ColliderComponents::swapComponents(uint32 index1, uint32 index2) {
Transform localToWorldTransform1 = mLocalToWorldTransforms[index1];
List<uint64> overlappingPairs = mOverlappingPairs[index1];
bool hasCollisionShapeChangedSize = mHasCollisionShapeChangedSize[index1];
bool isTrigger = mIsTrigger[index1];
// Destroy component 1
destroyComponent(index1);
@ -195,6 +202,7 @@ void ColliderComponents::swapComponents(uint32 index1, uint32 index2) {
new (mLocalToWorldTransforms + index2) Transform(localToWorldTransform1);
new (mOverlappingPairs + index2) List<uint64>(overlappingPairs);
mHasCollisionShapeChangedSize[index2] = hasCollisionShapeChangedSize;
mIsTrigger[index2] = isTrigger;
// Update the entity to component index mapping
mMapEntityToComponentIndex.add(Pair<Entity, uint32>(colliderEntity1, index2));

View File

@ -40,7 +40,7 @@ OverlappingPairs::OverlappingPairs(MemoryAllocator& persistentMemoryAllocator, M
mNbPairs(0), mConcavePairsStartIndex(0), mPairDataSize(sizeof(uint64) + sizeof(int32) + sizeof(int32) + sizeof(Entity) +
sizeof(Entity) + sizeof(Map<uint64, LastFrameCollisionInfo*>) +
sizeof(bool) + sizeof(bool) + sizeof(NarrowPhaseAlgorithmType) +
sizeof(bool)),
sizeof(bool) + sizeof(bool) + sizeof(bool)),
mNbAllocatedPairs(0), mBuffer(nullptr),
mMapPairIdToPairIndex(persistentMemoryAllocator),
mColliderComponents(colliderComponents), mCollisionBodyComponents(collisionBodyComponents),
@ -211,6 +211,8 @@ void OverlappingPairs::allocate(uint64 nbPairsToAllocate) {
bool* newIsActive = reinterpret_cast<bool*>(newNeedToTestOverlap + nbPairsToAllocate);
NarrowPhaseAlgorithmType* newNarrowPhaseAlgorithmType = reinterpret_cast<NarrowPhaseAlgorithmType*>(newIsActive + nbPairsToAllocate);
bool* newIsShape1Convex = reinterpret_cast<bool*>(newNarrowPhaseAlgorithmType + nbPairsToAllocate);
bool* wereCollidingInPreviousFrame = reinterpret_cast<bool*>(newIsShape1Convex + nbPairsToAllocate);
bool* areCollidingInCurrentFrame = reinterpret_cast<bool*>(wereCollidingInPreviousFrame + nbPairsToAllocate);
// If there was already pairs before
if (mNbPairs > 0) {
@ -226,6 +228,8 @@ void OverlappingPairs::allocate(uint64 nbPairsToAllocate) {
memcpy(newIsActive, mIsActive, 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));
// Deallocate previous memory
mPersistentAllocator.release(mBuffer, mNbAllocatedPairs * mPairDataSize);
@ -242,6 +246,8 @@ void OverlappingPairs::allocate(uint64 nbPairsToAllocate) {
mIsActive = newIsActive;
mNarrowPhaseAlgorithmType = newNarrowPhaseAlgorithmType;
mIsShape1Convex = newIsShape1Convex;
mCollidingInPreviousFrame = wereCollidingInPreviousFrame;
mCollidingInCurrentFrame = areCollidingInCurrentFrame;
mNbAllocatedPairs = nbPairsToAllocate;
}
@ -298,6 +304,8 @@ uint64 OverlappingPairs::addPair(Collider* shape1, Collider* shape2) {
new (mIsActive + index) bool(true);
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));
@ -335,6 +343,8 @@ void OverlappingPairs::movePairToIndex(uint64 srcIndex, uint64 destIndex) {
mIsActive[destIndex] = mIsActive[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);
@ -361,6 +371,8 @@ void OverlappingPairs::swapPairs(uint64 index1, uint64 index2) {
bool isActive = mIsActive[index1];
NarrowPhaseAlgorithmType narrowPhaseAlgorithmType = mNarrowPhaseAlgorithmType[index1];
bool isShape1Convex = mIsShape1Convex[index1];
bool wereCollidingInPreviousFrame = mCollidingInPreviousFrame[index1];
bool areCollidingInCurrentFrame = mCollidingInCurrentFrame[index1];
// Destroy pair 1
destroyPair(index1);
@ -378,6 +390,8 @@ void OverlappingPairs::swapPairs(uint64 index1, uint64 index2) {
mIsActive[index2] = isActive;
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));
@ -476,7 +490,7 @@ void OverlappingPairs::clearObsoleteLastFrameCollisionInfos() {
RP3D_PROFILE("OverlappingPairs::clearObsoleteLastFrameCollisionInfos()", mProfiler);
// For each convex vs convex overlapping pair
// For each overlapping pair
for (uint64 i=0; i < mNbPairs; i++) {
// For each collision info
@ -501,3 +515,13 @@ void OverlappingPairs::clearObsoleteLastFrameCollisionInfos() {
}
}
}
// 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++) {
mCollidingInPreviousFrame[i] = mCollidingInCurrentFrame[i];
}
}

View File

@ -338,7 +338,7 @@ void PhysicsWorld::update(decimal timeStep) {
createIslands();
// Report the contacts to the user
mCollisionDetection.reportContacts();
mCollisionDetection.reportContactsAndTriggers();
// Disable the joints for pair of sleeping bodies
disableJointsOfSleepingBodies();
@ -718,9 +718,6 @@ void PhysicsWorld::addJointToBodies(Entity body1, Entity body2, Entity joint) {
/// it). Then, we create an island with this group of connected bodies.
void PhysicsWorld::createIslands() {
// list of contact pairs involving a non-rigid body
List<uint> nonRigidBodiesContactPairs(mMemoryManager.getSingleFrameAllocator());
RP3D_PROFILE("PhysicsWorld::createIslands()", mProfiler);
// Reset all the isAlreadyInIsland variables of bodies and joints
@ -783,14 +780,15 @@ void PhysicsWorld::createIslands() {
for (uint p=0; p < contactPairs.size(); p++) {
ContactPair& pair = (*mCollisionDetection.mCurrentContactPairs)[contactPairs[p]];
assert(pair.potentialContactManifoldsIndices.size() > 0);
// Check if the current contact pair has already been added into an island
if (pair.isAlreadyInIsland) continue;
// If the colliding body is a RigidBody (and not a CollisionBody instead)
if (mRigidBodyComponents.hasComponent(pair.body1Entity) && mRigidBodyComponents.hasComponent(pair.body2Entity)) {
// If the colliding body is a RigidBody (and not a CollisionBody) and is not a trigger
if (mRigidBodyComponents.hasComponent(pair.body1Entity) && mRigidBodyComponents.hasComponent(pair.body2Entity)
&& !mCollidersComponents.getIsTrigger(pair.collider1Entity) && !mCollidersComponents.getIsTrigger(pair.collider2Entity)) {
assert(pair.potentialContactManifoldsIndices.size() > 0);
nbTotalManifolds += pair.potentialContactManifoldsIndices.size();
// Add the contact manifold into the island
@ -809,7 +807,6 @@ void PhysicsWorld::createIslands() {
else {
// Add the contact pair index in the list of contact pairs that won't be part of islands
nonRigidBodiesContactPairs.add(pair.contactPairIndex);
pair.isAlreadyInIsland = true;
}
}

View File

@ -61,10 +61,10 @@ CollisionDetectionSystem::CollisionDetectionSystem(PhysicsWorld* world, Collider
mNarrowPhaseInput(mMemoryManager.getSingleFrameAllocator(), mOverlappingPairs), mPotentialContactPoints(mMemoryManager.getSingleFrameAllocator()),
mPotentialContactManifolds(mMemoryManager.getSingleFrameAllocator()), mContactPairs1(mMemoryManager.getPoolAllocator()),
mContactPairs2(mMemoryManager.getPoolAllocator()), mPreviousContactPairs(&mContactPairs1), mCurrentContactPairs(&mContactPairs2),
mMapPairIdToContactPairIndex1(mMemoryManager.getPoolAllocator()), mMapPairIdToContactPairIndex2(mMemoryManager.getPoolAllocator()),
mPreviousMapPairIdToContactPairIndex(&mMapPairIdToContactPairIndex1), mCurrentMapPairIdToContactPairIndex(&mMapPairIdToContactPairIndex2),
mContactManifolds1(mMemoryManager.getPoolAllocator()), mContactManifolds2(mMemoryManager.getPoolAllocator()),
mPreviousContactManifolds(&mContactManifolds1), mCurrentContactManifolds(&mContactManifolds2),
mLostContactPairs(mMemoryManager.getSingleFrameAllocator()), mMapPairIdToContactPairIndex1(mMemoryManager.getPoolAllocator()),
mMapPairIdToContactPairIndex2(mMemoryManager.getPoolAllocator()), mPreviousMapPairIdToContactPairIndex(&mMapPairIdToContactPairIndex1),
mCurrentMapPairIdToContactPairIndex(&mMapPairIdToContactPairIndex2), mContactManifolds1(mMemoryManager.getPoolAllocator()),
mContactManifolds2(mMemoryManager.getPoolAllocator()), mPreviousContactManifolds(&mContactManifolds1), mCurrentContactManifolds(&mContactManifolds2),
mContactPoints1(mMemoryManager.getPoolAllocator()),
mContactPoints2(mMemoryManager.getPoolAllocator()), mPreviousContactPoints(&mContactPoints1),
mCurrentContactPoints(&mContactPoints2), mMapBodyToContactPairs(mMemoryManager.getSingleFrameAllocator()) {
@ -88,7 +88,7 @@ void CollisionDetectionSystem::computeCollisionDetection() {
computeBroadPhase();
// Compute the middle-phase collision detection
computeMiddlePhase(mNarrowPhaseInput);
computeMiddlePhase(mNarrowPhaseInput, true);
// Compute the narrow-phase collision detection
computeNarrowPhase();
@ -117,7 +117,6 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() {
RP3D_PROFILE("CollisionDetectionSystem::removeNonOverlappingPairs()", mProfiler);
// For each possible convex vs convex pair of bodies
for (uint64 i=0; i < mOverlappingPairs.getNbPairs(); i++) {
// Check if we need to test overlap. If so, test if the two shapes are still overlapping.
@ -128,6 +127,14 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() {
mOverlappingPairs.mNeedToTestOverlap[i] = false;
}
else {
// If the two colliders of the pair were colliding in the previous frame
if (mOverlappingPairs.mCollidingInPreviousFrame[i]) {
// Create a new lost contact pair
addLostContactPair(i);
}
mOverlappingPairs.removePair(mOverlappingPairs.mPairIds[i]);
i--;
}
@ -135,6 +142,25 @@ void CollisionDetectionSystem::removeNonOverlappingPairs() {
}
}
// Add a lost contact pair (pair of colliders that are not in contact anymore)
void CollisionDetectionSystem::addLostContactPair(uint64 overlappingPairIndex) {
const Entity collider1Entity = mOverlappingPairs.mColliders1[overlappingPairIndex];
const Entity collider2Entity = mOverlappingPairs.mColliders2[overlappingPairIndex];
const Entity body1Entity = mCollidersComponents.getBody(collider1Entity);
const Entity body2Entity = mCollidersComponents.getBody(collider2Entity);
const bool isCollider1Trigger = mCollidersComponents.getIsTrigger(collider1Entity);
const bool isCollider2Trigger = mCollidersComponents.getIsTrigger(collider2Entity);
const bool isTrigger = isCollider1Trigger || isCollider2Trigger;
// Create a lost contact pair
ContactPair lostContactPair(mOverlappingPairs.mPairIds[overlappingPairIndex], body1Entity, body2Entity, collider1Entity, collider2Entity, mLostContactPairs.size(),
true, isTrigger, mMemoryManager.getHeapAllocator());
mLostContactPairs.add(lostContactPair);
}
// Take a list of overlapping nodes in the broad-phase and create new overlapping pairs if necessary
void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int32, int32>>& overlappingNodes) {
@ -204,7 +230,7 @@ void CollisionDetectionSystem::updateOverlappingPairs(const List<Pair<int32, int
}
// Compute the middle-phase collision detection
void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseInput) {
void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseInput, bool needToReportContacts) {
RP3D_PROFILE("CollisionDetectionSystem::computeMiddlePhase()", mProfiler);
@ -235,12 +261,18 @@ void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseI
NarrowPhaseAlgorithmType algorithmType = mOverlappingPairs.mNarrowPhaseAlgorithmType[i];
const bool isCollider1Trigger = mCollidersComponents.mIsTrigger[collider1Index];
const bool isCollider2Trigger = mCollidersComponents.mIsTrigger[collider2Index];
const bool reportContacts = needToReportContacts && !isCollider1Trigger && !isCollider2Trigger;
// 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, mMemoryManager.getSingleFrameAllocator());
algorithmType, reportContacts, mMemoryManager.getSingleFrameAllocator());
mOverlappingPairs.mCollidingInCurrentFrame[i] = false;
}
}
@ -256,12 +288,15 @@ void CollisionDetectionSystem::computeMiddlePhase(NarrowPhaseInput& narrowPhaseI
if (mOverlappingPairs.mIsActive[i]) {
computeConvexVsConcaveMiddlePhase(i, mMemoryManager.getSingleFrameAllocator(), narrowPhaseInput);
mOverlappingPairs.mCollidingInCurrentFrame[i] = false;
}
}
}
// Compute the middle-phase collision detection
void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs, NarrowPhaseInput& narrowPhaseInput) {
void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>& convexPairs, List<uint64>& concavePairs, NarrowPhaseInput& narrowPhaseInput,
bool reportContacts) {
RP3D_PROFILE("CollisionDetectionSystem::computeMiddlePhase()", mProfiler);
@ -299,7 +334,7 @@ void CollisionDetectionSystem::computeMiddlePhaseCollisionSnapshot(List<uint64>&
narrowPhaseInput.addNarrowPhaseTest(pairId, pairIndex, collider1Entity, collider2Entity, collisionShape1, collisionShape2,
mCollidersComponents.mLocalToWorldTransforms[collider1Index],
mCollidersComponents.mLocalToWorldTransforms[collider2Index],
algorithmType, mMemoryManager.getSingleFrameAllocator());
algorithmType, reportContacts, mMemoryManager.getSingleFrameAllocator());
}
@ -365,6 +400,10 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
assert(triangleVertices.size() % 3 == 0);
assert(triangleVerticesNormals.size() % 3 == 0);
const bool isCollider1Trigger = mCollidersComponents.mIsTrigger[collider1Index];
const bool isCollider2Trigger = mCollidersComponents.mIsTrigger[collider2Index];
const bool reportContacts = !isCollider1Trigger && !isCollider2Trigger;
// For each overlapping triangle
for (uint i=0; i < shapeIds.size(); i++)
{
@ -384,13 +423,13 @@ void CollisionDetectionSystem::computeConvexVsConcaveMiddlePhase(uint64 pairInde
narrowPhaseInput.addNarrowPhaseTest(mOverlappingPairs.mPairIds[pairIndex], pairIndex, collider1, collider2, isShape1Convex ? convexShape : triangleShape,
isShape1Convex ? triangleShape : convexShape,
shape1LocalToWorldTransform, shape2LocalToWorldTransform,
mOverlappingPairs.mNarrowPhaseAlgorithmType[pairIndex], allocator);
mOverlappingPairs.mNarrowPhaseAlgorithmType[pairIndex], reportContacts, allocator);
}
}
// Execute the narrow-phase collision detection algorithm on batches
bool CollisionDetectionSystem::testNarrowPhaseCollision(NarrowPhaseInput& narrowPhaseInput, bool reportContacts,
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& allocator) {
bool CollisionDetectionSystem::testNarrowPhaseCollision(NarrowPhaseInput& narrowPhaseInput,
bool clipWithPreviousAxisIfStillColliding, MemoryAllocator& allocator) {
bool contactFound = false;
@ -402,32 +441,32 @@ bool CollisionDetectionSystem::testNarrowPhaseCollision(NarrowPhaseInput& narrow
CapsuleVsConvexPolyhedronAlgorithm* capsuleVsConvexPolyAlgo = mCollisionDispatch.getCapsuleVsConvexPolyhedronAlgorithm();
ConvexPolyhedronVsConvexPolyhedronAlgorithm* convexPolyVsConvexPolyAlgo = mCollisionDispatch.getConvexPolyhedronVsConvexPolyhedronAlgorithm();
// get the narrow-phase batches to test for collision
SphereVsSphereNarrowPhaseInfoBatch& sphereVsSphereBatch = narrowPhaseInput.getSphereVsSphereBatch();
SphereVsCapsuleNarrowPhaseInfoBatch& sphereVsCapsuleBatch = narrowPhaseInput.getSphereVsCapsuleBatch();
CapsuleVsCapsuleNarrowPhaseInfoBatch& capsuleVsCapsuleBatch = narrowPhaseInput.getCapsuleVsCapsuleBatch();
NarrowPhaseInfoBatch& sphereVsConvexPolyhedronBatch = narrowPhaseInput.getSphereVsConvexPolyhedronBatch();
NarrowPhaseInfoBatch& capsuleVsConvexPolyhedronBatch = narrowPhaseInput.getCapsuleVsConvexPolyhedronBatch();
NarrowPhaseInfoBatch& convexPolyhedronVsConvexPolyhedronBatch = narrowPhaseInput.getConvexPolyhedronVsConvexPolyhedronBatch();
// get the narrow-phase batches to test for collision for contacts
SphereVsSphereNarrowPhaseInfoBatch& sphereVsSphereBatchContacts = narrowPhaseInput.getSphereVsSphereBatch();
SphereVsCapsuleNarrowPhaseInfoBatch& sphereVsCapsuleBatchContacts = narrowPhaseInput.getSphereVsCapsuleBatch();
CapsuleVsCapsuleNarrowPhaseInfoBatch& capsuleVsCapsuleBatchContacts = narrowPhaseInput.getCapsuleVsCapsuleBatch();
NarrowPhaseInfoBatch& sphereVsConvexPolyhedronBatchContacts = narrowPhaseInput.getSphereVsConvexPolyhedronBatch();
NarrowPhaseInfoBatch& capsuleVsConvexPolyhedronBatchContacts = narrowPhaseInput.getCapsuleVsConvexPolyhedronBatch();
NarrowPhaseInfoBatch& convexPolyhedronVsConvexPolyhedronBatchContacts = narrowPhaseInput.getConvexPolyhedronVsConvexPolyhedronBatch();
// Compute the narrow-phase collision detection for each kind of collision shapes
if (sphereVsSphereBatch.getNbObjects() > 0) {
contactFound |= sphereVsSphereAlgo->testCollision(sphereVsSphereBatch, 0, sphereVsSphereBatch.getNbObjects(), reportContacts, allocator);
// Compute the narrow-phase collision detection for each kind of collision shapes (for contacts)
if (sphereVsSphereBatchContacts.getNbObjects() > 0) {
contactFound |= sphereVsSphereAlgo->testCollision(sphereVsSphereBatchContacts, 0, sphereVsSphereBatchContacts.getNbObjects(), allocator);
}
if (sphereVsCapsuleBatch.getNbObjects() > 0) {
contactFound |= sphereVsCapsuleAlgo->testCollision(sphereVsCapsuleBatch, 0, sphereVsCapsuleBatch.getNbObjects(), reportContacts, allocator);
if (sphereVsCapsuleBatchContacts.getNbObjects() > 0) {
contactFound |= sphereVsCapsuleAlgo->testCollision(sphereVsCapsuleBatchContacts, 0, sphereVsCapsuleBatchContacts.getNbObjects(), allocator);
}
if (capsuleVsCapsuleBatch.getNbObjects() > 0) {
contactFound |= capsuleVsCapsuleAlgo->testCollision(capsuleVsCapsuleBatch, 0, capsuleVsCapsuleBatch.getNbObjects(), reportContacts, allocator);
if (capsuleVsCapsuleBatchContacts.getNbObjects() > 0) {
contactFound |= capsuleVsCapsuleAlgo->testCollision(capsuleVsCapsuleBatchContacts, 0, capsuleVsCapsuleBatchContacts.getNbObjects(), allocator);
}
if (sphereVsConvexPolyhedronBatch.getNbObjects() > 0) {
contactFound |= sphereVsConvexPolyAlgo->testCollision(sphereVsConvexPolyhedronBatch, 0, sphereVsConvexPolyhedronBatch.getNbObjects(), reportContacts, clipWithPreviousAxisIfStillColliding, allocator);
if (sphereVsConvexPolyhedronBatchContacts.getNbObjects() > 0) {
contactFound |= sphereVsConvexPolyAlgo->testCollision(sphereVsConvexPolyhedronBatchContacts, 0, sphereVsConvexPolyhedronBatchContacts.getNbObjects(), clipWithPreviousAxisIfStillColliding, allocator);
}
if (capsuleVsConvexPolyhedronBatch.getNbObjects() > 0) {
contactFound |= capsuleVsConvexPolyAlgo->testCollision(capsuleVsConvexPolyhedronBatch, 0, capsuleVsConvexPolyhedronBatch.getNbObjects(), reportContacts, clipWithPreviousAxisIfStillColliding, allocator);
if (capsuleVsConvexPolyhedronBatchContacts.getNbObjects() > 0) {
contactFound |= capsuleVsConvexPolyAlgo->testCollision(capsuleVsConvexPolyhedronBatchContacts, 0, capsuleVsConvexPolyhedronBatchContacts.getNbObjects(), clipWithPreviousAxisIfStillColliding, allocator);
}
if (convexPolyhedronVsConvexPolyhedronBatch.getNbObjects() > 0) {
contactFound |= convexPolyVsConvexPolyAlgo->testCollision(convexPolyhedronVsConvexPolyhedronBatch, 0, convexPolyhedronVsConvexPolyhedronBatch.getNbObjects(), reportContacts, clipWithPreviousAxisIfStillColliding, allocator);
if (convexPolyhedronVsConvexPolyhedronBatchContacts.getNbObjects() > 0) {
contactFound |= convexPolyVsConvexPolyAlgo->testCollision(convexPolyhedronVsConvexPolyhedronBatchContacts, 0, convexPolyhedronVsConvexPolyhedronBatchContacts.getNbObjects(), clipWithPreviousAxisIfStillColliding, allocator);
}
return contactFound;
@ -478,7 +517,7 @@ void CollisionDetectionSystem::computeNarrowPhase() {
swapPreviousAndCurrentContacts();
// Test the narrow-phase collision detection on the batches to be tested
testNarrowPhaseCollision(mNarrowPhaseInput, true, true, allocator);
testNarrowPhaseCollision(mNarrowPhaseInput, true, allocator);
// Process all the potential contacts after narrow-phase collision
processAllPotentialContacts(mNarrowPhaseInput, true, mPotentialContactPoints, mCurrentMapPairIdToContactPairIndex,
@ -505,15 +544,16 @@ bool CollisionDetectionSystem::computeNarrowPhaseOverlapSnapshot(NarrowPhaseInpu
MemoryAllocator& allocator = mMemoryManager.getPoolAllocator();
// Test the narrow-phase collision detection on the batches to be tested
bool collisionFound = testNarrowPhaseCollision(narrowPhaseInput, false, false, allocator);
bool collisionFound = testNarrowPhaseCollision(narrowPhaseInput, false, allocator);
if (collisionFound && callback != nullptr) {
// Compute the overlapping bodies
List<Pair<Entity, Entity>> overlapBodies(allocator);
computeSnapshotContactPairs(narrowPhaseInput, overlapBodies);
// Compute the overlapping colliders
List<ContactPair> contactPairs(allocator);
List<ContactPair> lostContactPairs(allocator); // Always empty in this case (snapshot)
computeOverlapSnapshotContactPairs(narrowPhaseInput, contactPairs);
// Report overlapping bodies
OverlapCallback::CallbackData callbackData(overlapBodies, *mWorld);
// Report overlapping colliders
OverlapCallback::CallbackData callbackData(contactPairs, lostContactPairs, *mWorld);
(*callback).onOverlap(callbackData);
}
@ -521,7 +561,9 @@ bool CollisionDetectionSystem::computeNarrowPhaseOverlapSnapshot(NarrowPhaseInpu
}
// Process the potential overlapping bodies for the testOverlap() methods
void CollisionDetectionSystem::computeSnapshotContactPairs(NarrowPhaseInput& narrowPhaseInput, List<Pair<Entity, Entity>>& overlapPairs) const {
void CollisionDetectionSystem::computeOverlapSnapshotContactPairs(NarrowPhaseInput& narrowPhaseInput, List<ContactPair>& contactPairs) const {
Set<uint64> setOverlapContactPairId(mMemoryManager.getHeapAllocator());
// get the narrow-phase batches to test for collision
NarrowPhaseInfoBatch& sphereVsSphereBatch = narrowPhaseInput.getSphereVsSphereBatch();
@ -532,12 +574,12 @@ void CollisionDetectionSystem::computeSnapshotContactPairs(NarrowPhaseInput& nar
NarrowPhaseInfoBatch& convexPolyhedronVsConvexPolyhedronBatch = narrowPhaseInput.getConvexPolyhedronVsConvexPolyhedronBatch();
// Process the potential contacts
computeSnapshotContactPairs(sphereVsSphereBatch, overlapPairs);
computeSnapshotContactPairs(sphereVsCapsuleBatch, overlapPairs);
computeSnapshotContactPairs(capsuleVsCapsuleBatch, overlapPairs);
computeSnapshotContactPairs(sphereVsConvexPolyhedronBatch, overlapPairs);
computeSnapshotContactPairs(capsuleVsConvexPolyhedronBatch, overlapPairs);
computeSnapshotContactPairs(convexPolyhedronVsConvexPolyhedronBatch, overlapPairs);
computeOverlapSnapshotContactPairs(sphereVsSphereBatch, contactPairs, setOverlapContactPairId);
computeOverlapSnapshotContactPairs(sphereVsCapsuleBatch, contactPairs, setOverlapContactPairId);
computeOverlapSnapshotContactPairs(capsuleVsCapsuleBatch, contactPairs, setOverlapContactPairId);
computeOverlapSnapshotContactPairs(sphereVsConvexPolyhedronBatch, contactPairs, setOverlapContactPairId);
computeOverlapSnapshotContactPairs(capsuleVsConvexPolyhedronBatch, contactPairs, setOverlapContactPairId);
computeOverlapSnapshotContactPairs(convexPolyhedronVsConvexPolyhedronBatch, contactPairs, setOverlapContactPairId);
}
// Notify that the overlapping pairs where a given collider is involved need to be tested for overlap
@ -554,19 +596,38 @@ void CollisionDetectionSystem::notifyOverlappingPairsToTestOverlap(Collider* col
}
// Convert the potential overlapping bodies for the testOverlap() methods
void CollisionDetectionSystem::computeSnapshotContactPairs(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, List<Pair<Entity, Entity>>& overlapPairs) const {
void CollisionDetectionSystem::computeOverlapSnapshotContactPairs(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, List<ContactPair>& contactPairs,
Set<uint64>& setOverlapContactPairId) const {
RP3D_PROFILE("CollisionDetectionSystem::computeSnapshotContactPairs()", mProfiler);
// For each narrow phase info object
for(uint i=0; i < narrowPhaseInfoBatch.getNbObjects(); i++) {
// If there is a contact
// If there is a collision
if (narrowPhaseInfoBatch.isColliding[i]) {
// Add the pair of bodies in contact into the list
overlapPairs.add(Pair<Entity, Entity>(mCollidersComponents.getBody(narrowPhaseInfoBatch.colliderEntities1[i]),
mCollidersComponents.getBody(narrowPhaseInfoBatch.colliderEntities2[i])));
// If the contact pair does not already exist
if (!setOverlapContactPairId.contains(narrowPhaseInfoBatch.overlappingPairIds[i])) {
const Entity collider1Entity = narrowPhaseInfoBatch.colliderEntities1[i];
const Entity collider2Entity = narrowPhaseInfoBatch.colliderEntities2[i];
const uint32 collider1Index = mCollidersComponents.getEntityIndex(collider1Entity);
const uint32 collider2Index = mCollidersComponents.getEntityIndex(collider2Entity);
const Entity body1Entity = mCollidersComponents.mBodiesEntities[collider1Index];
const Entity body2Entity = mCollidersComponents.mBodiesEntities[collider2Index];
const bool isTrigger = mCollidersComponents.mIsTrigger[collider1Index] || mCollidersComponents.mIsTrigger[collider2Index];
// Create a new contact pair
ContactPair contactPair(narrowPhaseInfoBatch.overlappingPairIds[i], body1Entity, body2Entity, collider1Entity, collider2Entity,
contactPairs.size(), isTrigger, false, mMemoryManager.getHeapAllocator());
contactPairs.add(contactPair);
setOverlapContactPairId.add(narrowPhaseInfoBatch.overlappingPairIds[i]);
}
}
narrowPhaseInfoBatch.resetContactPoints(i);
@ -582,7 +643,7 @@ bool CollisionDetectionSystem::computeNarrowPhaseCollisionSnapshot(NarrowPhaseIn
MemoryAllocator& allocator = mMemoryManager.getHeapAllocator();
// Test the narrow-phase collision detection on the batches to be tested
bool collisionFound = testNarrowPhaseCollision(narrowPhaseInput, true, false, allocator);
bool collisionFound = testNarrowPhaseCollision(narrowPhaseInput, false, allocator);
// If collision has been found, create contacts
if (collisionFound) {
@ -591,6 +652,7 @@ bool CollisionDetectionSystem::computeNarrowPhaseCollisionSnapshot(NarrowPhaseIn
List<ContactManifoldInfo> potentialContactManifolds(allocator);
Map<uint64, uint> mapPairIdToContactPairIndex(allocator);
List<ContactPair> contactPairs(allocator);
List<ContactPair> lostContactPairs(allocator); // Not used during collision snapshots
List<ContactManifold> contactManifolds(allocator);
List<ContactPoint> contactPoints(allocator);
Map<Entity, List<uint>> mapBodyToContactPairs(allocator);
@ -607,7 +669,7 @@ bool CollisionDetectionSystem::computeNarrowPhaseCollisionSnapshot(NarrowPhaseIn
potentialContactPoints);
// Report the contacts to the user
reportContacts(callback, &contactPairs, &contactManifolds, &contactPoints);
reportContacts(callback, &contactPairs, &contactManifolds, &contactPoints, lostContactPairs);
}
return collisionFound;
@ -654,7 +716,6 @@ void CollisionDetectionSystem::createContacts() {
for (uint p=0; p < (*mCurrentContactPairs).size(); p++) {
ContactPair& contactPair = (*mCurrentContactPairs)[p];
assert(contactPair.potentialContactManifoldsIndices.size() > 0);
contactPair.contactManifoldsIndex = mCurrentContactManifolds->size();
contactPair.nbContactManifolds = contactPair.potentialContactManifoldsIndices.size();
@ -696,16 +757,38 @@ void CollisionDetectionSystem::createContacts() {
// Initialize the current contacts with the contacts from the previous frame (for warmstarting)
initContactsWithPreviousOnes();
// Report contacts to the user
if (mWorld->mEventListener != nullptr) {
reportContacts(*(mWorld->mEventListener), mCurrentContactPairs, mCurrentContactManifolds, mCurrentContactPoints);
}
// Compute the lost contacts (contact pairs that were colliding in previous frame but not in this one)
computeLostContactPairs();
mPreviousContactPoints->clear();
mPreviousContactManifolds->clear();
mPreviousContactPairs->clear();
mPreviousMapPairIdToContactPairIndex->clear();
// Reset the potential contacts
mPotentialContactPoints.clear(true);
mPotentialContactManifolds.clear(true);
}
// 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++) {
// 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 both bodies still exist
if (mCollidersComponents.hasComponent(mOverlappingPairs.mColliders1[i]) && mCollidersComponents.hasComponent(mOverlappingPairs.mColliders2[i])) {
// Create a lost contact pair
addLostContactPair(i);
}
}
}
}
// Create the actual contact manifolds and contacts points for testCollision() methods
void CollisionDetectionSystem::createSnapshotContacts(List<ContactPair>& contactPairs,
List<ContactManifold>& contactManifolds,
@ -784,7 +867,7 @@ void CollisionDetectionSystem::initContactsWithPreviousOnes() {
const uint contactManifoldsIndex = currentContactPair.contactManifoldsIndex;
const uint nbContactManifolds = currentContactPair.nbContactManifolds;
// For each current contact manifold of the contact pair
// For each current contact manifold of the current contact pair
for (uint m=contactManifoldsIndex; m < contactManifoldsIndex + nbContactManifolds; m++) {
assert(m < mCurrentContactManifolds->size());
@ -823,7 +906,7 @@ void CollisionDetectionSystem::initContactsWithPreviousOnes() {
const uint contactPointsIndex = currentContactPair.contactPointsIndex;
const uint nbTotalContactPoints = currentContactPair.nbToTalContactPoints;
// For each current contact point of the contact pair
// For each current contact point of the current contact pair
for (uint c=contactPointsIndex; c < contactPointsIndex + nbTotalContactPoints; c++) {
assert(c < mCurrentContactPoints->size());
@ -850,11 +933,6 @@ void CollisionDetectionSystem::initContactsWithPreviousOnes() {
}
}
}
mPreviousContactPoints->clear();
mPreviousContactManifolds->clear();
mPreviousContactPairs->clear();
mPreviousMapPairIdToContactPairIndex->clear();
}
// Remove a body from the collision detection
@ -897,11 +975,11 @@ void CollisionDetectionSystem::raycast(RaycastCallback* raycastCallback,
// Convert the potential contact into actual contacts
void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& narrowPhaseInfoBatch, bool updateLastFrameInfo,
List<ContactPointInfo>& potentialContactPoints,
Map<uint64, uint>* mapPairIdToContactPairIndex,
List<ContactManifoldInfo>& potentialContactManifolds,
List<ContactPair>* contactPairs,
Map<Entity, List<uint>>& mapBodyToContactPairs) {
List<ContactPointInfo>& potentialContactPoints,
Map<uint64, uint>* mapPairIdToContactPairIndex,
List<ContactManifoldInfo>& potentialContactManifolds,
List<ContactPair>* contactPairs,
Map<Entity, List<uint>>& mapBodyToContactPairs) {
RP3D_PROFILE("CollisionDetectionSystem::processPotentialContacts()", mProfiler);
@ -915,32 +993,82 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
narrowPhaseInfoBatch.lastFrameCollisionInfos[i]->isValid = true;
}
// Add the potential contacts
for (uint j=0; j < narrowPhaseInfoBatch.contactPoints[i].size(); j++) {
const uint64 pairId = narrowPhaseInfoBatch.overlappingPairIds[i];
const uint64 pairIndex = mOverlappingPairs.mMapPairIdToPairIndex[pairId];
assert(narrowPhaseInfoBatch.isColliding[i]);
// If the two colliders are colliding
if (narrowPhaseInfoBatch.isColliding[i]) {
const ContactPointInfo& contactPoint = *(narrowPhaseInfoBatch.contactPoints[i][j]);
mOverlappingPairs.mCollidingInCurrentFrame[pairIndex] = true;
// Add the contact point to the list of potential contact points
const uint contactPointIndex = static_cast<uint>(potentialContactPoints.size());
potentialContactPoints.add(contactPoint);
bool similarManifoldFound = false;
// If there is already a contact pair for this overlapping pair
const uint64 pairId = narrowPhaseInfoBatch.overlappingPairIds[i];
// If there is not already a contact pair for this overlapping pair
auto it = mapPairIdToContactPairIndex->find(pairId);
ContactPair* pairContact = nullptr;
if (it != mapPairIdToContactPairIndex->end()) {
if (it == mapPairIdToContactPairIndex->end()) {
// Create a new ContactPair
const Entity collider1Entity = narrowPhaseInfoBatch.colliderEntities1[i];
const Entity collider2Entity = narrowPhaseInfoBatch.colliderEntities2[i];
const uint32 collider1Index = mCollidersComponents.getEntityIndex(collider1Entity);
const uint32 collider2Index = mCollidersComponents.getEntityIndex(collider2Entity);
const Entity body1Entity = mCollidersComponents.mBodiesEntities[collider1Index];
const Entity body2Entity = mCollidersComponents.mBodiesEntities[collider2Index];
const bool isTrigger = mCollidersComponents.mIsTrigger[collider1Index] || mCollidersComponents.mIsTrigger[collider2Index];
assert(!mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) || !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity));
const uint newContactPairIndex = contactPairs->size();
ContactPair overlappingPairContact(pairId, body1Entity, body2Entity,
collider1Entity, collider2Entity,
newContactPairIndex, mOverlappingPairs.getCollidingInPreviousFrame(pairId), isTrigger, mMemoryManager.getHeapAllocator());
contactPairs->add(overlappingPairContact);
pairContact = &((*contactPairs)[newContactPairIndex]);
mapPairIdToContactPairIndex->add(Pair<uint64, uint>(pairId, newContactPairIndex));
auto itbodyContactPairs = mapBodyToContactPairs.find(body1Entity);
if (itbodyContactPairs != mapBodyToContactPairs.end()) {
itbodyContactPairs->second.add(newContactPairIndex);
}
else {
List<uint> contactPairs(mMemoryManager.getPoolAllocator(), 1);
contactPairs.add(newContactPairIndex);
mapBodyToContactPairs.add(Pair<Entity, List<uint>>(body1Entity, contactPairs));
}
itbodyContactPairs = mapBodyToContactPairs.find(body2Entity);
if (itbodyContactPairs != mapBodyToContactPairs.end()) {
itbodyContactPairs->second.add(newContactPairIndex);
}
else {
List<uint> contactPairs(mMemoryManager.getPoolAllocator(), 1);
contactPairs.add(newContactPairIndex);
mapBodyToContactPairs.add(Pair<Entity, List<uint>>(body2Entity, contactPairs));
}
}
else { // If a ContactPair already exists for this overlapping pair, we use this one
assert(it->first == pairId);
const uint pairContactIndex = it->second;
pairContact = &((*contactPairs)[pairContactIndex]);
}
assert(pairContact->potentialContactManifoldsIndices.size() > 0);
assert(pairContact != nullptr);
// Add the potential contacts
for (uint j=0; j < narrowPhaseInfoBatch.contactPoints[i].size(); j++) {
const ContactPointInfo& contactPoint = *(narrowPhaseInfoBatch.contactPoints[i][j]);
// Add the contact point to the list of potential contact points
const uint contactPointIndex = static_cast<uint>(potentialContactPoints.size());
potentialContactPoints.add(contactPoint);
bool similarManifoldFound = false;
// For each contact manifold of the overlapping pair
for (uint m=0; m < pairContact->potentialContactManifoldsIndices.size(); m++) {
@ -964,71 +1092,32 @@ void CollisionDetectionSystem::processPotentialContacts(NarrowPhaseInfoBatch& na
break;
}
}
}
// If we have not found a manifold with a similar contact normal for the contact point
if (!similarManifoldFound) {
// If we have not found a manifold with a similar contact normal for the contact point
if (!similarManifoldFound) {
// Create a new contact manifold for the overlapping pair
ContactManifoldInfo contactManifoldInfo(pairId, mMemoryManager.getPoolAllocator());
// Create a new contact manifold for the overlapping pair
ContactManifoldInfo contactManifoldInfo(pairId, mMemoryManager.getPoolAllocator());
// Add the contact point to the manifold
contactManifoldInfo.potentialContactPointsIndices.add(contactPointIndex);
// Add the contact point to the manifold
contactManifoldInfo.potentialContactPointsIndices.add(contactPointIndex);
// If the overlapping pair contact does not exists yet
if (pairContact == nullptr) {
assert(pairContact != nullptr);
const Entity collider1Entity = narrowPhaseInfoBatch.colliderEntities1[i];
const Entity collider2Entity = narrowPhaseInfoBatch.colliderEntities2[i];
// Add the potential contact manifold
uint contactManifoldIndex = static_cast<uint>(potentialContactManifolds.size());
potentialContactManifolds.add(contactManifoldInfo);
const Entity body1Entity = mCollidersComponents.getBody(collider1Entity);
const Entity body2Entity = mCollidersComponents.getBody(collider2Entity);
assert(!mWorld->mCollisionBodyComponents.getIsEntityDisabled(body1Entity) || !mWorld->mCollisionBodyComponents.getIsEntityDisabled(body2Entity));
const uint newContactPairIndex = contactPairs->size();
ContactPair overlappingPairContact(pairId, body1Entity, body2Entity,
collider1Entity, collider2Entity,
newContactPairIndex, mMemoryManager.getHeapAllocator());
contactPairs->add(overlappingPairContact);
pairContact = &((*contactPairs)[newContactPairIndex]);
mapPairIdToContactPairIndex->add(Pair<uint64, uint>(pairId, newContactPairIndex));
auto itbodyContactPairs = mapBodyToContactPairs.find(body1Entity);
if (itbodyContactPairs != mapBodyToContactPairs.end()) {
itbodyContactPairs->second.add(newContactPairIndex);
}
else {
List<uint> contactPairs(mMemoryManager.getPoolAllocator(), 1);
contactPairs.add(newContactPairIndex);
mapBodyToContactPairs.add(Pair<Entity, List<uint>>(body1Entity, contactPairs));
}
itbodyContactPairs = mapBodyToContactPairs.find(body2Entity);
if (itbodyContactPairs != mapBodyToContactPairs.end()) {
itbodyContactPairs->second.add(newContactPairIndex);
}
else {
List<uint> contactPairs(mMemoryManager.getPoolAllocator(), 1);
contactPairs.add(newContactPairIndex);
mapBodyToContactPairs.add(Pair<Entity, List<uint>>(body2Entity, contactPairs));
}
// Add the contact manifold to the overlapping pair contact
assert(pairContact->pairId == contactManifoldInfo.pairId);
pairContact->potentialContactManifoldsIndices.add(contactManifoldIndex);
}
assert(pairContact != nullptr);
// Add the potential contact manifold
uint contactManifoldIndex = static_cast<uint>(potentialContactManifolds.size());
potentialContactManifolds.add(contactManifoldInfo);
// Add the contact manifold to the overlapping pair contact
assert(pairContact->pairId == contactManifoldInfo.pairId);
pairContact->potentialContactManifoldsIndices.add(contactManifoldIndex);
assert(pairContact->potentialContactManifoldsIndices.size() > 0);
}
assert(pairContact->potentialContactManifoldsIndices.size() > 0);
narrowPhaseInfoBatch.resetContactPoints(i);
}
narrowPhaseInfoBatch.resetContactPoints(i);
}
}
@ -1044,8 +1133,6 @@ void CollisionDetectionSystem::reducePotentialContactManifolds(List<ContactPair>
ContactPair& contactPair = (*contactPairs)[i];
assert(contactPair.potentialContactManifoldsIndices.size() > 0);
// While there are too many manifolds in the contact pair
while(contactPair.potentialContactManifoldsIndices.size() > mWorld->mConfig.nbMaxContactManifolds) {
@ -1296,31 +1383,51 @@ void CollisionDetectionSystem::reduceContactPoints(ContactManifoldInfo& manifold
manifold.potentialContactPointsIndices.add(pointsToKeepIndices[3]);
}
// Report contacts
void CollisionDetectionSystem::reportContacts() {
// Report contacts and triggers
void CollisionDetectionSystem::reportContactsAndTriggers() {
if (mWorld->mEventListener != nullptr) {
reportContacts(*(mWorld->mEventListener), mCurrentContactPairs, mCurrentContactManifolds,
mCurrentContactPoints);
}
if (mWorld->mEventListener != nullptr) {
reportContacts(*(mWorld->mEventListener), mCurrentContactPairs, mCurrentContactManifolds, mCurrentContactPoints, mLostContactPairs);
reportTriggers(*(mWorld->mEventListener), mCurrentContactPairs, mLostContactPairs);
}
mOverlappingPairs.updateCollidingInPreviousFrame();
mLostContactPairs.clear(true);
}
// Report all contacts
void CollisionDetectionSystem::reportContacts(CollisionCallback& callback, List<ContactPair>* contactPairs,
List<ContactManifold>* manifolds, List<ContactPoint>* contactPoints) {
List<ContactManifold>* manifolds, List<ContactPoint>* contactPoints, List<ContactPair>& lostContactPairs) {
RP3D_PROFILE("CollisionDetectionSystem::reportContacts()", mProfiler);
// If there are contacts
if (contactPairs->size() > 0) {
if (contactPairs->size() + lostContactPairs.size() > 0) {
CollisionCallback::CallbackData callbackData(contactPairs, manifolds, contactPoints, *mWorld);
CollisionCallback::CallbackData callbackData(contactPairs, manifolds, contactPoints, lostContactPairs, *mWorld);
// Call the callback method to report the contacts
callback.onContact(callbackData);
}
}
// Report all triggers
void CollisionDetectionSystem::reportTriggers(EventListener& eventListener, List<ContactPair>* contactPairs, List<ContactPair>& lostContactPairs) {
RP3D_PROFILE("CollisionDetectionSystem::reportTriggers()", mProfiler);
// If there are contacts
if (contactPairs->size() + lostContactPairs.size() > 0) {
OverlapCallback::CallbackData callbackData(*contactPairs, lostContactPairs, *mWorld);
// Call the callback method to report the overlapping shapes
eventListener.onTrigger(callbackData);
}
}
// Return true if two bodies overlap (collide)
bool CollisionDetectionSystem::testOverlap(CollisionBody* body1, CollisionBody* body2) {
@ -1337,7 +1444,7 @@ bool CollisionDetectionSystem::testOverlap(CollisionBody* body1, CollisionBody*
if (convexPairs.size() > 0 || concavePairs.size() > 0) {
// Compute the middle-phase collision detection
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput);
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput, false);
// Compute the narrow-phase collision detection
return computeNarrowPhaseOverlapSnapshot(narrowPhaseInput, nullptr);
@ -1355,7 +1462,7 @@ void CollisionDetectionSystem::testOverlap(OverlapCallback& callback) {
computeBroadPhase();
// Compute the middle-phase collision detection
computeMiddlePhase(narrowPhaseInput);
computeMiddlePhase(narrowPhaseInput, false);
// Compute the narrow-phase collision detection and report overlapping shapes
computeNarrowPhaseOverlapSnapshot(narrowPhaseInput, &callback);
@ -1377,7 +1484,7 @@ void CollisionDetectionSystem::testOverlap(CollisionBody* body, OverlapCallback&
if (convexPairs.size() > 0 || concavePairs.size() > 0) {
// Compute the middle-phase collision detection
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput);
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput, false);
// Compute the narrow-phase collision detection
computeNarrowPhaseOverlapSnapshot(narrowPhaseInput, &callback);
@ -1400,7 +1507,7 @@ void CollisionDetectionSystem::testCollision(CollisionBody* body1, CollisionBody
if (convexPairs.size() > 0 || concavePairs.size() > 0) {
// Compute the middle-phase collision detection
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput);
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput, true);
// Compute the narrow-phase collision detection and report contacts
computeNarrowPhaseCollisionSnapshot(narrowPhaseInput, callback);
@ -1423,7 +1530,7 @@ void CollisionDetectionSystem::testCollision(CollisionBody* body, CollisionCallb
if (convexPairs.size() > 0 || concavePairs.size() > 0) {
// Compute the middle-phase collision detection
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput);
computeMiddlePhaseCollisionSnapshot(convexPairs, concavePairs, narrowPhaseInput, true);
// Compute the narrow-phase collision detection and report contacts
computeNarrowPhaseCollisionSnapshot(narrowPhaseInput, callback);
@ -1439,7 +1546,7 @@ void CollisionDetectionSystem::testCollision(CollisionCallback& callback) {
computeBroadPhase();
// Compute the middle-phase collision detection
computeMiddlePhase(narrowPhaseInput);
computeMiddlePhase(narrowPhaseInput, true);
// Compute the narrow-phase collision detection and report contacts
computeNarrowPhaseCollisionSnapshot(narrowPhaseInput, callback);

View File

@ -207,3 +207,7 @@ void Scene::onContact(const rp3d::CollisionCallback::CallbackData& callbackData)
}
}
}
void Scene::onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData) {
}

View File

@ -238,6 +238,8 @@ class Scene : public rp3d::EventListener {
/// Called when some contacts occur
virtual void onContact(const rp3d::CollisionCallback::CallbackData& callbackData) override;
virtual void onTrigger(const rp3d::OverlapCallback::CallbackData& callbackData) override;
};
// Called when a keyboard event occurs