Add methods to test collision and AABB overlap in physics world

This commit is contained in:
Daniel Chappuis 2014-12-28 00:54:34 +01:00
parent 6aba26dc49
commit aae4da54d0
19 changed files with 965 additions and 65 deletions

View File

@ -36,7 +36,6 @@ CollisionBody::CollisionBody(const Transform& transform, CollisionWorld& world,
: Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL), : Body(id), mType(DYNAMIC), mTransform(transform), mProxyCollisionShapes(NULL),
mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) { mNbCollisionShapes(0), mContactManifoldsList(NULL), mWorld(world) {
mIsCollisionEnabled = true;
mInterpolationFactor = 0.0; mInterpolationFactor = 0.0;
// Initialize the old transform // Initialize the old transform
@ -305,3 +304,26 @@ bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
return isHit; return isHit;
} }
// Compute and return the AABB of the body by merging all proxy shapes AABBs
AABB CollisionBody::getAABB() const {
AABB bodyAABB;
if (mProxyCollisionShapes == NULL) return bodyAABB;
mProxyCollisionShapes->getCollisionShape()->computeAABB(bodyAABB, mTransform * mProxyCollisionShapes->getLocalToBodyTransform());
// For each proxy shape of the body
for (ProxyShape* shape = mProxyCollisionShapes->mNext; shape != NULL; shape = shape->mNext) {
// Compute the world-space AABB of the collision shape
AABB aabb;
shape->getCollisionShape()->computeAABB(aabb, mTransform * shape->getLocalToBodyTransform());
// Merge the proxy shape AABB with the current body AABB
bodyAABB.mergeWithAABB(aabb);
}
return bodyAABB;
}

View File

