Refactor the way to create the contact manifolds and contact points
This commit is contained in:
parent
6eec956eb0
commit
8b82c4ac81
|
@ -132,6 +132,7 @@ SET (REACTPHYSICS3D_SOURCES
|
||||||
"src/collision/CollisionDetection.h"
|
"src/collision/CollisionDetection.h"
|
||||||
"src/collision/CollisionDetection.cpp"
|
"src/collision/CollisionDetection.cpp"
|
||||||
"src/collision/NarrowPhaseInfo.h"
|
"src/collision/NarrowPhaseInfo.h"
|
||||||
|
"src/collision/NarrowPhaseInfo.cpp"
|
||||||
"src/collision/ContactManifold.h"
|
"src/collision/ContactManifold.h"
|
||||||
"src/collision/ContactManifold.cpp"
|
"src/collision/ContactManifold.cpp"
|
||||||
"src/collision/ContactManifoldSet.h"
|
"src/collision/ContactManifoldSet.h"
|
||||||
|
@ -167,6 +168,9 @@ SET (REACTPHYSICS3D_SOURCES
|
||||||
"src/engine/Profiler.cpp"
|
"src/engine/Profiler.cpp"
|
||||||
"src/engine/Timer.h"
|
"src/engine/Timer.h"
|
||||||
"src/engine/Timer.cpp"
|
"src/engine/Timer.cpp"
|
||||||
|
"src/collision/CollisionCallback.h"
|
||||||
|
"src/collision/CollisionCallback.cpp"
|
||||||
|
"src/collision/OverlapCallback.h"
|
||||||
"src/mathematics/mathematics.h"
|
"src/mathematics/mathematics.h"
|
||||||
"src/mathematics/mathematics_functions.h"
|
"src/mathematics/mathematics_functions.h"
|
||||||
"src/mathematics/mathematics_functions.cpp"
|
"src/mathematics/mathematics_functions.cpp"
|
||||||
|
|
|
@ -177,7 +177,7 @@ void CollisionBody::resetContactManifoldsList() {
|
||||||
// Delete the linked list of contact manifolds of that body
|
// Delete the linked list of contact manifolds of that body
|
||||||
ContactManifoldListElement* currentElement = mContactManifoldsList;
|
ContactManifoldListElement* currentElement = mContactManifoldsList;
|
||||||
while (currentElement != nullptr) {
|
while (currentElement != nullptr) {
|
||||||
ContactManifoldListElement* nextElement = currentElement->next;
|
ContactManifoldListElement* nextElement = currentElement->getNext();
|
||||||
|
|
||||||
// Delete the current element
|
// Delete the current element
|
||||||
currentElement->~ContactManifoldListElement();
|
currentElement->~ContactManifoldListElement();
|
||||||
|
@ -272,8 +272,8 @@ int CollisionBody::resetIsAlreadyInIslandAndCountManifolds() {
|
||||||
// this body
|
// this body
|
||||||
ContactManifoldListElement* currentElement = mContactManifoldsList;
|
ContactManifoldListElement* currentElement = mContactManifoldsList;
|
||||||
while (currentElement != nullptr) {
|
while (currentElement != nullptr) {
|
||||||
currentElement->contactManifold->mIsAlreadyInIsland = false;
|
currentElement->getContactManifold()->mIsAlreadyInIsland = false;
|
||||||
currentElement = currentElement->next;
|
currentElement = currentElement->getNext();
|
||||||
nbManifolds++;
|
nbManifolds++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
79
src/collision/CollisionCallback.cpp
Normal file
79
src/collision/CollisionCallback.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 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 "collision/CollisionCallback.h"
|
||||||
|
#include "engine/OverlappingPair.h"
|
||||||
|
#include "memory/Allocator.h"
|
||||||
|
#include "collision/ContactManifold.h"
|
||||||
|
|
||||||
|
// We want to use the ReactPhysics3D namespace
|
||||||
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
CollisionCallback::CollisionCallbackInfo::CollisionCallbackInfo(OverlappingPair* pair, Allocator& allocator) :
|
||||||
|
contactManifoldElements(nullptr), body1(pair->getShape1()->getBody()),
|
||||||
|
body2(pair->getShape2()->getBody()),
|
||||||
|
proxyShape1(pair->getShape1()), proxyShape2(pair->getShape2()),
|
||||||
|
mMemoryAllocator(allocator) {
|
||||||
|
|
||||||
|
assert(pair != nullptr);
|
||||||
|
|
||||||
|
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
||||||
|
|
||||||
|
// For each contact manifold in the set of manifolds in the pair
|
||||||
|
ContactManifold* contactManifold = manifoldSet.getContactManifolds();
|
||||||
|
while (contactManifold != nullptr) {
|
||||||
|
|
||||||
|
assert(contactManifold->getNbContactPoints() > 0);
|
||||||
|
|
||||||
|
// Add the contact manifold at the beginning of the linked
|
||||||
|
// list of contact manifolds of the first body
|
||||||
|
ContactManifoldListElement* element = new (mMemoryAllocator.allocate(sizeof(ContactManifoldListElement)))
|
||||||
|
ContactManifoldListElement(contactManifold,
|
||||||
|
contactManifoldElements);
|
||||||
|
contactManifoldElements = element;
|
||||||
|
|
||||||
|
contactManifold = contactManifold->getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
CollisionCallback::CollisionCallbackInfo::~CollisionCallbackInfo() {
|
||||||
|
|
||||||
|
// Release memory allocator for the contact manifold list elements
|
||||||
|
ContactManifoldListElement* element = contactManifoldElements;
|
||||||
|
while (element != nullptr) {
|
||||||
|
|
||||||
|
ContactManifoldListElement* nextElement = element->getNext();
|
||||||
|
|
||||||
|
// Delete and release memory
|
||||||
|
element->~ContactManifoldListElement();
|
||||||
|
mMemoryAllocator.release(element, sizeof(ContactManifoldListElement));
|
||||||
|
|
||||||
|
element = nextElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
89
src/collision/CollisionCallback.h
Normal file
89
src/collision/CollisionCallback.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 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_CALLBACK_H
|
||||||
|
#define REACTPHYSICS3D_COLLISION_CALLBACK_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "collision/ContactManifold.h"
|
||||||
|
|
||||||
|
/// ReactPhysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// 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 notifyContact() method. This method will called each time a contact
|
||||||
|
* point is reported.
|
||||||
|
*/
|
||||||
|
class CollisionCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Structure CollisionCallbackInfo
|
||||||
|
/**
|
||||||
|
* This structure represents the contact information between two collision
|
||||||
|
* shapes of two bodies
|
||||||
|
*/
|
||||||
|
struct CollisionCallbackInfo {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Pointer to the first element of the linked-list that contains contact manifolds
|
||||||
|
ContactManifoldListElement* contactManifoldElements;
|
||||||
|
|
||||||
|
/// Pointer to the first body of the contact
|
||||||
|
CollisionBody* body1;
|
||||||
|
|
||||||
|
/// Pointer to the second body of the contact
|
||||||
|
CollisionBody* body2;
|
||||||
|
|
||||||
|
/// Pointer to the proxy shape of first body
|
||||||
|
const ProxyShape* proxyShape1;
|
||||||
|
|
||||||
|
/// Pointer to the proxy shape of second body
|
||||||
|
const ProxyShape* proxyShape2;
|
||||||
|
|
||||||
|
/// Memory allocator
|
||||||
|
Allocator& mMemoryAllocator;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
CollisionCallbackInfo(OverlappingPair* pair, Allocator& allocator);
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
~CollisionCallbackInfo();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
virtual ~CollisionCallback() = default;
|
||||||
|
|
||||||
|
/// This method will be called for each reported contact point
|
||||||
|
virtual void notifyContact(const CollisionCallbackInfo& collisionCallbackInfo)=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -26,10 +26,13 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "CollisionDetection.h"
|
#include "CollisionDetection.h"
|
||||||
#include "engine/CollisionWorld.h"
|
#include "engine/CollisionWorld.h"
|
||||||
|
#include "collision/OverlapCallback.h"
|
||||||
#include "body/Body.h"
|
#include "body/Body.h"
|
||||||
#include "collision/shapes/BoxShape.h"
|
#include "collision/shapes/BoxShape.h"
|
||||||
#include "body/RigidBody.h"
|
#include "body/RigidBody.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "collision/CollisionCallback.h"
|
||||||
|
#include "collision/OverlapCallback.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -43,7 +46,7 @@ using namespace std;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
CollisionDetection::CollisionDetection(CollisionWorld* world, PoolAllocator& memoryAllocator, SingleFrameAllocator& singleFrameAllocator)
|
CollisionDetection::CollisionDetection(CollisionWorld* world, PoolAllocator& memoryAllocator, SingleFrameAllocator& singleFrameAllocator)
|
||||||
: mMemoryAllocator(memoryAllocator), mSingleFrameAllocator(singleFrameAllocator),
|
: mPoolAllocator(memoryAllocator), mSingleFrameAllocator(singleFrameAllocator),
|
||||||
mWorld(world), mNarrowPhaseInfoList(nullptr), mBroadPhaseAlgorithm(*this),
|
mWorld(world), mNarrowPhaseInfoList(nullptr), mBroadPhaseAlgorithm(*this),
|
||||||
mIsCollisionShapesAdded(false) {
|
mIsCollisionShapesAdded(false) {
|
||||||
|
|
||||||
|
@ -83,7 +86,7 @@ void CollisionDetection::computeBroadPhase() {
|
||||||
// Ask the broad-phase to recompute the overlapping pairs of collision
|
// Ask the broad-phase to recompute the overlapping pairs of collision
|
||||||
// shapes. This call can only add new overlapping pairs in the collision
|
// shapes. This call can only add new overlapping pairs in the collision
|
||||||
// detection.
|
// detection.
|
||||||
mBroadPhaseAlgorithm.computeOverlappingPairs(mMemoryAllocator);
|
mBroadPhaseAlgorithm.computeOverlappingPairs(mPoolAllocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,25 +104,24 @@ void CollisionDetection::computeMiddlePhase() {
|
||||||
|
|
||||||
OverlappingPair* pair = it->second;
|
OverlappingPair* pair = it->second;
|
||||||
|
|
||||||
|
// Make all the contact manifolds and contact points of the pair obselete
|
||||||
|
pair->makeContactsObselete();
|
||||||
|
|
||||||
ProxyShape* shape1 = pair->getShape1();
|
ProxyShape* shape1 = pair->getShape1();
|
||||||
ProxyShape* shape2 = pair->getShape2();
|
ProxyShape* shape2 = pair->getShape2();
|
||||||
|
|
||||||
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
||||||
|
|
||||||
// Check if the collision filtering allows collision between the two shapes and
|
// Check if the two shapes are still overlapping. Otherwise, we destroy the
|
||||||
// that the two shapes are still overlapping. Otherwise, we destroy the
|
|
||||||
// overlapping pair
|
// overlapping pair
|
||||||
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||||
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) ||
|
|
||||||
!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
|
||||||
|
|
||||||
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
|
||||||
|
|
||||||
// Destroy the overlapping pair
|
// Destroy the overlapping pair
|
||||||
itToRemove->second->~OverlappingPair();
|
itToRemove->second->~OverlappingPair();
|
||||||
|
|
||||||
mWorld->mPoolAllocator.release(itToRemove->second, sizeof(OverlappingPair));
|
mWorld->mPoolAllocator.release(itToRemove->second, sizeof(OverlappingPair));
|
||||||
mOverlappingPairs.erase(itToRemove);
|
mOverlappingPairs.erase(itToRemove);
|
||||||
continue;
|
continue;
|
||||||
|
@ -128,6 +130,10 @@ void CollisionDetection::computeMiddlePhase() {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the collision filtering allows collision between the two shapes
|
||||||
|
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) != 0 &&
|
||||||
|
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) != 0)) {
|
||||||
|
|
||||||
CollisionBody* const body1 = shape1->getBody();
|
CollisionBody* const body1 = shape1->getBody();
|
||||||
CollisionBody* const body2 = shape2->getBody();
|
CollisionBody* const body2 = shape2->getBody();
|
||||||
|
|
||||||
|
@ -181,6 +187,7 @@ void CollisionDetection::computeMiddlePhase() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the concave vs convex middle-phase algorithm for a given pair of bodies
|
// Compute the concave vs convex middle-phase algorithm for a given pair of bodies
|
||||||
void CollisionDetection::computeConvexVsConcaveMiddlePhase(OverlappingPair* pair, Allocator& allocator,
|
void CollisionDetection::computeConvexVsConcaveMiddlePhase(OverlappingPair* pair, Allocator& allocator,
|
||||||
|
@ -231,7 +238,7 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
|
|
||||||
PROFILE("CollisionDetection::computeNarrowPhase()");
|
PROFILE("CollisionDetection::computeNarrowPhase()");
|
||||||
|
|
||||||
const NarrowPhaseInfo* currentNarrowPhaseInfo = mNarrowPhaseInfoList;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = mNarrowPhaseInfoList;
|
||||||
while (currentNarrowPhaseInfo != nullptr) {
|
while (currentNarrowPhaseInfo != nullptr) {
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -245,30 +252,16 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mSingleFrameAllocator);
|
if (narrowPhaseAlgorithm->testCollision(currentNarrowPhaseInfo, true)) {
|
||||||
if (narrowPhaseAlgorithm->testCollision(currentNarrowPhaseInfo, contactManifoldInfo)) {
|
|
||||||
|
|
||||||
// Reduce the number of points in the contact manifold (if necessary)
|
// Add the contact points as a potential contact manifold into the pair
|
||||||
contactManifoldInfo.reduce(currentNarrowPhaseInfo->shape1ToWorldTransform);
|
currentNarrowPhaseInfo->addContactPointsAsPotentialContactManifold();
|
||||||
|
|
||||||
// If it is the first contact since the pairs are overlapping
|
|
||||||
if (currentNarrowPhaseInfo->overlappingPair->getNbContactPoints() == 0) {
|
|
||||||
|
|
||||||
// Trigger a callback event
|
|
||||||
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->beginContact(contactManifoldInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the contact manifold to the corresponding overlapping pair
|
|
||||||
currentNarrowPhaseInfo->overlappingPair->addContactManifold(contactManifoldInfo);
|
|
||||||
|
|
||||||
// Add the overlapping pair into the set of pairs in contact during narrow-phase
|
// Add the overlapping pair into the set of pairs in contact during narrow-phase
|
||||||
overlappingpairid pairId = OverlappingPair::computeID(currentNarrowPhaseInfo->overlappingPair->getShape1(),
|
overlappingpairid pairId = OverlappingPair::computeID(currentNarrowPhaseInfo->overlappingPair->getShape1(),
|
||||||
currentNarrowPhaseInfo->overlappingPair->getShape2());
|
currentNarrowPhaseInfo->overlappingPair->getShape2());
|
||||||
mContactOverlappingPairs[pairId] = currentNarrowPhaseInfo->overlappingPair;
|
mContactOverlappingPairs[pairId] = currentNarrowPhaseInfo->overlappingPair;
|
||||||
|
|
||||||
// Trigger a callback event for the new contact
|
|
||||||
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->newContact(contactManifoldInfo);
|
|
||||||
|
|
||||||
currentNarrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasColliding = true;
|
currentNarrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasColliding = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -282,8 +275,14 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
currentNarrowPhaseInfo = currentNarrowPhaseInfo->next;
|
currentNarrowPhaseInfo = currentNarrowPhaseInfo->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the potential contact into actual contacts
|
||||||
|
processAllPotentialContacts();
|
||||||
|
|
||||||
// Add all the contact manifolds (between colliding bodies) to the bodies
|
// Add all the contact manifolds (between colliding bodies) to the bodies
|
||||||
addAllContactManifoldsToBodies();
|
addAllContactManifoldsToBodies();
|
||||||
|
|
||||||
|
// Report contacts to the user
|
||||||
|
reportAllContacts();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow the broadphase to notify the collision detection about an overlapping pair.
|
// Allow the broadphase to notify the collision detection about an overlapping pair.
|
||||||
|
@ -302,13 +301,9 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro
|
||||||
// Check if the overlapping pair already exists
|
// Check if the overlapping pair already exists
|
||||||
if (mOverlappingPairs.find(pairID) != mOverlappingPairs.end()) return;
|
if (mOverlappingPairs.find(pairID) != mOverlappingPairs.end()) return;
|
||||||
|
|
||||||
// Compute the maximum number of contact manifolds for this pair
|
|
||||||
int nbMaxManifolds = CollisionShape::computeNbMaxContactManifolds(shape1->getCollisionShape()->getType(),
|
|
||||||
shape2->getCollisionShape()->getType());
|
|
||||||
|
|
||||||
// Create the overlapping pair and add it into the set of overlapping pairs
|
// Create the overlapping pair and add it into the set of overlapping pairs
|
||||||
OverlappingPair* newPair = new (mWorld->mPoolAllocator.allocate(sizeof(OverlappingPair)))
|
OverlappingPair* newPair = new (mPoolAllocator.allocate(sizeof(OverlappingPair)))
|
||||||
OverlappingPair(shape1, shape2, nbMaxManifolds, mWorld->mPoolAllocator);
|
OverlappingPair(shape1, shape2, mPoolAllocator, mSingleFrameAllocator);
|
||||||
assert(newPair != nullptr);
|
assert(newPair != nullptr);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -372,40 +367,173 @@ void CollisionDetection::addContactManifoldToBody(OverlappingPair* pair) {
|
||||||
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
||||||
|
|
||||||
// For each contact manifold in the set of manifolds in the pair
|
// For each contact manifold in the set of manifolds in the pair
|
||||||
for (int i=0; i<manifoldSet.getNbContactManifolds(); i++) {
|
ContactManifold* contactManifold = manifoldSet.getContactManifolds();
|
||||||
|
while (contactManifold != nullptr) {
|
||||||
ContactManifold* contactManifold = manifoldSet.getContactManifold(i);
|
|
||||||
|
|
||||||
assert(contactManifold->getNbContactPoints() > 0);
|
assert(contactManifold->getNbContactPoints() > 0);
|
||||||
|
|
||||||
// Add the contact manifold at the beginning of the linked
|
// Add the contact manifold at the beginning of the linked
|
||||||
// list of contact manifolds of the first body
|
// list of contact manifolds of the first body
|
||||||
void* allocatedMemory1 = mWorld->mPoolAllocator.allocate(sizeof(ContactManifoldListElement));
|
ContactManifoldListElement* listElement1 = new (mPoolAllocator.allocate(sizeof(ContactManifoldListElement)))
|
||||||
ContactManifoldListElement* listElement1 = new (allocatedMemory1)
|
|
||||||
ContactManifoldListElement(contactManifold,
|
ContactManifoldListElement(contactManifold,
|
||||||
body1->mContactManifoldsList);
|
body1->mContactManifoldsList);
|
||||||
body1->mContactManifoldsList = listElement1;
|
body1->mContactManifoldsList = listElement1;
|
||||||
|
|
||||||
// Add the contact manifold at the beginning of the linked
|
// Add the contact manifold at the beginning of the linked
|
||||||
// list of the contact manifolds of the second body
|
// list of the contact manifolds of the second body
|
||||||
void* allocatedMemory2 = mWorld->mPoolAllocator.allocate(sizeof(ContactManifoldListElement));
|
ContactManifoldListElement* listElement2 = new (mPoolAllocator.allocate(sizeof(ContactManifoldListElement)))
|
||||||
ContactManifoldListElement* listElement2 = new (allocatedMemory2)
|
|
||||||
ContactManifoldListElement(contactManifold,
|
ContactManifoldListElement(contactManifold,
|
||||||
body2->mContactManifoldsList);
|
body2->mContactManifoldsList);
|
||||||
body2->mContactManifoldsList = listElement2;
|
body2->mContactManifoldsList = listElement2;
|
||||||
|
|
||||||
|
contactManifold = contactManifold->getNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all the contact points in the currently overlapping pairs
|
/// Convert the potential contact into actual contacts
|
||||||
void CollisionDetection::clearContactPoints() {
|
void CollisionDetection::processAllPotentialContacts() {
|
||||||
|
|
||||||
// For each overlapping pair
|
// For each overlapping pairs in contact during the narrow-phase
|
||||||
std::map<overlappingpairid, OverlappingPair*>::iterator it;
|
std::map<overlappingpairid, OverlappingPair*>::iterator it;
|
||||||
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
|
for (it = mContactOverlappingPairs.begin(); it != mContactOverlappingPairs.end(); ++it) {
|
||||||
it->second->clearContactPoints();
|
|
||||||
|
// Process the potential contacts of the overlapping pair
|
||||||
|
processPotentialContacts(it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the potential contact manifold of a pair to create actual contact manifold
|
||||||
|
void CollisionDetection::processPotentialContacts(OverlappingPair* pair) {
|
||||||
|
|
||||||
|
// Reduce the number of contact points of the manifold
|
||||||
|
pair->reducePotentialContactManifolds();
|
||||||
|
|
||||||
|
// If there is a concave mesh shape in the pair
|
||||||
|
if (pair->hasConcaveShape()) {
|
||||||
|
|
||||||
|
processSmoothMeshContacts(pair);
|
||||||
|
}
|
||||||
|
else { // If both collision shapes are convex
|
||||||
|
|
||||||
|
// Add all the potential contact manifolds as actual contact manifolds to the pair
|
||||||
|
ContactManifoldInfo* potentialManifold = pair->getPotentialContactManifolds();
|
||||||
|
while (potentialManifold != nullptr) {
|
||||||
|
|
||||||
|
pair->addContactManifold(potentialManifold);
|
||||||
|
|
||||||
|
potentialManifold = potentialManifold->mNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the obselete contact manifolds and contact points
|
||||||
|
pair->clearObseleteManifoldsAndContactPoints();
|
||||||
|
|
||||||
|
// Reset the potential contacts of the pair
|
||||||
|
pair->clearPotentialContactManifolds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report contacts for all the colliding overlapping pairs
|
||||||
|
void CollisionDetection::reportAllContacts() {
|
||||||
|
|
||||||
|
// For each overlapping pairs in contact during the narrow-phase
|
||||||
|
std::map<overlappingpairid, OverlappingPair*>::iterator it;
|
||||||
|
for (it = mContactOverlappingPairs.begin(); it != mContactOverlappingPairs.end(); ++it) {
|
||||||
|
|
||||||
|
// If there is a user callback
|
||||||
|
if (mWorld->mEventListener != nullptr) {
|
||||||
|
|
||||||
|
CollisionCallback::CollisionCallbackInfo collisionInfo(it->second, mPoolAllocator);
|
||||||
|
|
||||||
|
// Trigger a callback event to report the new contact to the user
|
||||||
|
mWorld->mEventListener->newContact(collisionInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the potential contacts where one collion is a concave shape.
|
||||||
|
// This method processes the concave triangle mesh collision using the smooth mesh collision algorithm described
|
||||||
|
// by Pierre Terdiman (http://www.codercorner.com/MeshContacts.pdf). This is used to avoid the collision
|
||||||
|
// issue with some internal edges.
|
||||||
|
void CollisionDetection::processSmoothMeshContacts(OverlappingPair* pair) {
|
||||||
|
|
||||||
|
// // Set with the triangle vertices already processed to void further contacts with same triangle
|
||||||
|
// std::unordered_multimap<int, Vector3> processTriangleVertices;
|
||||||
|
|
||||||
|
// std::vector<SmoothMeshContactInfo*> smoothContactPoints;
|
||||||
|
|
||||||
|
// // If the collision shape 1 is the triangle
|
||||||
|
// bool isFirstShapeTriangle = pair->getShape1()->getCollisionShape()->getType() == CollisionShapeType::TRIANGLE;
|
||||||
|
// assert(isFirstShapeTriangle || pair->getShape2()->getCollisionShape()->getType() == CollisionShapeType::TRIANGLE);
|
||||||
|
// assert(!isFirstShapeTriangle || pair->getShape2()->getCollisionShape()->getType() != CollisionShapeType::TRIANGLE);
|
||||||
|
|
||||||
|
// const TriangleShape* triangleShape = nullptr;
|
||||||
|
// if (isFirstShapeTriangle) {
|
||||||
|
// triangleShape = static_cast<const TriangleShape*>(pair->getShape1()->getCollisionShape());
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// triangleShape = static_cast<const TriangleShape*>(pair->getShape2()->getCollisionShape());
|
||||||
|
// }
|
||||||
|
// assert(triangleShape != nullptr);
|
||||||
|
|
||||||
|
// // Get the temporary memory allocator
|
||||||
|
// Allocator& allocator = pair->getTemporaryAllocator();
|
||||||
|
|
||||||
|
// // For each potential contact manifold of the pair
|
||||||
|
// ContactManifoldInfo* potentialManifold = pair->getPotentialContactManifolds();
|
||||||
|
// while (potentialManifold != nullptr) {
|
||||||
|
|
||||||
|
// // For each contact point of the potential manifold
|
||||||
|
// ContactPointInfo* contactPointInfo = potentialManifold->getFirstContactPointInfo();
|
||||||
|
// while (contactPointInfo != nullptr) {
|
||||||
|
|
||||||
|
// // Compute the barycentric coordinates of the point in the triangle
|
||||||
|
// decimal u, v, w;
|
||||||
|
// computeBarycentricCoordinatesInTriangle(triangleShape->getVertexPosition(0),
|
||||||
|
// triangleShape->getVertexPosition(1),
|
||||||
|
// triangleShape->getVertexPosition(2),
|
||||||
|
// isFirstShapeTriangle ? contactPointInfo->localPoint1 : contactPointInfo->localPoint2,
|
||||||
|
// u, v, w);
|
||||||
|
// int nbZeros = 0;
|
||||||
|
// bool isUZero = approxEqual(u, 0, 0.0001);
|
||||||
|
// bool isVZero = approxEqual(v, 0, 0.0001);
|
||||||
|
// bool isWZero = approxEqual(w, 0, 0.0001);
|
||||||
|
// if (isUZero) nbZeros++;
|
||||||
|
// if (isVZero) nbZeros++;
|
||||||
|
// if (isWZero) nbZeros++;
|
||||||
|
|
||||||
|
// // If the triangle contact point is on a triangle vertex of a triangle edge
|
||||||
|
// if (nbZeros == 1 || nbZeros == 2) {
|
||||||
|
|
||||||
|
|
||||||
|
// // Create a smooth mesh contact info
|
||||||
|
// SmoothMeshContactInfo* smoothContactInfo = new (allocator.allocate(sizeof(SmoothMeshContactInfo)))
|
||||||
|
// SmoothMeshContactInfo(potentialManifold, contactInfo, isFirstShapeTriangle,
|
||||||
|
// triangleShape->getVertexPosition(0),
|
||||||
|
// triangleShape->getVertexPosition(1),
|
||||||
|
// triangleShape->getVertexPosition(2));
|
||||||
|
|
||||||
|
// smoothContactPoints.push_back(smoothContactInfo);
|
||||||
|
|
||||||
|
// // Remove the contact point info from the manifold. If the contact point will be kept in the future, we
|
||||||
|
// // will put the contact point back in the manifold.
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Note that we do not remove the contact points that are not on the vertices or edges of the triangle
|
||||||
|
// // from the contact manifold because we know we will keep to contact points. We only remove the vertices
|
||||||
|
// // and edges contact points for the moment. If those points will be kept in the future, we will have to
|
||||||
|
// // put them back again in the contact manifold
|
||||||
|
// }
|
||||||
|
|
||||||
|
// potentialManifold = potentialManifold->mNext;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Sort the list of narrow-phase contacts according to their penetration depth
|
||||||
|
// std::sort(smoothContactPoints.begin(), smoothContactPoints.end(), ContactsDepthCompare());
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between two proxy shapes
|
// Compute the middle-phase collision detection between two proxy shapes
|
||||||
NarrowPhaseInfo* CollisionDetection::computeMiddlePhaseForProxyShapes(OverlappingPair* pair) {
|
NarrowPhaseInfo* CollisionDetection::computeMiddlePhaseForProxyShapes(OverlappingPair* pair) {
|
||||||
|
|
||||||
|
@ -424,7 +552,7 @@ NarrowPhaseInfo* CollisionDetection::computeMiddlePhaseForProxyShapes(Overlappin
|
||||||
|
|
||||||
// No middle-phase is necessary, simply create a narrow phase info
|
// No middle-phase is necessary, simply create a narrow phase info
|
||||||
// for the narrow-phase collision detection
|
// for the narrow-phase collision detection
|
||||||
narrowPhaseInfo = new (mMemoryAllocator.allocate(sizeof(NarrowPhaseInfo))) NarrowPhaseInfo(pair, shape1->getCollisionShape(),
|
narrowPhaseInfo = new (mPoolAllocator.allocate(sizeof(NarrowPhaseInfo))) NarrowPhaseInfo(pair, shape1->getCollisionShape(),
|
||||||
shape2->getCollisionShape(), shape1->getLocalToWorldTransform(),
|
shape2->getCollisionShape(), shape1->getLocalToWorldTransform(),
|
||||||
shape2->getLocalToWorldTransform(), shape1->getCachedCollisionData(),
|
shape2->getLocalToWorldTransform(), shape1->getCachedCollisionData(),
|
||||||
shape2->getCachedCollisionData());
|
shape2->getCachedCollisionData());
|
||||||
|
@ -436,7 +564,7 @@ NarrowPhaseInfo* CollisionDetection::computeMiddlePhaseForProxyShapes(Overlappin
|
||||||
|
|
||||||
// Run the middle-phase collision detection algorithm to find the triangles of the concave
|
// Run the middle-phase collision detection algorithm to find the triangles of the concave
|
||||||
// shape we need to use during the narrow-phase collision detection
|
// shape we need to use during the narrow-phase collision detection
|
||||||
computeConvexVsConcaveMiddlePhase(pair, mMemoryAllocator, &narrowPhaseInfo);
|
computeConvexVsConcaveMiddlePhase(pair, mPoolAllocator, &narrowPhaseInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return narrowPhaseInfo;
|
return narrowPhaseInfo;
|
||||||
|
@ -450,7 +578,7 @@ void CollisionDetection::testAABBOverlap(const AABB& aabb, OverlapCallback* over
|
||||||
std::unordered_set<bodyindex> reportedBodies;
|
std::unordered_set<bodyindex> reportedBodies;
|
||||||
|
|
||||||
// Ask the broad-phase to get all the overlapping shapes
|
// Ask the broad-phase to get all the overlapping shapes
|
||||||
LinkedList<int> overlappingNodes(mMemoryAllocator);
|
LinkedList<int> overlappingNodes(mPoolAllocator);
|
||||||
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(aabb, overlappingNodes);
|
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(aabb, overlappingNodes);
|
||||||
|
|
||||||
// For each overlaping proxy shape
|
// For each overlaping proxy shape
|
||||||
|
@ -504,7 +632,7 @@ bool CollisionDetection::testOverlap(CollisionBody* body1, CollisionBody* body2)
|
||||||
const CollisionShapeType shape2Type = body2ProxyShape->getCollisionShape()->getType();
|
const CollisionShapeType shape2Type = body2ProxyShape->getCollisionShape()->getType();
|
||||||
|
|
||||||
// Create a temporary overlapping pair
|
// Create a temporary overlapping pair
|
||||||
OverlappingPair pair(body1ProxyShape, body2ProxyShape, 0, mMemoryAllocator);
|
OverlappingPair pair(body1ProxyShape, body2ProxyShape, mPoolAllocator, mPoolAllocator);
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between the two shapes
|
// Compute the middle-phase collision detection between the two shapes
|
||||||
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
||||||
|
@ -526,16 +654,18 @@ bool CollisionDetection::testOverlap(CollisionBody* body1, CollisionBody* body2)
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, false);
|
||||||
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
||||||
narrowPhaseInfo = narrowPhaseInfo->next;
|
narrowPhaseInfo = narrowPhaseInfo->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
currentNarrowPhaseInfo->~NarrowPhaseInfo();
|
||||||
|
|
||||||
// Release the allocated memory
|
// Release the allocated memory
|
||||||
mMemoryAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if we have found a narrow-phase collision
|
// Return if we have found a narrow-phase collision
|
||||||
|
@ -570,7 +700,7 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
||||||
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
|
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
|
||||||
|
|
||||||
// Ask the broad-phase to get all the overlapping shapes
|
// Ask the broad-phase to get all the overlapping shapes
|
||||||
LinkedList<int> overlappingNodes(mMemoryAllocator);
|
LinkedList<int> overlappingNodes(mPoolAllocator);
|
||||||
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
|
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
|
||||||
|
|
||||||
const bodyindex bodyId = body->getID();
|
const bodyindex bodyId = body->getID();
|
||||||
|
@ -595,7 +725,7 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
||||||
const CollisionShapeType shape2Type = proxyShape->getCollisionShape()->getType();
|
const CollisionShapeType shape2Type = proxyShape->getCollisionShape()->getType();
|
||||||
|
|
||||||
// Create a temporary overlapping pair
|
// Create a temporary overlapping pair
|
||||||
OverlappingPair pair(bodyProxyShape, proxyShape, 0, mMemoryAllocator);
|
OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator);
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between the two shapes
|
// Compute the middle-phase collision detection between the two shapes
|
||||||
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
||||||
|
@ -617,16 +747,18 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, false);
|
||||||
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
||||||
narrowPhaseInfo = narrowPhaseInfo->next;
|
narrowPhaseInfo = narrowPhaseInfo->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
currentNarrowPhaseInfo->~NarrowPhaseInfo();
|
||||||
|
|
||||||
// Release the allocated memory
|
// Release the allocated memory
|
||||||
mMemoryAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if we have found a narrow-phase collision
|
// Return if we have found a narrow-phase collision
|
||||||
|
@ -673,7 +805,7 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
|
||||||
if (aabb1.testCollision(aabb2)) {
|
if (aabb1.testCollision(aabb2)) {
|
||||||
|
|
||||||
// Create a temporary overlapping pair
|
// Create a temporary overlapping pair
|
||||||
OverlappingPair pair(body1ProxyShape, body2ProxyShape, 0, mMemoryAllocator);
|
OverlappingPair pair(body1ProxyShape, body2ProxyShape, mPoolAllocator, mPoolAllocator);
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between the two shapes
|
// Compute the middle-phase collision detection between the two shapes
|
||||||
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
||||||
|
@ -693,26 +825,29 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true)) {
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
|
||||||
|
|
||||||
// Reduce the number of points in the contact manifold (if necessary)
|
// Add the contact points as a potential contact manifold into the pair
|
||||||
contactManifoldInfo.reduce(narrowPhaseInfo->shape1ToWorldTransform);
|
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, body1, body2,
|
|
||||||
body1ProxyShape, body2ProxyShape);
|
|
||||||
|
|
||||||
// Report the contact to the user
|
|
||||||
collisionCallback->notifyContact(collisionInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
||||||
narrowPhaseInfo = narrowPhaseInfo->next;
|
narrowPhaseInfo = narrowPhaseInfo->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
currentNarrowPhaseInfo->~NarrowPhaseInfo();
|
||||||
|
|
||||||
// Release the allocated memory
|
// Release the allocated memory
|
||||||
mMemoryAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the potential contacts
|
||||||
|
processPotentialContacts(&pair);
|
||||||
|
|
||||||
|
// Report the contacts to the user
|
||||||
|
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mPoolAllocator);
|
||||||
|
collisionCallback->notifyContact(collisionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go to the next proxy shape
|
// Go to the next proxy shape
|
||||||
|
@ -737,7 +872,7 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
|
||||||
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
|
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
|
||||||
|
|
||||||
// Ask the broad-phase to get all the overlapping shapes
|
// Ask the broad-phase to get all the overlapping shapes
|
||||||
LinkedList<int> overlappingNodes(mMemoryAllocator);
|
LinkedList<int> overlappingNodes(mPoolAllocator);
|
||||||
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
|
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
|
||||||
|
|
||||||
const bodyindex bodyId = body->getID();
|
const bodyindex bodyId = body->getID();
|
||||||
|
@ -760,7 +895,7 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
|
||||||
const CollisionShapeType shape2Type = proxyShape->getCollisionShape()->getType();
|
const CollisionShapeType shape2Type = proxyShape->getCollisionShape()->getType();
|
||||||
|
|
||||||
// Create a temporary overlapping pair
|
// Create a temporary overlapping pair
|
||||||
OverlappingPair pair(bodyProxyShape, proxyShape, 0, mMemoryAllocator);
|
OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator);
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between the two shapes
|
// Compute the middle-phase collision detection between the two shapes
|
||||||
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
||||||
|
@ -777,17 +912,13 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true)) {
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
|
||||||
|
|
||||||
// Reduce the number of points in the contact manifold (if necessary)
|
// Add the contact points as a potential contact manifold into the pair
|
||||||
contactManifoldInfo.reduce(narrowPhaseInfo->shape1ToWorldTransform);
|
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, body,
|
// Report the contacts to the user
|
||||||
proxyShape->getBody(), bodyProxyShape,
|
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mPoolAllocator);
|
||||||
proxyShape);
|
|
||||||
|
|
||||||
// Report the contact to the user
|
|
||||||
callback->notifyContact(collisionInfo);
|
callback->notifyContact(collisionInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -795,9 +926,15 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
|
||||||
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
||||||
narrowPhaseInfo = narrowPhaseInfo->next;
|
narrowPhaseInfo = narrowPhaseInfo->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
currentNarrowPhaseInfo->~NarrowPhaseInfo();
|
||||||
|
|
||||||
// Release the allocated memory
|
// Release the allocated memory
|
||||||
mMemoryAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the potential contacts
|
||||||
|
processPotentialContacts(&pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,10 +959,14 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
|
||||||
map<overlappingpairid, OverlappingPair*>::iterator it;
|
map<overlappingpairid, OverlappingPair*>::iterator it;
|
||||||
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
|
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
|
||||||
|
|
||||||
OverlappingPair* pair = it->second;
|
OverlappingPair* originalPair = it->second;
|
||||||
|
|
||||||
ProxyShape* shape1 = pair->getShape1();
|
// Create a new overlapping pair so that we do not work on the original one
|
||||||
ProxyShape* shape2 = pair->getShape2();
|
OverlappingPair pair(originalPair->getShape1(), originalPair->getShape2(), mPoolAllocator,
|
||||||
|
mPoolAllocator);
|
||||||
|
|
||||||
|
ProxyShape* shape1 = pair.getShape1();
|
||||||
|
ProxyShape* shape2 = pair.getShape2();
|
||||||
|
|
||||||
// Check if the collision filtering allows collision between the two shapes and
|
// Check if the collision filtering allows collision between the two shapes and
|
||||||
// that the two shapes are still overlapping.
|
// that the two shapes are still overlapping.
|
||||||
|
@ -834,14 +975,14 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
|
||||||
mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||||
|
|
||||||
// Compute the middle-phase collision detection between the two shapes
|
// Compute the middle-phase collision detection between the two shapes
|
||||||
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(pair);
|
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
|
||||||
|
|
||||||
const CollisionShapeType shape1Type = shape1->getCollisionShape()->getType();
|
|
||||||
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
|
|
||||||
|
|
||||||
// For each narrow-phase info object
|
// For each narrow-phase info object
|
||||||
while (narrowPhaseInfo != nullptr) {
|
while (narrowPhaseInfo != nullptr) {
|
||||||
|
|
||||||
|
const CollisionShapeType shape1Type = shape1->getCollisionShape()->getType();
|
||||||
|
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
|
||||||
|
|
||||||
// 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(shape1Type, shape2Type);
|
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(shape1Type, shape2Type);
|
||||||
|
|
||||||
|
@ -851,29 +992,29 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true)) {
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
|
||||||
|
|
||||||
// Reduce the number of points in the contact manifold (if necessary)
|
// Add the contact points as a potential contact manifold into the pair
|
||||||
contactManifoldInfo.reduce(narrowPhaseInfo->shape1ToWorldTransform);
|
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, shape1->getBody(),
|
// Report the contacts to the user
|
||||||
shape2->getBody(), shape1, shape2);
|
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mPoolAllocator);
|
||||||
|
|
||||||
// Report the contact to the user
|
|
||||||
callback->notifyContact(collisionInfo);
|
callback->notifyContact(collisionInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The previous frame collision info is now valid
|
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().isValid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
|
||||||
narrowPhaseInfo = narrowPhaseInfo->next;
|
narrowPhaseInfo = narrowPhaseInfo->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
currentNarrowPhaseInfo->~NarrowPhaseInfo();
|
||||||
|
|
||||||
// Release the allocated memory
|
// Release the allocated memory
|
||||||
mMemoryAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process the potential contacts
|
||||||
|
processPotentialContacts(&pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class CollisionDetection {
|
||||||
NarrowPhaseAlgorithm* mCollisionMatrix[NB_COLLISION_SHAPE_TYPES][NB_COLLISION_SHAPE_TYPES];
|
NarrowPhaseAlgorithm* mCollisionMatrix[NB_COLLISION_SHAPE_TYPES][NB_COLLISION_SHAPE_TYPES];
|
||||||
|
|
||||||
/// Reference to the memory allocator
|
/// Reference to the memory allocator
|
||||||
PoolAllocator& mMemoryAllocator;
|
PoolAllocator& mPoolAllocator;
|
||||||
|
|
||||||
/// Reference to the single frame memory allocator
|
/// Reference to the single frame memory allocator
|
||||||
SingleFrameAllocator& mSingleFrameAllocator;
|
SingleFrameAllocator& mSingleFrameAllocator;
|
||||||
|
@ -118,9 +118,6 @@ class CollisionDetection {
|
||||||
/// involed in the corresponding contact.
|
/// involed in the corresponding contact.
|
||||||
void addContactManifoldToBody(OverlappingPair* pair);
|
void addContactManifoldToBody(OverlappingPair* pair);
|
||||||
|
|
||||||
/// Delete all the contact points in the currently overlapping pairs
|
|
||||||
void clearContactPoints();
|
|
||||||
|
|
||||||
/// Fill-in the collision detection matrix
|
/// Fill-in the collision detection matrix
|
||||||
void fillInCollisionMatrix();
|
void fillInCollisionMatrix();
|
||||||
|
|
||||||
|
@ -138,6 +135,18 @@ class CollisionDetection {
|
||||||
/// Compute the middle-phase collision detection between two proxy shapes
|
/// Compute the middle-phase collision detection between two proxy shapes
|
||||||
NarrowPhaseInfo* computeMiddlePhaseForProxyShapes(OverlappingPair* pair);
|
NarrowPhaseInfo* computeMiddlePhaseForProxyShapes(OverlappingPair* pair);
|
||||||
|
|
||||||
|
/// Convert the potential contact into actual contacts
|
||||||
|
void processAllPotentialContacts();
|
||||||
|
|
||||||
|
/// Process the potential contact manifold of a pair to create actual contact manifold
|
||||||
|
void processPotentialContacts(OverlappingPair* pair);
|
||||||
|
|
||||||
|
/// Report contacts for all the colliding overlapping pairs
|
||||||
|
void reportAllContacts();
|
||||||
|
|
||||||
|
/// Process the potential contacts where one collion is a concave shape
|
||||||
|
void processSmoothMeshContacts(OverlappingPair* pair);
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
|
@ -30,15 +30,14 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ContactManifold::ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifold::ContactManifold(const ContactManifoldInfo* manifoldInfo, ProxyShape* shape1, ProxyShape* shape2, Allocator& memoryAllocator)
|
||||||
PoolAllocator& memoryAllocator, short normalDirectionId)
|
: mShape1(shape1), mShape2(shape2), mContactPoints(nullptr), mContactNormalId(manifoldInfo->getContactNormalId()),
|
||||||
: mShape1(shape1), mShape2(shape2), mNormalDirectionId(normalDirectionId),
|
|
||||||
mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0),
|
mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0),
|
||||||
mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false),
|
mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false),
|
||||||
mMemoryAllocator(memoryAllocator) {
|
mMemoryAllocator(memoryAllocator), mNext(nullptr), mPrevious(nullptr), mIsObselete(false) {
|
||||||
|
|
||||||
// For each contact point info in the manifold
|
// For each contact point info in the manifold
|
||||||
const ContactPointInfo* pointInfo = manifoldInfo.getFirstContactPointInfo();
|
const ContactPointInfo* pointInfo = manifoldInfo->getFirstContactPointInfo();
|
||||||
while(pointInfo != nullptr) {
|
while(pointInfo != nullptr) {
|
||||||
|
|
||||||
// Create the new contact point
|
// Create the new contact point
|
||||||
|
@ -46,7 +45,8 @@ ContactManifold::ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyS
|
||||||
ContactPoint(pointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
ContactPoint(pointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
||||||
|
|
||||||
// Add the new contact point into the manifold
|
// Add the new contact point into the manifold
|
||||||
mContactPoints[mNbContactPoints] = contact;
|
contact->setNext(mContactPoints);
|
||||||
|
mContactPoints = contact;
|
||||||
mNbContactPoints++;
|
mNbContactPoints++;
|
||||||
|
|
||||||
pointInfo = pointInfo->next;
|
pointInfo = pointInfo->next;
|
||||||
|
@ -58,49 +58,69 @@ ContactManifold::ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyS
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
ContactManifold::~ContactManifold() {
|
ContactManifold::~ContactManifold() {
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the contact manifold
|
// Delete all the contact points
|
||||||
void ContactManifold::clear() {
|
ContactPoint* contactPoint = mContactPoints;
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
while(contactPoint != nullptr) {
|
||||||
|
|
||||||
// Call the destructor explicitly and tell the memory allocator that
|
ContactPoint* nextContactPoint = contactPoint->getNext();
|
||||||
// the corresponding memory block is now free
|
|
||||||
mContactPoints[i]->~ContactPoint();
|
// TODO : Delete this
|
||||||
mMemoryAllocator.release(mContactPoints[i], sizeof(ContactPoint));
|
bool test = mMemoryAllocator.isReleaseNeeded();
|
||||||
|
|
||||||
|
// Delete the contact point
|
||||||
|
contactPoint->~ContactPoint();
|
||||||
|
mMemoryAllocator.release(contactPoint, sizeof(ContactPoint));
|
||||||
|
|
||||||
|
contactPoint = nextContactPoint;
|
||||||
}
|
}
|
||||||
mNbContactPoints = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a contact point
|
// Add a contact point
|
||||||
void ContactManifold::addContactPoint(const ContactPointInfo* contactPointInfo) {
|
void ContactManifold::addContactPoint(const ContactPointInfo* contactPointInfo) {
|
||||||
|
|
||||||
assert(mNbContactPoints < MAX_CONTACT_POINTS_IN_MANIFOLD);
|
|
||||||
|
|
||||||
// Create the new contact point
|
// Create the new contact point
|
||||||
ContactPoint* contactPoint = new (mMemoryAllocator.allocate(sizeof(ContactPoint)))
|
ContactPoint* contactPoint = new (mMemoryAllocator.allocate(sizeof(ContactPoint)))
|
||||||
ContactPoint(contactPointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
ContactPoint(contactPointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
||||||
|
|
||||||
// Add the new contact point into the manifold
|
// Add the new contact point into the manifold
|
||||||
mContactPoints[mNbContactPoints] = contactPoint;
|
contactPoint->setNext(mContactPoints);
|
||||||
mNbContactPoints++;
|
mContactPoints = contactPoint;
|
||||||
|
|
||||||
|
mNbContactPoints++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a contact point
|
// Clear the obselete contact points
|
||||||
void ContactManifold::removeContactPoint(int index) {
|
void ContactManifold::clearObseleteContactPoints() {
|
||||||
|
|
||||||
assert(mNbContactPoints > 0);
|
ContactPoint* contactPoint = mContactPoints;
|
||||||
assert(index >= 0 && index < mNbContactPoints);
|
ContactPoint* previousContactPoint = nullptr;
|
||||||
|
while (contactPoint != nullptr) {
|
||||||
|
|
||||||
// Delete the contact
|
ContactPoint* nextContactPoint = contactPoint->getNext();
|
||||||
mContactPoints[index]->~ContactPoint();
|
|
||||||
mMemoryAllocator.release(mContactPoints[index], sizeof(ContactPoint));
|
|
||||||
|
|
||||||
for (int i=index; (i+1) < mNbContactPoints; i++) {
|
if (contactPoint->getIsObselete()) {
|
||||||
mContactPoints[i] = mContactPoints[i+1];
|
|
||||||
|
// Delete the contact point
|
||||||
|
contactPoint->~ContactPoint();
|
||||||
|
mMemoryAllocator.release(contactPoint, sizeof(ContactPoint));
|
||||||
|
|
||||||
|
if (previousContactPoint != nullptr) {
|
||||||
|
previousContactPoint->setNext(nextContactPoint);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mContactPoints = nextContactPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
mNbContactPoints--;
|
mNbContactPoints--;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
previousContactPoint = contactPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
contactPoint = nextContactPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mNbContactPoints >= 0);
|
||||||
|
assert(mNbContactPoints <= MAX_CONTACT_POINTS_IN_MANIFOLD);
|
||||||
|
}
|
||||||
|
|
|
@ -46,40 +46,43 @@ class ContactManifold;
|
||||||
*/
|
*/
|
||||||
struct ContactManifoldListElement {
|
struct ContactManifoldListElement {
|
||||||
|
|
||||||
public:
|
private:
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
/// Pointer to the actual contact manifold
|
/// Pointer to a contact manifold with contact points
|
||||||
ContactManifold* contactManifold;
|
ContactManifold* mContactManifold;
|
||||||
|
|
||||||
/// Next element of the list
|
/// Next element of the list
|
||||||
ContactManifoldListElement* next;
|
ContactManifoldListElement* mNext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
ContactManifoldListElement(ContactManifold* initContactManifold,
|
ContactManifoldListElement(ContactManifold* contactManifold,
|
||||||
ContactManifoldListElement* initNext)
|
ContactManifoldListElement* next)
|
||||||
:contactManifold(initContactManifold), next(initNext) {
|
:mContactManifold(contactManifold), mNext(next) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the contact manifold
|
||||||
|
ContactManifold* getContactManifold() {
|
||||||
|
return mContactManifold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the next element in the linked-list
|
||||||
|
ContactManifoldListElement* getNext() {
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class ContactManifold
|
// Class ContactManifold
|
||||||
/**
|
/**
|
||||||
* This class represents the set of contact points between two bodies.
|
* This class represents the set of contact points between two bodies.
|
||||||
* The contact manifold is implemented in a way to cache the contact
|
* The contact manifold is implemented in a way to cache the contact
|
||||||
* points among the frames for better stability following the
|
* points among the frames for better stability.
|
||||||
* "Contact Generation" presentation of Erwin Coumans at GDC 2010
|
|
||||||
* conference (bullet.googlecode.com/files/GDC10_Coumans_Erwin_Contact.pdf).
|
|
||||||
* Some code of this class is based on the implementation of the
|
|
||||||
* btPersistentManifold class from Bullet physics engine (www.http://bulletphysics.org).
|
|
||||||
* The contacts between two bodies are added one after the other in the cache.
|
|
||||||
* When the cache is full, we have to remove one point. The idea is to keep
|
|
||||||
* the point with the deepest penetration depth and also to keep the
|
|
||||||
* points producing the larger area (for a more stable contact manifold).
|
|
||||||
* The new added point is always kept.
|
|
||||||
*/
|
*/
|
||||||
class ContactManifold {
|
class ContactManifold {
|
||||||
|
|
||||||
|
@ -94,10 +97,10 @@ class ContactManifold {
|
||||||
ProxyShape* mShape2;
|
ProxyShape* mShape2;
|
||||||
|
|
||||||
/// Contact points in the manifold
|
/// Contact points in the manifold
|
||||||
ContactPoint* mContactPoints[MAX_CONTACT_POINTS_IN_MANIFOLD];
|
ContactPoint* mContactPoints;
|
||||||
|
|
||||||
/// Normal direction Id (Unique Id representing the normal direction)
|
/// Normal direction Id (Unique Id representing the normal direction)
|
||||||
short int mNormalDirectionId;
|
short int mContactNormalId;
|
||||||
|
|
||||||
/// Number of contacts in the cache
|
/// Number of contacts in the cache
|
||||||
int8 mNbContactPoints;
|
int8 mNbContactPoints;
|
||||||
|
@ -124,20 +127,86 @@ class ContactManifold {
|
||||||
bool mIsAlreadyInIsland;
|
bool mIsAlreadyInIsland;
|
||||||
|
|
||||||
/// Reference to the memory allocator
|
/// Reference to the memory allocator
|
||||||
PoolAllocator& mMemoryAllocator;
|
Allocator& mMemoryAllocator;
|
||||||
|
|
||||||
|
/// Pointer to the next contact manifold in the linked-list
|
||||||
|
ContactManifold* mNext;
|
||||||
|
|
||||||
|
/// Pointer to the previous contact manifold in linked-list
|
||||||
|
ContactManifold* mPrevious;
|
||||||
|
|
||||||
|
/// True if the contact manifold is obselete
|
||||||
|
bool mIsObselete;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Return true if the contact manifold has already been added into an island
|
/// Return true if the contact manifold has already been added into an island
|
||||||
bool isAlreadyInIsland() const;
|
bool isAlreadyInIsland() const;
|
||||||
|
|
||||||
|
/// Set the pointer to the next element in the linked-list
|
||||||
|
void setNext(ContactManifold* nextManifold);
|
||||||
|
|
||||||
|
/// Return true if the manifold is obselete
|
||||||
|
bool getIsObselete() const;
|
||||||
|
|
||||||
|
/// Set to true to make the manifold obselete
|
||||||
|
void setIsObselete(bool isObselete, bool setContactPoints);
|
||||||
|
|
||||||
|
/// Clear the obselete contact points
|
||||||
|
void clearObseleteContactPoints();
|
||||||
|
|
||||||
|
/// Return the contact normal direction Id of the manifold
|
||||||
|
short getContactNormalId() const;
|
||||||
|
|
||||||
|
/// Return the largest depth of all the contact points
|
||||||
|
decimal getLargestContactDepth() const;
|
||||||
|
|
||||||
|
/// set the first friction vector at the center of the contact manifold
|
||||||
|
void setFrictionVector1(const Vector3& mFrictionVector1);
|
||||||
|
|
||||||
|
/// set the second friction vector at the center of the contact manifold
|
||||||
|
void setFrictionVector2(const Vector3& mFrictionVector2);
|
||||||
|
|
||||||
|
/// Set the first friction accumulated impulse
|
||||||
|
void setFrictionImpulse1(decimal frictionImpulse1);
|
||||||
|
|
||||||
|
/// Set the second friction accumulated impulse
|
||||||
|
void setFrictionImpulse2(decimal frictionImpulse2);
|
||||||
|
|
||||||
|
/// Add a contact point
|
||||||
|
void addContactPoint(const ContactPointInfo* contactPointInfo);
|
||||||
|
|
||||||
|
/// Set the friction twist accumulated impulse
|
||||||
|
void setFrictionTwistImpulse(decimal frictionTwistImpulse);
|
||||||
|
|
||||||
|
/// Set the accumulated rolling resistance impulse
|
||||||
|
void setRollingResistanceImpulse(const Vector3& rollingResistanceImpulse);
|
||||||
|
|
||||||
|
/// Set the pointer to the previous element in the linked-list
|
||||||
|
void setPrevious(ContactManifold* previousManifold);
|
||||||
|
|
||||||
|
/// Return the first friction vector at the center of the contact manifold
|
||||||
|
const Vector3& getFrictionVector1() const;
|
||||||
|
|
||||||
|
/// Return the second friction vector at the center of the contact manifold
|
||||||
|
const Vector3& getFrictionVector2() const;
|
||||||
|
|
||||||
|
/// Return the first friction accumulated impulse
|
||||||
|
decimal getFrictionImpulse1() const;
|
||||||
|
|
||||||
|
/// Return the second friction accumulated impulse
|
||||||
|
decimal getFrictionImpulse2() const;
|
||||||
|
|
||||||
|
/// Return the friction twist accumulated impulse
|
||||||
|
decimal getFrictionTwistImpulse() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifold(const ContactManifoldInfo* manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
|
||||||
PoolAllocator& memoryAllocator, short int normalDirectionId);
|
Allocator& memoryAllocator);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ContactManifold();
|
~ContactManifold();
|
||||||
|
@ -160,68 +229,25 @@ class ContactManifold {
|
||||||
/// Return a pointer to the second body of the contact manifold
|
/// Return a pointer to the second body of the contact manifold
|
||||||
CollisionBody* getBody2() const;
|
CollisionBody* getBody2() const;
|
||||||
|
|
||||||
/// Return the normal direction Id
|
|
||||||
short int getNormalDirectionId() const;
|
|
||||||
|
|
||||||
/// Clear the contact manifold
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/// Return the number of contact points in the manifold
|
/// Return the number of contact points in the manifold
|
||||||
int8 getNbContactPoints() const;
|
int8 getNbContactPoints() const;
|
||||||
|
|
||||||
/// Return the first friction vector at the center of the contact manifold
|
/// Return a pointer to the first contact point of the manifold
|
||||||
const Vector3& getFrictionVector1() const;
|
ContactPoint* getContactPoints() const;
|
||||||
|
|
||||||
/// set the first friction vector at the center of the contact manifold
|
/// Return a pointer to the previous element in the linked-list
|
||||||
void setFrictionVector1(const Vector3& mFrictionVector1);
|
ContactManifold* getPrevious() const;
|
||||||
|
|
||||||
/// Return the second friction vector at the center of the contact manifold
|
/// Return a pointer to the next element in the linked-list
|
||||||
const Vector3& getFrictionVector2() const;
|
ContactManifold* getNext() const;
|
||||||
|
|
||||||
/// set the second friction vector at the center of the contact manifold
|
|
||||||
void setFrictionVector2(const Vector3& mFrictionVector2);
|
|
||||||
|
|
||||||
/// Return the first friction accumulated impulse
|
|
||||||
decimal getFrictionImpulse1() const;
|
|
||||||
|
|
||||||
/// Set the first friction accumulated impulse
|
|
||||||
void setFrictionImpulse1(decimal frictionImpulse1);
|
|
||||||
|
|
||||||
/// Return the second friction accumulated impulse
|
|
||||||
decimal getFrictionImpulse2() const;
|
|
||||||
|
|
||||||
/// Set the second friction accumulated impulse
|
|
||||||
void setFrictionImpulse2(decimal frictionImpulse2);
|
|
||||||
|
|
||||||
/// Return the friction twist accumulated impulse
|
|
||||||
decimal getFrictionTwistImpulse() const;
|
|
||||||
|
|
||||||
/// Set the friction twist accumulated impulse
|
|
||||||
void setFrictionTwistImpulse(decimal frictionTwistImpulse);
|
|
||||||
|
|
||||||
/// Set the accumulated rolling resistance impulse
|
|
||||||
void setRollingResistanceImpulse(const Vector3& rollingResistanceImpulse);
|
|
||||||
|
|
||||||
/// Return a contact point of the manifold
|
|
||||||
ContactPoint* getContactPoint(uint index) const;
|
|
||||||
|
|
||||||
/// Return the normalized averaged normal vector
|
|
||||||
Vector3 getAverageContactNormal() const;
|
|
||||||
|
|
||||||
/// Return the largest depth of all the contact points
|
|
||||||
decimal getLargestContactDepth() const;
|
|
||||||
|
|
||||||
/// Add a contact point
|
|
||||||
void addContactPoint(const ContactPointInfo* contactPointInfo);
|
|
||||||
|
|
||||||
/// Remove a contact point
|
|
||||||
void removeContactPoint(int index);
|
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
friend class DynamicsWorld;
|
friend class DynamicsWorld;
|
||||||
friend class Island;
|
friend class Island;
|
||||||
friend class CollisionBody;
|
friend class CollisionBody;
|
||||||
|
friend class ContactManifoldSet;
|
||||||
|
friend class ContactSolver;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a pointer to the first proxy shape of the contact
|
// Return a pointer to the first proxy shape of the contact
|
||||||
|
@ -244,11 +270,6 @@ inline CollisionBody* ContactManifold::getBody2() const {
|
||||||
return mShape2->getBody();
|
return mShape2->getBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the normal direction Id
|
|
||||||
inline short int ContactManifold::getNormalDirectionId() const {
|
|
||||||
return mNormalDirectionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the number of contact points in the manifold
|
// Return the number of contact points in the manifold
|
||||||
inline int8 ContactManifold::getNbContactPoints() const {
|
inline int8 ContactManifold::getNbContactPoints() const {
|
||||||
return mNbContactPoints;
|
return mNbContactPoints;
|
||||||
|
@ -309,10 +330,9 @@ inline void ContactManifold::setRollingResistanceImpulse(const Vector3& rollingR
|
||||||
mRollingResistanceImpulse = rollingResistanceImpulse;
|
mRollingResistanceImpulse = rollingResistanceImpulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a contact point of the manifold
|
// Return a pointer to the first contact point of the manifold
|
||||||
inline ContactPoint* ContactManifold::getContactPoint(uint index) const {
|
inline ContactPoint* ContactManifold::getContactPoints() const {
|
||||||
assert(index < mNbContactPoints);
|
return mContactPoints;
|
||||||
return mContactPoints[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if the contact manifold has already been added into an island
|
// Return true if the contact manifold has already been added into an island
|
||||||
|
@ -320,31 +340,69 @@ inline bool ContactManifold::isAlreadyInIsland() const {
|
||||||
return mIsAlreadyInIsland;
|
return mIsAlreadyInIsland;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the normalized averaged normal vector
|
|
||||||
inline Vector3 ContactManifold::getAverageContactNormal() const {
|
|
||||||
Vector3 averageNormal;
|
|
||||||
|
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
|
||||||
averageNormal += mContactPoints[i]->getNormal();
|
|
||||||
}
|
|
||||||
|
|
||||||
return averageNormal.getUnit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the largest depth of all the contact points
|
// Return the largest depth of all the contact points
|
||||||
inline decimal ContactManifold::getLargestContactDepth() const {
|
inline decimal ContactManifold::getLargestContactDepth() const {
|
||||||
decimal largestDepth = 0.0f;
|
decimal largestDepth = 0.0f;
|
||||||
|
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
assert(mNbContactPoints > 0);
|
||||||
decimal depth = mContactPoints[i]->getPenetrationDepth();
|
|
||||||
|
ContactPoint* contactPoint = mContactPoints;
|
||||||
|
while(contactPoint != nullptr){
|
||||||
|
decimal depth = contactPoint->getPenetrationDepth();
|
||||||
if (depth > largestDepth) {
|
if (depth > largestDepth) {
|
||||||
largestDepth = depth;
|
largestDepth = depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contactPoint = contactPoint->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
return largestDepth;
|
return largestDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return a pointer to the previous element in the linked-list
|
||||||
|
inline ContactManifold* ContactManifold::getPrevious() const {
|
||||||
|
return mPrevious;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pointer to the previous element in the linked-list
|
||||||
|
inline void ContactManifold::setPrevious(ContactManifold* previousManifold) {
|
||||||
|
mPrevious = previousManifold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a pointer to the next element in the linked-list
|
||||||
|
inline ContactManifold* ContactManifold::getNext() const {
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pointer to the next element in the linked-list
|
||||||
|
inline void ContactManifold::setNext(ContactManifold* nextManifold) {
|
||||||
|
mNext = nextManifold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if the manifold is obselete
|
||||||
|
inline bool ContactManifold::getIsObselete() const {
|
||||||
|
return mIsObselete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set to true to make the manifold obselete
|
||||||
|
inline void ContactManifold::setIsObselete(bool isObselete, bool setContactPoints) {
|
||||||
|
mIsObselete = isObselete;
|
||||||
|
|
||||||
|
if (setContactPoints) {
|
||||||
|
ContactPoint* contactPoint = mContactPoints;
|
||||||
|
while (contactPoint != nullptr) {
|
||||||
|
contactPoint->setIsObselete(isObselete);
|
||||||
|
|
||||||
|
contactPoint = contactPoint->getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the contact normal direction Id of the manifold
|
||||||
|
inline short ContactManifold::getContactNormalId() const {
|
||||||
|
return mContactNormalId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ using namespace reactphysics3d;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ContactManifoldInfo::ContactManifoldInfo(Allocator& allocator)
|
ContactManifoldInfo::ContactManifoldInfo(Allocator& allocator)
|
||||||
: mContactPointsList(nullptr), mAllocator(allocator), mNbContactPoints(0) {}
|
: mContactPointsList(nullptr), mNbContactPoints(0), mNext(nullptr), mAllocator(allocator),
|
||||||
|
mContactNormalId(-1) {}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
ContactManifoldInfo::~ContactManifoldInfo() {
|
ContactManifoldInfo::~ContactManifoldInfo() {
|
||||||
|
@ -40,14 +41,13 @@ ContactManifoldInfo::~ContactManifoldInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new contact point into the manifold
|
// Add a new contact point into the manifold
|
||||||
void ContactManifoldInfo::addContactPoint(const Vector3& contactNormal, decimal penDepth,
|
void ContactManifoldInfo::addContactPoint(ContactPointInfo* contactPointInfo, short contactNormalId) {
|
||||||
const Vector3& localPt1, const Vector3& localPt2) {
|
|
||||||
|
|
||||||
assert(penDepth > decimal(0.0));
|
assert(contactPointInfo->penetrationDepth > decimal(0.0));
|
||||||
|
assert(contactNormalId >= 0);
|
||||||
|
assert(mContactNormalId == -1 || contactNormalId == mContactNormalId);
|
||||||
|
|
||||||
// Create the contact point info
|
mContactNormalId = contactNormalId;
|
||||||
ContactPointInfo* contactPointInfo = new (mAllocator.allocate(sizeof(ContactPointInfo)))
|
|
||||||
ContactPointInfo(contactNormal, penDepth, localPt1, localPt2);
|
|
||||||
|
|
||||||
// Add it into the linked list of contact points
|
// Add it into the linked list of contact points
|
||||||
contactPointInfo->next = mContactPointsList;
|
contactPointInfo->next = mContactPointsList;
|
||||||
|
@ -73,15 +73,31 @@ void ContactManifoldInfo::reset() {
|
||||||
mNbContactPoints = 0;
|
mNbContactPoints = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the number of points in the contact manifold
|
// Return the largest penetration depth among its contact points
|
||||||
|
decimal ContactManifoldInfo::getLargestPenetrationDepth() const {
|
||||||
|
|
||||||
|
ContactPointInfo* contactPoint = mContactPointsList;
|
||||||
|
assert(contactPoint != nullptr);
|
||||||
|
decimal maxDepth = decimal(0.0);
|
||||||
|
while (contactPoint != nullptr) {
|
||||||
|
|
||||||
|
if (contactPoint->penetrationDepth > maxDepth) {
|
||||||
|
maxDepth = contactPoint->penetrationDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
contactPoint = contactPoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the number of contact points of the currently computed manifold
|
||||||
// This is based on the technique described by Dirk Gregorius in his
|
// This is based on the technique described by Dirk Gregorius in his
|
||||||
// "Contacts Creation" GDC presentation
|
// "Contacts Creation" GDC presentation
|
||||||
void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
|
void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
|
||||||
|
|
||||||
assert(mContactPointsList != nullptr);
|
assert(mContactPointsList != nullptr);
|
||||||
|
|
||||||
// TODO : Implement this (do not forget to deallocate removed points)
|
|
||||||
|
|
||||||
// The following algorithm only works to reduce to 4 contact points
|
// The following algorithm only works to reduce to 4 contact points
|
||||||
assert(MAX_CONTACT_POINTS_IN_MANIFOLD == 4);
|
assert(MAX_CONTACT_POINTS_IN_MANIFOLD == 4);
|
||||||
|
|
||||||
|
@ -221,10 +237,10 @@ void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
|
||||||
largestArea = area;
|
largestArea = area;
|
||||||
pointsToKeep[3] = element;
|
pointsToKeep[3] = element;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
element = element->next;
|
element = element->next;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
assert(pointsToKeep[3] != nullptr);
|
assert(pointsToKeep[3] != nullptr);
|
||||||
|
|
||||||
// Delete the contact points we do not want to keep from the linked list
|
// Delete the contact points we do not want to keep from the linked list
|
||||||
|
@ -250,6 +266,9 @@ void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
|
||||||
}
|
}
|
||||||
element = element->next;
|
element = element->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
elementToDelete->~ContactPointInfo();
|
||||||
|
|
||||||
// Delete the current element
|
// Delete the current element
|
||||||
mAllocator.release(elementToDelete, sizeof(ContactPointInfo));
|
mAllocator.release(elementToDelete, sizeof(ContactPointInfo));
|
||||||
}
|
}
|
||||||
|
@ -258,21 +277,4 @@ void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the largest penetration depth among the contact points
|
|
||||||
decimal ContactManifoldInfo::getLargestPenetrationDepth() const {
|
|
||||||
|
|
||||||
decimal maxDepth = decimal(0.0);
|
|
||||||
ContactPointInfo* element = mContactPointsList;
|
|
||||||
while(element != nullptr) {
|
|
||||||
|
|
||||||
if (element->penetrationDepth > maxDepth) {
|
|
||||||
maxDepth = element->penetrationDepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
element = element->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxDepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const uint MAX_CONTACT_POINTS_IN_MANIFOLD = 4; // Maximum number of contacts in the manifold
|
const int8 MAX_CONTACT_POINTS_IN_MANIFOLD = 4; // Maximum number of contacts in the manifold
|
||||||
|
|
||||||
// Class ContactManifoldInfo
|
// Class ContactManifoldInfo
|
||||||
/**
|
/**
|
||||||
|
@ -50,12 +50,18 @@ class ContactManifoldInfo {
|
||||||
/// Linked list with all the contact points
|
/// Linked list with all the contact points
|
||||||
ContactPointInfo* mContactPointsList;
|
ContactPointInfo* mContactPointsList;
|
||||||
|
|
||||||
/// Memory allocator used to allocate contact points
|
|
||||||
Allocator& mAllocator;
|
|
||||||
|
|
||||||
/// Number of contact points in the manifold
|
/// Number of contact points in the manifold
|
||||||
uint mNbContactPoints;
|
uint mNbContactPoints;
|
||||||
|
|
||||||
|
/// Next element in the linked-list of contact manifold info
|
||||||
|
ContactManifoldInfo* mNext;
|
||||||
|
|
||||||
|
/// Reference the the memory allocator where the contact point infos have been allocated
|
||||||
|
Allocator& mAllocator;
|
||||||
|
|
||||||
|
/// Contact normal direction Id (Identify the contact normal direction of points in manifold)
|
||||||
|
short mContactNormalId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
@ -66,15 +72,14 @@ class ContactManifoldInfo {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ContactManifoldInfo();
|
~ContactManifoldInfo();
|
||||||
|
|
||||||
/// Deleted copy-constructor
|
/// Deleted Copy-constructor
|
||||||
ContactManifoldInfo(const ContactManifoldInfo& contactManifold) = delete;
|
ContactManifoldInfo(const ContactManifoldInfo& contactManifold) = delete;
|
||||||
|
|
||||||
/// Deleted assignment operator
|
/// Deleted assignment operator
|
||||||
ContactManifoldInfo& operator=(const ContactManifoldInfo& contactManifold) = delete;
|
ContactManifoldInfo& operator=(const ContactManifoldInfo& contactManifold) = delete;
|
||||||
|
|
||||||
/// Add a new contact point into the manifold
|
/// Add a new contact point into the manifold
|
||||||
void addContactPoint(const Vector3& contactNormal, decimal penDepth,
|
void addContactPoint(ContactPointInfo* contactPointInfo, short contactNormalId);
|
||||||
const Vector3& localPt1, const Vector3& localPt2);
|
|
||||||
|
|
||||||
/// Remove all the contact points
|
/// Remove all the contact points
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -82,11 +87,21 @@ class ContactManifoldInfo {
|
||||||
/// Get the first contact point info of the linked list of contact points
|
/// Get the first contact point info of the linked list of contact points
|
||||||
ContactPointInfo* getFirstContactPointInfo() const;
|
ContactPointInfo* getFirstContactPointInfo() const;
|
||||||
|
|
||||||
/// Reduce the number of points in the contact manifold
|
/// Return the largest penetration depth among its contact points
|
||||||
|
decimal getLargestPenetrationDepth() const;
|
||||||
|
|
||||||
|
/// Return the pointer to the next manifold info in the linked-list
|
||||||
|
ContactManifoldInfo* getNext();
|
||||||
|
|
||||||
|
/// Return the contact normal Id
|
||||||
|
short getContactNormalId() const;
|
||||||
|
|
||||||
|
/// Reduce the number of contact points of the currently computed manifold
|
||||||
void reduce(const Transform& shape1ToWorldTransform);
|
void reduce(const Transform& shape1ToWorldTransform);
|
||||||
|
|
||||||
/// Return the largest penetration depth among the contact points
|
// Friendship
|
||||||
decimal getLargestPenetrationDepth() const;
|
friend class OverlappingPair;
|
||||||
|
friend class CollisionDetection;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the first contact point info of the linked list of contact points
|
// Get the first contact point info of the linked list of contact points
|
||||||
|
@ -94,6 +109,16 @@ inline ContactPointInfo* ContactManifoldInfo::getFirstContactPointInfo() const {
|
||||||
return mContactPointsList;
|
return mContactPointsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the pointer to the next manifold info in the linked-list
|
||||||
|
inline ContactManifoldInfo* ContactManifoldInfo::getNext() {
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the contact normal Id
|
||||||
|
inline short ContactManifoldInfo::getContactNormalId() const {
|
||||||
|
return mContactNormalId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,12 @@ using namespace reactphysics3d;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ContactManifoldSet::ContactManifoldSet(ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifoldSet::ContactManifoldSet(ProxyShape* shape1, ProxyShape* shape2,
|
||||||
PoolAllocator& memoryAllocator, int nbMaxManifolds)
|
Allocator& memoryAllocator)
|
||||||
: mNbMaxManifolds(nbMaxManifolds), mNbManifolds(0), mShape1(shape1),
|
: mNbManifolds(0), mShape1(shape1),
|
||||||
mShape2(shape2), mMemoryAllocator(memoryAllocator) {
|
mShape2(shape2), mMemoryAllocator(memoryAllocator), mManifolds(nullptr) {
|
||||||
|
|
||||||
|
// Compute the maximum number of manifolds allowed between the two shapes
|
||||||
|
mNbMaxManifolds = computeNbMaxContactManifolds(shape1->getCollisionShape(), shape2->getCollisionShape());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
|
@ -43,167 +45,131 @@ ContactManifoldSet::~ContactManifoldSet() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContactManifoldSet::addContactManifold(const ContactManifoldInfo& contactManifoldInfo) {
|
void ContactManifoldSet::addContactManifold(const ContactManifoldInfo* contactManifoldInfo) {
|
||||||
|
|
||||||
assert(contactManifoldInfo.getFirstContactPointInfo() != nullptr);
|
assert(contactManifoldInfo->getFirstContactPointInfo() != nullptr);
|
||||||
|
|
||||||
// If there is no contact manifold yet
|
// Try to find an existing contact manifold with similar contact normal
|
||||||
if (mNbManifolds == 0) {
|
ContactManifold* similarManifold = selectManifoldWithSimilarNormal(contactManifoldInfo->getContactNormalId());
|
||||||
|
|
||||||
// If the maximum number of manifold is 1
|
|
||||||
if (mNbMaxManifolds == 1) {
|
|
||||||
createManifold(contactManifoldInfo, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Compute an Id corresponding to the normal direction (using a cubemap)
|
|
||||||
short int normalDirectionId = computeCubemapNormalId(contactManifoldInfo.getFirstContactPointInfo()->normal);
|
|
||||||
|
|
||||||
createManifold(contactManifoldInfo, normalDirectionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // If there is already at least one contact manifold in the set
|
|
||||||
|
|
||||||
// If the maximum number of manifold is 1
|
|
||||||
if (mNbMaxManifolds == 1) {
|
|
||||||
|
|
||||||
// Replace the old manifold with the new one
|
|
||||||
updateManifoldWithNewOne(0, contactManifoldInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Compute an Id corresponding to the normal direction (using a cubemap)
|
|
||||||
short int normalDirectionId = computeCubemapNormalId(contactManifoldInfo.getFirstContactPointInfo()->normal);
|
|
||||||
|
|
||||||
// Select the manifold with the most similar normal (if exists)
|
|
||||||
int similarManifoldIndex = 0;
|
|
||||||
if (mNbMaxManifolds > 1) {
|
|
||||||
similarManifoldIndex = selectManifoldWithSimilarNormal(normalDirectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a similar manifold has been found
|
// If a similar manifold has been found
|
||||||
if (similarManifoldIndex != -1) {
|
if (similarManifold != nullptr) {
|
||||||
|
|
||||||
// Replace the old manifold with the new one
|
// Update the old manifold with the new one
|
||||||
updateManifoldWithNewOne(similarManifoldIndex, contactManifoldInfo);
|
updateManifoldWithNewOne(similarManifold, contactManifoldInfo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
// If we have not reach the maximum number of manifolds
|
// If there are too much contact manifolds in the set
|
||||||
if (mNbManifolds < mNbMaxManifolds) {
|
if (mNbManifolds >= mNbMaxManifolds) {
|
||||||
|
|
||||||
// Create the new contact manifold
|
// We need to remove a manifold from the set.
|
||||||
createManifold(contactManifoldInfo, normalDirectionId);
|
// We seach for the one with the smallest maximum penetration depth among its contact points
|
||||||
}
|
ContactManifold* minDepthManifold = getManifoldWithSmallestContactPenetrationDepth(contactManifoldInfo->getLargestPenetrationDepth());
|
||||||
else {
|
|
||||||
|
|
||||||
decimal newManifoldPenDepth = contactManifoldInfo.getLargestPenetrationDepth();
|
// If the manifold with the minimum penetration depth is an existing one
|
||||||
|
if (minDepthManifold != nullptr) {
|
||||||
|
|
||||||
// We have reached the maximum number of manifold, we do not
|
// Remove the manifold
|
||||||
// want to keep the manifold with the smallest penetration detph
|
removeManifold(minDepthManifold);
|
||||||
int smallestPenDepthManifoldIndex = getManifoldWithSmallestContactPenetrationDepth(newManifoldPenDepth);
|
|
||||||
|
|
||||||
// If the manifold with the smallest penetration depth is not the new one,
|
// Create a new contact manifold
|
||||||
// we have to keep the new manifold and remove the one with the smallest depth
|
createManifold(contactManifoldInfo);
|
||||||
if (smallestPenDepthManifoldIndex >= 0) {
|
|
||||||
removeManifold(smallestPenDepthManifoldIndex);
|
|
||||||
createManifold(contactManifoldInfo, normalDirectionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new contact manifold
|
||||||
|
createManifold(contactManifoldInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a previous similar manifold with a new one
|
// Update a previous similar manifold with a new one
|
||||||
void ContactManifoldSet::updateManifoldWithNewOne(int oldManifoldIndex, const ContactManifoldInfo& newManifold) {
|
void ContactManifoldSet::updateManifoldWithNewOne(ContactManifold* oldManifold, const ContactManifoldInfo* newManifold) {
|
||||||
|
|
||||||
// For each contact point of the previous manifold
|
assert(oldManifold != nullptr);
|
||||||
for (int i=0; i<mManifolds[oldManifoldIndex]->getNbContactPoints(); ) {
|
assert(newManifold != nullptr);
|
||||||
|
|
||||||
ContactPoint* contactPoint = mManifolds[oldManifoldIndex]->getContactPoint(i);
|
// For each contact point of the new manifold
|
||||||
|
ContactPointInfo* contactPointInfo = newManifold->getFirstContactPointInfo();
|
||||||
|
assert(contactPointInfo != nullptr);
|
||||||
|
while (contactPointInfo != nullptr) {
|
||||||
|
|
||||||
// For each contact point in the new manifold
|
// For each contact point in the old manifold
|
||||||
ContactPointInfo* newPoint = newManifold.getFirstContactPointInfo();
|
bool isSimilarPointFound = false;
|
||||||
bool needToRemovePoint = true;
|
ContactPoint* oldContactPoint = oldManifold->getContactPoints();
|
||||||
while (newPoint != nullptr) {
|
while (oldContactPoint != nullptr) {
|
||||||
|
|
||||||
|
assert(oldContactPoint != nullptr);
|
||||||
|
|
||||||
// If the new contact point is similar (very close) to the old contact point
|
// If the new contact point is similar (very close) to the old contact point
|
||||||
if (!newPoint->isUsed && contactPoint->isSimilarWithContactPoint(newPoint)) {
|
if (oldContactPoint->isSimilarWithContactPoint(contactPointInfo)) {
|
||||||
|
|
||||||
// Replace (update) the old contact point with the new one
|
// Replace (update) the old contact point with the new one
|
||||||
contactPoint->update(newPoint, mManifolds[oldManifoldIndex]->getShape1()->getLocalToWorldTransform(),
|
oldContactPoint->update(contactPointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
||||||
mManifolds[oldManifoldIndex]->getShape2()->getLocalToWorldTransform());
|
isSimilarPointFound = true;
|
||||||
needToRemovePoint = false;
|
|
||||||
newPoint->isUsed = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
newPoint = newPoint->next;
|
oldContactPoint = oldContactPoint->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no new contact point is similar to the old one
|
// If we have not found a similar contact point
|
||||||
if (needToRemovePoint) {
|
if (!isSimilarPointFound) {
|
||||||
|
|
||||||
// Remove the old contact point
|
// Add the contact point to the manifold
|
||||||
mManifolds[oldManifoldIndex]->removeContactPoint(i);
|
oldManifold->addContactPoint(contactPointInfo);
|
||||||
}
|
|
||||||
else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each point of the new manifold that have not been used yet (to update
|
contactPointInfo = contactPointInfo->next;
|
||||||
// an existing point in the previous manifold), add it into the previous manifold
|
|
||||||
const ContactPointInfo* newPointInfo = newManifold.getFirstContactPointInfo();
|
|
||||||
while (newPointInfo != nullptr) {
|
|
||||||
|
|
||||||
if (!newPointInfo->isUsed) {
|
|
||||||
mManifolds[oldManifoldIndex]->addContactPoint(newPointInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newPointInfo = newPointInfo->next;
|
// The old manifold is no longer obselete
|
||||||
}
|
oldManifold->setIsObselete(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the manifold with the smallest contact penetration depth
|
// Return the manifold with the smallest contact penetration depth among its points
|
||||||
int ContactManifoldSet::getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const {
|
ContactManifold* ContactManifoldSet::getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const {
|
||||||
|
|
||||||
// The contact point will be in a new contact manifold, we now have too much
|
|
||||||
// manifolds condidates. We need to remove one. We choose to remove the manifold
|
|
||||||
// with the smallest contact depth among their points
|
|
||||||
int smallestDepthManifoldIndex = -1;
|
|
||||||
decimal minDepth = initDepth;
|
|
||||||
assert(mNbManifolds == mNbMaxManifolds);
|
assert(mNbManifolds == mNbMaxManifolds);
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
|
||||||
decimal depth = mManifolds[i]->getLargestContactDepth();
|
ContactManifold* minDepthManifold = nullptr;
|
||||||
|
decimal minDepth = initDepth;
|
||||||
|
ContactManifold* manifold = mManifolds;
|
||||||
|
while (manifold != nullptr) {
|
||||||
|
decimal depth = manifold->getLargestContactDepth();
|
||||||
if (depth < minDepth) {
|
if (depth < minDepth) {
|
||||||
minDepth = depth;
|
minDepth = depth;
|
||||||
smallestDepthManifoldIndex = i;
|
minDepthManifold = manifold;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return smallestDepthManifoldIndex;
|
manifold = manifold->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the index of the contact manifold with a similar average normal.
|
return minDepthManifold;
|
||||||
// If no manifold has close enough average normal, it returns -1
|
}
|
||||||
int ContactManifoldSet::selectManifoldWithSimilarNormal(short int normalDirectionId) const {
|
|
||||||
|
// Return the contact manifold with a similar average normal.
|
||||||
|
// If no manifold has close enough average normal, it returns nullptr
|
||||||
|
ContactManifold* ContactManifoldSet::selectManifoldWithSimilarNormal(short int normalDirectionId) const {
|
||||||
|
|
||||||
|
ContactManifold* manifold = mManifolds;
|
||||||
|
|
||||||
// Return the Id of the manifold with the same normal direction id (if exists)
|
// Return the Id of the manifold with the same normal direction id (if exists)
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
while (manifold != nullptr) {
|
||||||
if (normalDirectionId == mManifolds[i]->getNormalDirectionId()) {
|
if (normalDirectionId == manifold->getContactNormalId()) {
|
||||||
return i;
|
return manifold;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
manifold = manifold->getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the normal vector into a cubemap face bucket (a face contains 4x4 buckets)
|
// Map the normal vector into a cubemap face bucket (a face contains 4x4 buckets)
|
||||||
// Each face of the cube is divided into 4x4 buckets. This method maps the
|
// Each face of the cube is divided into 4x4 buckets. This method maps the
|
||||||
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
||||||
short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) const {
|
short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) {
|
||||||
|
|
||||||
assert(normal.lengthSquare() > MACHINE_EPSILON);
|
assert(normal.lengthSquare() > MACHINE_EPSILON);
|
||||||
|
|
||||||
|
@ -240,36 +206,100 @@ short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) cons
|
||||||
// Clear the contact manifold set
|
// Clear the contact manifold set
|
||||||
void ContactManifoldSet::clear() {
|
void ContactManifoldSet::clear() {
|
||||||
|
|
||||||
// Destroy all the contact manifolds
|
ContactManifold* manifold = mManifolds;
|
||||||
for (int i=mNbManifolds-1; i>=0; i--) {
|
while(manifold != nullptr) {
|
||||||
removeManifold(i);
|
|
||||||
|
ContactManifold* nextManifold = manifold->getNext();
|
||||||
|
|
||||||
|
// Delete the contact manifold
|
||||||
|
manifold->~ContactManifold();
|
||||||
|
mMemoryAllocator.release(manifold, sizeof(ContactManifold));
|
||||||
|
|
||||||
|
manifold = nextManifold;
|
||||||
|
|
||||||
|
mNbManifolds--;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(mNbManifolds == 0);
|
assert(mNbManifolds == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new contact manifold and add it to the set
|
// Create a new contact manifold and add it to the set
|
||||||
void ContactManifoldSet::createManifold(const ContactManifoldInfo& manifoldInfo, short int normalDirectionId) {
|
void ContactManifoldSet::createManifold(const ContactManifoldInfo* manifoldInfo) {
|
||||||
assert(mNbManifolds < mNbMaxManifolds);
|
assert(mNbManifolds < mNbMaxManifolds);
|
||||||
|
|
||||||
mManifolds[mNbManifolds] = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
|
ContactManifold* manifold = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
|
||||||
ContactManifold(manifoldInfo, mShape1, mShape2, mMemoryAllocator, normalDirectionId);
|
ContactManifold(manifoldInfo, mShape1, mShape2, mMemoryAllocator);
|
||||||
|
manifold->setPrevious(nullptr);
|
||||||
|
manifold->setNext(mManifolds);
|
||||||
|
mManifolds = manifold;
|
||||||
|
|
||||||
mNbManifolds++;
|
mNbManifolds++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a contact manifold from the set
|
// Remove a contact manifold from the set
|
||||||
void ContactManifoldSet::removeManifold(int index) {
|
void ContactManifoldSet::removeManifold(ContactManifold* manifold) {
|
||||||
|
|
||||||
assert(mNbManifolds > 0);
|
assert(mNbManifolds > 0);
|
||||||
assert(index >= 0 && index < mNbManifolds);
|
|
||||||
|
|
||||||
// Delete the new contact
|
ContactManifold* previous = manifold->getPrevious();
|
||||||
mManifolds[index]->~ContactManifold();
|
ContactManifold* next = manifold->getNext();
|
||||||
mMemoryAllocator.release(mManifolds[index], sizeof(ContactManifold));
|
|
||||||
|
|
||||||
for (int i=index; (i+1) < mNbManifolds; i++) {
|
if (previous != nullptr) {
|
||||||
mManifolds[i] = mManifolds[i+1];
|
previous->setNext(manifold->getNext());
|
||||||
}
|
}
|
||||||
|
if (next != nullptr) {
|
||||||
|
next->setPrevious(manifold->getPrevious());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the contact manifold
|
||||||
|
manifold->~ContactManifold();
|
||||||
|
mMemoryAllocator.release(manifold, sizeof(ContactManifold));
|
||||||
|
|
||||||
mNbManifolds--;
|
mNbManifolds--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make all the contact manifolds and contact points obselete
|
||||||
|
void ContactManifoldSet::makeContactsObselete() {
|
||||||
|
|
||||||
|
ContactManifold* manifold = mManifolds;
|
||||||
|
while (manifold != nullptr) {
|
||||||
|
|
||||||
|
manifold->setIsObselete(true, true);
|
||||||
|
|
||||||
|
manifold = manifold->getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the obselete contact manifolds and contact points
|
||||||
|
void ContactManifoldSet::clearObseleteManifoldsAndContactPoints() {
|
||||||
|
|
||||||
|
ContactManifold* manifold = mManifolds;
|
||||||
|
ContactManifold* previousManifold = nullptr;
|
||||||
|
while (manifold != nullptr) {
|
||||||
|
ContactManifold* nextManifold = manifold->getNext();
|
||||||
|
|
||||||
|
if (manifold->getIsObselete()) {
|
||||||
|
|
||||||
|
if (previousManifold != nullptr) {
|
||||||
|
previousManifold->setNext(nextManifold);
|
||||||
|
|
||||||
|
if (nextManifold != nullptr) {
|
||||||
|
nextManifold->setPrevious(previousManifold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mManifolds = nextManifold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the contact manifold
|
||||||
|
removeManifold(manifold);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
manifold->clearObseleteContactPoints();
|
||||||
|
previousManifold = manifold;
|
||||||
|
}
|
||||||
|
|
||||||
|
manifold = nextManifold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,33 +60,34 @@ class ContactManifoldSet {
|
||||||
/// Pointer to the second proxy shape of the contact
|
/// Pointer to the second proxy shape of the contact
|
||||||
ProxyShape* mShape2;
|
ProxyShape* mShape2;
|
||||||
|
|
||||||
/// Reference to the memory allocator
|
/// Reference to the memory allocator for the contact manifolds
|
||||||
PoolAllocator& mMemoryAllocator;
|
Allocator& mMemoryAllocator;
|
||||||
|
|
||||||
/// Contact manifolds of the set
|
/// Contact manifolds of the set
|
||||||
ContactManifold* mManifolds[MAX_MANIFOLDS_IN_CONTACT_MANIFOLD_SET];
|
ContactManifold* mManifolds;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Create a new contact manifold and add it to the set
|
/// Create a new contact manifold and add it to the set
|
||||||
void createManifold(const ContactManifoldInfo& manifoldInfo, short normalDirectionId);
|
void createManifold(const ContactManifoldInfo* manifoldInfo);
|
||||||
|
|
||||||
/// Remove a contact manifold from the set
|
// Return the contact manifold with a similar average normal.
|
||||||
void removeManifold(int index);
|
ContactManifold* selectManifoldWithSimilarNormal(short int normalDirectionId) const;
|
||||||
|
|
||||||
// Return the index of the contact manifold with a similar average normal.
|
|
||||||
int selectManifoldWithSimilarNormal(short int normalDirectionId) const;
|
|
||||||
|
|
||||||
// Map the normal vector into a cubemap face bucket (a face contains 4x4 buckets)
|
|
||||||
// Each face of the cube is divided into 4x4 buckets. This method maps the
|
|
||||||
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
|
||||||
short int computeCubemapNormalId(const Vector3& normal) const;
|
|
||||||
|
|
||||||
/// Return the manifold with the smallest contact penetration depth
|
/// Return the manifold with the smallest contact penetration depth
|
||||||
int getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const;
|
ContactManifold* getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const;
|
||||||
|
|
||||||
/// Update a previous similar manifold with a new one
|
/// Update a previous similar manifold with a new one
|
||||||
void updateManifoldWithNewOne(int oldManifoldIndex, const ContactManifoldInfo& newManifold);
|
void updateManifoldWithNewOne(ContactManifold* oldManifold, const ContactManifoldInfo* newManifold);
|
||||||
|
|
||||||
|
/// Return the maximum number of contact manifolds allowed between to collision shapes
|
||||||
|
int computeNbMaxContactManifolds(const CollisionShape* shape1, const CollisionShape* shape2);
|
||||||
|
|
||||||
|
/// Clear the contact manifold set
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// Delete a contact manifold
|
||||||
|
void removeManifold(ContactManifold* manifold);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -94,13 +95,13 @@ class ContactManifoldSet {
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
ContactManifoldSet(ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifoldSet(ProxyShape* shape1, ProxyShape* shape2,
|
||||||
PoolAllocator& memoryAllocator, int nbMaxManifolds);
|
Allocator& memoryAllocator);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ContactManifoldSet();
|
~ContactManifoldSet();
|
||||||
|
|
||||||
/// Add a contact manifold in the set
|
/// Add a contact manifold in the set
|
||||||
void addContactManifold(const ContactManifoldInfo& contactManifoldInfo);
|
void addContactManifold(const ContactManifoldInfo* contactManifoldInfo);
|
||||||
|
|
||||||
/// Return the first proxy shape
|
/// Return the first proxy shape
|
||||||
ProxyShape* getShape1() const;
|
ProxyShape* getShape1() const;
|
||||||
|
@ -108,17 +109,25 @@ class ContactManifoldSet {
|
||||||
/// Return the second proxy shape
|
/// Return the second proxy shape
|
||||||
ProxyShape* getShape2() const;
|
ProxyShape* getShape2() const;
|
||||||
|
|
||||||
/// Clear the contact manifold set
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/// Return the number of manifolds in the set
|
/// Return the number of manifolds in the set
|
||||||
int getNbContactManifolds() const;
|
int getNbContactManifolds() const;
|
||||||
|
|
||||||
/// Return a given contact manifold
|
/// Return a pointer to the first element of the linked-list of contact manifolds
|
||||||
ContactManifold* getContactManifold(int index) const;
|
ContactManifold* getContactManifolds() const;
|
||||||
|
|
||||||
|
/// Make all the contact manifolds and contact points obselete
|
||||||
|
void makeContactsObselete();
|
||||||
|
|
||||||
/// Return the total number of contact points in the set of manifolds
|
/// Return the total number of contact points in the set of manifolds
|
||||||
int getTotalNbContactPoints() const;
|
int getTotalNbContactPoints() const;
|
||||||
|
|
||||||
|
/// Clear the obselete contact manifolds and contact points
|
||||||
|
void clearObseleteManifoldsAndContactPoints();
|
||||||
|
|
||||||
|
// Map the normal vector into a cubemap face bucket (a face contains 4x4 buckets)
|
||||||
|
// Each face of the cube is divided into 4x4 buckets. This method maps the
|
||||||
|
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
||||||
|
static short int computeCubemapNormalId(const Vector3& normal);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the first proxy shape
|
// Return the first proxy shape
|
||||||
|
@ -136,21 +145,38 @@ inline int ContactManifoldSet::getNbContactManifolds() const {
|
||||||
return mNbManifolds;
|
return mNbManifolds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a given contact manifold
|
// Return a pointer to the first element of the linked-list of contact manifolds
|
||||||
inline ContactManifold* ContactManifoldSet::getContactManifold(int index) const {
|
inline ContactManifold* ContactManifoldSet::getContactManifolds() const {
|
||||||
assert(index >= 0 && index < mNbManifolds);
|
return mManifolds;
|
||||||
return mManifolds[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the total number of contact points in the set of manifolds
|
// Return the total number of contact points in the set of manifolds
|
||||||
inline int ContactManifoldSet::getTotalNbContactPoints() const {
|
inline int ContactManifoldSet::getTotalNbContactPoints() const {
|
||||||
int nbPoints = 0;
|
int nbPoints = 0;
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
|
||||||
nbPoints += mManifolds[i]->getNbContactPoints();
|
ContactManifold* manifold = mManifolds;
|
||||||
|
while (manifold != nullptr) {
|
||||||
|
nbPoints += manifold->getNbContactPoints();
|
||||||
|
|
||||||
|
manifold = manifold->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
return nbPoints;
|
return nbPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the maximum number of contact manifolds allowed between to collision shapes
|
||||||
|
inline int ContactManifoldSet::computeNbMaxContactManifolds(const CollisionShape* shape1, const CollisionShape* shape2) {
|
||||||
|
|
||||||
|
// If both shapes are convex
|
||||||
|
if (shape1->isConvex() && shape2->isConvex()) {
|
||||||
|
return NB_MAX_CONTACT_MANIFOLDS_CONVEX_SHAPE;
|
||||||
|
|
||||||
|
} // If there is at least one concave shape
|
||||||
|
else {
|
||||||
|
return NB_MAX_CONTACT_MANIFOLDS_CONCAVE_SHAPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
97
src/collision/NarrowPhaseInfo.cpp
Normal file
97
src/collision/NarrowPhaseInfo.cpp
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 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 <iostream>
|
||||||
|
#include "NarrowPhaseInfo.h"
|
||||||
|
#include "ContactPointInfo.h"
|
||||||
|
#include "engine/OverlappingPair.h"
|
||||||
|
|
||||||
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
NarrowPhaseInfo::NarrowPhaseInfo(OverlappingPair* pair, const CollisionShape* shape1,
|
||||||
|
const CollisionShape* shape2, const Transform& shape1Transform,
|
||||||
|
const Transform& shape2Transform, void** cachedData1, void** cachedData2)
|
||||||
|
: overlappingPair(pair), collisionShape1(shape1), collisionShape2(shape2),
|
||||||
|
shape1ToWorldTransform(shape1Transform), shape2ToWorldTransform(shape2Transform),
|
||||||
|
contactPoints(nullptr), cachedCollisionData1(cachedData1),
|
||||||
|
cachedCollisionData2(cachedData2), next(nullptr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
NarrowPhaseInfo::~NarrowPhaseInfo() {
|
||||||
|
|
||||||
|
assert(contactPoints == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new contact point
|
||||||
|
void NarrowPhaseInfo::addContactPoint(const Vector3& contactNormal, decimal penDepth,
|
||||||
|
const Vector3& localPt1, const Vector3& localPt2) {
|
||||||
|
|
||||||
|
assert(penDepth > decimal(0.0));
|
||||||
|
|
||||||
|
// Get the memory allocator
|
||||||
|
Allocator& allocator = overlappingPair->getTemporaryAllocator();
|
||||||
|
|
||||||
|
// Create the contact point info
|
||||||
|
ContactPointInfo* contactPointInfo = new (allocator.allocate(sizeof(ContactPointInfo)))
|
||||||
|
ContactPointInfo(contactNormal, penDepth, localPt1, localPt2);
|
||||||
|
|
||||||
|
// Add it into the linked list of contact points
|
||||||
|
contactPointInfo->next = contactPoints;
|
||||||
|
contactPoints = contactPointInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take all the generated contact points and create a new potential
|
||||||
|
/// contact manifold into the overlapping pair
|
||||||
|
void NarrowPhaseInfo::addContactPointsAsPotentialContactManifold() {
|
||||||
|
overlappingPair->addPotentialContactPoints(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the remaining contact points
|
||||||
|
void NarrowPhaseInfo::resetContactPoints() {
|
||||||
|
|
||||||
|
// Get the memory allocator
|
||||||
|
Allocator& allocator = overlappingPair->getTemporaryAllocator();
|
||||||
|
|
||||||
|
// For each remaining contact point info
|
||||||
|
ContactPointInfo* element = contactPoints;
|
||||||
|
while(element != nullptr) {
|
||||||
|
|
||||||
|
ContactPointInfo* elementToDelete = element;
|
||||||
|
|
||||||
|
element = element->next;
|
||||||
|
|
||||||
|
// Call the destructor
|
||||||
|
elementToDelete->~ContactPointInfo();
|
||||||
|
|
||||||
|
// Delete the current element
|
||||||
|
allocator.release(elementToDelete, sizeof(ContactPointInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
contactPoints = nullptr;
|
||||||
|
}
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "shapes/CollisionShape.h"
|
#include "shapes/CollisionShape.h"
|
||||||
|
#include "collision/ContactManifoldInfo.h"
|
||||||
|
|
||||||
/// Namespace ReactPhysics3D
|
/// Namespace ReactPhysics3D
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
@ -58,6 +59,9 @@ struct NarrowPhaseInfo {
|
||||||
/// Transform that maps from collision shape 2 local-space to world-space
|
/// Transform that maps from collision shape 2 local-space to world-space
|
||||||
Transform shape2ToWorldTransform;
|
Transform shape2ToWorldTransform;
|
||||||
|
|
||||||
|
/// Linked-list of contact points created during the narrow-phase
|
||||||
|
ContactPointInfo* contactPoints;
|
||||||
|
|
||||||
/// Cached collision data of the proxy shape
|
/// Cached collision data of the proxy shape
|
||||||
// TODO : Check if we can use separating axis in OverlappingPair instead of cachedCollisionData1 and cachedCollisionData2
|
// TODO : Check if we can use separating axis in OverlappingPair instead of cachedCollisionData1 and cachedCollisionData2
|
||||||
void** cachedCollisionData1;
|
void** cachedCollisionData1;
|
||||||
|
@ -72,12 +76,20 @@ struct NarrowPhaseInfo {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
NarrowPhaseInfo(OverlappingPair* pair, const CollisionShape* shape1,
|
NarrowPhaseInfo(OverlappingPair* pair, const CollisionShape* shape1,
|
||||||
const CollisionShape* shape2, const Transform& shape1Transform,
|
const CollisionShape* shape2, const Transform& shape1Transform,
|
||||||
const Transform& shape2Transform, void** cachedData1, void** cachedData2)
|
const Transform& shape2Transform, void** cachedData1, void** cachedData2);
|
||||||
: overlappingPair(pair), collisionShape1(shape1), collisionShape2(shape2),
|
|
||||||
shape1ToWorldTransform(shape1Transform), shape2ToWorldTransform(shape2Transform),
|
|
||||||
cachedCollisionData1(cachedData1), cachedCollisionData2(cachedData2), next(nullptr) {
|
|
||||||
|
|
||||||
}
|
/// Destructor
|
||||||
|
~NarrowPhaseInfo();
|
||||||
|
|
||||||
|
/// Add a new contact point
|
||||||
|
void addContactPoint(const Vector3& contactNormal, decimal penDepth,
|
||||||
|
const Vector3& localPt1, const Vector3& localPt2);
|
||||||
|
|
||||||
|
/// Create a new potential contact manifold into the overlapping pair using current contact points
|
||||||
|
void addContactPointsAsPotentialContactManifold();
|
||||||
|
|
||||||
|
/// Reset the remaining contact points
|
||||||
|
void resetContactPoints();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
57
src/collision/OverlapCallback.h
Normal file
57
src/collision/OverlapCallback.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 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_OVERLAP_CALLBACK_H
|
||||||
|
#define REACTPHYSICS3D_OVERLAP_CALLBACK_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "body/CollisionBody.h"
|
||||||
|
|
||||||
|
/// ReactPhysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Class OverlapCallback
|
||||||
|
/**
|
||||||
|
* This class can be used to register a callback for collision overlap queries.
|
||||||
|
* You should implement your own class inherited from this one and implement
|
||||||
|
* the notifyOverlap() method. This method will called each time a contact
|
||||||
|
* point is reported.
|
||||||
|
*/
|
||||||
|
class OverlapCallback {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
virtual ~OverlapCallback() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method will be called for each reported overlapping bodies
|
||||||
|
virtual void notifyOverlap(CollisionBody* collisionBody)=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -33,7 +33,7 @@ using namespace reactphysics3d;
|
||||||
// Compute the narrow-phase collision detection between two capsules
|
// Compute the narrow-phase collision detection between two capsules
|
||||||
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
||||||
// by Dirk Gregorius.
|
// by Dirk Gregorius.
|
||||||
bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) {
|
bool CapsuleVsCapsuleAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
|
|
||||||
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CAPSULE);
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CAPSULE);
|
||||||
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CAPSULE);
|
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CAPSULE);
|
||||||
|
@ -116,8 +116,8 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
decimal penetrationDepth = sumRadius - segmentsDistance;
|
decimal penetrationDepth = sumRadius - segmentsDistance;
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointACapsule1Local, contactPointACapsule2Local);
|
narrowPhaseInfo->addContactPoint(normalWorld, penetrationDepth, contactPointACapsule1Local, contactPointACapsule2Local);
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointBCapsule1Local, contactPointBCapsule2Local);
|
narrowPhaseInfo->addContactPoint(normalWorld, penetrationDepth, contactPointBCapsule1Local, contactPointBCapsule2Local);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
decimal penetrationDepth = sumRadius - closestPointsDistance;
|
decimal penetrationDepth = sumRadius - closestPointsDistance;
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointCapsule1Local, contactPointCapsule2Local);
|
narrowPhaseInfo->addContactPoint(normalWorld, penetrationDepth, contactPointCapsule1Local, contactPointCapsule2Local);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,7 @@ class CapsuleVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
CapsuleVsCapsuleAlgorithm& operator=(const CapsuleVsCapsuleAlgorithm& algorithm) = delete;
|
CapsuleVsCapsuleAlgorithm& operator=(const CapsuleVsCapsuleAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute the narrow-phase collision detection between two capsules
|
/// Compute the narrow-phase collision detection between two capsules
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,12 @@ using namespace reactphysics3d;
|
||||||
// Compute the narrow-phase collision detection between a capsule and a polyhedron
|
// Compute the narrow-phase collision detection between a capsule and a polyhedron
|
||||||
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
||||||
// by Dirk Gregorius.
|
// by Dirk Gregorius.
|
||||||
bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
ContactManifoldInfo& contactManifoldInfo) {
|
|
||||||
|
|
||||||
// First, we run the GJK algorithm
|
// First, we run the GJK algorithm
|
||||||
GJKAlgorithm gjkAlgorithm;
|
GJKAlgorithm gjkAlgorithm;
|
||||||
SATAlgorithm satAlgorithm;
|
SATAlgorithm satAlgorithm;
|
||||||
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, contactManifoldInfo);
|
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, reportContacts);
|
||||||
|
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = true;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = true;
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = false;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = false;
|
||||||
|
@ -61,7 +60,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* na
|
||||||
// two contact points instead of a single one (as in the deep contact case with SAT algorithm)
|
// two contact points instead of a single one (as in the deep contact case with SAT algorithm)
|
||||||
|
|
||||||
// Get the contact point created by GJK
|
// Get the contact point created by GJK
|
||||||
ContactPointInfo* contactPoint = contactManifoldInfo.getFirstContactPointInfo();
|
ContactPointInfo* contactPoint = narrowPhaseInfo->contactPoints;
|
||||||
assert(contactPoint != nullptr);
|
assert(contactPoint != nullptr);
|
||||||
|
|
||||||
bool isCapsuleShape1 = narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CAPSULE;
|
bool isCapsuleShape1 = narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CAPSULE;
|
||||||
|
@ -96,7 +95,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* na
|
||||||
&& areParallelVectors(faceNormalWorld, contactPoint->normal)) {
|
&& areParallelVectors(faceNormalWorld, contactPoint->normal)) {
|
||||||
|
|
||||||
// Remove the previous contact point computed by GJK
|
// Remove the previous contact point computed by GJK
|
||||||
contactManifoldInfo.reset();
|
narrowPhaseInfo->resetContactPoints();
|
||||||
|
|
||||||
const Transform capsuleToWorld = isCapsuleShape1 ? narrowPhaseInfo->shape1ToWorldTransform : narrowPhaseInfo->shape2ToWorldTransform;
|
const Transform capsuleToWorld = isCapsuleShape1 ? narrowPhaseInfo->shape1ToWorldTransform : narrowPhaseInfo->shape2ToWorldTransform;
|
||||||
const Transform polyhedronToCapsuleTransform = capsuleToWorld.getInverse() * polyhedronToWorld;
|
const Transform polyhedronToCapsuleTransform = capsuleToWorld.getInverse() * polyhedronToWorld;
|
||||||
|
@ -116,7 +115,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* na
|
||||||
satAlgorithm.computeCapsulePolyhedronFaceContactPoints(f, capsuleShape->getRadius(), polyhedron, contactPoint->penetrationDepth,
|
satAlgorithm.computeCapsulePolyhedronFaceContactPoints(f, capsuleShape->getRadius(), polyhedron, contactPoint->penetrationDepth,
|
||||||
polyhedronToCapsuleTransform, faceNormalWorld, separatingAxisCapsuleSpace,
|
polyhedronToCapsuleTransform, faceNormalWorld, separatingAxisCapsuleSpace,
|
||||||
capsuleSegAPolyhedronSpace, capsuleSegBPolyhedronSpace,
|
capsuleSegAPolyhedronSpace, capsuleSegBPolyhedronSpace,
|
||||||
contactManifoldInfo, isCapsuleShape1);
|
narrowPhaseInfo, isCapsuleShape1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +132,7 @@ bool CapsuleVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* na
|
||||||
if (result == GJKAlgorithm::GJKResult::INTERPENETRATE) {
|
if (result == GJKAlgorithm::GJKResult::INTERPENETRATE) {
|
||||||
|
|
||||||
// Run the SAT algorithm to find the separating axis and compute contact point
|
// Run the SAT algorithm to find the separating axis and compute contact point
|
||||||
bool isColliding = satAlgorithm.testCollisionCapsuleVsConvexPolyhedron(narrowPhaseInfo, contactManifoldInfo);
|
bool isColliding = satAlgorithm.testCollisionCapsuleVsConvexPolyhedron(narrowPhaseInfo, reportContacts);
|
||||||
|
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
||||||
|
|
|
@ -61,8 +61,7 @@ class CapsuleVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
CapsuleVsConvexPolyhedronAlgorithm& operator=(const CapsuleVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
CapsuleVsConvexPolyhedronAlgorithm& operator=(const CapsuleVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute the narrow-phase collision detection between a capsule and a polyhedron
|
/// Compute the narrow-phase collision detection between a capsule and a polyhedron
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,114 +141,114 @@ void ConcaveVsConvexAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseI
|
||||||
// Process the concave triangle mesh collision using the smooth mesh collision algorithm described
|
// Process the concave triangle mesh collision using the smooth mesh collision algorithm described
|
||||||
// by Pierre Terdiman (http://www.codercorner.com/MeshContacts.pdf). This is used to avoid the collision
|
// by Pierre Terdiman (http://www.codercorner.com/MeshContacts.pdf). This is used to avoid the collision
|
||||||
// issue with some internal edges.
|
// issue with some internal edges.
|
||||||
void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overlappingPair,
|
//void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overlappingPair,
|
||||||
std::vector<SmoothMeshContactInfo> contactPoints,
|
// std::vector<SmoothMeshContactInfo> contactPoints,
|
||||||
NarrowPhaseCallback* narrowPhaseCallback) {
|
// NarrowPhaseCallback* narrowPhaseCallback) {
|
||||||
|
|
||||||
// Set with the triangle vertices already processed to void further contacts with same triangle
|
// // Set with the triangle vertices already processed to void further contacts with same triangle
|
||||||
std::unordered_multimap<int, Vector3> processTriangleVertices;
|
// std::unordered_multimap<int, Vector3> processTriangleVertices;
|
||||||
|
|
||||||
// Sort the list of narrow-phase contacts according to their penetration depth
|
// // Sort the list of narrow-phase contacts according to their penetration depth
|
||||||
std::sort(contactPoints.begin(), contactPoints.end(), ContactsDepthCompare());
|
// std::sort(contactPoints.begin(), contactPoints.end(), ContactsDepthCompare());
|
||||||
|
|
||||||
// For each contact point (from smaller penetration depth to larger)
|
// // For each contact point (from smaller penetration depth to larger)
|
||||||
std::vector<SmoothMeshContactInfo>::const_iterator it;
|
// std::vector<SmoothMeshContactInfo>::const_iterator it;
|
||||||
for (it = contactPoints.begin(); it != contactPoints.end(); ++it) {
|
// for (it = contactPoints.begin(); it != contactPoints.end(); ++it) {
|
||||||
|
|
||||||
const SmoothMeshContactInfo info = *it;
|
// const SmoothMeshContactInfo info = *it;
|
||||||
const Vector3& contactPoint = info.isFirstShapeTriangle ? info.contactInfo.localPoint1 : info.contactInfo.localPoint2;
|
// const Vector3& contactPoint = info.isFirstShapeTriangle ? info.contactInfo.localPoint1 : info.contactInfo.localPoint2;
|
||||||
|
|
||||||
// Compute the barycentric coordinates of the point in the triangle
|
// // Compute the barycentric coordinates of the point in the triangle
|
||||||
decimal u, v, w;
|
// decimal u, v, w;
|
||||||
computeBarycentricCoordinatesInTriangle(info.triangleVertices[0],
|
// computeBarycentricCoordinatesInTriangle(info.triangleVertices[0],
|
||||||
info.triangleVertices[1],
|
// info.triangleVertices[1],
|
||||||
info.triangleVertices[2],
|
// info.triangleVertices[2],
|
||||||
contactPoint, u, v, w);
|
// contactPoint, u, v, w);
|
||||||
int nbZeros = 0;
|
// int nbZeros = 0;
|
||||||
bool isUZero = approxEqual(u, 0, 0.0001);
|
// bool isUZero = approxEqual(u, 0, 0.0001);
|
||||||
bool isVZero = approxEqual(v, 0, 0.0001);
|
// bool isVZero = approxEqual(v, 0, 0.0001);
|
||||||
bool isWZero = approxEqual(w, 0, 0.0001);
|
// bool isWZero = approxEqual(w, 0, 0.0001);
|
||||||
if (isUZero) nbZeros++;
|
// if (isUZero) nbZeros++;
|
||||||
if (isVZero) nbZeros++;
|
// if (isVZero) nbZeros++;
|
||||||
if (isWZero) nbZeros++;
|
// if (isWZero) nbZeros++;
|
||||||
|
|
||||||
// If it is a vertex contact
|
// // If it is a vertex contact
|
||||||
if (nbZeros == 2) {
|
// if (nbZeros == 2) {
|
||||||
|
|
||||||
Vector3 contactVertex = !isUZero ? info.triangleVertices[0] : (!isVZero ? info.triangleVertices[1] : info.triangleVertices[2]);
|
// Vector3 contactVertex = !isUZero ? info.triangleVertices[0] : (!isVZero ? info.triangleVertices[1] : info.triangleVertices[2]);
|
||||||
|
|
||||||
// Check that this triangle vertex has not been processed yet
|
// // Check that this triangle vertex has not been processed yet
|
||||||
if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex)) {
|
// if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex)) {
|
||||||
|
|
||||||
// Keep the contact as it is and report it
|
// // Keep the contact as it is and report it
|
||||||
narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
// narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else if (nbZeros == 1) { // If it is an edge contact
|
// else if (nbZeros == 1) { // If it is an edge contact
|
||||||
|
|
||||||
Vector3 contactVertex1 = isUZero ? info.triangleVertices[1] : (isVZero ? info.triangleVertices[0] : info.triangleVertices[0]);
|
// Vector3 contactVertex1 = isUZero ? info.triangleVertices[1] : (isVZero ? info.triangleVertices[0] : info.triangleVertices[0]);
|
||||||
Vector3 contactVertex2 = isUZero ? info.triangleVertices[2] : (isVZero ? info.triangleVertices[2] : info.triangleVertices[1]);
|
// Vector3 contactVertex2 = isUZero ? info.triangleVertices[2] : (isVZero ? info.triangleVertices[2] : info.triangleVertices[1]);
|
||||||
|
|
||||||
// Check that this triangle edge has not been processed yet
|
// // Check that this triangle edge has not been processed yet
|
||||||
if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex1) &&
|
// if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex1) &&
|
||||||
!hasVertexBeenProcessed(processTriangleVertices, contactVertex2)) {
|
// !hasVertexBeenProcessed(processTriangleVertices, contactVertex2)) {
|
||||||
|
|
||||||
// Keep the contact as it is and report it
|
// // Keep the contact as it is and report it
|
||||||
narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
// narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
else { // If it is a face contact
|
// else { // If it is a face contact
|
||||||
|
|
||||||
ContactPointInfo newContactInfo(info.contactInfo);
|
// ContactPointInfo newContactInfo(info.contactInfo);
|
||||||
|
|
||||||
ProxyShape* firstShape;
|
// ProxyShape* firstShape;
|
||||||
ProxyShape* secondShape;
|
// ProxyShape* secondShape;
|
||||||
if (info.isFirstShapeTriangle) {
|
// if (info.isFirstShapeTriangle) {
|
||||||
firstShape = overlappingPair->getShape1();
|
// firstShape = overlappingPair->getShape1();
|
||||||
secondShape = overlappingPair->getShape2();
|
// secondShape = overlappingPair->getShape2();
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
firstShape = overlappingPair->getShape2();
|
// firstShape = overlappingPair->getShape2();
|
||||||
secondShape = overlappingPair->getShape1();
|
// secondShape = overlappingPair->getShape1();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// We use the triangle normal as the contact normal
|
// // We use the triangle normal as the contact normal
|
||||||
Vector3 a = info.triangleVertices[1] - info.triangleVertices[0];
|
// Vector3 a = info.triangleVertices[1] - info.triangleVertices[0];
|
||||||
Vector3 b = info.triangleVertices[2] - info.triangleVertices[0];
|
// Vector3 b = info.triangleVertices[2] - info.triangleVertices[0];
|
||||||
Vector3 localNormal = a.cross(b);
|
// Vector3 localNormal = a.cross(b);
|
||||||
newContactInfo.normal = firstShape->getLocalToWorldTransform().getOrientation() * localNormal;
|
// newContactInfo.normal = firstShape->getLocalToWorldTransform().getOrientation() * localNormal;
|
||||||
Vector3 firstLocalPoint = info.isFirstShapeTriangle ? info.contactInfo.localPoint1 : info.contactInfo.localPoint2;
|
// Vector3 firstLocalPoint = info.isFirstShapeTriangle ? info.contactInfo.localPoint1 : info.contactInfo.localPoint2;
|
||||||
Vector3 firstWorldPoint = firstShape->getLocalToWorldTransform() * firstLocalPoint;
|
// Vector3 firstWorldPoint = firstShape->getLocalToWorldTransform() * firstLocalPoint;
|
||||||
newContactInfo.normal.normalize();
|
// newContactInfo.normal.normalize();
|
||||||
if (newContactInfo.normal.dot(info.contactInfo.normal) < 0) {
|
// if (newContactInfo.normal.dot(info.contactInfo.normal) < 0) {
|
||||||
newContactInfo.normal = -newContactInfo.normal;
|
// newContactInfo.normal = -newContactInfo.normal;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// We recompute the contact point on the second body with the new normal as described in
|
// // We recompute the contact point on the second body with the new normal as described in
|
||||||
// the Smooth Mesh Contacts with GJK of the Game Physics Pearls book (from Gino van Den Bergen and
|
// // the Smooth Mesh Contacts with GJK of the Game Physics Pearls book (from Gino van Den Bergen and
|
||||||
// Dirk Gregorius) to avoid adding torque
|
// // Dirk Gregorius) to avoid adding torque
|
||||||
Transform worldToLocalSecondPoint = secondShape->getLocalToWorldTransform().getInverse();
|
// Transform worldToLocalSecondPoint = secondShape->getLocalToWorldTransform().getInverse();
|
||||||
if (info.isFirstShapeTriangle) {
|
// if (info.isFirstShapeTriangle) {
|
||||||
Vector3 newSecondWorldPoint = firstWorldPoint + newContactInfo.normal;
|
// Vector3 newSecondWorldPoint = firstWorldPoint + newContactInfo.normal;
|
||||||
newContactInfo.localPoint2 = worldToLocalSecondPoint * newSecondWorldPoint;
|
// newContactInfo.localPoint2 = worldToLocalSecondPoint * newSecondWorldPoint;
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
Vector3 newSecondWorldPoint = firstWorldPoint - newContactInfo.normal;
|
// Vector3 newSecondWorldPoint = firstWorldPoint - newContactInfo.normal;
|
||||||
newContactInfo.localPoint1 = worldToLocalSecondPoint * newSecondWorldPoint;
|
// newContactInfo.localPoint1 = worldToLocalSecondPoint * newSecondWorldPoint;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Report the contact
|
// // Report the contact
|
||||||
narrowPhaseCallback->notifyContact(overlappingPair, newContactInfo);
|
// narrowPhaseCallback->notifyContact(overlappingPair, newContactInfo);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add the three vertices of the triangle to the set of processed
|
// // Add the three vertices of the triangle to the set of processed
|
||||||
// triangle vertices
|
// // triangle vertices
|
||||||
addProcessedVertex(processTriangleVertices, info.triangleVertices[0]);
|
// addProcessedVertex(processTriangleVertices, info.triangleVertices[0]);
|
||||||
addProcessedVertex(processTriangleVertices, info.triangleVertices[1]);
|
// addProcessedVertex(processTriangleVertices, info.triangleVertices[1]);
|
||||||
addProcessedVertex(processTriangleVertices, info.triangleVertices[2]);
|
// addProcessedVertex(processTriangleVertices, info.triangleVertices[2]);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Return true if the vertex is in the set of already processed vertices
|
// Return true if the vertex is in the set of already processed vertices
|
||||||
bool ConcaveVsConvexAlgorithm::hasVertexBeenProcessed(const std::unordered_multimap<int, Vector3>& processTriangleVertices, const Vector3& vertex) const {
|
bool ConcaveVsConvexAlgorithm::hasVertexBeenProcessed(const std::unordered_multimap<int, Vector3>& processTriangleVertices, const Vector3& vertex) const {
|
||||||
|
|
|
@ -83,25 +83,35 @@ class MiddlePhaseTriangleCallback : public TriangleCallback {
|
||||||
|
|
||||||
// Class SmoothMeshContactInfo
|
// Class SmoothMeshContactInfo
|
||||||
/**
|
/**
|
||||||
* This class is used to store data about a contact with a triangle for the smooth
|
* Contains data for of potential smooth contact during the smooth mesh
|
||||||
* mesh algorithm.
|
* contacts computation.
|
||||||
*/
|
*/
|
||||||
class SmoothMeshContactInfo {
|
struct SmoothMeshContactInfo {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ContactPointInfo contactInfo;
|
ContactManifoldInfo* contactManifoldInfo;
|
||||||
|
ContactPointInfo* contactInfo;
|
||||||
bool isFirstShapeTriangle;
|
bool isFirstShapeTriangle;
|
||||||
Vector3 triangleVertices[3];
|
Vector3 triangleVertices[3];
|
||||||
|
bool isUVWZero[3];
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
SmoothMeshContactInfo(const ContactPointInfo& contact, bool firstShapeTriangle, const Vector3& trianglePoint1,
|
SmoothMeshContactInfo(ContactManifoldInfo* manifoldInfo, ContactPointInfo* contactPointInfo,
|
||||||
const Vector3& trianglePoint2, const Vector3& trianglePoint3)
|
bool firstShapeTriangle,
|
||||||
: contactInfo(contact) {
|
const Vector3& trianglePoint1, const Vector3& trianglePoint2,
|
||||||
|
const Vector3& trianglePoint3, bool isUZero, bool isVZero, bool isWZero)
|
||||||
|
: contactManifoldInfo(manifoldInfo), contactInfo(contactPointInfo) {
|
||||||
|
|
||||||
isFirstShapeTriangle = firstShapeTriangle;
|
isFirstShapeTriangle = firstShapeTriangle;
|
||||||
|
|
||||||
triangleVertices[0] = trianglePoint1;
|
triangleVertices[0] = trianglePoint1;
|
||||||
triangleVertices[1] = trianglePoint2;
|
triangleVertices[1] = trianglePoint2;
|
||||||
triangleVertices[2] = trianglePoint3;
|
triangleVertices[2] = trianglePoint3;
|
||||||
|
|
||||||
|
isUVWZero[0] = isUZero;
|
||||||
|
isUVWZero[1] = isVZero;
|
||||||
|
isUVWZero[2] = isWZero;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -109,7 +119,7 @@ class SmoothMeshContactInfo {
|
||||||
struct ContactsDepthCompare {
|
struct ContactsDepthCompare {
|
||||||
bool operator()(const SmoothMeshContactInfo& contact1, const SmoothMeshContactInfo& contact2)
|
bool operator()(const SmoothMeshContactInfo& contact1, const SmoothMeshContactInfo& contact2)
|
||||||
{
|
{
|
||||||
return contact1.contactInfo.penetrationDepth < contact2.contactInfo.penetrationDepth;
|
return contact1.contactInfo->penetrationDepth < contact2.contactInfo->penetrationDepth;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,11 @@ using namespace reactphysics3d;
|
||||||
// Compute the narrow-phase collision detection between two convex polyhedra
|
// Compute the narrow-phase collision detection between two convex polyhedra
|
||||||
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
||||||
// by Dirk Gregorius.
|
// by Dirk Gregorius.
|
||||||
bool ConvexPolyhedronVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool ConvexPolyhedronVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
ContactManifoldInfo& contactManifoldInfo) {
|
|
||||||
|
|
||||||
// Run the SAT algorithm to find the separating axis and compute contact point
|
// Run the SAT algorithm to find the separating axis and compute contact point
|
||||||
SATAlgorithm satAlgorithm;
|
SATAlgorithm satAlgorithm;
|
||||||
bool isColliding = satAlgorithm.testCollisionConvexPolyhedronVsConvexPolyhedron(narrowPhaseInfo, contactManifoldInfo);
|
bool isColliding = satAlgorithm.testCollisionConvexPolyhedronVsConvexPolyhedron(narrowPhaseInfo, reportContacts);
|
||||||
|
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
||||||
|
|
|
@ -61,8 +61,7 @@ class ConvexPolyhedronVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm
|
||||||
ConvexPolyhedronVsConvexPolyhedronAlgorithm& operator=(const ConvexPolyhedronVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
ConvexPolyhedronVsConvexPolyhedronAlgorithm& operator=(const ConvexPolyhedronVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute the narrow-phase collision detection between two convex polyhedra
|
/// Compute the narrow-phase collision detection between two convex polyhedra
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,7 @@ using namespace reactphysics3d;
|
||||||
/// algorithm on the enlarged object to obtain a simplex polytope that contains the
|
/// algorithm on the enlarged object to obtain a simplex polytope that contains the
|
||||||
/// origin, they we give that simplex polytope to the EPA algorithm which will compute
|
/// origin, they we give that simplex polytope to the EPA algorithm which will compute
|
||||||
/// the correct penetration depth and contact points between the enlarged objects.
|
/// the correct penetration depth and contact points between the enlarged objects.
|
||||||
GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
ContactManifoldInfo& contactManifoldInfo) {
|
|
||||||
|
|
||||||
PROFILE("GJKAlgorithm::testCollision()");
|
PROFILE("GJKAlgorithm::testCollision()");
|
||||||
|
|
||||||
|
@ -209,7 +208,7 @@ GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(const NarrowPhaseInfo* narro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a new contact point
|
// Add a new contact point
|
||||||
contactManifoldInfo.addContactPoint(normal, penetrationDepth, pA, pB);
|
narrowPhaseInfo->addContactPoint(normal, penetrationDepth, pA, pB);
|
||||||
|
|
||||||
return GJKResult::COLLIDE_IN_MARGIN;
|
return GJKResult::COLLIDE_IN_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,16 +87,13 @@ class GJKAlgorithm {
|
||||||
GJKAlgorithm& operator=(const GJKAlgorithm& algorithm) = delete;
|
GJKAlgorithm& operator=(const GJKAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volumes collide.
|
/// Compute a contact info if the two bounding volumes collide.
|
||||||
GJKResult testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
GJKResult testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts);
|
||||||
ContactManifoldInfo& contactManifoldInfo);
|
|
||||||
|
|
||||||
/// Use the GJK Algorithm to find if a point is inside a convex collision shape
|
/// Use the GJK Algorithm to find if a point is inside a convex collision shape
|
||||||
bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape);
|
bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape);
|
||||||
|
|
||||||
/// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
/// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
||||||
bool raycast(const Ray& ray, ProxyShape* proxyShape, RaycastInfo& raycastInfo);
|
bool raycast(const Ray& ray, ProxyShape* proxyShape, RaycastInfo& raycastInfo);
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,8 +83,10 @@ class NarrowPhaseAlgorithm {
|
||||||
/// Deleted assignment operator
|
/// Deleted assignment operator
|
||||||
NarrowPhaseAlgorithm& operator=(const NarrowPhaseAlgorithm& algorithm) = delete;
|
NarrowPhaseAlgorithm& operator=(const NarrowPhaseAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
|
// TODO : Use the following reportContacts variable in all narrow-phase algorithms
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo)=0;
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ using namespace reactphysics3d;
|
||||||
const decimal SATAlgorithm::SAME_SEPARATING_AXIS_BIAS = decimal(0.001);
|
const decimal SATAlgorithm::SAME_SEPARATING_AXIS_BIAS = decimal(0.001);
|
||||||
|
|
||||||
// Test collision between a sphere and a convex mesh
|
// Test collision between a sphere and a convex mesh
|
||||||
bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) const {
|
bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) const {
|
||||||
|
|
||||||
PROFILE("SATAlgorithm::testCollisionSphereVsConvexPolyhedron()");
|
PROFILE("SATAlgorithm::testCollisionSphereVsConvexPolyhedron()");
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(const NarrowPhaseInfo*
|
||||||
const Vector3 contactPointPolyhedronLocal = sphereCenter + minFaceNormal * (minPenetrationDepth - sphere->getRadius());
|
const Vector3 contactPointPolyhedronLocal = sphereCenter + minFaceNormal * (minPenetrationDepth - sphere->getRadius());
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactManifoldInfo.addContactPoint(isSphereShape1 ? normalWorld : -normalWorld, minPenetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
||||||
isSphereShape1 ? contactPointSphereLocal : contactPointPolyhedronLocal,
|
isSphereShape1 ? contactPointSphereLocal : contactPointPolyhedronLocal,
|
||||||
isSphereShape1 ? contactPointPolyhedronLocal : contactPointSphereLocal);
|
isSphereShape1 ? contactPointPolyhedronLocal : contactPointSphereLocal);
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ decimal SATAlgorithm::computePolyhedronFaceVsSpherePenetrationDepth(uint faceInd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test collision between a capsule and a convex mesh
|
// Test collision between a capsule and a convex mesh
|
||||||
bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) const {
|
bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) const {
|
||||||
|
|
||||||
PROFILE("SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron()");
|
PROFILE("SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron()");
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(const NarrowPhaseInfo*
|
||||||
computeCapsulePolyhedronFaceContactPoints(minFaceIndex, capsuleRadius, polyhedron, minPenetrationDepth,
|
computeCapsulePolyhedronFaceContactPoints(minFaceIndex, capsuleRadius, polyhedron, minPenetrationDepth,
|
||||||
polyhedronToCapsuleTransform, normalWorld, separatingAxisCapsuleSpace,
|
polyhedronToCapsuleTransform, normalWorld, separatingAxisCapsuleSpace,
|
||||||
capsuleSegAPolyhedronSpace, capsuleSegBPolyhedronSpace,
|
capsuleSegAPolyhedronSpace, capsuleSegBPolyhedronSpace,
|
||||||
contactManifoldInfo, isCapsuleShape1);
|
narrowPhaseInfo, isCapsuleShape1);
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = true;
|
lastFrameInfo.satIsAxisFacePolyhedron1 = true;
|
||||||
lastFrameInfo.satMinAxisFaceIndex = minFaceIndex;
|
lastFrameInfo.satMinAxisFaceIndex = minFaceIndex;
|
||||||
|
@ -406,7 +406,7 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(const NarrowPhaseInfo*
|
||||||
const Vector3 contactPointCapsule = (polyhedronToCapsuleTransform * closestPointCapsuleInnerSegment) - separatingAxisCapsuleSpace * capsuleRadius;
|
const Vector3 contactPointCapsule = (polyhedronToCapsuleTransform * closestPointCapsuleInnerSegment) - separatingAxisCapsuleSpace * capsuleRadius;
|
||||||
|
|
||||||
// Create the contact point
|
// Create the contact point
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, minPenetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
||||||
isCapsuleShape1 ? contactPointCapsule : closestPointPolyhedronEdge,
|
isCapsuleShape1 ? contactPointCapsule : closestPointPolyhedronEdge,
|
||||||
isCapsuleShape1 ? closestPointPolyhedronEdge : contactPointCapsule);
|
isCapsuleShape1 ? closestPointPolyhedronEdge : contactPointCapsule);
|
||||||
|
|
||||||
|
@ -477,7 +477,7 @@ void SATAlgorithm::computeCapsulePolyhedronFaceContactPoints(uint referenceFaceI
|
||||||
decimal penetrationDepth, const Transform& polyhedronToCapsuleTransform,
|
decimal penetrationDepth, const Transform& polyhedronToCapsuleTransform,
|
||||||
const Vector3& normalWorld, const Vector3& separatingAxisCapsuleSpace,
|
const Vector3& normalWorld, const Vector3& separatingAxisCapsuleSpace,
|
||||||
const Vector3& capsuleSegAPolyhedronSpace, const Vector3& capsuleSegBPolyhedronSpace,
|
const Vector3& capsuleSegAPolyhedronSpace, const Vector3& capsuleSegBPolyhedronSpace,
|
||||||
ContactManifoldInfo& contactManifoldInfo, bool isCapsuleShape1) const {
|
NarrowPhaseInfo* narrowPhaseInfo, bool isCapsuleShape1) const {
|
||||||
|
|
||||||
HalfEdgeStructure::Face face = polyhedron->getFace(referenceFaceIndex);
|
HalfEdgeStructure::Face face = polyhedron->getFace(referenceFaceIndex);
|
||||||
uint firstEdgeIndex = face.edgeIndex;
|
uint firstEdgeIndex = face.edgeIndex;
|
||||||
|
@ -523,7 +523,7 @@ void SATAlgorithm::computeCapsulePolyhedronFaceContactPoints(uint referenceFaceI
|
||||||
const Vector3 contactPointCapsule = (polyhedronToCapsuleTransform * clipSegment[i]) - separatingAxisCapsuleSpace * capsuleRadius;
|
const Vector3 contactPointCapsule = (polyhedronToCapsuleTransform * clipSegment[i]) - separatingAxisCapsuleSpace * capsuleRadius;
|
||||||
|
|
||||||
// Create the contact point
|
// Create the contact point
|
||||||
contactManifoldInfo.addContactPoint(isCapsuleShape1 ? -normalWorld : normalWorld, penetrationDepth,
|
narrowPhaseInfo->addContactPoint(isCapsuleShape1 ? -normalWorld : normalWorld, penetrationDepth,
|
||||||
isCapsuleShape1 ? contactPointCapsule : contactPointPolyhedron,
|
isCapsuleShape1 ? contactPointCapsule : contactPointPolyhedron,
|
||||||
isCapsuleShape1 ? contactPointPolyhedron : contactPointCapsule);
|
isCapsuleShape1 ? contactPointPolyhedron : contactPointCapsule);
|
||||||
}
|
}
|
||||||
|
@ -543,8 +543,8 @@ bool SATAlgorithm::isMinkowskiFaceCapsuleVsEdge(const Vector3& capsuleSegment, c
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test collision between two convex polyhedrons
|
// Test collision between two convex polyhedrons
|
||||||
bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactManifoldInfo& contactManifoldInfo) const {
|
bool reportContacts) const {
|
||||||
|
|
||||||
PROFILE("SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron()");
|
PROFILE("SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron()");
|
||||||
|
|
||||||
|
@ -869,7 +869,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(const NarrowP
|
||||||
Vector3 contactPointReferencePolyhedron = projectPointOntoPlane(*itPoints, axisReferenceSpace, referenceFaceVertex);
|
Vector3 contactPointReferencePolyhedron = projectPointOntoPlane(*itPoints, axisReferenceSpace, referenceFaceVertex);
|
||||||
|
|
||||||
// Create a new contact point
|
// Create a new contact point
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, minPenetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
||||||
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
|
isMinPenetrationFaceNormalPolyhedron1 ? contactPointReferencePolyhedron : contactPointIncidentPolyhedron,
|
||||||
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron);
|
isMinPenetrationFaceNormalPolyhedron1 ? contactPointIncidentPolyhedron : contactPointReferencePolyhedron);
|
||||||
}
|
}
|
||||||
|
@ -893,7 +893,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(const NarrowP
|
||||||
const Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
|
const Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
|
||||||
|
|
||||||
// Create the contact point
|
// Create the contact point
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, minPenetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
||||||
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
|
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = false;
|
lastFrameInfo.satIsAxisFacePolyhedron1 = false;
|
||||||
|
|
|
@ -113,24 +113,24 @@ class SATAlgorithm {
|
||||||
SATAlgorithm& operator=(const SATAlgorithm& algorithm) = delete;
|
SATAlgorithm& operator=(const SATAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Test collision between a sphere and a convex mesh
|
/// Test collision between a sphere and a convex mesh
|
||||||
bool testCollisionSphereVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) const;
|
bool testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) const;
|
||||||
|
|
||||||
/// Test collision between a capsule and a convex mesh
|
/// Test collision between a capsule and a convex mesh
|
||||||
bool testCollisionCapsuleVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) const;
|
bool testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) const;
|
||||||
|
|
||||||
/// Compute the two contact points between a polyhedron and a capsule when the separating axis is a face normal of the polyhedron
|
/// Compute the two contact points between a polyhedron and a capsule when the separating axis is a face normal of the polyhedron
|
||||||
void computeCapsulePolyhedronFaceContactPoints(uint referenceFaceIndex, decimal capsuleRadius, const ConvexPolyhedronShape* polyhedron,
|
void computeCapsulePolyhedronFaceContactPoints(uint referenceFaceIndex, decimal capsuleRadius, const ConvexPolyhedronShape* polyhedron,
|
||||||
decimal penetrationDepth, const Transform& polyhedronToCapsuleTransform,
|
decimal penetrationDepth, const Transform& polyhedronToCapsuleTransform,
|
||||||
const Vector3& normalWorld, const Vector3& separatingAxisCapsuleSpace,
|
const Vector3& normalWorld, const Vector3& separatingAxisCapsuleSpace,
|
||||||
const Vector3& capsuleSegAPolyhedronSpace, const Vector3& capsuleSegBPolyhedronSpace,
|
const Vector3& capsuleSegAPolyhedronSpace, const Vector3& capsuleSegBPolyhedronSpace,
|
||||||
ContactManifoldInfo& contactManifoldInfo, bool isCapsuleShape1) const;
|
NarrowPhaseInfo* narrowPhaseInfo, bool isCapsuleShape1) const;
|
||||||
|
|
||||||
// This method returns true if an edge of a polyhedron and a capsule forms a face of the Minkowski Difference
|
// This method returns true if an edge of a polyhedron and a capsule forms a face of the Minkowski Difference
|
||||||
bool isMinkowskiFaceCapsuleVsEdge(const Vector3& capsuleSegment, const Vector3& edgeAdjacentFace1Normal,
|
bool isMinkowskiFaceCapsuleVsEdge(const Vector3& capsuleSegment, const Vector3& edgeAdjacentFace1Normal,
|
||||||
const Vector3& edgeAdjacentFace2Normal) const;
|
const Vector3& edgeAdjacentFace2Normal) const;
|
||||||
|
|
||||||
/// Test collision between two convex meshes
|
/// Test collision between two convex meshes
|
||||||
bool testCollisionConvexPolyhedronVsConvexPolyhedron(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) const;
|
bool testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ using namespace reactphysics3d;
|
||||||
// Compute the narrow-phase collision detection between a sphere and a capsule
|
// Compute the narrow-phase collision detection between a sphere and a capsule
|
||||||
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
||||||
// by Dirk Gregorius.
|
// by Dirk Gregorius.
|
||||||
bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) {
|
bool SphereVsCapsuleAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
|
|
||||||
bool isSphereShape1 = narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE;
|
bool isSphereShape1 = narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE;
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, penetrationDepth,
|
||||||
isSphereShape1 ? contactPointSphereLocal : contactPointCapsuleLocal,
|
isSphereShape1 ? contactPointSphereLocal : contactPointCapsuleLocal,
|
||||||
isSphereShape1 ? contactPointCapsuleLocal : contactPointSphereLocal);
|
isSphereShape1 ? contactPointCapsuleLocal : contactPointSphereLocal);
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,7 @@ class SphereVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
SphereVsCapsuleAlgorithm& operator=(const SphereVsCapsuleAlgorithm& algorithm) = delete;
|
SphereVsCapsuleAlgorithm& operator=(const SphereVsCapsuleAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute the narrow-phase collision detection between a sphere and a capsule
|
/// Compute the narrow-phase collision detection between a sphere and a capsule
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,12 +34,11 @@ using namespace reactphysics3d;
|
||||||
// Compute the narrow-phase collision detection between a sphere and a convex polyhedron
|
// Compute the narrow-phase collision detection between a sphere and a convex polyhedron
|
||||||
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
// This technique is based on the "Robust Contact Creation for Physics Simulations" presentation
|
||||||
// by Dirk Gregorius.
|
// by Dirk Gregorius.
|
||||||
bool SphereVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SphereVsConvexPolyhedronAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
ContactManifoldInfo& contactManifoldInfo) {
|
|
||||||
|
|
||||||
// First, we run the GJK algorithm
|
// First, we run the GJK algorithm
|
||||||
GJKAlgorithm gjkAlgorithm;
|
GJKAlgorithm gjkAlgorithm;
|
||||||
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, contactManifoldInfo);
|
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, reportContacts);
|
||||||
|
|
||||||
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CONVEX_POLYHEDRON ||
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CONVEX_POLYHEDRON ||
|
||||||
narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CONVEX_POLYHEDRON);
|
narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CONVEX_POLYHEDRON);
|
||||||
|
@ -61,7 +60,7 @@ bool SphereVsConvexPolyhedronAlgorithm::testCollision(const NarrowPhaseInfo* nar
|
||||||
|
|
||||||
// Run the SAT algorithm to find the separating axis and compute contact point
|
// Run the SAT algorithm to find the separating axis and compute contact point
|
||||||
SATAlgorithm satAlgorithm;
|
SATAlgorithm satAlgorithm;
|
||||||
bool isColliding = satAlgorithm.testCollisionSphereVsConvexPolyhedron(narrowPhaseInfo, contactManifoldInfo);
|
bool isColliding = satAlgorithm.testCollisionSphereVsConvexPolyhedron(narrowPhaseInfo, reportContacts);
|
||||||
|
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingGJK = false;
|
||||||
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo().wasUsingSAT = true;
|
||||||
|
|
|
@ -61,8 +61,7 @@ class SphereVsConvexPolyhedronAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
SphereVsConvexPolyhedronAlgorithm& operator=(const SphereVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
SphereVsConvexPolyhedronAlgorithm& operator=(const SphereVsConvexPolyhedronAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute the narrow-phase collision detection between a sphere and a convex polyhedron
|
/// Compute the narrow-phase collision detection between a sphere and a convex polyhedron
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,7 @@
|
||||||
// We want to use the ReactPhysics3D namespace
|
// We want to use the ReactPhysics3D namespace
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SphereVsSphereAlgorithm::testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) {
|
||||||
ContactManifoldInfo& contactManifoldInfo) {
|
|
||||||
|
|
||||||
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE);
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE);
|
||||||
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::SPHERE);
|
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::SPHERE);
|
||||||
|
@ -62,7 +61,7 @@ bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseIn
|
||||||
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
|
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactManifoldInfo.addContactPoint(vectorBetweenCenters.getUnit(), penetrationDepth,
|
narrowPhaseInfo->addContactPoint(vectorBetweenCenters.getUnit(), penetrationDepth,
|
||||||
intersectionOnBody1, intersectionOnBody2);
|
intersectionOnBody1, intersectionOnBody2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -61,8 +61,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
SphereVsSphereAlgorithm& operator=(const SphereVsSphereAlgorithm& algorithm) = delete;
|
SphereVsSphereAlgorithm& operator=(const SphereVsSphereAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(NarrowPhaseInfo* narrowPhaseInfo, bool reportContacts) override;
|
||||||
ContactManifoldInfo& contactManifoldInfo) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,8 @@ inline Vector3 BoxShape::getFaceNormal(uint faceIndex) const {
|
||||||
case 4: return Vector3(0, -1, 0);
|
case 4: return Vector3(0, -1, 0);
|
||||||
case 5: return Vector3(0, 1, 0);
|
case 5: return Vector3(0, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the centroid of the box
|
// Return the centroid of the box
|
||||||
|
|
|
@ -118,10 +118,6 @@ class CollisionShape {
|
||||||
/// Return true if the collision shape type is a convex shape
|
/// Return true if the collision shape type is a convex shape
|
||||||
static bool isConvex(CollisionShapeType shapeType);
|
static bool isConvex(CollisionShapeType shapeType);
|
||||||
|
|
||||||
/// Return the maximum number of contact manifolds in an overlapping pair given two shape types
|
|
||||||
static int computeNbMaxContactManifolds(CollisionShapeType shapeType1,
|
|
||||||
CollisionShapeType shapeType2);
|
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
friend class ProxyShape;
|
friend class ProxyShape;
|
||||||
|
@ -151,19 +147,6 @@ inline void CollisionShape::setLocalScaling(const Vector3& scaling) {
|
||||||
mScaling = scaling;
|
mScaling = scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the maximum number of contact manifolds allowed in an overlapping
|
|
||||||
// pair wit the given two collision shape types
|
|
||||||
inline int CollisionShape::computeNbMaxContactManifolds(CollisionShapeType shapeType1,
|
|
||||||
CollisionShapeType shapeType2) {
|
|
||||||
// If both shapes are convex
|
|
||||||
if (isConvex(shapeType1) && isConvex(shapeType2)) {
|
|
||||||
return NB_MAX_CONTACT_MANIFOLDS_CONVEX_SHAPE;
|
|
||||||
} // If there is at least one concave shape
|
|
||||||
else {
|
|
||||||
return NB_MAX_CONTACT_MANIFOLDS_CONCAVE_SHAPE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,19 +37,20 @@ ContactPoint::ContactPoint(const ContactPointInfo* contactInfo, const Transform&
|
||||||
mPenetrationDepth(contactInfo->penetrationDepth),
|
mPenetrationDepth(contactInfo->penetrationDepth),
|
||||||
mLocalPointOnBody1(contactInfo->localPoint1),
|
mLocalPointOnBody1(contactInfo->localPoint1),
|
||||||
mLocalPointOnBody2(contactInfo->localPoint2),
|
mLocalPointOnBody2(contactInfo->localPoint2),
|
||||||
mIsRestingContact(false) {
|
mIsRestingContact(false), mIsObselete(false), mNext(nullptr) {
|
||||||
|
|
||||||
assert(mPenetrationDepth > decimal(0.0));
|
assert(mPenetrationDepth > decimal(0.0));
|
||||||
|
|
||||||
// Compute the world position of the contact points
|
// Compute the world position of the contact points
|
||||||
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
||||||
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
||||||
|
|
||||||
|
mIsObselete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the contact point with a new one that is similar (very close)
|
// Update the contact point with a new one that is similar (very close)
|
||||||
/// The idea is to keep the cache impulse (for warm starting the contact solver)
|
/// The idea is to keep the cache impulse (for warm starting the contact solver)
|
||||||
void ContactPoint::update(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
void ContactPoint::update(const ContactPointInfo* contactInfo, const Transform& body1Transform, const Transform& body2Transform) {
|
||||||
const Transform& body2Transform) {
|
|
||||||
|
|
||||||
assert(isSimilarWithContactPoint(contactInfo));
|
assert(isSimilarWithContactPoint(contactInfo));
|
||||||
assert(contactInfo->penetrationDepth > decimal(0.0));
|
assert(contactInfo->penetrationDepth > decimal(0.0));
|
||||||
|
@ -62,4 +63,6 @@ void ContactPoint::update(const ContactPointInfo* contactInfo, const Transform&
|
||||||
// Compute the world position of the contact points
|
// Compute the world position of the contact points
|
||||||
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
||||||
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
||||||
|
|
||||||
|
mIsObselete = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,37 @@ class ContactPoint {
|
||||||
/// Cached penetration impulse
|
/// Cached penetration impulse
|
||||||
decimal mPenetrationImpulse;
|
decimal mPenetrationImpulse;
|
||||||
|
|
||||||
|
/// True if the contact point is obselete
|
||||||
|
bool mIsObselete;
|
||||||
|
|
||||||
|
/// Pointer to the next contact point in the linked-list
|
||||||
|
ContactPoint* mNext;
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
/// Update the contact point with a new one that is similar (very close)
|
||||||
|
void update(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
||||||
|
const Transform& body2Transform);
|
||||||
|
|
||||||
|
/// Return true if the contact point is similar (close enougth) to another given contact point
|
||||||
|
bool isSimilarWithContactPoint(const ContactPointInfo* contactPoint) const;
|
||||||
|
|
||||||
|
/// Set the cached penetration impulse
|
||||||
|
void setPenetrationImpulse(decimal impulse);
|
||||||
|
|
||||||
|
|
||||||
|
/// Set the mIsRestingContact variable
|
||||||
|
void setIsRestingContact(bool isRestingContact);
|
||||||
|
|
||||||
|
/// Set to true to make the contact point obselete
|
||||||
|
void setIsObselete(bool isObselete);
|
||||||
|
|
||||||
|
/// Set the next contact point in the linked list
|
||||||
|
void setNext(ContactPoint* next);
|
||||||
|
|
||||||
|
/// Return true if the contact point is obselete
|
||||||
|
bool getIsObselete() const;
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
@ -88,10 +119,6 @@ class ContactPoint {
|
||||||
/// Deleted assignment operator
|
/// Deleted assignment operator
|
||||||
ContactPoint& operator=(const ContactPoint& contact) = delete;
|
ContactPoint& operator=(const ContactPoint& contact) = delete;
|
||||||
|
|
||||||
/// Update the contact point with a new one that is similar (very close)
|
|
||||||
void update(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
|
||||||
const Transform& body2Transform);
|
|
||||||
|
|
||||||
/// Return the normal vector of the contact
|
/// Return the normal vector of the contact
|
||||||
Vector3 getNormal() const;
|
Vector3 getNormal() const;
|
||||||
|
|
||||||
|
@ -110,23 +137,22 @@ class ContactPoint {
|
||||||
/// Return the cached penetration impulse
|
/// Return the cached penetration impulse
|
||||||
decimal getPenetrationImpulse() const;
|
decimal getPenetrationImpulse() const;
|
||||||
|
|
||||||
/// Return true if the contact point is similar (close enougth) to another given contact point
|
|
||||||
bool isSimilarWithContactPoint(const ContactPointInfo* contactPoint) const;
|
|
||||||
|
|
||||||
/// Set the cached penetration impulse
|
|
||||||
void setPenetrationImpulse(decimal impulse);
|
|
||||||
|
|
||||||
/// Return true if the contact is a resting contact
|
/// Return true if the contact is a resting contact
|
||||||
bool getIsRestingContact() const;
|
bool getIsRestingContact() const;
|
||||||
|
|
||||||
/// Set the mIsRestingContact variable
|
/// Return the next contact point in the linked list
|
||||||
void setIsRestingContact(bool isRestingContact);
|
ContactPoint* getNext() const;
|
||||||
|
|
||||||
/// Return the penetration depth
|
/// Return the penetration depth
|
||||||
decimal getPenetrationDepth() const;
|
decimal getPenetrationDepth() const;
|
||||||
|
|
||||||
/// Return the number of bytes used by the contact point
|
/// Return the number of bytes used by the contact point
|
||||||
size_t getSizeInBytes() const;
|
size_t getSizeInBytes() const;
|
||||||
|
|
||||||
|
// Friendship
|
||||||
|
friend class ContactManifold;
|
||||||
|
friend class ContactManifoldSet;
|
||||||
|
friend class ContactSolver;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return the normal vector of the contact
|
// Return the normal vector of the contact
|
||||||
|
@ -180,6 +206,26 @@ inline void ContactPoint::setIsRestingContact(bool isRestingContact) {
|
||||||
mIsRestingContact = isRestingContact;
|
mIsRestingContact = isRestingContact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the contact point is obselete
|
||||||
|
inline bool ContactPoint::getIsObselete() const {
|
||||||
|
return mIsObselete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set to true to make the contact point obselete
|
||||||
|
inline void ContactPoint::setIsObselete(bool isObselete) {
|
||||||
|
mIsObselete = isObselete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the next contact point in the linked list
|
||||||
|
inline ContactPoint* ContactPoint::getNext() const {
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the next contact point in the linked list
|
||||||
|
inline void ContactPoint::setNext(ContactPoint* next) {
|
||||||
|
mNext = next;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the penetration depth of the contact
|
// Return the penetration depth of the contact
|
||||||
inline decimal ContactPoint::getPenetrationDepth() const {
|
inline decimal ContactPoint::getPenetrationDepth() const {
|
||||||
return mPenetrationDepth;
|
return mPenetrationDepth;
|
||||||
|
|
|
@ -233,64 +233,6 @@ inline void CollisionWorld::testOverlap(CollisionBody* body, OverlapCallback* ov
|
||||||
mCollisionDetection.testOverlap(body, overlapCallback, categoryMaskBits);
|
mCollisionDetection.testOverlap(body, overlapCallback, categoryMaskBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 notifyContact() method. This method will called each time a contact
|
|
||||||
* point is reported.
|
|
||||||
*/
|
|
||||||
class CollisionCallback {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct CollisionCallbackInfo {
|
|
||||||
|
|
||||||
public:
|
|
||||||
const ContactManifoldInfo& contactManifold;
|
|
||||||
CollisionBody* body1;
|
|
||||||
CollisionBody* body2;
|
|
||||||
const ProxyShape* proxyShape1;
|
|
||||||
const ProxyShape* proxyShape2;
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
CollisionCallbackInfo(const ContactManifoldInfo& manifold, CollisionBody* b1, CollisionBody* b2,
|
|
||||||
const ProxyShape* proxShape1, const ProxyShape* proxShape2) :
|
|
||||||
contactManifold(manifold), body1(b1), body2(b2),
|
|
||||||
proxyShape1(proxShape1), proxyShape2(proxShape2) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Destructor
|
|
||||||
virtual ~CollisionCallback() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method will be called for each reported contact point
|
|
||||||
virtual void notifyContact(const CollisionCallbackInfo& collisionCallbackInfo)=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Class OverlapCallback
|
|
||||||
/**
|
|
||||||
* This class can be used to register a callback for collision overlap queries.
|
|
||||||
* You should implement your own class inherited from this one and implement
|
|
||||||
* the notifyOverlap() method. This method will called each time a contact
|
|
||||||
* point is reported.
|
|
||||||
*/
|
|
||||||
class OverlapCallback {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Destructor
|
|
||||||
virtual ~OverlapCallback() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This method will be called for each reported overlapping bodies
|
|
||||||
virtual void notifyOverlap(CollisionBody* collisionBody)=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -148,10 +148,8 @@ void ContactSolver::initializeForIsland(Island* island) {
|
||||||
const Vector3& w2 = mAngularVelocities[mContactConstraints[mNbContactManifolds].indexBody2];
|
const Vector3& w2 = mAngularVelocities[mContactConstraints[mNbContactManifolds].indexBody2];
|
||||||
|
|
||||||
// For each contact point of the contact manifold
|
// For each contact point of the contact manifold
|
||||||
for (uint c=0; c<externalManifold->getNbContactPoints(); c++) {
|
ContactPoint* externalContact = externalManifold->getContactPoints();
|
||||||
|
while (externalContact != nullptr) {
|
||||||
// Get a contact point
|
|
||||||
ContactPoint* externalContact = externalManifold->getContactPoint(c);
|
|
||||||
|
|
||||||
// Get the contact point on the two bodies
|
// Get the contact point on the two bodies
|
||||||
Vector3 p1 = externalContact->getWorldPointOnBody1();
|
Vector3 p1 = externalContact->getWorldPointOnBody1();
|
||||||
|
@ -200,6 +198,8 @@ void ContactSolver::initializeForIsland(Island* island) {
|
||||||
mContactConstraints[mNbContactManifolds].normal += mContactPoints[mNbContactPoints].normal;
|
mContactConstraints[mNbContactManifolds].normal += mContactPoints[mNbContactPoints].normal;
|
||||||
|
|
||||||
mNbContactPoints++;
|
mNbContactPoints++;
|
||||||
|
|
||||||
|
externalContact = externalContact->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
mContactConstraints[mNbContactManifolds].frictionPointBody1 /=static_cast<decimal>(mContactConstraints[mNbContactManifolds].nbContacts);
|
mContactConstraints[mNbContactManifolds].frictionPointBody1 /=static_cast<decimal>(mContactConstraints[mNbContactManifolds].nbContacts);
|
||||||
|
|
|
@ -683,9 +683,9 @@ void DynamicsWorld::computeIslands() {
|
||||||
// For each contact manifold in which the current body is involded
|
// For each contact manifold in which the current body is involded
|
||||||
ContactManifoldListElement* contactElement;
|
ContactManifoldListElement* contactElement;
|
||||||
for (contactElement = bodyToVisit->mContactManifoldsList; contactElement != nullptr;
|
for (contactElement = bodyToVisit->mContactManifoldsList; contactElement != nullptr;
|
||||||
contactElement = contactElement->next) {
|
contactElement = contactElement->getNext()) {
|
||||||
|
|
||||||
ContactManifold* contactManifold = contactElement->contactManifold;
|
ContactManifold* contactManifold = contactElement->getContactManifold();
|
||||||
|
|
||||||
assert(contactManifold->getNbContactPoints() > 0);
|
assert(contactManifold->getNbContactPoints() > 0);
|
||||||
|
|
||||||
|
@ -842,12 +842,13 @@ std::vector<const ContactManifold*> DynamicsWorld::getContactsList() const {
|
||||||
|
|
||||||
// For each contact manifold of the pair
|
// For each contact manifold of the pair
|
||||||
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
||||||
for (int i=0; i<manifoldSet.getNbContactManifolds(); i++) {
|
ContactManifold* manifold = manifoldSet.getContactManifolds();
|
||||||
|
while (manifold != nullptr) {
|
||||||
ContactManifold* manifold = manifoldSet.getContactManifold(i);
|
|
||||||
|
|
||||||
// Get the contact manifold
|
// Get the contact manifold
|
||||||
contactManifolds.push_back(manifold);
|
contactManifolds.push_back(manifold);
|
||||||
|
|
||||||
|
manifold = manifold->getNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define REACTPHYSICS3D_EVENT_LISTENER_H
|
#define REACTPHYSICS3D_EVENT_LISTENER_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "collision/ContactManifoldInfo.h"
|
#include "collision/CollisionCallback.h"
|
||||||
|
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
@ -49,17 +49,11 @@ class EventListener {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~EventListener() = default;
|
virtual ~EventListener() = default;
|
||||||
|
|
||||||
/// Called when a new contact point is found between two bodies that were separated before
|
|
||||||
/**
|
|
||||||
* @param contact Information about the contact
|
|
||||||
*/
|
|
||||||
virtual void beginContact(const ContactManifoldInfo& contactManifold) {}
|
|
||||||
|
|
||||||
/// Called when a new contact point is found between two bodies
|
/// Called when a new contact point is found between two bodies
|
||||||
/**
|
/**
|
||||||
* @param contact Information about the contact
|
* @param contact Information about the contact
|
||||||
*/
|
*/
|
||||||
virtual void newContact(const ContactManifoldInfo& contactManifold) {}
|
virtual void newContact(const CollisionCallback::CollisionCallbackInfo& collisionInfo) {}
|
||||||
|
|
||||||
/// Called at the beginning of an internal tick of the simulation step.
|
/// Called at the beginning of an internal tick of the simulation step.
|
||||||
/// Each time the DynamicsWorld::update() method is called, the physics
|
/// Each time the DynamicsWorld::update() method is called, the physics
|
||||||
|
|
|
@ -26,12 +26,108 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include "OverlappingPair.h"
|
#include "OverlappingPair.h"
|
||||||
|
#include "collision/ContactManifoldInfo.h"
|
||||||
|
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
|
OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
|
||||||
int nbMaxContactManifolds, PoolAllocator& memoryAllocator)
|
Allocator& manifoldsAllocator, Allocator& temporaryMemoryAllocator)
|
||||||
: mContactManifoldSet(shape1, shape2, memoryAllocator, nbMaxContactManifolds) {
|
: mContactManifoldSet(shape1, shape2, manifoldsAllocator), mPotentialContactManifolds(nullptr),
|
||||||
|
mTempMemoryAllocator(temporaryMemoryAllocator) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new potential contact manifold using contact-points from narrow-phase
|
||||||
|
void OverlappingPair::addPotentialContactPoints(NarrowPhaseInfo* narrowPhaseInfo) {
|
||||||
|
|
||||||
|
assert(narrowPhaseInfo->contactPoints != nullptr);
|
||||||
|
|
||||||
|
// For each potential contact point to add
|
||||||
|
ContactPointInfo* contactPoint = narrowPhaseInfo->contactPoints;
|
||||||
|
while (contactPoint != nullptr) {
|
||||||
|
|
||||||
|
ContactPointInfo* nextContactPoint = contactPoint->next;
|
||||||
|
|
||||||
|
// Compute the contact normal id
|
||||||
|
short contactNormalId = ContactManifoldSet::computeCubemapNormalId(contactPoint->normal);
|
||||||
|
|
||||||
|
// Look if the contact point correspond to an existing potential manifold
|
||||||
|
// (if the contact point normal is similar to the normal of an existing manifold)
|
||||||
|
ContactManifoldInfo* manifold = mPotentialContactManifolds;
|
||||||
|
bool similarManifoldFound = false;
|
||||||
|
while(manifold != nullptr) {
|
||||||
|
|
||||||
|
// If we have found a corresponding manifold for the new contact point
|
||||||
|
// (a manifold with a similar contact normal direction)
|
||||||
|
if (manifold->getContactNormalId() == contactNormalId) {
|
||||||
|
|
||||||
|
// Add the contact point to the manifold
|
||||||
|
manifold->addContactPoint(contactPoint, contactNormalId);
|
||||||
|
|
||||||
|
similarManifoldFound = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
manifold = manifold->getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have not found an existing manifold with a similar contact normal
|
||||||
|
if (!similarManifoldFound) {
|
||||||
|
|
||||||
|
// Create a new potential contact manifold
|
||||||
|
ContactManifoldInfo* manifoldInfo = new (mTempMemoryAllocator.allocate(sizeof(ContactManifoldInfo)))
|
||||||
|
ContactManifoldInfo(mTempMemoryAllocator);
|
||||||
|
|
||||||
|
// Add the manifold into the linked-list of potential contact manifolds
|
||||||
|
manifoldInfo->mNext = mPotentialContactManifolds;
|
||||||
|
mPotentialContactManifolds = manifoldInfo;
|
||||||
|
|
||||||
|
// Add the contact point to the manifold
|
||||||
|
manifoldInfo->addContactPoint(contactPoint, contactNormalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
contactPoint = nextContactPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the contact point info of the narrow-phase info have been moved
|
||||||
|
// into the potential contacts of the overlapping pair
|
||||||
|
narrowPhaseInfo->contactPoints = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all the potential contact manifolds
|
||||||
|
void OverlappingPair::clearPotentialContactManifolds() {
|
||||||
|
|
||||||
|
// Do we need to release memory
|
||||||
|
if (mTempMemoryAllocator.isReleaseNeeded()) {
|
||||||
|
|
||||||
|
ContactManifoldInfo* element = mPotentialContactManifolds;
|
||||||
|
while(element != nullptr) {
|
||||||
|
|
||||||
|
// Remove the proxy collision shape
|
||||||
|
ContactManifoldInfo* elementToRemove = element;
|
||||||
|
element = element->getNext();
|
||||||
|
|
||||||
|
// Delete the element
|
||||||
|
elementToRemove->~ContactManifoldInfo();
|
||||||
|
mTempMemoryAllocator.release(elementToRemove, sizeof(ContactManifoldInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPotentialContactManifolds = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the number of contact points of all the potential contact manifolds
|
||||||
|
void OverlappingPair::reducePotentialContactManifolds() {
|
||||||
|
|
||||||
|
// For each potential contact manifold
|
||||||
|
ContactManifoldInfo* manifold = mPotentialContactManifolds;
|
||||||
|
while (manifold != nullptr) {
|
||||||
|
|
||||||
|
// Reduce the number of contact points of the manifold
|
||||||
|
manifold->reduce(mContactManifoldSet.getShape1()->getLocalToWorldTransform());
|
||||||
|
|
||||||
|
manifold = manifold->getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -102,13 +102,19 @@ class OverlappingPair {
|
||||||
/// Collision information about the last frame (for temporal coherence)
|
/// Collision information about the last frame (for temporal coherence)
|
||||||
LastFrameCollisionInfo mLastFrameCollisionInfo;
|
LastFrameCollisionInfo mLastFrameCollisionInfo;
|
||||||
|
|
||||||
|
/// Linked-list of potential contact manifold
|
||||||
|
ContactManifoldInfo* mPotentialContactManifolds;
|
||||||
|
|
||||||
|
/// Memory allocator used to allocated memory for the ContactManifoldInfo and ContactPointInfo
|
||||||
|
Allocator& mTempMemoryAllocator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
|
OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
|
||||||
int nbMaxContactManifolds, PoolAllocator& memoryAllocator);
|
Allocator& memoryAllocator, Allocator& temporaryMemoryAllocator);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~OverlappingPair() = default;
|
~OverlappingPair() = default;
|
||||||
|
@ -125,9 +131,6 @@ class OverlappingPair {
|
||||||
/// Return the pointer to second body
|
/// Return the pointer to second body
|
||||||
ProxyShape* getShape2() const;
|
ProxyShape* getShape2() const;
|
||||||
|
|
||||||
/// Add a contact manifold
|
|
||||||
void addContactManifold(const ContactManifoldInfo& contactManifoldInfo);
|
|
||||||
|
|
||||||
/// Return the last frame collision info
|
/// Return the last frame collision info
|
||||||
LastFrameCollisionInfo& getLastFrameCollisionInfo();
|
LastFrameCollisionInfo& getLastFrameCollisionInfo();
|
||||||
|
|
||||||
|
@ -137,8 +140,32 @@ class OverlappingPair {
|
||||||
/// Return the a reference to the contact manifold set
|
/// Return the a reference to the contact manifold set
|
||||||
const ContactManifoldSet& getContactManifoldSet();
|
const ContactManifoldSet& getContactManifoldSet();
|
||||||
|
|
||||||
/// Clear the contact points of the contact manifold
|
/// Clear all the potential contact manifolds
|
||||||
void clearContactPoints();
|
void clearPotentialContactManifolds();
|
||||||
|
|
||||||
|
/// Add potential contact-points from narrow-phase into potential contact manifolds
|
||||||
|
void addPotentialContactPoints(NarrowPhaseInfo* narrowPhaseInfo);
|
||||||
|
|
||||||
|
/// Add a contact to the contact manifold
|
||||||
|
void addContactManifold(const ContactManifoldInfo* contactManifoldInfo);
|
||||||
|
|
||||||
|
/// Return a reference to the temporary memory allocator
|
||||||
|
Allocator& getTemporaryAllocator();
|
||||||
|
|
||||||
|
/// Return true if one of the shapes of the pair is a concave shape
|
||||||
|
bool hasConcaveShape() const;
|
||||||
|
|
||||||
|
/// Return a pointer to the first potential contact manifold in the linked-list
|
||||||
|
ContactManifoldInfo* getPotentialContactManifolds();
|
||||||
|
|
||||||
|
/// Reduce the number of contact points of all the potential contact manifolds
|
||||||
|
void reducePotentialContactManifolds();
|
||||||
|
|
||||||
|
/// Make the contact manifolds and contact points obselete
|
||||||
|
void makeContactsObselete();
|
||||||
|
|
||||||
|
/// Clear the obselete contact manifold and contact points
|
||||||
|
void clearObseleteManifoldsAndContactPoints();
|
||||||
|
|
||||||
/// 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);
|
||||||
|
@ -162,7 +189,7 @@ inline ProxyShape* OverlappingPair::getShape2() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a contact to the contact manifold
|
// Add a contact to the contact manifold
|
||||||
inline void OverlappingPair::addContactManifold(const ContactManifoldInfo& contactManifoldInfo) {
|
inline void OverlappingPair::addContactManifold(const ContactManifoldInfo* contactManifoldInfo) {
|
||||||
mContactManifoldSet.addContactManifold(contactManifoldInfo);
|
mContactManifoldSet.addContactManifold(contactManifoldInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +208,12 @@ inline const ContactManifoldSet& OverlappingPair::getContactManifoldSet() {
|
||||||
return mContactManifoldSet;
|
return mContactManifoldSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make the contact manifolds and contact points obselete
|
||||||
|
inline void OverlappingPair::makeContactsObselete() {
|
||||||
|
|
||||||
|
mContactManifoldSet.makeContactsObselete();
|
||||||
|
}
|
||||||
|
|
||||||
// Return the pair of bodies index
|
// Return the pair of bodies index
|
||||||
inline overlappingpairid OverlappingPair::computeID(ProxyShape* shape1, ProxyShape* shape2) {
|
inline overlappingpairid OverlappingPair::computeID(ProxyShape* shape1, ProxyShape* shape2) {
|
||||||
assert(shape1->mBroadPhaseID >= 0 && shape2->mBroadPhaseID >= 0);
|
assert(shape1->mBroadPhaseID >= 0 && shape2->mBroadPhaseID >= 0);
|
||||||
|
@ -205,9 +238,25 @@ inline bodyindexpair OverlappingPair::computeBodiesIndexPair(CollisionBody* body
|
||||||
return indexPair;
|
return indexPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the contact points of the contact manifold
|
// Return a reference to the temporary memory allocator
|
||||||
inline void OverlappingPair::clearContactPoints() {
|
inline Allocator& OverlappingPair::getTemporaryAllocator() {
|
||||||
mContactManifoldSet.clear();
|
return mTempMemoryAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if one of the shapes of the pair is a concave shape
|
||||||
|
inline bool OverlappingPair::hasConcaveShape() const {
|
||||||
|
return !getShape1()->getCollisionShape()->isConvex() ||
|
||||||
|
!getShape2()->getCollisionShape()->isConvex();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a pointer to the first potential contact manifold in the linked-list
|
||||||
|
inline ContactManifoldInfo* OverlappingPair::getPotentialContactManifolds() {
|
||||||
|
return mPotentialContactManifolds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the obselete contact manifold and contact points
|
||||||
|
inline void OverlappingPair::clearObseleteManifoldsAndContactPoints() {
|
||||||
|
mContactManifoldSet.clearObseleteManifoldsAndContactPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,9 @@ class Allocator {
|
||||||
|
|
||||||
/// Release previously allocated memory.
|
/// Release previously allocated memory.
|
||||||
virtual void release(void* pointer, size_t size)=0;
|
virtual void release(void* pointer, size_t size)=0;
|
||||||
|
|
||||||
|
/// Return true if memory needs to be release with this allocator
|
||||||
|
virtual bool isReleaseNeeded() const=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,16 @@ class PoolAllocator : public Allocator {
|
||||||
/// Release previously allocated memory.
|
/// Release previously allocated memory.
|
||||||
virtual void release(void* pointer, size_t size) override;
|
virtual void release(void* pointer, size_t size) override;
|
||||||
|
|
||||||
|
/// Return true if memory needs to be release with this allocator
|
||||||
|
virtual bool isReleaseNeeded() const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return true if memory needs to be release with this allocator
|
||||||
|
inline bool PoolAllocator::isReleaseNeeded() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -72,10 +72,15 @@ class SingleFrameAllocator : public Allocator {
|
||||||
/// Reset the marker of the current allocated memory
|
/// Reset the marker of the current allocated memory
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
|
||||||
|
/// Return true if memory needs to be release with this allocator
|
||||||
|
virtual bool isReleaseNeeded() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return true if memory needs to be release with this allocator
|
||||||
|
inline bool SingleFrameAllocator::isReleaseNeeded() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,6 +58,8 @@
|
||||||
#include "collision/PolyhedronMesh.h"
|
#include "collision/PolyhedronMesh.h"
|
||||||
#include "collision/TriangleVertexArray.h"
|
#include "collision/TriangleVertexArray.h"
|
||||||
#include "collision/PolygonVertexArray.h"
|
#include "collision/PolygonVertexArray.h"
|
||||||
|
#include "collision/CollisionCallback.h"
|
||||||
|
#include "collision/OverlapCallback.h"
|
||||||
#include "constraint/BallAndSocketJoint.h"
|
#include "constraint/BallAndSocketJoint.h"
|
||||||
#include "constraint/SliderJoint.h"
|
#include "constraint/SliderJoint.h"
|
||||||
#include "constraint/HingeJoint.h"
|
#include "constraint/HingeJoint.h"
|
||||||
|
|
|
@ -79,26 +79,34 @@ class ContactManager : public rp3d::CollisionCallback {
|
||||||
/// This method will be called for each reported contact point
|
/// This method will be called for each reported contact point
|
||||||
virtual void notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) override {
|
virtual void notifyContact(const CollisionCallbackInfo& collisionCallbackInfo) override {
|
||||||
|
|
||||||
|
// For each contact manifold
|
||||||
|
rp3d::ContactManifoldListElement* manifoldElement = collisionCallbackInfo.contactManifoldElements;
|
||||||
|
while (manifoldElement != nullptr) {
|
||||||
|
|
||||||
|
// Get the contact manifold
|
||||||
|
rp3d::ContactManifold* contactManifold = manifoldElement->getContactManifold();
|
||||||
|
|
||||||
// For each contact point
|
// For each contact point
|
||||||
rp3d::ContactPointInfo* contactPointInfo = collisionCallbackInfo.contactManifold.getFirstContactPointInfo();
|
rp3d::ContactPoint* contactPoint = contactManifold->getContactPoints();
|
||||||
while (contactPointInfo != nullptr) {
|
while (contactPoint != nullptr) {
|
||||||
|
|
||||||
// Contact normal
|
// Contact normal
|
||||||
rp3d::Vector3 normal = contactPointInfo->normal;
|
rp3d::Vector3 normal = contactPoint->getNormal();
|
||||||
openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z);
|
openglframework::Vector3 contactNormal(normal.x, normal.y, normal.z);
|
||||||
|
|
||||||
rp3d::Vector3 point1 = contactPointInfo->localPoint1;
|
rp3d::Vector3 point1 = contactPoint->getLocalPointOnBody1();
|
||||||
point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1;
|
point1 = collisionCallbackInfo.proxyShape1->getLocalToWorldTransform() * point1;
|
||||||
|
|
||||||
openglframework::Vector3 position1(point1.x, point1.y, point1.z);
|
openglframework::Vector3 position1(point1.x, point1.y, point1.z);
|
||||||
mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red()));
|
mContactPoints.push_back(ContactPoint(position1, contactNormal, openglframework::Color::red()));
|
||||||
|
|
||||||
rp3d::Vector3 point2 = contactPointInfo->localPoint2;
|
rp3d::Vector3 point2 = contactPoint->getLocalPointOnBody2();
|
||||||
point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2;
|
point2 = collisionCallbackInfo.proxyShape2->getLocalToWorldTransform() * point2;
|
||||||
openglframework::Vector3 position2(point2.x, point2.y, point2.z);
|
openglframework::Vector3 position2(point2.x, point2.y, point2.z);
|
||||||
mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue()));
|
mContactPoints.push_back(ContactPoint(position2, contactNormal, openglframework::Color::blue()));
|
||||||
|
|
||||||
contactPointInfo = contactPointInfo->next;
|
contactPoint = contactPoint->getNext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,14 +342,16 @@ std::vector<ContactPoint> SceneDemo::computeContactPointsOfWorld(const rp3d::Dyn
|
||||||
const rp3d::ContactManifold* manifold = *it;
|
const rp3d::ContactManifold* manifold = *it;
|
||||||
|
|
||||||
// For each contact point of the manifold
|
// For each contact point of the manifold
|
||||||
for (uint i=0; i<manifold->getNbContactPoints(); i++) {
|
rp3d::ContactPoint* contactPoint = manifold->getContactPoints();
|
||||||
|
while (contactPoint != nullptr) {
|
||||||
|
|
||||||
rp3d::ContactPoint* contactPoint = manifold->getContactPoint(i);
|
|
||||||
rp3d::Vector3 point = contactPoint->getWorldPointOnBody1();
|
rp3d::Vector3 point = contactPoint->getWorldPointOnBody1();
|
||||||
rp3d::Vector3 normalWorld = contactPoint->getNormal();
|
rp3d::Vector3 normalWorld = contactPoint->getNormal();
|
||||||
openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z);
|
openglframework::Vector3 normal = openglframework::Vector3(normalWorld.x, normalWorld.y, normalWorld.z);
|
||||||
ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red());
|
ContactPoint contact(openglframework::Vector3(point.x, point.y, point.z), normal, openglframework::Color::red());
|
||||||
contactPoints.push_back(contact);
|
contactPoints.push_back(contact);
|
||||||
|
|
||||||
|
contactPoint = contactPoint->getNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user