Report narrow-phase contacts to the collision detection in a more generic way

This commit is contained in:
Daniel Chappuis 2015-10-12 18:02:18 +02:00
parent ec5e41c19e
commit c7846d4a29
11 changed files with 92 additions and 80 deletions

View File

@ -175,7 +175,6 @@ void CollisionDetection::computeNarrowPhase() {
// For each possible collision pair of bodies
map<overlappingpairid, OverlappingPair*>::iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
ContactPointInfo* contactInfo = NULL;
OverlappingPair* pair = it->second;
@ -239,27 +238,9 @@ void CollisionDetection::computeNarrowPhase() {
pair, shape2->getCachedCollisionData());
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision
if (narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, contactInfo)) {
assert(contactInfo != NULL);
// If it is the first contact since the pair are overlapping
if (pair->getNbContactPoints() == 0) {
// Trigger a callback event
if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo);
}
// Create a new contact
createContact(pair, contactInfo);
// Trigger a callback event for the new contact
if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo);
// Delete and remove the contact info from the memory allocator
contactInfo->~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
}
// if there really is a collision. If a collision occurs, the
// notifyContact() callback method will be called.
narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, this);
}
// Add all the contact manifolds (between colliding bodies) to the bodies
@ -361,19 +342,7 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision
if (narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, contactInfo)) {
assert(contactInfo != NULL);
// Create a new contact
createContact(pair, contactInfo);
// Notify the collision callback about this new contact
if (callback != NULL) callback->notifyContact(*contactInfo);
// Delete and remove the contact info from the memory allocator
contactInfo->~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
}
narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, this);
}
// Add all the contact manifolds (between colliding bodies) to the bodies
@ -443,6 +412,30 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) {
mBroadPhaseAlgorithm.removeProxyCollisionShape(proxyShape);
}
// Called by a narrow-phase collision algorithm when a new contact has been found
void CollisionDetection::notifyContact(OverlappingPair* overlappingPair, ContactPointInfo* contactInfo) {
assert(contactInfo != NULL);
// If it is the first contact since the pairs are overlapping
if (overlappingPair->getNbContactPoints() == 0) {
// Trigger a callback event
if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo);
}
// TODO : Try not to allocate ContactPointInfo dynamically
// Create a new contact
createContact(overlappingPair, contactInfo);
// Trigger a callback event for the new contact
if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo);
// Delete and remove the contact info from the memory allocator
contactInfo->~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
}
// Create a new contact
void CollisionDetection::createContact(OverlappingPair* overlappingPair,
const ContactPointInfo* contactInfo) {

View File

@ -54,7 +54,7 @@ class CollisionCallback;
* collide and then we run a narrow-phase algorithm to compute the
* collision contacts between bodies.
*/
class CollisionDetection {
class CollisionDetection : public NarrowPhaseCallback {
private :
@ -203,6 +203,9 @@ class CollisionDetection {
/// Return a reference to the world memory allocator
MemoryAllocator& getWorldMemoryAllocator();
/// Called by a narrow-phase collision algorithm when a new contact has been found
virtual void notifyContact(OverlappingPair* overlappingPair, ContactPointInfo* contactInfo);
/// Create a new contact
void createContact(OverlappingPair* overlappingPair, const ContactPointInfo* contactInfo);

View File

@ -45,7 +45,7 @@ ConcaveVsConvexAlgorithm::~ConcaveVsConvexAlgorithm() {
// Return true and compute a contact info if the two bounding volumes collide
bool ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo) {
NarrowPhaseCallback* narrowPhaseCallback) {
ProxyShape* convexProxyShape;
ProxyShape* concaveProxyShape;
@ -67,6 +67,7 @@ bool ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& shape1Inf
}
// Set the parameters of the callback object
mConvexVsTriangleCallback.setNarrowPhaseCallback(narrowPhaseCallback);
mConvexVsTriangleCallback.setCollisionDetection(mCollisionDetection);
mConvexVsTriangleCallback.setConvexShape(convexShape);
mConvexVsTriangleCallback.setProxyShapes(convexProxyShape, concaveProxyShape);
@ -102,29 +103,5 @@ void ConvexVsTriangleCallback::reportTriangle(const Vector3* trianglePoints) {
mOverlappingPair, mConcaveProxyShape->getCachedCollisionData());
// Use the collision algorithm to test collision between the triangle and the other convex shape
ContactPointInfo* contactInfo = NULL;
if (algo->testCollision(shapeConvexInfo, shapeConcaveInfo, contactInfo)) {
assert(contactInfo != NULL);
// If it is the first contact since the pair are overlapping
if (mOverlappingPair->getNbContactPoints() == 0) {
// Trigger a callback event
if (mCollisionDetection->getWorldEventListener() != NULL) {
mCollisionDetection->getWorldEventListener()->beginContact(*contactInfo);
}
}
// Create a new contact
mCollisionDetection->createContact(mOverlappingPair, contactInfo);
// Trigger a callback event for the new contact
if (mCollisionDetection->getWorldEventListener() != NULL) {
mCollisionDetection->getWorldEventListener()->newContact(*contactInfo);
}
// Delete and remove the contact info from the memory allocator
contactInfo->~ContactPointInfo();
mCollisionDetection->getWorldMemoryAllocator().release(contactInfo, sizeof(ContactPointInfo));
}
algo->testCollision(shapeConvexInfo, shapeConcaveInfo, mNarrowPhaseCallback);
}

View File

@ -47,6 +47,9 @@ class ConvexVsTriangleCallback : public TriangleCallback {
/// Pointer to the collision detection object
CollisionDetection* mCollisionDetection;
/// Narrow-phase collision callback
NarrowPhaseCallback* mNarrowPhaseCallback;
/// Convex collision shape to test collision with
const ConvexShape* mConvexShape;
@ -66,6 +69,11 @@ class ConvexVsTriangleCallback : public TriangleCallback {
mCollisionDetection = collisionDetection;
}
/// Set the narrow-phase collision callback
void setNarrowPhaseCallback(NarrowPhaseCallback* callback) {
mNarrowPhaseCallback = callback;
}
/// Set the convex collision shape to test collision with
void setConvexShape(const ConvexShape* convexShape) {
mConvexShape = convexShape;
@ -124,7 +132,7 @@ class ConcaveVsConvexAlgorithm : public NarrowPhaseAlgorithm {
/// Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo);
NarrowPhaseCallback* narrowPhaseCallback);
};
}

View File

@ -86,7 +86,8 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
const Transform& transform1,
CollisionShapeInfo shape2Info,
const Transform& transform2,
Vector3& v, ContactPointInfo*& contactInfo) {
Vector3& v,
NarrowPhaseCallback* narrowPhaseCallback) {
assert(shape1Info.collisionShape->isConvex());
assert(shape2Info.collisionShape->isConvex());
@ -426,9 +427,11 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
assert(penetrationDepth > 0.0);
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape, normal,
penetrationDepth, pALocal, pBLocal);
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
return true;
}

View File

@ -31,6 +31,7 @@
#include "collision/shapes/CollisionShape.h"
#include "collision/CollisionShapeInfo.h"
#include "constraint/ContactPoint.h"
#include "collision/narrowphase/NarrowPhaseAlgorithm.h"
#include "mathematics/mathematics.h"
#include "TriangleEPA.h"
#include "memory/MemoryAllocator.h"
@ -127,7 +128,8 @@ class EPAAlgorithm {
const Transform& transform1,
CollisionShapeInfo shape2Info,
const Transform& transform2,
Vector3& v, ContactPointInfo*& contactInfo);
Vector3& v,
NarrowPhaseCallback* narrowPhaseCallback);
};
// Add a triangle face in the candidate triangle heap in the EPA algorithm