@ -79,9 +79,6 @@ class CollisionBody : public Body {
/// Interpolation factor used for the state interpolation /// Interpolation factor used for the state interpolation
decimal mInterpolationFactor; decimal mInterpolationFactor;
/// True if the body can collide with others bodies
bool mIsCollisionEnabled;
/// First element of the linked list of proxy collision shapes of this body /// First element of the linked list of proxy collision shapes of this body
ProxyShape* mProxyCollisionShapes; ProxyShape* mProxyCollisionShapes;
@ -166,7 +163,7 @@ class CollisionBody : public Body {
void enableCollision(bool isCollisionEnabled); void enableCollision(bool isCollisionEnabled);
/// Return the first element of the linked list of contact manifolds involving this body /// Return the first element of the linked list of contact manifolds involving this body
const ContactManifoldListElement* getContactManifoldsLists() const; const ContactManifoldListElement* getContactManifoldsList() const;
/// Return true if a point is inside the collision body /// Return true if a point is inside the collision body
bool testPointInside(const Vector3& worldPoint) const; bool testPointInside(const Vector3& worldPoint) const;
@ -174,6 +171,27 @@ class CollisionBody : public Body {
/// Raycast method with feedback information /// Raycast method with feedback information
bool raycast(const Ray& ray, RaycastInfo& raycastInfo); bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
/// Compute and return the AABB of the body by merging all proxy shapes AABBs
AABB getAABB() const;
/// Return the linked list of proxy shapes of that body
ProxyShape* getProxyShapesList();
/// Return the linked list of proxy shapes of that body
const ProxyShape* getProxyShapesList() const;
/// Return the world-space coordinates of a point given the local-space coordinates of the body
Vector3 getWorldPoint(const Vector3& localPoint) const;
/// Return the world-space vector of a vector given in local-space coordinates of the body
Vector3 getWorldVector(const Vector3& localVector) const;
/// Return the body local-space coordinates of a point given in the world-space coordinates
Vector3 getLocalPoint(const Vector3& worldPoint) const;
/// Return the body local-space coordinates of a vector given in the world-space coordinates
Vector3 getLocalVector(const Vector3& worldVector) const;
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class CollisionWorld; friend class CollisionWorld;
@ -226,16 +244,6 @@ inline void CollisionBody::setTransform(const Transform& transform) {
updateBroadPhaseState(); updateBroadPhaseState();
} }
// Return true if the body can collide with others bodies
inline bool CollisionBody::isCollisionEnabled() const {
return mIsCollisionEnabled;
}
// Enable/disable the collision with this body
inline void CollisionBody::enableCollision(bool isCollisionEnabled) {
mIsCollisionEnabled = isCollisionEnabled;
}
// Update the old transform with the current one. // Update the old transform with the current one.
/// This is used to compute the interpolated position and orientation of the body /// This is used to compute the interpolated position and orientation of the body
inline void CollisionBody::updateOldTransform() { inline void CollisionBody::updateOldTransform() {
@ -243,10 +251,40 @@ inline void CollisionBody::updateOldTransform() {
} }
// Return the first element of the linked list of contact manifolds involving this body // Return the first element of the linked list of contact manifolds involving this body
inline const ContactManifoldListElement* CollisionBody::getContactManifoldsLists() const { inline const ContactManifoldListElement* CollisionBody::getContactManifoldsList() const {
return mContactManifoldsList; return mContactManifoldsList;
} }
// Return the linked list of proxy shapes of that body
inline ProxyShape* CollisionBody::getProxyShapesList() {
return mProxyCollisionShapes;
}
// Return the linked list of proxy shapes of that body
inline const ProxyShape* CollisionBody::getProxyShapesList() const {
return mProxyCollisionShapes;
}
// Return the world-space coordinates of a point given the local-space coordinates of the body
inline Vector3 CollisionBody::getWorldPoint(const Vector3& localPoint) const {
return mTransform * localPoint;
}
// Return the world-space vector of a vector given in local-space coordinates of the body
inline Vector3 CollisionBody::getWorldVector(const Vector3& localVector) const {
return mTransform.getOrientation() * localVector;
}
// Return the body local-space coordinates of a point given in the world-space coordinates
inline Vector3 CollisionBody::getLocalPoint(const Vector3& worldPoint) const {
return mTransform.getInverse() * worldPoint;
}
// Return the body local-space coordinates of a vector given in the world-space coordinates
inline Vector3 CollisionBody::getLocalVector(const Vector3& worldVector) const {
return mTransform.getOrientation().getInverse() * worldVector;
}
} }
#endif #endif

View File

@ -191,6 +191,9 @@ class RigidBody : public CollisionBody {
/// Return the first element of the linked list of joints involving this body /// Return the first element of the linked list of joints involving this body
const JointListElement* getJointsList() const; const JointListElement* getJointsList() const;
/// Return the first element of the linked list of joints involving this body
JointListElement* getJointsList();
/// Set the variable to know whether or not the body is sleeping /// Set the variable to know whether or not the body is sleeping
virtual void setIsSleeping(bool isSleeping); virtual void setIsSleeping(bool isSleeping);
@ -344,6 +347,11 @@ inline const JointListElement* RigidBody::getJointsList() const {
return mJointsList; return mJointsList;
} }
// Return the first element of the linked list of joints involving this body
inline JointListElement* RigidBody::getJointsList() {
return mJointsList;
}
// Set the variable to know whether or not the body is sleeping // Set the variable to know whether or not the body is sleeping
inline void RigidBody::setIsSleeping(bool isSleeping) { inline void RigidBody::setIsSleeping(bool isSleeping) {

View File

@ -51,7 +51,7 @@ CollisionDetection::CollisionDetection(CollisionWorld* world, MemoryAllocator& m
// Destructor // Destructor
CollisionDetection::~CollisionDetection() { CollisionDetection::~CollisionDetection() {
} }
// Compute the collision detection // Compute the collision detection
@ -66,6 +66,79 @@ void CollisionDetection::computeCollisionDetection() {
computeNarrowPhase(); computeNarrowPhase();
} }
// Compute the collision detection
void CollisionDetection::testCollisionBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2) {
// Compute the broad-phase collision detection
computeBroadPhase();
// Delete all the contact points in the currently overlapping pairs
clearContactPoints();
// Compute the narrow-phase collision detection among given sets of shapes
computeNarrowPhaseBetweenShapes(callback, shapes1, shapes2);
}
// Report collision between two sets of shapes
void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2) {
// For each possible collision pair of bodies
map<overlappingpairid, OverlappingPair*>::iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;
ProxyShape* shape1 = pair->getShape1();
ProxyShape* shape2 = pair->getShape2();
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
// If both shapes1 and shapes2 sets are non-empty, we check that
// shape1 is among on set and shape2 is among the other one
if (!shapes1.empty() && !shapes2.empty() &&
(shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) &&
(shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) {
continue;
}
if (!shapes1.empty() && shapes2.empty() &&
shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0)
{
continue;
}
if (!shapes2.empty() && shapes1.empty() &&
shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0)
{
continue;
}
// For each contact manifold of the overlapping pair
ContactManifold* manifold = pair->getContactManifold();
for (int i=0; i<manifold->getNbContactPoints(); i++) {
ContactPoint* contactPoint = manifold->getContactPoint(i);
// Create the contact info object for the contact
ContactPointInfo* contactInfo = new (mWorld->mMemoryAllocator.allocate(sizeof(ContactPointInfo)))
ContactPointInfo(manifold->getShape1(), manifold->getShape2(),
contactPoint->getNormal(),
contactPoint->getPenetrationDepth(),
contactPoint->getLocalPointOnBody1(),
contactPoint->getLocalPointOnBody2());
// 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::~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
}
}
}
// Compute the broad-phase collision detection // Compute the broad-phase collision detection
void CollisionDetection::computeBroadPhase() { void CollisionDetection::computeBroadPhase() {
@ -130,7 +203,7 @@ void CollisionDetection::computeNarrowPhase() {
if (body1->isSleeping() && body2->isSleeping()) continue; if (body1->isSleeping() && body2->isSleeping()) continue;
// Select the narrow phase algorithm to use according to the two collision shapes // Select the narrow phase algorithm to use according to the two collision shapes
NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm( NarrowPhaseAlgorithm& narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(
shape1->getCollisionShape(), shape1->getCollisionShape(),
shape2->getCollisionShape()); shape2->getCollisionShape());
@ -142,9 +215,120 @@ void CollisionDetection::computeNarrowPhase() {
if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) { if (narrowPhaseAlgorithm.testCollision(shape1, shape2, contactInfo)) {
assert(contactInfo != NULL); 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 // Create a new contact
createContact(pair, contactInfo); 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::~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
}
}
}
// Compute the narrow-phase collision detection
void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2) {
// 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;
ProxyShape* shape1 = pair->getShape1();
ProxyShape* shape2 = pair->getShape2();
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
bool test1 = shapes1.count(shape1->mBroadPhaseID) == 0;
bool test2 = shapes2.count(shape2->mBroadPhaseID) == 0;
bool test3 = shapes1.count(shape2->mBroadPhaseID) == 0;
bool test4 = shapes2.count(shape1->mBroadPhaseID) == 0;
bool test5 = !shapes1.empty() && !shapes2.empty();
// If both shapes1 and shapes2 sets are non-empty, we check that
// shape1 is among on set and shape2 is among the other one
if (!shapes1.empty() && !shapes2.empty() &&
(shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) &&
(shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) {
++it;
continue;
}
if (!shapes1.empty() && shapes2.empty() &&
shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0)
{
++it;
continue;
}
if (!shapes2.empty() && shapes1.empty() &&
shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0)
{
++it;
continue;
}
// Check that the two shapes are overlapping. If the shapes are not overlapping
// anymore, we remove the overlapping pair.
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
++it;
// Destroy the overlapping pair
itToRemove->second->OverlappingPair::~OverlappingPair();
mWorld->mMemoryAllocator.release(itToRemove->second, sizeof(OverlappingPair));
mOverlappingPairs.erase(itToRemove);
continue;
}
else {
++it;
}
CollisionBody* const body1 = shape1->getBody();
CollisionBody* const body2 = shape2->getBody();
// Update the contact cache of the overlapping pair
pair->update();
// Check if the two bodies are allowed to collide, otherwise, we do not test for collision
if (body1->getType() != DYNAMIC && body2->getType() != DYNAMIC) continue;
bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2);
if (mNoCollisionPairs.count(bodiesIndex) > 0) continue;
// Check if the two bodies are sleeping, if so, we do no test collision between them
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());
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
narrowPhaseAlgorithm.setCurrentOverlappingPair(pair);
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision
if (narrowPhaseAlgorithm.testCollision(shape1, shape2, 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 // Delete and remove the contact info from the memory allocator
contactInfo->ContactPointInfo::~ContactPointInfo(); contactInfo->ContactPointInfo::~ContactPointInfo();
mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo)); mWorld->mMemoryAllocator.release(contactInfo, sizeof(ContactPointInfo));
@ -210,13 +394,6 @@ void CollisionDetection::createContact(OverlappingPair* overlappingPair,
ContactPoint(*contactInfo); ContactPoint(*contactInfo);
assert(contact != NULL); assert(contact != NULL);
// If it is the first contact since the pair are overlapping
if (overlappingPair->getNbContactPoints() == 0) {
// Trigger a callback event
if (mWorld->mEventListener != NULL) mWorld->mEventListener->beginContact(*contactInfo);
}
// Add the contact to the contact cache of the corresponding overlapping pair // Add the contact to the contact cache of the corresponding overlapping pair
overlappingPair->addContact(contact); overlappingPair->addContact(contact);
@ -225,9 +402,6 @@ void CollisionDetection::createContact(OverlappingPair* overlappingPair,
addContactManifoldToBody(overlappingPair->getContactManifold(), addContactManifoldToBody(overlappingPair->getContactManifold(),
overlappingPair->getShape1()->getBody(), overlappingPair->getShape1()->getBody(),
overlappingPair->getShape2()->getBody()); overlappingPair->getShape2()->getBody());
// Trigger a callback event for the new contact
if (mWorld->mEventListener != NULL) mWorld->mEventListener->newContact(*contactInfo);
} }
// Add a contact manifold to the linked list of contact manifolds of the two bodies involved // Add a contact manifold to the linked list of contact manifolds of the two bodies involved
@ -253,3 +427,13 @@ void CollisionDetection::addContactManifoldToBody(ContactManifold* contactManifo
body2->mContactManifoldsList); body2->mContactManifoldsList);
body2->mContactManifoldsList = listElement2; body2->mContactManifoldsList = listElement2;
} }
// Delete all the contact points in the currently overlapping pairs
void CollisionDetection::clearContactPoints() {
// For each overlapping pair
std::map<overlappingpairid, OverlappingPair*>::iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
it->second->clearContactPoints();
}
}

