Allow the user to use custom collision detection algorithm

This commit is contained in:
Daniel Chappuis 2015-08-19 18:48:08 +02:00
parent 7ce44f9775
commit c76e5247aa
16 changed files with 325 additions and 58 deletions

View File

@ -53,6 +53,9 @@ SET (REACTPHYSICS3D_SOURCES
"src/collision/broadphase/BroadPhaseAlgorithm.cpp"
"src/collision/broadphase/DynamicAABBTree.h"
"src/collision/broadphase/DynamicAABBTree.cpp"
"src/collision/narrowphase/CollisionDispatch.h"
"src/collision/narrowphase/DefaultCollisionDispatch.h"
"src/collision/narrowphase/DefaultCollisionDispatch.cpp"
"src/collision/narrowphase/EPA/EdgeEPA.h"
"src/collision/narrowphase/EPA/EdgeEPA.cpp"
"src/collision/narrowphase/EPA/EPAAlgorithm.h"

View File

@ -42,11 +42,15 @@ using namespace std;
// Constructor
CollisionDetection::CollisionDetection(CollisionWorld* world, MemoryAllocator& memoryAllocator)
: mWorld(world), mBroadPhaseAlgorithm(*this),
mNarrowPhaseGJKAlgorithm(memoryAllocator),
mNarrowPhaseSphereVsSphereAlgorithm(memoryAllocator),
: mMemoryAllocator(memoryAllocator),
mWorld(world), mBroadPhaseAlgorithm(*this),
mIsCollisionShapesAdded(false) {
// Set the default collision dispatch configuration
setCollisionDispatch(&mDefaultCollisionDispatch);
// Fill-in the collision detection matrix with algorithms
fillInCollisionMatrix();
}
// Destructor
@ -209,16 +213,16 @@ void CollisionDetection::computeNarrowPhase() {
if (mNoCollisionPairs.count(bodiesIndex) > 0) continue;
// Select the narrow phase algorithm to use according to the two collision shapes
NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(
shape1->getCollisionShape(),
shape2->getCollisionShape());
const CollisionShapeType shape1Type = shape1->getCollisionShape()->getType();
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = mCollisionMatrix[shape1Type][shape2Type];
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
narrowPhaseAlgorithm.setCurrentOverlappingPair(pair);
narrowPhaseAlgorithm->setCurrentOverlappingPair(pair);
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision
if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) {
if (narrowPhaseAlgorithm->testCollision(shape1, shape2, contactInfo)) {
assert(contactInfo != NULL);
// If it is the first contact since the pair are overlapping
@ -316,16 +320,16 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
if (body1->isSleeping() && body2->isSleeping()) continue;
// Select the narrow phase algorithm to use according to the two collision shapes
NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(
shape1->getCollisionShape(),
shape2->getCollisionShape());
const CollisionShapeType shape1Type = shape1->getCollisionShape()->getType();
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = mCollisionMatrix[shape1Type][shape2Type];
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
narrowPhaseAlgorithm.setCurrentOverlappingPair(pair);
narrowPhaseAlgorithm->setCurrentOverlappingPair(pair);
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision
if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) {
if (narrowPhaseAlgorithm->testCollision(shape1, shape2, contactInfo)) {
assert(contactInfo != NULL);
// Create a new contact
@ -452,3 +456,15 @@ void CollisionDetection::clearContactPoints() {
it->second->clearContactPoints();
}
}
// Fill-in the collision detection matrix
void CollisionDetection::fillInCollisionMatrix() {
// For each possible type of collision shape
for (int i=0; i<NB_COLLISION_SHAPE_TYPES; i++) {
for (int j=0; j<NB_COLLISION_SHAPE_TYPES; j++) {
mCollisionMatrix[i][j] = mCollisionDispatch->selectAlgorithm(i, j);
assert(mCollisionMatrix[i][j] != NULL);
}
}
}

View File

@ -30,8 +30,7 @@
#include "body/CollisionBody.h"
#include "broadphase/BroadPhaseAlgorithm.h"
#include "engine/OverlappingPair.h"
#include "narrowphase/GJK/GJKAlgorithm.h"
#include "narrowphase/SphereVsSphereAlgorithm.h"
#include "narrowphase/DefaultCollisionDispatch.h"
#include "memory/MemoryAllocator.h"
#include "constraint/ContactPoint.h"
#include <vector>
@ -60,6 +59,18 @@ class CollisionDetection {
// -------------------- Attributes -------------------- //
/// Collision Detection Dispatch configuration
CollisionDispatch* mCollisionDispatch;
/// Default collision dispatch configuration
DefaultCollisionDispatch mDefaultCollisionDispatch;
/// Collision detection matrix (algorithms to use)
NarrowPhaseAlgorithm* mCollisionMatrix[NB_COLLISION_SHAPE_TYPES][NB_COLLISION_SHAPE_TYPES];
/// Reference to the memory allocator
MemoryAllocator& mMemoryAllocator;
/// Pointer to the physics world
CollisionWorld* mWorld;
@ -70,9 +81,11 @@ class CollisionDetection {
BroadPhaseAlgorithm mBroadPhaseAlgorithm;
/// Narrow-phase GJK algorithm
// TODO : Delete this
GJKAlgorithm mNarrowPhaseGJKAlgorithm;
/// Narrow-phase Sphere vs Sphere algorithm
// TODO : Delete this
SphereVsSphereAlgorithm mNarrowPhaseSphereVsSphereAlgorithm;
/// Set of pair of bodies that cannot collide between each other
@ -95,10 +108,6 @@ class CollisionDetection {
/// Compute the narrow-phase collision detection
void computeNarrowPhase();
/// Select the narrow phase algorithm to use given two collision shapes
NarrowPhaseAlgorithm& selectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2);
/// Create a new contact
void createContact(OverlappingPair* overlappingPair, const ContactPointInfo* contactInfo);
@ -110,6 +119,9 @@ class CollisionDetection {
/// Delete all the contact points in the currently overlapping pairs
void clearContactPoints();
/// Fill-in the collision detection matrix
void fillInCollisionMatrix();
public :
// -------------------- Methods -------------------- //
@ -120,6 +132,9 @@ class CollisionDetection {
/// Destructor
~CollisionDetection();
/// Set the collision dispatch configuration
void setCollisionDispatch(CollisionDispatch* collisionDispatch);
/// Add a proxy collision shape to the collision detection
void addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb);
@ -178,18 +193,14 @@ class CollisionDetection {
friend class ConvexMeshShape;
};
// Select the narrow-phase collision algorithm to use given two collision shapes
inline NarrowPhaseAlgorithm& CollisionDetection::selectNarrowPhaseAlgorithm(
const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2) {
/// Set the collision dispatch configuration
inline void CollisionDetection::setCollisionDispatch(CollisionDispatch* collisionDispatch) {
mCollisionDispatch = collisionDispatch;
// Sphere vs Sphere algorithm
if (collisionShape1->getType() == SPHERE && collisionShape2->getType() == SPHERE) {
return mNarrowPhaseSphereVsSphereAlgorithm;
}
else { // GJK algorithm
return mNarrowPhaseGJKAlgorithm;
}
mCollisionDispatch->init(&mMemoryAllocator);
// Fill-in the collision matrix with the new algorithms to use
fillInCollisionMatrix();
}
// Add a body to the collision detection

View File

@ -0,0 +1,66 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2015 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
#ifndef REACTPHYSICS3D_COLLISION_DISPATCH_H
#define REACTPHYSICS3D_COLLISION_DISPATCH_H
// Libraries
#include "NarrowPhaseAlgorithm.h"
namespace reactphysics3d {
// Class CollisionDispatch
/**
* This is the abstract base class for dispatching the narrow-phase
* collision detection algorithm. Collision dispatching decides which collision
* algorithm to use given two types of proxy collision shapes.
*/
class CollisionDispatch {
protected:
public:
/// Constructor
CollisionDispatch() {}
/// Destructor
virtual ~CollisionDispatch() {}
/// Initialize the collision dispatch configuration
virtual void init(MemoryAllocator* memoryAllocator) {
}
/// Select and return the narrow-phase collision detection algorithm to
/// use between two types of collision shapes.
virtual NarrowPhaseAlgorithm* selectAlgorithm(int shape1Type,
int shape2Type)=0;
};
}
#endif

View File

@ -0,0 +1,61 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2015 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
// Libraries
#include "DefaultCollisionDispatch.h"
using namespace reactphysics3d;
// Constructor
DefaultCollisionDispatch::DefaultCollisionDispatch() {
}
// Destructor
DefaultCollisionDispatch::~DefaultCollisionDispatch() {
}
/// Initialize the collision dispatch configuration
void DefaultCollisionDispatch::init(MemoryAllocator* memoryAllocator) {
// Initialize the collision algorithms
mSphereVsSphereAlgorithm.init(memoryAllocator);
mGJKAlgorithm.init(memoryAllocator);
}
// Select and return the narrow-phase collision detection algorithm to
// use between two types of collision shapes.
NarrowPhaseAlgorithm* DefaultCollisionDispatch::selectAlgorithm(int shape1Type,
int shape2Type) {
// Sphere vs Sphere algorithm
if (shape1Type == SPHERE && shape2Type == SPHERE) {
return &mSphereVsSphereAlgorithm;
}
else { // GJK algorithm
return &mGJKAlgorithm;
}
}

View File

@ -0,0 +1,74 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2015 Daniel Chappuis *
*********************************************************************************
* *
* This software is provided 'as-is', without any express or implied warranty. *
* In no event will the authors be held liable for any damages arising from the *
* use of this software. *
* *
* Permission is granted to anyone to use this software for any purpose, *
* including commercial applications, and to alter it and redistribute it *
* freely, subject to the following restrictions: *
* *
* 1. The origin of this software must not be misrepresented; you must not claim *
* that you wrote the original software. If you use this software in a *
* product, an acknowledgment in the product documentation would be *
* appreciated but is not required. *
* *
* 2. Altered source versions must be plainly marked as such, and must not be *
* misrepresented as being the original software. *
* *
* 3. This notice may not be removed or altered from any source distribution. *
* *
********************************************************************************/
#ifndef REACTPHYSICS3D_DEFAULT_COLLISION_DISPATCH_H
#define REACTPHYSICS3D_DEFAULT_COLLISION_DISPATCH_H
// Libraries
#include "CollisionDispatch.h"
#include "SphereVsSphereAlgorithm.h"
#include "GJK/GJKAlgorithm.h"
namespace reactphysics3d {
// Class DefaultCollisionDispatch
/**
* This is the default collision dispatch configuration use in ReactPhysics3D.
* Collision dispatching decides which collision
* algorithm to use given two types of proxy collision shapes.
*/
class DefaultCollisionDispatch : public CollisionDispatch {
protected:
/// Sphere vs Sphere collision algorithm
SphereVsSphereAlgorithm mSphereVsSphereAlgorithm;
/// GJK Algorithm
GJKAlgorithm mGJKAlgorithm;
public:
/// Constructor
DefaultCollisionDispatch();
/// Destructor
virtual ~DefaultCollisionDispatch();
/// Initialize the collision dispatch configuration
virtual void init(MemoryAllocator* memoryAllocator);
/// Select and return the narrow-phase collision detection algorithm to
/// use between two types of collision shapes.
virtual NarrowPhaseAlgorithm* selectAlgorithm(int shape1Type,
int shape2Type);
};
}
#endif

View File

@ -32,8 +32,7 @@
using namespace reactphysics3d;
// Constructor
EPAAlgorithm::EPAAlgorithm(MemoryAllocator& memoryAllocator)
: mMemoryAllocator(memoryAllocator) {
EPAAlgorithm::EPAAlgorithm() {
}
@ -418,7 +417,7 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
assert(penetrationDepth > 0.0);
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2, normal,
penetrationDepth, pALocal, pBLocal);

View File

@ -86,7 +86,7 @@ class EPAAlgorithm {
// -------------------- Attributes -------------------- //
/// Reference to the memory allocator
MemoryAllocator& mMemoryAllocator;
MemoryAllocator* mMemoryAllocator;
/// Triangle comparison operator
TriangleComparison mTriangleComparison;
@ -112,11 +112,14 @@ class EPAAlgorithm {
// -------------------- Methods -------------------- //
/// Constructor
EPAAlgorithm(MemoryAllocator& memoryAllocator);
EPAAlgorithm();
/// Destructor
~EPAAlgorithm();
/// Initalize the algorithm
void init(MemoryAllocator* memoryAllocator);
/// Compute the penetration depth with EPA algorithm.
bool computePenetrationDepthAndContactPoints(const Simplex& simplex,
ProxyShape* collisionShape1,
@ -144,6 +147,11 @@ inline void EPAAlgorithm::addFaceCandidate(TriangleEPA* triangle, TriangleEPA**
}
}
// Initalize the algorithm
inline void EPAAlgorithm::init(MemoryAllocator* memoryAllocator) {
mMemoryAllocator = memoryAllocator;
}
}
#endif

View File

@ -37,8 +37,7 @@
using namespace reactphysics3d;
// Constructor
GJKAlgorithm::GJKAlgorithm(MemoryAllocator& memoryAllocator)
:NarrowPhaseAlgorithm(memoryAllocator), mAlgoEPA(memoryAllocator) {
GJKAlgorithm::GJKAlgorithm() : NarrowPhaseAlgorithm() {
}
@ -140,7 +139,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2, normal,
penetrationDepth, pA, pB);
@ -172,7 +171,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2, normal,
penetrationDepth, pA, pB);
@ -202,7 +201,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2, normal,
penetrationDepth, pA, pB);
@ -239,7 +238,7 @@ bool GJKAlgorithm::testCollision(ProxyShape* collisionShape1, ProxyShape* collis
if (penetrationDepth <= 0.0) return false;
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2, normal,
penetrationDepth, pA, pB);

View File

@ -86,11 +86,14 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
// -------------------- Methods -------------------- //
/// Constructor
GJKAlgorithm(MemoryAllocator& memoryAllocator);
GJKAlgorithm();
/// Destructor
~GJKAlgorithm();
/// Initalize the algorithm
virtual void init(MemoryAllocator* memoryAllocator);
/// Return true and compute a contact info if the two bounding volumes collide.
virtual bool testCollision(ProxyShape* collisionShape1, ProxyShape* collisionShape2,
ContactPointInfo*& contactInfo);
@ -102,6 +105,12 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo);
};
// Initalize the algorithm
inline void GJKAlgorithm::init(MemoryAllocator* memoryAllocator) {
NarrowPhaseAlgorithm::init(memoryAllocator);
mAlgoEPA.init(memoryAllocator);
}
}
#endif

View File

@ -30,8 +30,8 @@
using namespace reactphysics3d;
// Constructor
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryAllocator& memoryAllocator)
:mMemoryAllocator(memoryAllocator), mCurrentOverlappingPair(NULL) {
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm()
: mMemoryAllocator(NULL), mCurrentOverlappingPair(NULL) {
}
@ -39,3 +39,8 @@ NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryAllocator& memoryAllocator)
NarrowPhaseAlgorithm::~NarrowPhaseAlgorithm() {
}
// Initalize the algorithm
void NarrowPhaseAlgorithm::init(MemoryAllocator* memoryAllocator) {
mMemoryAllocator = memoryAllocator;
}

View File

@ -38,10 +38,9 @@ namespace reactphysics3d {
// Class NarrowPhaseAlgorithm
/**
* This class is an abstract class that represents an algorithm
* used to perform the narrow-phase of a collision detection. The
* goal of the narrow phase algorithm is to compute contact
* informations of a collision between two bodies.
* This abstract class is the base class for a narrow-phase collision
* detection algorithm. The goal of the narrow phase algorithm is to
* compute information about the contact between two proxy shapes.
*/
class NarrowPhaseAlgorithm {
@ -49,8 +48,8 @@ class NarrowPhaseAlgorithm {
// -------------------- Attributes -------------------- //
/// Reference to the memory allocator
MemoryAllocator& mMemoryAllocator;
/// Pointer to the memory allocator
MemoryAllocator* mMemoryAllocator;
/// Overlapping pair of the bodies currently tested for collision
OverlappingPair* mCurrentOverlappingPair;
@ -68,11 +67,14 @@ class NarrowPhaseAlgorithm {
// -------------------- Methods -------------------- //
/// Constructor
NarrowPhaseAlgorithm(MemoryAllocator& memoryAllocator);
NarrowPhaseAlgorithm();
/// Destructor
virtual ~NarrowPhaseAlgorithm();
/// Initalize the algorithm
virtual void init(MemoryAllocator* memoryAllocator);
/// Set the current overlapping pair of bodies
void setCurrentOverlappingPair(OverlappingPair* overlappingPair);

View File

@ -31,8 +31,7 @@
using namespace reactphysics3d;
// Constructor
SphereVsSphereAlgorithm::SphereVsSphereAlgorithm(MemoryAllocator& memoryAllocator)
:NarrowPhaseAlgorithm(memoryAllocator) {
SphereVsSphereAlgorithm::SphereVsSphereAlgorithm() : NarrowPhaseAlgorithm() {
}
@ -75,7 +74,7 @@ bool SphereVsSphereAlgorithm::testCollision(ProxyShape* collisionShape1,
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
// Create the contact info object
contactInfo = new (mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
contactInfo = new (mMemoryAllocator->allocate(sizeof(ContactPointInfo)))
ContactPointInfo(collisionShape1, collisionShape2,
vectorBetweenCenters.getUnit(), penetrationDepth,
intersectionOnBody1, intersectionOnBody2);

View File

@ -57,7 +57,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
// -------------------- Methods -------------------- //
/// Constructor
SphereVsSphereAlgorithm(MemoryAllocator& memoryAllocator);
SphereVsSphereAlgorithm();
/// Destructor
virtual ~SphereVsSphereAlgorithm();

View File

@ -41,6 +41,7 @@ namespace reactphysics3d {
/// Type of the collision shape
enum CollisionShapeType {BOX, SPHERE, CONE, CYLINDER, CAPSULE, CONVEX_MESH};
const int NB_COLLISION_SHAPE_TYPES = 6;
// Declarations
class ProxyShape;

View File

@ -123,6 +123,9 @@ class CollisionWorld {
/// Destroy a collision body
void destroyCollisionBody(CollisionBody* collisionBody);
/// Set the collision dispatch configuration
void setCollisionDispatch(CollisionDispatch* collisionDispatch);
/// Ray cast method
void raycast(const Ray& ray, RaycastCallback* raycastCallback,
unsigned short raycastWithCategoryMaskBits = 0xFFFF) const;
@ -182,6 +185,17 @@ inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator()
return mBodies.end();
}
// Set the collision dispatch configuration
/// This can be used to replace default collision detection algorithms by your
/// custom algorithm for instance.
/**
* @param CollisionDispatch Pointer to a collision dispatch object describing
* which collision detection algorithm to use for two given collision shapes
*/
inline void CollisionWorld::setCollisionDispatch(CollisionDispatch* collisionDispatch) {
mCollisionDetection.setCollisionDispatch(collisionDispatch);
}
// Ray cast method
/**
* @param ray Ray to use for raycasting