From c7846d4a29e0b41a372f8ba4c53a97ba22150f18 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Mon, 12 Oct 2015 18:02:18 +0200 Subject: [PATCH] Report narrow-phase contacts to the collision detection in a more generic way --- src/collision/CollisionDetection.cpp | 63 +++++++++---------- src/collision/CollisionDetection.h | 5 +- .../narrowphase/ConcaveVsConvexAlgorithm.cpp | 29 +-------- .../narrowphase/ConcaveVsConvexAlgorithm.h | 10 ++- .../narrowphase/EPA/EPAAlgorithm.cpp | 7 ++- src/collision/narrowphase/EPA/EPAAlgorithm.h | 4 +- .../narrowphase/GJK/GJKAlgorithm.cpp | 24 ++++--- src/collision/narrowphase/GJK/GJKAlgorithm.h | 5 +- .../narrowphase/NarrowPhaseAlgorithm.h | 16 ++++- .../narrowphase/SphereVsSphereAlgorithm.cpp | 7 ++- .../narrowphase/SphereVsSphereAlgorithm.h | 2 +- 11 files changed, 92 insertions(+), 80 deletions(-) diff --git a/src/collision/CollisionDetection.cpp b/src/collision/CollisionDetection.cpp index 7908c2a8..d1e97942 100644 --- a/src/collision/CollisionDetection.cpp +++ b/src/collision/CollisionDetection.cpp @@ -175,7 +175,6 @@ void CollisionDetection::computeNarrowPhase() { // For each possible collision pair of bodies map::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) { diff --git a/src/collision/CollisionDetection.h b/src/collision/CollisionDetection.h index 3efff172..398460cc 100644 --- a/src/collision/CollisionDetection.h +++ b/src/collision/CollisionDetection.h @@ -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); diff --git a/src/collision/narrowphase/ConcaveVsConvexAlgorithm.cpp b/src/collision/narrowphase/ConcaveVsConvexAlgorithm.cpp index 5067ed39..91fc431c 100644 --- a/src/collision/narrowphase/ConcaveVsConvexAlgorithm.cpp +++ b/src/collision/narrowphase/ConcaveVsConvexAlgorithm.cpp @@ -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); } diff --git a/src/collision/narrowphase/ConcaveVsConvexAlgorithm.h b/src/collision/narrowphase/ConcaveVsConvexAlgorithm.h index a5270691..fc3a7287 100644 --- a/src/collision/narrowphase/ConcaveVsConvexAlgorithm.h +++ b/src/collision/narrowphase/ConcaveVsConvexAlgorithm.h @@ -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); }; } diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp index 7f5d9db2..02cc148a 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.cpp +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.cpp @@ -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; } diff --git a/src/collision/narrowphase/EPA/EPAAlgorithm.h b/src/collision/narrowphase/EPA/EPAAlgorithm.h index 7867cf95..d0b8dfa4 100644 --- a/src/collision/narrowphase/EPA/EPAAlgorithm.h +++ b/src/collision/narrowphase/EPA/EPAAlgorithm.h @@ -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 diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp index 67b49726..7554d6d1 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.cpp +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.cpp @@ -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 diff --git a/src/collision/narrowphase/GJK/GJKAlgorithm.h b/src/collision/narrowphase/GJK/GJKAlgorithm.h index 270899f4..2c3c5641 100644 --- a/src/collision/narrowphase/GJK/GJKAlgorithm.h +++ b/src/collision/narrowphase/GJK/GJKAlgorithm.h @@ -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); diff --git a/src/collision/narrowphase/NarrowPhaseAlgorithm.h b/src/collision/narrowphase/NarrowPhaseAlgorithm.h index 7dd1bbd6..725ba6c5 100644 --- a/src/collision/narrowphase/NarrowPhaseAlgorithm.h +++ b/src/collision/narrowphase/NarrowPhaseAlgorithm.h @@ -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 diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp index c49d8304..72655632 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.cpp @@ -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(shape1Info.collisionShape); @@ -70,10 +70,13 @@ 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; } diff --git a/src/collision/narrowphase/SphereVsSphereAlgorithm.h b/src/collision/narrowphase/SphereVsSphereAlgorithm.h index 1d7c6762..f0bf69a2 100644 --- a/src/collision/narrowphase/SphereVsSphereAlgorithm.h +++ b/src/collision/narrowphase/SphereVsSphereAlgorithm.h @@ -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); }; }