View File

@ -45,6 +45,7 @@ namespace reactphysics3d {
// Declarations // Declarations
class BroadPhaseAlgorithm; class BroadPhaseAlgorithm;
class CollisionWorld; class CollisionWorld;
class CollisionCallback;
// Class CollisionDetection // Class CollisionDetection
/** /**
@ -95,7 +96,7 @@ class CollisionDetection {
void computeNarrowPhase(); void computeNarrowPhase();
/// Select the narrow phase algorithm to use given two collision shapes /// Select the narrow phase algorithm to use given two collision shapes
NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1, NarrowPhaseAlgorithm& selectNarrowPhaseAlgorithm(const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2); const CollisionShape* collisionShape2);
/// Create a new contact /// Create a new contact
@ -105,6 +106,9 @@ class CollisionDetection {
/// involed in the corresponding contact. /// involed in the corresponding contact.
void addContactManifoldToBody(ContactManifold* contactManifold, void addContactManifoldToBody(ContactManifold* contactManifold,
CollisionBody *body1, CollisionBody *body2); CollisionBody *body1, CollisionBody *body2);
/// Delete all the contact points in the currently overlapping pairs
void clearContactPoints();
public : public :
@ -138,12 +142,35 @@ class CollisionDetection {
/// Compute the collision detection /// Compute the collision detection
void computeCollisionDetection(); void computeCollisionDetection();
/// Compute the collision detection
void testCollisionBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2);
/// Report collision between two sets of shapes
void reportCollisionBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2) ;
/// Ray casting method /// Ray casting method
void raycast(RaycastCallback* raycastCallback, const Ray& ray) const; void raycast(RaycastCallback* raycastCallback, const Ray& ray) const;
/// Test if the AABBs of two bodies overlap
bool testAABBOverlap(const CollisionBody* body1,
const CollisionBody* body2) const;
/// Test if the AABBs of two proxy shapes overlap
bool testAABBOverlap(const ProxyShape* shape1,
const ProxyShape* shape2) const;
/// Allow the broadphase to notify the collision detection about an overlapping pair. /// Allow the broadphase to notify the collision detection about an overlapping pair.
void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2); void broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2);
// Compute the narrow-phase collision detection
void computeNarrowPhaseBetweenShapes(CollisionCallback* callback,
const std::set<uint>& shapes1,
const std::set<uint>& shapes2);
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class DynamicsWorld; friend class DynamicsWorld;
@ -151,7 +178,7 @@ class CollisionDetection {
}; };
// Select the narrow-phase collision algorithm to use given two collision shapes // Select the narrow-phase collision algorithm to use given two collision shapes
inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm( inline NarrowPhaseAlgorithm& CollisionDetection::selectNarrowPhaseAlgorithm(
const CollisionShape* collisionShape1, const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2) { const CollisionShape* collisionShape2) {
@ -210,6 +237,18 @@ inline void CollisionDetection::raycast(RaycastCallback* raycastCallback,
mBroadPhaseAlgorithm.raycast(ray, rayCastTest); mBroadPhaseAlgorithm.raycast(ray, rayCastTest);
} }
// Test if the AABBs of two proxy shapes overlap
inline bool CollisionDetection::testAABBOverlap(const ProxyShape* shape1,
const ProxyShape* shape2) const {
// If one of the shape's body is not active, we return no overlap
if (!shape1->getBody()->isActive() || !shape2->getBody()->isActive()) {
return false;
}
return mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2);
}
} }
#endif #endif

View File

@ -64,6 +64,12 @@ class ProxyShape {
/// Return the collision shape margin /// Return the collision shape margin
decimal getMargin() const; decimal getMargin() const;
/// Return the next proxy shape in the linked list of proxy shapes
ProxyShape* getNext();
/// Return the next proxy shape in the linked list of proxy shapes
const ProxyShape* getNext() const;
public: public:
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
@ -110,6 +116,8 @@ class ProxyShape {
friend class BroadPhaseAlgorithm; friend class BroadPhaseAlgorithm;
friend class DynamicAABBTree; friend class DynamicAABBTree;
friend class CollisionDetection; friend class CollisionDetection;
friend class CollisionWorld;
friend class DynamicsWorld;
friend class EPAAlgorithm; friend class EPAAlgorithm;
friend class GJKAlgorithm; friend class GJKAlgorithm;
friend class ConvexMeshShape; friend class ConvexMeshShape;
@ -174,6 +182,16 @@ inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
return mCollisionShape->raycast(ray, raycastInfo, this); return mCollisionShape->raycast(ray, raycastInfo, this);
} }
// Return the next proxy shape in the linked list of proxy shapes
inline ProxyShape* ProxyShape::getNext() {
return mNext;
}
// Return the next proxy shape in the linked list of proxy shapes
inline const ProxyShape* ProxyShape::getNext() const {
return mNext;
}
} }
#endif #endif

View File

@ -156,7 +156,7 @@ class BroadPhaseAlgorithm {
void computeOverlappingPairs(); void computeOverlappingPairs();
/// Return true if the two broad-phase collision shapes are overlapping /// Return true if the two broad-phase collision shapes are overlapping
bool testOverlappingShapes(ProxyShape* shape1, ProxyShape* shape2) const; bool testOverlappingShapes(const ProxyShape* shape1, const ProxyShape* shape2) const;
/// Ray casting method /// Ray casting method
void raycast(const Ray& ray, RaycastTest& raycastTest) const; void raycast(const Ray& ray, RaycastTest& raycastTest) const;
@ -173,8 +173,8 @@ inline bool BroadPair::smallerThan(const BroadPair& pair1, const BroadPair& pair
} }
// Return true if the two broad-phase collision shapes are overlapping // Return true if the two broad-phase collision shapes are overlapping
inline bool BroadPhaseAlgorithm::testOverlappingShapes(ProxyShape* shape1, inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1,
ProxyShape* shape2) const { const ProxyShape* shape2) const {
// Get the two AABBs of the collision shapes // Get the two AABBs of the collision shapes
const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1->mBroadPhaseID); const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1->mBroadPhaseID);
const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID); const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID);

View File

@ -53,6 +53,17 @@ AABB::~AABB() {
} }
// Merge the AABB in parameter with the current one
void AABB::mergeWithAABB(const AABB& aabb) {
mMinCoordinates.x = std::min(mMinCoordinates.x, aabb.mMinCoordinates.x);
mMinCoordinates.y = std::min(mMinCoordinates.y, aabb.mMinCoordinates.y);
mMinCoordinates.z = std::min(mMinCoordinates.z, aabb.mMinCoordinates.z);
mMaxCoordinates.x = std::max(mMaxCoordinates.x, aabb.mMaxCoordinates.x);
mMaxCoordinates.y = std::max(mMaxCoordinates.y, aabb.mMaxCoordinates.y);
mMaxCoordinates.z = std::max(mMaxCoordinates.z, aabb.mMaxCoordinates.z);
}
// Replace the current AABB with a new AABB that is the union of two AABBs in parameters // Replace the current AABB with a new AABB that is the union of two AABBs in parameters
void AABB::mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2) { void AABB::mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2) {
mMinCoordinates.x = std::min(aabb1.mMinCoordinates.x, aabb2.mMinCoordinates.x); mMinCoordinates.x = std::min(aabb1.mMinCoordinates.x, aabb2.mMinCoordinates.x);

View File

@ -88,6 +88,9 @@ class AABB {
/// Return the volume of the AABB /// Return the volume of the AABB
decimal getVolume() const; decimal getVolume() const;
/// Merge the AABB in parameter with the current one
void mergeWithAABB(const AABB& aabb);
/// Replace the current AABB with a new AABB that is the union of two AABBs in parameters /// Replace the current AABB with a new AABB that is the union of two AABBs in parameters
void mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2); void mergeTwoAABBs(const AABB& aabb1, const AABB& aabb2);

View File

@ -166,4 +166,124 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) {
} }
} }
// Reset all the contact manifolds linked list of each body
void CollisionWorld::resetContactManifoldListsOfBodies() {
// For each rigid body of the world
for (std::set<CollisionBody*>::iterator it = mBodies.begin(); it != mBodies.end(); ++it) {
// Reset the contact manifold list of the body
(*it)->resetContactManifoldsList();
}
}
// Test if the AABBs of two bodies overlap
bool CollisionWorld::testAABBOverlap(const CollisionBody* body1,
const CollisionBody* body2) const {
// If one of the body is not active, we return no overlap
if (!body1->isActive() || !body2->isActive()) return false;
// Compute the AABBs of both bodies
AABB body1AABB = body1->getAABB();
AABB body2AABB = body2->getAABB();
// Return true if the two AABBs overlap
return body1AABB.testCollision(body2AABB);
}
// Test and report collisions between a given shape and all the others
// shapes of the world.
void CollisionWorld::testCollision(const ProxyShape* shape,
CollisionCallback* callback) {
// Reset all the contact manifolds lists of each body
resetContactManifoldListsOfBodies();
// Create the sets of shapes
std::set<uint> shapes;
shapes.insert(shape->mBroadPhaseID);
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.testCollisionBetweenShapes(callback, shapes, emptySet);
}
// Test and report collisions between two given shapes
void CollisionWorld::testCollision(const ProxyShape* shape1,
const ProxyShape* shape2,
CollisionCallback* callback) {
// Reset all the contact manifolds lists of each body
resetContactManifoldListsOfBodies();
// Create the sets of shapes
std::set<uint> shapes1;
shapes1.insert(shape1->mBroadPhaseID);
std::set<uint> shapes2;
shapes2.insert(shape2->mBroadPhaseID);
// Perform the collision detection and report contacts
mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2);
}
// Test and report collisions between a body and all the others bodies of the
// world
void CollisionWorld::testCollision(const CollisionBody* body,
CollisionCallback* callback) {
// Reset all the contact manifolds lists of each body
resetContactManifoldListsOfBodies();
// Create the sets of shapes
std::set<uint> shapes1;
// For each shape of the body
for (const ProxyShape* shape=body->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes1.insert(shape->mBroadPhaseID);
}
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, emptySet);
}
// Test and report collisions between two bodies
void CollisionWorld::testCollision(const CollisionBody* body1,
const CollisionBody* body2,
CollisionCallback* callback) {
// Reset all the contact manifolds lists of each body
resetContactManifoldListsOfBodies();
// Create the sets of shapes
std::set<uint> shapes1;
for (const ProxyShape* shape=body1->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes1.insert(shape->mBroadPhaseID);
}
std::set<uint> shapes2;
for (const ProxyShape* shape=body2->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes2.insert(shape->mBroadPhaseID);
}
// Perform the collision detection and report contacts
mCollisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2);
}
// Test and report collisions between all shapes of the world
void CollisionWorld::testCollision(CollisionCallback* callback) {
// Reset all the contact manifolds lists of each body
resetContactManifoldListsOfBodies();
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.testCollisionBetweenShapes(callback, emptySet, emptySet);
}

View File

@ -45,6 +45,9 @@
/// Namespace reactphysics3d /// Namespace reactphysics3d
namespace reactphysics3d { namespace reactphysics3d {
// Declarations
class CollisionCallback;
// Class CollisionWorld // Class CollisionWorld
/** /**
* This class represent a world where it is possible to move bodies * This class represent a world where it is possible to move bodies
@ -95,6 +98,9 @@ class CollisionWorld {
/// Create a new collision shape in the world. /// Create a new collision shape in the world.
CollisionShape* createCollisionShape(const CollisionShape& collisionShape); CollisionShape* createCollisionShape(const CollisionShape& collisionShape);
/// Reset all the contact manifolds linked list of each body
void resetContactManifoldListsOfBodies();
public : public :
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
@ -120,6 +126,37 @@ class CollisionWorld {
/// Ray cast method /// Ray cast method
void raycast(const Ray& ray, RaycastCallback* raycastCallback) const; void raycast(const Ray& ray, RaycastCallback* raycastCallback) const;
/// Test if the AABBs of two bodies overlap
bool testAABBOverlap(const CollisionBody* body1,
const CollisionBody* body2) const;
/// Test if the AABBs of two proxy shapes overlap
bool testAABBOverlap(const ProxyShape* shape1,
const ProxyShape* shape2) const;
/// Test and report collisions between a given shape and all the others
/// shapes of the world
virtual void testCollision(const ProxyShape* shape,
CollisionCallback* callback);
/// Test and report collisions between two given shapes
virtual void testCollision(const ProxyShape* shape1,
const ProxyShape* shape2,
CollisionCallback* callback);
/// Test and report collisions between a body and all the others bodies of the
/// world
virtual void testCollision(const CollisionBody* body,
CollisionCallback* callback);
/// Test and report collisions between two bodies
virtual void testCollision(const CollisionBody* body1,
const CollisionBody* body2,
CollisionCallback* callback);
/// Test and report collisions between all shapes of the world
virtual void testCollision(CollisionCallback* callback);
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class CollisionDetection; friend class CollisionDetection;
@ -144,6 +181,33 @@ inline void CollisionWorld::raycast(const Ray& ray,
mCollisionDetection.raycast(raycastCallback, ray); mCollisionDetection.raycast(raycastCallback, ray);
} }
// Test if the AABBs of two proxy shapes overlap
inline bool CollisionWorld::testAABBOverlap(const ProxyShape* shape1,
const ProxyShape* shape2) const {
return mCollisionDetection.testAABBOverlap(shape1, shape2);
}
// Class CollisionCallback
/**
* This class can be used to register a callback for collision test queries.
* You should implement your own class inherited from this one and implement
* the notifyRaycastHit() method. This method will be called for each ProxyShape
* that is hit by the ray.
*/
class CollisionCallback {
public:
/// Destructor
virtual ~CollisionCallback() {
}
/// This method will be called for contact
virtual void notifyContact(const ContactPointInfo& contactPointInfo)=0;
};
} }
#endif #endif