View File

@ -58,7 +58,7 @@ GJKAlgorithm::~GJKAlgorithm() {
/// the correct penetration depth and contact points between the enlarged objects.
bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo) {
NarrowPhaseCallback* narrowPhaseCallback) {
Vector3 suppA; // Support point of object A
Vector3 suppB; // Support point of object B
@ -147,10 +147,12 @@ bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape, normal,
penetrationDepth, pA, pB);
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
// There is an intersection, therefore we return true
return true;
}
@ -179,10 +181,12 @@ bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape, normal,
penetrationDepth, pA, pB);
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
// There is an intersection, therefore we return true
return true;
}
@ -209,10 +213,12 @@ bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape, normal,
penetrationDepth, pA, pB);
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
// There is an intersection, therefore we return true
return true;
}
@ -246,10 +252,12 @@ bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape, normal,
penetrationDepth, pA, pB);
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
// There is an intersection, therefore we return true
return true;
}
@ -261,7 +269,7 @@ bool GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
// the origin. Then, we give that simplex polytope to the EPA algorithm to compute
// the correct penetration depth and contact points between the enlarged objects.
return computePenetrationDepthForEnlargedObjects(shape1Info, transform1, shape2Info,
transform2, contactInfo, v);
transform2, narrowPhaseCallback, v);
}
/// This method runs the GJK algorithm on the two enlarged objects (with margin)
@ -273,7 +281,7 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
const Transform& transform1,
const CollisionShapeInfo& shape2Info,
const Transform& transform2,
ContactPointInfo*& contactInfo,
NarrowPhaseCallback* narrowPhaseCallback,
Vector3& v) {
Simplex simplex;
Vector3 suppA;
@ -344,7 +352,7 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
// between the two enlarged objects
return mAlgoEPA.computePenetrationDepthAndContactPoints(simplex, shape1Info,
transform1, shape2Info, transform2,
v, contactInfo);
v, narrowPhaseCallback);
}
// Use the GJK Algorithm to find if a point is inside a convex collision shape