View File

@ -30,9 +30,9 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
ContactManifold::ContactManifold(CollisionBody* body1, CollisionBody* body2, ContactManifold::ContactManifold(ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& memoryAllocator) MemoryAllocator& memoryAllocator)
: mBody1(body1), mBody2(body2), mNbContactPoints(0), mFrictionImpulse1(0.0), : mShape1(shape1), mShape2(shape2), mNbContactPoints(0), mFrictionImpulse1(0.0),
mFrictionImpulse2(0.0), mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false), mFrictionImpulse2(0.0), mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false),
mMemoryAllocator(memoryAllocator) { mMemoryAllocator(memoryAllocator) {

View File

@ -29,6 +29,7 @@
// Libraries // Libraries
#include <vector> #include <vector>
#include "body/CollisionBody.h" #include "body/CollisionBody.h"
#include "collision/ProxyShape.h"
#include "constraint/ContactPoint.h" #include "constraint/ContactPoint.h"
#include "memory/MemoryAllocator.h" #include "memory/MemoryAllocator.h"
@ -88,11 +89,11 @@ class ContactManifold {
// -------------------- Attributes -------------------- // // -------------------- Attributes -------------------- //
/// Pointer to the first body of the contact /// Pointer to the first proxy shape of the contact
CollisionBody* mBody1; ProxyShape* mShape1;
/// Pointer to the second body of the contact /// Pointer to the second proxy shape of the contact
CollisionBody* mBody2; ProxyShape* mShape2;
/// Contact points in the manifold /// Contact points in the manifold
ContactPoint* mContactPoints[MAX_CONTACT_POINTS_IN_MANIFOLD]; ContactPoint* mContactPoints[MAX_CONTACT_POINTS_IN_MANIFOLD];
@ -129,12 +130,6 @@ class ContactManifold {
/// Private assignment operator /// Private assignment operator
ContactManifold& operator=(const ContactManifold& contactManifold); ContactManifold& operator=(const ContactManifold& contactManifold);
/// Return a pointer to the first body of the contact manifold
CollisionBody* getBody1() const;
/// Return a pointer to the second body of the contact manifold
CollisionBody* getBody2() const;
/// Return the index of maximum area /// Return the index of maximum area
int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const; int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const;
@ -155,12 +150,24 @@ class ContactManifold {
// -------------------- Methods -------------------- // // -------------------- Methods -------------------- //
/// Constructor /// Constructor
ContactManifold(CollisionBody* body1, CollisionBody* body2, ContactManifold(ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& memoryAllocator); MemoryAllocator& memoryAllocator);
/// Destructor /// Destructor
~ContactManifold(); ~ContactManifold();
/// Return a pointer to the first proxy shape of the contact
ProxyShape* getShape1() const;
/// Return a pointer to the second proxy shape of the contact
ProxyShape* getShape2() const;
/// Return a pointer to the first body of the contact manifold
CollisionBody* getBody1() const;
/// Return a pointer to the second body of the contact manifold
CollisionBody* getBody2() const;
/// Add a contact point to the manifold /// Add a contact point to the manifold
void addContactPoint(ContactPoint* contact); void addContactPoint(ContactPoint* contact);
@ -213,14 +220,24 @@ class ContactManifold {
friend class CollisionBody; friend class CollisionBody;
}; };
// Return a pointer to the first proxy shape of the contact
inline ProxyShape* ContactManifold::getShape1() const {
return mShape1;
}
// Return a pointer to the second proxy shape of the contact
inline ProxyShape* ContactManifold::getShape2() const {
return mShape2;
}
// Return a pointer to the first body of the contact manifold // Return a pointer to the first body of the contact manifold
inline CollisionBody* ContactManifold::getBody1() const { inline CollisionBody* ContactManifold::getBody1() const {
return mBody1; return mShape1->getBody();
} }
// Return a pointer to the second body of the contact manifold // Return a pointer to the second body of the contact manifold
inline CollisionBody* ContactManifold::getBody2() const { inline CollisionBody* ContactManifold::getBody2() const {
return mBody2; return mShape2->getBody();
} }
// Return the number of contact points in the manifold // Return the number of contact points in the manifold

View File

@ -34,8 +34,6 @@
using namespace reactphysics3d; using namespace reactphysics3d;
using namespace std; using namespace std;
// TODO : Check if we really need to store the contact manifolds also in mContactManifolds.
// Constructor // Constructor
DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP)
: CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true), : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityEnabled(true),
@ -621,17 +619,6 @@ void DynamicsWorld::addJointToBody(Joint* joint) {
joint->mBody2->mJointsList = jointListElement2; joint->mBody2->mJointsList = jointListElement2;
} }
// Reset all the contact manifolds linked list of each body
void DynamicsWorld::resetContactManifoldListsOfBodies() {
// For each rigid body of the world
for (std::set<RigidBody*>::iterator it = mRigidBodies.begin(); it != mRigidBodies.end(); ++it) {
// Reset the contact manifold list of the body
(*it)->resetContactManifoldsList();
}
}
// Compute the islands of awake bodies. // Compute the islands of awake bodies.
/// An island is an isolated group of rigid bodies that have constraints (joints or contacts) /// An island is an isolated group of rigid bodies that have constraints (joints or contacts)
/// between each other. This method computes the islands at each time step as follows: For each /// between each other. This method computes the islands at each time step as follows: For each
@ -867,3 +854,93 @@ void DynamicsWorld::enableSleeping(bool isSleepingEnabled) {
} }
} }
} }
// Test and report collisions between a given shape and all the others
// shapes of the world.
/// This method should be called after calling the
/// DynamicsWorld::update() method that will compute the collisions.
void DynamicsWorld::testCollision(const ProxyShape* shape,
CollisionCallback* callback) {
// Create the sets of shapes
std::set<uint> shapes;
shapes.insert(shape->mBroadPhaseID);
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.reportCollisionBetweenShapes(callback, shapes, emptySet);
}
// Test and report collisions between two given shapes.
/// This method should be called after calling the
/// DynamicsWorld::update() method that will compute the collisions.
void DynamicsWorld::testCollision(const ProxyShape* shape1,
const ProxyShape* shape2,
CollisionCallback* callback) {
// Create the sets of shapes
std::set<uint> shapes1;
shapes1.insert(shape1->mBroadPhaseID);
std::set<uint> shapes2;
shapes2.insert(shape2->mBroadPhaseID);
// Perform the collision detection and report contacts
mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, shapes2);
}
// Test and report collisions between a body and all the others bodies of the
// world.
/// This method should be called after calling the
/// DynamicsWorld::update() method that will compute the collisions.
void DynamicsWorld::testCollision(const CollisionBody* body,
CollisionCallback* callback) {
// Create the sets of shapes
std::set<uint> shapes1;
// For each shape of the body
for (const ProxyShape* shape=body->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes1.insert(shape->mBroadPhaseID);
}
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, emptySet);
}
// Test and report collisions between two bodies.
/// This method should be called after calling the
/// DynamicsWorld::update() method that will compute the collisions.
void DynamicsWorld::testCollision(const CollisionBody* body1,
const CollisionBody* body2,
CollisionCallback* callback) {
// Create the sets of shapes
std::set<uint> shapes1;
for (const ProxyShape* shape=body1->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes1.insert(shape->mBroadPhaseID);
}
std::set<uint> shapes2;
for (const ProxyShape* shape=body2->getProxyShapesList(); shape != NULL;
shape = shape->getNext()) {
shapes2.insert(shape->mBroadPhaseID);
}
// Perform the collision detection and report contacts
mCollisionDetection.reportCollisionBetweenShapes(callback, shapes1, shapes2);
}
// Test and report collisions between all shapes of the world.
/// This method should be called after calling the
/// DynamicsWorld::update() method that will compute the collisions.
void DynamicsWorld::testCollision(CollisionCallback* callback) {
std::set<uint> emptySet;
// Perform the collision detection and report contacts
mCollisionDetection.reportCollisionBetweenShapes(callback, emptySet, emptySet);
}

View File

@ -224,9 +224,6 @@ class DynamicsWorld : public CollisionWorld {
/// Add the joint to the list of joints of the two bodies involved in the joint /// Add the joint to the list of joints of the two bodies involved in the joint
void addJointToBody(Joint* joint); void addJointToBody(Joint* joint);
/// Reset all the contact manifolds linked list of each body
void resetContactManifoldListsOfBodies();
/// Return the gravity vector of the world /// Return the gravity vector of the world
Vector3 getGravity() const; Vector3 getGravity() const;
@ -278,6 +275,29 @@ class DynamicsWorld : public CollisionWorld {
/// Set an event listener object to receive events callbacks. /// Set an event listener object to receive events callbacks.
void setEventListener(EventListener* eventListener); void setEventListener(EventListener* eventListener);
/// Test and report collisions between a given shape and all the others
/// shapes of the world
virtual void testCollision(const ProxyShape* shape,
CollisionCallback* callback);
/// Test and report collisions between two given shapes
virtual void testCollision(const ProxyShape* shape1,
const ProxyShape* shape2,
CollisionCallback* callback);
/// Test and report collisions between a body and all
/// the others bodies of the world
virtual void testCollision(const CollisionBody* body,
CollisionCallback* callback);
/// Test and report collisions between two bodies
virtual void testCollision(const CollisionBody* body1,
const CollisionBody* body2,
CollisionCallback* callback);
/// Test and report collisions between all shapes of the world
virtual void testCollision(CollisionCallback* callback);
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class RigidBody; friend class RigidBody;

View File

@ -33,7 +33,7 @@ using namespace reactphysics3d;
OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2, OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& memoryAllocator) MemoryAllocator& memoryAllocator)
: mShape1(shape1), mShape2(shape2), : mShape1(shape1), mShape2(shape2),
mContactManifold(shape1->getBody(), shape2->getBody(), memoryAllocator), mContactManifold(shape1, shape2, memoryAllocator),
mCachedSeparatingAxis(1.0, 1.0, 1.0) { mCachedSeparatingAxis(1.0, 1.0, 1.0) {
} }