View File

@ -79,7 +79,8 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
const Transform& transform1,
const CollisionShapeInfo& shape2Info,
const Transform& transform2,
ContactPointInfo*& contactInfo, Vector3& v);
NarrowPhaseCallback* narrowPhaseCallback,
Vector3& v);
public :
@ -98,7 +99,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
/// Return true and compute a contact info if the two bounding volumes collide.
virtual bool testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo);
NarrowPhaseCallback* narrowPhaseCallback);
/// Use the GJK Algorithm to find if a point is inside a convex collision shape
bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape);

View File

@ -38,6 +38,20 @@ namespace reactphysics3d {
class CollisionDetection;
// Class NarrowPhaseCallback
/**
* This abstract class is the base class for a narrow-phase collision
* callback class.
*/
class NarrowPhaseCallback {
public:
/// Called by a narrow-phase collision algorithm when a new contact has been found
virtual void notifyContact(OverlappingPair* overlappingPair, ContactPointInfo* contactInfo)=0;
};
// Class NarrowPhaseAlgorithm
/**
* This abstract class is the base class for a narrow-phase collision
@ -86,7 +100,7 @@ class NarrowPhaseAlgorithm {
/// Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo)=0;
NarrowPhaseCallback* narrowPhaseCallback)=0;
};
// Set the current overlapping pair of bodies

View File

@ -42,7 +42,7 @@ SphereVsSphereAlgorithm::~SphereVsSphereAlgorithm() {
bool SphereVsSphereAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo) {
NarrowPhaseCallback* narrowPhaseCallback) {
// Get the sphere collision shapes
const SphereShape* sphereShape1 = static_cast<const SphereShape*>(shape1Info.collisionShape);
@ -70,11 +70,14 @@ bool SphereVsSphereAlgorithm::testCollision(const CollisionShapeInfo& shape1Info
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
// Create the contact info object
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo* contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(shape1Info.proxyShape, shape2Info.proxyShape,
vectorBetweenCenters.getUnit(), penetrationDepth,
intersectionOnBody1, intersectionOnBody2);
// Notify about the new contact
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
return true;
}

View File

@ -65,7 +65,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
/// Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShapeInfo& shape1Info,
const CollisionShapeInfo& shape2Info,
ContactPointInfo*& contactInfo);
NarrowPhaseCallback* narrowPhaseCallback);
};
}