View File

@ -106,6 +106,9 @@ class OverlappingPair {
/// Return the contact manifold /// Return the contact manifold
ContactManifold* getContactManifold(); ContactManifold* getContactManifold();
/// Clear the contact points of the contact manifold
void clearContactPoints();
/// Return the pair of bodies index /// Return the pair of bodies index
static overlappingpairid computeID(ProxyShape* shape1, ProxyShape* shape2); static overlappingpairid computeID(ProxyShape* shape1, ProxyShape* shape2);
@ -183,6 +186,11 @@ inline bodyindexpair OverlappingPair::computeBodiesIndexPair(CollisionBody* body
return indexPair; return indexPair;
} }
// Clear the contact points of the contact manifold
inline void OverlappingPair::clearContactPoints() {
mContactManifold.clear();
}
} }
#endif #endif

View File

@ -33,6 +33,7 @@
#include "tests/mathematics/TestMatrix3x3.h" #include "tests/mathematics/TestMatrix3x3.h"
#include "tests/collision/TestPointInside.h" #include "tests/collision/TestPointInside.h"
#include "tests/collision/TestRaycast.h" #include "tests/collision/TestRaycast.h"
#include "tests/collision/TestCollisionWorld.h"
using namespace reactphysics3d; using namespace reactphysics3d;
@ -53,6 +54,7 @@ int main() {
testSuite.addTest(new TestPointInside("IsPointInside")); testSuite.addTest(new TestPointInside("IsPointInside"));
testSuite.addTest(new TestRaycast("Raycasting")); testSuite.addTest(new TestRaycast("Raycasting"));
testSuite.addTest(new TestCollisionWorld("CollisionWorld"));
// Run the tests // Run the tests
testSuite.run(); testSuite.run();

View File

@ -0,0 +1,269 @@
/********************************************************************************
* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ *
* Copyright (c) 2010-2013 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 TEST_COLLISION_WORLD_H
#define TEST_COLLISION_WORLD_H
// Libraries
#include "reactphysics3d.h"
/// Reactphysics3D namespace
namespace reactphysics3d {
// Class
class WorldCollisionCallback : public CollisionCallback
{
public:
bool boxCollideWithSphere1;
bool boxCollideWithCylinder;
bool sphere1CollideWithCylinder;
bool sphere1CollideWithSphere2;
CollisionBody* boxBody;
CollisionBody* sphere1Body;
CollisionBody* sphere2Body;
CollisionBody* cylinderBody;
WorldCollisionCallback()
{
reset();
}
void reset()
{
boxCollideWithSphere1 = false;
boxCollideWithCylinder = false;
sphere1CollideWithCylinder = false;
sphere1CollideWithSphere2 = false;
}
// This method will be called for contact
virtual void notifyContact(const ContactPointInfo& contactPointInfo) {
if (isContactBetweenBodies(boxBody, sphere1Body, contactPointInfo)) {
boxCollideWithSphere1 = true;
}
else if (isContactBetweenBodies(boxBody, cylinderBody, contactPointInfo)) {
boxCollideWithCylinder = true;
}
else if (isContactBetweenBodies(sphere1Body, cylinderBody, contactPointInfo)) {
sphere1CollideWithCylinder = true;
}
else if (isContactBetweenBodies(sphere1Body, sphere2Body, contactPointInfo)) {
sphere1CollideWithSphere2 = true;
}
}
bool isContactBetweenBodies(const CollisionBody* body1, const CollisionBody* body2,
const ContactPointInfo& contactPointInfo) {
return (contactPointInfo.shape1->getBody()->getID() == body1->getID() &&
contactPointInfo.shape2->getBody()->getID() == body2->getID()) ||
(contactPointInfo.shape2->getBody()->getID() == body1->getID() &&
contactPointInfo.shape1->getBody()->getID() == body2->getID());
}
};
// Class TestCollisionWorld
/**
* Unit test for the CollisionWorld class.
*/
class TestCollisionWorld : public Test {
private :
// ---------- Atributes ---------- //
// Physics world
CollisionWorld* mWorld;
// Bodies
CollisionBody* mBoxBody;
CollisionBody* mSphere1Body;
CollisionBody* mSphere2Body;
CollisionBody* mCylinderBody;
// Shapes
ProxyShape* mBoxShape;
ProxyShape* mSphere1Shape;
ProxyShape* mSphere2Shape;
ProxyShape* mCylinderShape;
// Collision callback class
WorldCollisionCallback mCollisionCallback;
public :
// ---------- Methods ---------- //
/// Constructor
TestCollisionWorld(const std::string& name) : Test(name) {
// Create the world
mWorld = new CollisionWorld();
// Create the bodies
Transform boxTransform(Vector3(10, 0, 0), Quaternion::identity());
mBoxBody = mWorld->createCollisionBody(boxTransform);
BoxShape boxShape(Vector3(3, 3, 3));
mBoxShape = mBoxBody->addCollisionShape(boxShape, Transform::identity());
SphereShape sphereShape(3.0);
Transform sphere1Transform(Vector3(10,5, 0), Quaternion::identity());
mSphere1Body = mWorld->createCollisionBody(sphere1Transform);
mSphere1Shape = mSphere1Body->addCollisionShape(sphereShape, Transform::identity());
Transform sphere2Transform(Vector3(30, 10, 10), Quaternion::identity());
mSphere2Body = mWorld->createCollisionBody(sphere2Transform);
mSphere2Shape = mSphere2Body->addCollisionShape(sphereShape, Transform::identity());
Transform cylinderTransform(Vector3(10, -5, 0), Quaternion::identity());
mCylinderBody = mWorld->createCollisionBody(cylinderTransform);
CylinderShape cylinderShape(2, 5);
mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, Transform::identity());
mCollisionCallback.boxBody = mBoxBody;
mCollisionCallback.sphere1Body = mSphere1Body;
mCollisionCallback.sphere2Body = mSphere2Body;
mCollisionCallback.cylinderBody = mCylinderBody;
}
/// Run the tests
void run() {
testCollisions();
}
void testCollisions() {
mCollisionCallback.reset();
mWorld->testCollision(&mCollisionCallback);
test(mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
test(mWorld->testAABBOverlap(mBoxBody, mSphere1Body));
test(mWorld->testAABBOverlap(mBoxBody, mCylinderBody));
test(!mWorld->testAABBOverlap(mSphere1Body, mCylinderBody));
test(!mWorld->testAABBOverlap(mSphere1Body, mSphere2Body));
test(mWorld->testAABBOverlap(mBoxShape, mSphere1Shape));
test(mWorld->testAABBOverlap(mBoxShape, mCylinderShape));
test(!mWorld->testAABBOverlap(mSphere1Shape, mCylinderShape));
test(!mWorld->testAABBOverlap(mSphere1Shape, mSphere2Shape));
mCollisionCallback.reset();
mWorld->testCollision(mCylinderBody, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mBoxBody, mSphere1Body, &mCollisionCallback);
test(mCollisionCallback.boxCollideWithSphere1);
test(!mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mBoxBody, mCylinderBody, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mCylinderShape, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mBoxShape, mCylinderShape, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
// Move sphere 1 to collide with sphere 2
mSphere1Body->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity()));
mCollisionCallback.reset();
mWorld->testCollision(&mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mBoxBody, mSphere1Body, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(!mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
mCollisionCallback.reset();
mWorld->testCollision(mBoxBody, mCylinderBody, &mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
// Test collision with inactive bodies
mCollisionCallback.reset();
mBoxBody->setIsActive(false);
mCylinderBody->setIsActive(false);
mSphere1Body->setIsActive(false);
mSphere2Body->setIsActive(false);
mWorld->testCollision(&mCollisionCallback);
test(!mCollisionCallback.boxCollideWithSphere1);
test(!mCollisionCallback.boxCollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithCylinder);
test(!mCollisionCallback.sphere1CollideWithSphere2);
test(!mWorld->testAABBOverlap(mBoxBody, mSphere1Body));
test(!mWorld->testAABBOverlap(mBoxBody, mCylinderBody));
test(!mWorld->testAABBOverlap(mSphere1Body, mCylinderBody));
test(!mWorld->testAABBOverlap(mSphere1Body, mSphere2Body));
test(!mWorld->testAABBOverlap(mBoxShape, mSphere1Shape));
test(!mWorld->testAABBOverlap(mBoxShape, mCylinderShape));
test(!mWorld->testAABBOverlap(mSphere1Shape, mCylinderShape));
test(!mWorld->testAABBOverlap(mSphere1Shape, mSphere2Shape));
mBoxBody->setIsActive(true);
mCylinderBody->setIsActive(true);
mSphere1Body->setIsActive(true);
mSphere2Body->setIsActive(true);
}
};
}
#endif