Refactor contact points creation

This commit is contained in:
Daniel Chappuis 2018-09-09 21:59:02 +02:00
parent cd1661613f
commit bcf305b118
17 changed files with 1698 additions and 869 deletions

View File

@ -81,7 +81,6 @@ SET (REACTPHYSICS3D_HEADERS
"src/body/CollisionBody.h"
"src/body/RigidBody.h"
"src/collision/ContactPointInfo.h"
"src/collision/ContactManifoldInfo.h"
"src/collision/broadphase/BroadPhaseAlgorithm.h"
"src/collision/broadphase/DynamicAABBTree.h"
"src/collision/narrowphase/CollisionDispatch.h"
@ -167,7 +166,6 @@ SET (REACTPHYSICS3D_SOURCES
"src/body/Body.cpp"
"src/body/CollisionBody.cpp"
"src/body/RigidBody.cpp"
"src/collision/ContactManifoldInfo.cpp"
"src/collision/broadphase/BroadPhaseAlgorithm.cpp"
"src/collision/broadphase/DynamicAABBTree.cpp"
"src/collision/narrowphase/DefaultCollisionDispatch.cpp"

View File

@ -37,7 +37,6 @@
#include "collision/OverlapCallback.h"
#include "collision/NarrowPhaseInfo.h"
#include "collision/ContactManifold.h"
#include "collision/ContactManifoldInfo.h"
#include "utils/Profiler.h"
#include "engine/EventListener.h"
#include "collision/RaycastInfo.h"
@ -107,8 +106,7 @@ void CollisionDetection::computeMiddlePhase() {
RP3D_PROFILE("CollisionDetection::computeMiddlePhase()", mProfiler);
// For each possible collision pair of bodies
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
OverlappingPair* pair = it->second;
@ -130,9 +128,9 @@ void CollisionDetection::computeMiddlePhase() {
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
// Destroy the overlapping pair
it->second->~OverlappingPair();
pair->~OverlappingPair();
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, it->second, sizeof(OverlappingPair));
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, pair, sizeof(OverlappingPair));
it = mOverlappingPairs.remove(it);
continue;
}
@ -256,6 +254,8 @@ void CollisionDetection::computeNarrowPhase() {
RP3D_PROFILE("CollisionDetection::computeNarrowPhase()", mProfiler);
List<NarrowPhaseInfo*> narrowPhaseInfos(mMemoryManager.getSingleFrameAllocator());
NarrowPhaseInfo* currentNarrowPhaseInfo = mNarrowPhaseInfoList;
while (currentNarrowPhaseInfo != nullptr) {
@ -269,14 +269,13 @@ void CollisionDetection::computeNarrowPhase() {
LastFrameCollisionInfo* lastCollisionFrameInfo = currentNarrowPhaseInfo->getLastFrameCollisionInfo();
narrowPhaseInfos.add(currentNarrowPhaseInfo);
// Use the narrow-phase collision detection algorithm to check
// if there really is a collision. If a collision occurs, the
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(currentNarrowPhaseInfo, true, mMemoryManager.getSingleFrameAllocator())) {
// Add the contact points as a potential contact manifold into the pair
currentNarrowPhaseInfo->addContactPointsAsPotentialContactManifold();
lastCollisionFrameInfo->wasColliding = true;
}
else {
@ -287,24 +286,29 @@ void CollisionDetection::computeNarrowPhase() {
lastCollisionFrameInfo->isValid = true;
}
NarrowPhaseInfo* narrowPhaseInfoToDelete = currentNarrowPhaseInfo;
currentNarrowPhaseInfo = currentNarrowPhaseInfo->next;
// Call the destructor
narrowPhaseInfoToDelete->~NarrowPhaseInfo();
// Release the allocated memory for the narrow phase info
mMemoryManager.release(MemoryManager::AllocationType::Frame, narrowPhaseInfoToDelete, sizeof(NarrowPhaseInfo));
}
// Convert the potential contact into actual contacts
processAllPotentialContacts();
processAllPotentialContacts(narrowPhaseInfos, mOverlappingPairs);
// Add all the contact manifolds (between colliding bodies) to the bodies
addAllContactManifoldsToBodies();
// Report contacts to the user
reportAllContacts();
// Destroy the narrow phase infos
for (auto it = narrowPhaseInfos.begin(); it != narrowPhaseInfos.end(); ++it) {
NarrowPhaseInfo* narrowPhaseInfo = *it;
// Call the destructor
narrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory for the narrow phase info
mMemoryManager.release(MemoryManager::AllocationType::Frame, narrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
}
// Allow the broadphase to notify the collision detection about an overlapping pair.
@ -329,8 +333,10 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro
OverlappingPair* newPair = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(OverlappingPair)))
OverlappingPair(shape1, shape2, mMemoryManager.getPoolAllocator(),
mMemoryManager.getSingleFrameAllocator(), mWorld->mConfig);
assert(newPair != nullptr);
// Add the new overlapping pair
mOverlappingPairs.add(Pair<Pair<uint, uint>, OverlappingPair*>(pairID, newPair));
// Wake up the two bodies
@ -344,16 +350,18 @@ void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) {
assert(proxyShape->getBroadPhaseId() != -1);
// Remove all the overlapping pairs involving this proxy shape
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
if (it->second->getShape1()->getBroadPhaseId() == proxyShape->getBroadPhaseId()||
it->second->getShape2()->getBroadPhaseId() == proxyShape->getBroadPhaseId()) {
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
OverlappingPair* pair = it->second;
if (pair->getShape1()->getBroadPhaseId() == proxyShape->getBroadPhaseId()||
pair->getShape2()->getBroadPhaseId() == proxyShape->getBroadPhaseId()) {
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
// Destroy the overlapping pair
it->second->~OverlappingPair();
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, it->second, sizeof(OverlappingPair));
pair->~OverlappingPair();
mWorld->mMemoryManager.release(MemoryManager::AllocationType::Pool, pair, sizeof(OverlappingPair));
it = mOverlappingPairs.remove(it);
}
else {
@ -370,8 +378,7 @@ void CollisionDetection::addAllContactManifoldsToBodies() {
RP3D_PROFILE("CollisionDetection::addAllContactManifoldsToBodies()", mProfiler);
// For each overlapping pairs in contact during the narrow-phase
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
// Add all the contact manifolds of the pair into the list of contact manifolds
// of the two bodies involved in the contact
@ -430,42 +437,36 @@ void CollisionDetection::addContactManifoldToBody(OverlappingPair* pair) {
}
/// Convert the potential contact into actual contacts
void CollisionDetection::processAllPotentialContacts() {
void CollisionDetection::processAllPotentialContacts(const List<NarrowPhaseInfo*>& narrowPhaseInfos,
const OverlappingPairMap& overlappingPairs) {
RP3D_PROFILE("CollisionDetection::processAllPotentialContacts()", mProfiler);
// For each overlapping pairs in contact during the narrow-phase
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
// For each narrow phase info object
for (auto it = narrowPhaseInfos.begin(); it != narrowPhaseInfos.end(); ++it) {
// Process the potential contacts of the overlapping pair
processPotentialContacts(it->second);
NarrowPhaseInfo* narrowPhaseInfo = *it;
assert(narrowPhaseInfo != nullptr);
if (narrowPhaseInfo->contactPoints != nullptr) {
// Transfer the contact points from the narrow phase info to the overlapping pair
narrowPhaseInfo->overlappingPair->addPotentialContactPoints(narrowPhaseInfo);
}
}
}
// Process the potential contact manifold of a pair to create actual contact manifold
void CollisionDetection::processPotentialContacts(OverlappingPair* pair) {
// For each overlapping pairs in contact during the narrow-phase
for (auto it = overlappingPairs.begin(); it != overlappingPairs.end(); ++it) {
// Reduce the number of contact points of the manifold
pair->reducePotentialContactManifolds();
OverlappingPair* pair = it->second;
// Add all the potential contact manifolds as actual contact manifolds to the pair
ContactManifoldInfo* potentialManifold = pair->getPotentialContactManifolds();
while (potentialManifold != nullptr) {
// Clear the obsolete contact manifolds and contact points
pair->clearObsoleteManifoldsAndContactPoints();
pair->addContactManifold(potentialManifold);
potentialManifold = potentialManifold->mNext;
}
// Clear the obsolete contact manifolds and contact points
pair->clearObsoleteManifoldsAndContactPoints();
// Reduce the contact manifolds and contact points if there are too many of them
pair->reduceContactManifolds();
// Reset the potential contacts of the pair
pair->clearPotentialContactManifolds();
// Reduce the contact manifolds and contact points if there are too many of them
pair->reduceContactManifolds();
}
}
// Report contacts for all the colliding overlapping pairs
@ -474,13 +475,14 @@ void CollisionDetection::reportAllContacts() {
RP3D_PROFILE("CollisionDetection::reportAllContacts()", mProfiler);
// For each overlapping pairs in contact during the narrow-phase
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;
// If there is a user callback
if (mWorld->mEventListener != nullptr && it->second->hasContacts()) {
if (mWorld->mEventListener != nullptr && pair->hasContacts()) {
CollisionCallback::CollisionCallbackInfo collisionInfo(it->second, mMemoryManager);
CollisionCallback::CollisionCallbackInfo collisionInfo(pair, mMemoryManager);
// Trigger a callback event to report the new contact to the user
mWorld->mEventListener->newContact(collisionInfo);
@ -751,6 +753,10 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
assert(collisionCallback != nullptr);
List<NarrowPhaseInfo*> collidingNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
List<NarrowPhaseInfo*> allNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
OverlappingPairMap overlappingPairs(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the first body
ProxyShape* body1ProxyShape = body1->getProxyShapesList();
while (body1ProxyShape != nullptr) {
@ -766,16 +772,36 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
// Test if the AABBs of the two proxy shapes overlap
if (aabb1.testCollision(aabb2)) {
// Create a temporary overlapping pair
OverlappingPair pair(body1ProxyShape, body2ProxyShape, mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
OverlappingPair* pair;
const Pair<uint, uint> pairID = OverlappingPair::computeID(body1ProxyShape, body2ProxyShape);
// Try to retrieve a corresponding copy of the overlapping pair (if it exists)
auto itPair = overlappingPairs.find(pairID);
// If a copy of the overlapping pair does not exist yet
if (itPair == overlappingPairs.end()) {
// Create a temporary copy of the overlapping pair
pair = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(OverlappingPair)))
OverlappingPair(body1ProxyShape, body2ProxyShape, mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
overlappingPairs.add(Pair<Pair<uint, uint>, OverlappingPair*>(pairID, pair));
}
else { // If a temporary copy of this overlapping pair already exists
// Retrieve the existing copy of the overlapping pair
pair = itPair->second;
}
// Compute the middle-phase collision detection between the two shapes
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(pair);
// For each narrow-phase info object
while (narrowPhaseInfo != nullptr) {
allNarrowPhaseInfos.add(narrowPhaseInfo);
const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType();
const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType();
@ -790,30 +816,12 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true, mMemoryManager.getPoolAllocator())) {
// Add the contact points as a potential contact manifold into the pair
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
collidingNarrowPhaseInfos.add(narrowPhaseInfo);
}
}
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
narrowPhaseInfo = narrowPhaseInfo->next;
// Call the destructor
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory
mMemoryManager.release(MemoryManager::AllocationType::Pool, currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
// Process the potential contacts
processPotentialContacts(&pair);
if (pair.hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mMemoryManager);
collisionCallback->notifyContact(collisionInfo);
}
}
// Go to the next proxy shape
@ -823,6 +831,38 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
// Go to the next proxy shape
body1ProxyShape = body1ProxyShape->getNext();
}
// Process the potential contacts
processAllPotentialContacts(collidingNarrowPhaseInfos, overlappingPairs);
// For each overlapping pair
for (auto it = overlappingPairs.begin(); it != overlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;
if (pair->hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(pair, mMemoryManager);
collisionCallback->notifyContact(collisionInfo);
}
// Destroy the temporary overlapping pair
pair->~OverlappingPair();
mMemoryManager.release(MemoryManager::AllocationType::Pool, pair, sizeof(OverlappingPair));
}
// Destroy the narrow phase infos
for (auto it = allNarrowPhaseInfos.begin(); it != allNarrowPhaseInfos.end(); ++it) {
NarrowPhaseInfo* narrowPhaseInfo = *it;
// Call the destructor
narrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory for the narrow phase info
mMemoryManager.release(MemoryManager::AllocationType::Pool, narrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
}
// Test and report collisions between a body and all the others bodies of the world
@ -830,6 +870,10 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
assert(callback != nullptr);
List<NarrowPhaseInfo*> collidingNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
List<NarrowPhaseInfo*> allNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
OverlappingPairMap overlappingPairs(mMemoryManager.getPoolAllocator());
// For each proxy shape proxy shape of the body
ProxyShape* bodyProxyShape = body->getProxyShapesList();
while (bodyProxyShape != nullptr) {
@ -859,16 +903,36 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
// Check if the collision filtering allows collision between the two shapes
if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) {
// Create a temporary overlapping pair
OverlappingPair pair(bodyProxyShape, proxyShape, mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
OverlappingPair* pair;
const Pair<uint, uint> pairID = OverlappingPair::computeID(bodyProxyShape, proxyShape);
// Try to retrieve a corresponding copy of the overlapping pair (if it exists)
auto itPair = overlappingPairs.find(pairID);
// If a copy of the overlapping pair does not exist yet
if (itPair == overlappingPairs.end()) {
// Create a temporary overlapping pair
pair = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(OverlappingPair)))
OverlappingPair(bodyProxyShape, proxyShape, mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
overlappingPairs.add(Pair<Pair<uint, uint>, OverlappingPair*>(pairID, pair));
}
else { // If a temporary copy of this overlapping pair already exists
// Retrieve the existing copy of the overlapping pair
pair = itPair->second;
}
// Compute the middle-phase collision detection between the two shapes
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(pair);
// For each narrow-phase info object
while (narrowPhaseInfo != nullptr) {
allNarrowPhaseInfos.add(narrowPhaseInfo);
const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType();
const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType();
@ -883,29 +947,11 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true, mMemoryManager.getPoolAllocator())) {
// Add the contact points as a potential contact manifold into the pair
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
collidingNarrowPhaseInfos.add(narrowPhaseInfo);
}
}
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
narrowPhaseInfo = narrowPhaseInfo->next;
// Call the destructor
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory
mMemoryManager.release(MemoryManager::AllocationType::Pool, currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
// Process the potential contacts
processPotentialContacts(&pair);
if (pair.hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mMemoryManager);
callback->notifyContact(collisionInfo);
}
}
}
@ -918,6 +964,38 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
bodyProxyShape = bodyProxyShape->getNext();
}
}
// Process the potential contacts
processAllPotentialContacts(collidingNarrowPhaseInfos, overlappingPairs);
// For each overlapping pair
for (auto it = overlappingPairs.begin(); it != overlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;
if (pair->hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(pair, mMemoryManager);
callback->notifyContact(collisionInfo);
}
// Destroy the temporary overlapping pair
pair->~OverlappingPair();
mMemoryManager.release(MemoryManager::AllocationType::Pool, pair, sizeof(OverlappingPair));
}
// Destroy the narrow phase infos
for (auto it = allNarrowPhaseInfos.begin(); it != allNarrowPhaseInfos.end(); ++it) {
NarrowPhaseInfo* narrowPhaseInfo = *it;
// Call the destructor
narrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory for the narrow phase info
mMemoryManager.release(MemoryManager::AllocationType::Pool, narrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
}
// Test and report collisions between all shapes of the world
@ -928,18 +1006,39 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
// Compute the broad-phase collision detection
computeBroadPhase();
List<NarrowPhaseInfo*> collidingNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
List<NarrowPhaseInfo*> allNarrowPhaseInfos(mMemoryManager.getPoolAllocator());
OverlappingPairMap overlappingPairs(mMemoryManager.getPoolAllocator());
// For each possible collision pair of bodies
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
for (auto it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
OverlappingPair* originalPair = it->second;
// Create a new overlapping pair so that we do not work on the original one
OverlappingPair pair(originalPair->getShape1(), originalPair->getShape2(), mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
OverlappingPair* pair;
const Pair<uint, uint> pairID = OverlappingPair::computeID(originalPair->getShape1(), originalPair->getShape2());
ProxyShape* shape1 = pair.getShape1();
ProxyShape* shape2 = pair.getShape2();
// Try to retrieve a corresponding copy of the overlapping pair (if it exists)
auto itPair = overlappingPairs.find(pairID);
// If a copy of the overlapping pair does not exist yet
if (itPair == overlappingPairs.end()) {
// Create a temporary overlapping pair
pair = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(OverlappingPair)))
OverlappingPair(originalPair->getShape1(), originalPair->getShape2(), mMemoryManager.getPoolAllocator(),
mMemoryManager.getPoolAllocator(), mWorld->mConfig);
overlappingPairs.add(Pair<Pair<uint, uint>, OverlappingPair*>(pairID, pair));
}
else { // If a temporary copy of this overlapping pair already exists
// Retrieve the existing copy of the overlapping pair
pair = itPair->second;
}
ProxyShape* shape1 = pair->getShape1();
ProxyShape* shape2 = pair->getShape2();
// Check if the collision filtering allows collision between the two shapes and
// that the two shapes are still overlapping.
@ -948,11 +1047,13 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
// Compute the middle-phase collision detection between the two shapes
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(pair);
// For each narrow-phase info object
while (narrowPhaseInfo != nullptr) {
allNarrowPhaseInfos.add(narrowPhaseInfo);
const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType();
const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType();
@ -967,32 +1068,46 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true, mMemoryManager.getPoolAllocator())) {
// Add the contact points as a potential contact manifold into the pair
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
collidingNarrowPhaseInfos.add(narrowPhaseInfo);
}
}
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
narrowPhaseInfo = narrowPhaseInfo->next;
// Call the destructor
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory
mMemoryManager.release(MemoryManager::AllocationType::Pool, currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
// Process the potential contacts
processPotentialContacts(&pair);
if (pair.hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mMemoryManager);
callback->notifyContact(collisionInfo);
}
}
}
// Process the potential contacts
processAllPotentialContacts(collidingNarrowPhaseInfos, overlappingPairs);
// For each overlapping pair
for (auto it = overlappingPairs.begin(); it != overlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;
if (pair->hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(pair, mMemoryManager);
callback->notifyContact(collisionInfo);
}
// Destroy the temporary overlapping pair
pair->~OverlappingPair();
mMemoryManager.release(MemoryManager::AllocationType::Pool, pair, sizeof(OverlappingPair));
}
// Destroy the narrow phase infos
for (auto it = allNarrowPhaseInfos.begin(); it != allNarrowPhaseInfos.end(); ++it) {
NarrowPhaseInfo* narrowPhaseInfo = *it;
// Call the destructor
narrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory for the narrow phase info
mMemoryManager.release(MemoryManager::AllocationType::Pool, narrowPhaseInfo, sizeof(NarrowPhaseInfo));
}
}
// Fill-in the collision detection matrix

View File

@ -59,6 +59,8 @@ class CollisionDetection {
private :
using OverlappingPairMap = Map<Pair<uint, uint>, OverlappingPair*>;
// -------------------- Attributes -------------------- //
/// Memory manager
@ -80,7 +82,7 @@ class CollisionDetection {
NarrowPhaseInfo* mNarrowPhaseInfoList;
/// Broad-phase overlapping pairs
Map<Pair<uint, uint>, OverlappingPair*> mOverlappingPairs;
OverlappingPairMap mOverlappingPairs;
/// Broad-phase algorithm
BroadPhaseAlgorithm mBroadPhaseAlgorithm;
@ -131,17 +133,15 @@ class CollisionDetection {
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);
void processAllPotentialContacts(const List<NarrowPhaseInfo*>& narrowPhaseInfos,
const OverlappingPairMap& overlappingPairs);
/// 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 :
// -------------------- Methods -------------------- //

File diff suppressed because it is too large Load Diff

View File

@ -26,12 +26,11 @@
// Libraries
#include "ContactManifold.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifoldInfo.h"
using namespace reactphysics3d;
// Constructor
ContactManifold::ContactManifold(const ContactManifoldInfo* manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
ContactManifold::ContactManifold(ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& memoryAllocator, const WorldSettings& worldSettings)
: mShape1(shape1), mShape2(shape2), mContactPoints(nullptr),
mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0),
@ -39,18 +38,6 @@ ContactManifold::ContactManifold(const ContactManifoldInfo* manifoldInfo, ProxyS
mMemoryAllocator(memoryAllocator), mNext(nullptr), mPrevious(nullptr), mIsObsolete(false),
mWorldSettings(worldSettings) {
// For each contact point info in the manifold
const ContactPointInfo* pointInfo = manifoldInfo->getFirstContactPointInfo();
while(pointInfo != nullptr) {
// Add the new contact point
addContactPoint(pointInfo);
pointInfo = pointInfo->next;
}
assert(mNbContactPoints <= MAX_CONTACT_POINTS_IN_MANIFOLD);
assert(mNbContactPoints > 0);
}
// Destructor
@ -121,20 +108,45 @@ decimal ContactManifold::getLargestContactDepth() const {
// Add a contact point
void ContactManifold::addContactPoint(const ContactPointInfo* contactPointInfo) {
assert(contactPointInfo != nullptr);
// For each contact point in the manifold
bool isSimilarPointFound = false;
ContactPoint* oldContactPoint = mContactPoints;
while (oldContactPoint != nullptr) {
// Create the new contact point
ContactPoint* contactPoint = new (mMemoryAllocator.allocate(sizeof(ContactPoint))) ContactPoint(contactPointInfo, mWorldSettings);
assert(oldContactPoint != nullptr);
// Add the new contact point into the manifold
contactPoint->setNext(mContactPoints);
contactPoint->setPrevious(nullptr);
if (mContactPoints != nullptr) {
mContactPoints->setPrevious(contactPoint);
}
mContactPoints = contactPoint;
// If the new contact point is similar (very close) to the old contact point
if (oldContactPoint->isSimilarWithContactPoint(contactPointInfo)) {
mNbContactPoints++;
// Replace (update) the old contact point with the new one
oldContactPoint->update(contactPointInfo);
isSimilarPointFound = true;
break;
}
oldContactPoint = oldContactPoint->getNext();
}
// If we have not found a similar contact point
if (!isSimilarPointFound) {
// Create the new contact point
ContactPoint* contactPoint = new (mMemoryAllocator.allocate(sizeof(ContactPoint))) ContactPoint(contactPointInfo, mWorldSettings);
// Add the new contact point into the manifold
contactPoint->setNext(mContactPoints);
contactPoint->setPrevious(nullptr);
if (mContactPoints != nullptr) {
mContactPoints->setPrevious(contactPoint);
}
mContactPoints = contactPoint;
mNbContactPoints++;
}
// The old manifold is no longer obsolete
mIsObsolete = false;
}
// Set to true to make the manifold obsolete
@ -176,49 +188,202 @@ void ContactManifold::clearObsoleteContactPoints() {
assert(mContactPoints != nullptr);
}
// Make sure we do not have too much contact points by keeping only the best
// contact points of the manifold (with largest penetration depth)
void ContactManifold::reduce() {
// Reduce the number of contact points of the currently computed manifold
// This is based on the technique described by Dirk Gregorius in his
// "Contacts Creation" GDC presentation. This method will reduce the number of
// contact points to a maximum of 4 points (but it can be less).
void ContactManifold::reduce(const Transform& shape1ToWorldTransform) {
assert(mContactPoints != nullptr);
// Remove contact points while there is too much contact points
while (mNbContactPoints > MAX_CONTACT_POINTS_IN_MANIFOLD) {
removeNonOptimalContactPoint();
}
// The following algorithm only works to reduce to a maximum of 4 contact points
assert(MAX_CONTACT_POINTS_IN_MANIFOLD == 4);
assert(mNbContactPoints <= MAX_CONTACT_POINTS_IN_MANIFOLD && mNbContactPoints > 0);
assert(mContactPoints != nullptr);
}
// If there are too many contact points in the manifold
if (mNbContactPoints > MAX_CONTACT_POINTS_IN_MANIFOLD) {
// Remove a contact point that is not optimal (with a small penetration depth)
void ContactManifold::removeNonOptimalContactPoint() {
uint nbReducedPoints = 0;
assert(mContactPoints != nullptr);
assert(mNbContactPoints > MAX_CONTACT_POINTS_IN_MANIFOLD);
// Get the contact point with the minimum penetration depth among all points
ContactPoint* contactPoint = mContactPoints;
ContactPoint* minContactPoint = nullptr;
decimal minPenetrationDepth = DECIMAL_LARGEST;
while (contactPoint != nullptr) {
ContactPoint* nextContactPoint = contactPoint->getNext();
if (contactPoint->getPenetrationDepth() < minPenetrationDepth) {
minContactPoint = contactPoint;
minPenetrationDepth = contactPoint->getPenetrationDepth();
ContactPoint* pointsToKeep[MAX_CONTACT_POINTS_IN_MANIFOLD];
for (int i=0; i<MAX_CONTACT_POINTS_IN_MANIFOLD; i++) {
pointsToKeep[i] = nullptr;
}
contactPoint = nextContactPoint;
// Compute the initial contact point we need to keep.
// The first point we keep is always the point in a given
// constant direction (in order to always have same contact points
// between frames for better stability)
const Transform worldToShape1Transform = shape1ToWorldTransform.getInverse();
// Compute the contact normal of the manifold (we use the first contact point)
// in the local-space of the first collision shape
const Vector3 contactNormalShape1Space = worldToShape1Transform.getOrientation() * mContactPoints->getNormal();
// Compute a search direction
const Vector3 searchDirection(1, 1, 1);
ContactPoint* element = mContactPoints;
pointsToKeep[0] = element;
decimal maxDotProduct = searchDirection.dot(element->getLocalPointOnShape1());
element = element->getNext();
nbReducedPoints = 1;
while(element != nullptr) {
decimal dotProduct = searchDirection.dot(element->getLocalPointOnShape1());
if (dotProduct > maxDotProduct) {
maxDotProduct = dotProduct;
pointsToKeep[0] = element;
}
element = element->getNext();
}
assert(pointsToKeep[0] != nullptr);
assert(nbReducedPoints == 1);
// Compute the second contact point we need to keep.
// The second point we keep is the one farthest away from the first point.
decimal maxDistance = decimal(0.0);
element = mContactPoints;
while(element != nullptr) {
if (element == pointsToKeep[0]) {
element = element->getNext();
continue;
}
decimal distance = (pointsToKeep[0]->getLocalPointOnShape1() - element->getLocalPointOnShape1()).lengthSquare();
if (distance >= maxDistance) {
maxDistance = distance;
pointsToKeep[1] = element;
nbReducedPoints = 2;
}
element = element->getNext();
}
assert(pointsToKeep[1] != nullptr);
assert(nbReducedPoints == 2);
// Compute the third contact point we need to keep.
// The second point is the one producing the triangle with the larger area
// with first and second point.
// We compute the most positive or most negative triangle area (depending on winding)
ContactPoint* thirdPointMaxArea = nullptr;
ContactPoint* thirdPointMinArea = nullptr;
decimal minArea = decimal(0.0);
decimal maxArea = decimal(0.0);
bool isPreviousAreaPositive = true;
element = mContactPoints;
while(element != nullptr) {
if (element == pointsToKeep[0] || element == pointsToKeep[1]) {
element = element->getNext();
continue;
}
const Vector3 newToFirst = pointsToKeep[0]->getLocalPointOnShape1() - element->getLocalPointOnShape1();
const Vector3 newToSecond = pointsToKeep[1]->getLocalPointOnShape1() - element->getLocalPointOnShape1();
// Compute the triangle area
decimal area = newToFirst.cross(newToSecond).dot(contactNormalShape1Space);
if (area >= maxArea) {
maxArea = area;
thirdPointMaxArea = element;
}
if (area <= minArea) {
minArea = area;
thirdPointMinArea = element;
}
element = element->getNext();
}
assert(minArea <= decimal(0.0));
assert(maxArea >= decimal(0.0));
if (maxArea > (-minArea)) {
isPreviousAreaPositive = true;
pointsToKeep[2] = thirdPointMaxArea;
nbReducedPoints = 3;
}
else {
isPreviousAreaPositive = false;
pointsToKeep[2] = thirdPointMinArea;
nbReducedPoints = 3;
}
// Compute the 4th point by choosing the triangle that add the most
// triangle area to the previous triangle and has opposite sign area (opposite winding)
decimal largestArea = decimal(0.0); // Largest area (positive or negative)
element = mContactPoints;
if (nbReducedPoints == 3) {
// For each remaining point
while(element != nullptr) {
if (element == pointsToKeep[0] || element == pointsToKeep[1] || element == pointsToKeep[2]) {
element = element->getNext();
continue;
}
// For each edge of the triangle made by the first three points
for (uint i=0; i<3; i++) {
uint edgeVertex1Index = i;
uint edgeVertex2Index = i < 2 ? i + 1 : 0;
const Vector3 newToFirst = pointsToKeep[edgeVertex1Index]->getLocalPointOnShape1() - element->getLocalPointOnShape1();
const Vector3 newToSecond = pointsToKeep[edgeVertex2Index]->getLocalPointOnShape1() - element->getLocalPointOnShape1();
// Compute the triangle area
decimal area = newToFirst.cross(newToSecond).dot(contactNormalShape1Space);
// We are looking at the triangle with maximal area (positive or negative).
// If the previous area is positive, we are looking at negative area now.
// If the previous area is negative, we are looking at the positive area now.
if (isPreviousAreaPositive && area <= largestArea) {
largestArea = area;
pointsToKeep[3] = element;
nbReducedPoints = 4;
}
else if (!isPreviousAreaPositive && area >= largestArea) {
largestArea = area;
pointsToKeep[3] = element;
nbReducedPoints = 4;
}
}
element = element->getNext();
}
}
// Delete the contact points we do not want to keep from the linked list
element = mContactPoints;
ContactPoint* previousElement = nullptr;
while(element != nullptr) {
bool deletePoint = true;
// Skip the points we want to keep
for (uint i=0; i<nbReducedPoints; i++) {
if (element == pointsToKeep[i]) {
previousElement = element;
element = element->getNext();
deletePoint = false;
}
}
if (deletePoint) {
ContactPoint* contactPointToDelete = element;
element = element->getNext();
removeContactPoint(contactPointToDelete);
}
}
assert(nbReducedPoints > 0 && nbReducedPoints <= 4);
mNbContactPoints = nbReducedPoints;
}
assert(minContactPoint != nullptr);
// Remove the non optimal contact point
removeContactPoint(minContactPoint);
assert(mNbContactPoints > 0);
assert(mContactPoints != nullptr);
}

View File

@ -93,6 +93,11 @@ class ContactManifold {
private:
// -------------------- Constants -------------------- //
/// Maximum number of contact points in a reduced contact manifold
const int MAX_CONTACT_POINTS_IN_MANIFOLD = 4;
// -------------------- Attributes -------------------- //
/// Pointer to the first proxy shape of the contact
@ -181,11 +186,8 @@ class ContactManifold {
/// Add a contact point
void addContactPoint(const ContactPointInfo* contactPointInfo);
/// Make sure we do not have too much contact points by keeping only the best ones
void reduce();
/// Remove a contact point that is not optimal (with a small penetration depth)
void removeNonOptimalContactPoint();
/// Reduce the number of contact points of the currently computed manifold
void reduce(const Transform& shape1ToWorldTransform);
/// Remove a contact point
void removeContactPoint(ContactPoint* contactPoint);
@ -219,8 +221,8 @@ class ContactManifold {
// -------------------- Methods -------------------- //
/// Constructor
ContactManifold(const ContactManifoldInfo* manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& memoryAllocator, const WorldSettings& worldSettings);
ContactManifold(ProxyShape* shape1, ProxyShape* shape2, MemoryAllocator& memoryAllocator,
const WorldSettings& worldSettings);
/// Destructor
~ContactManifold();

View File

@ -1,305 +0,0 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2018 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 "ContactManifoldInfo.h"
#include "collision/ContactPointInfo.h"
using namespace reactphysics3d;
// Constructor
ContactManifoldInfo::ContactManifoldInfo(MemoryAllocator& allocator)
: mContactPointsList(nullptr), mNbContactPoints(0), mNext(nullptr), mAllocator(allocator) {
}
// Destructor
ContactManifoldInfo::~ContactManifoldInfo() {
// Remove all the contact points
reset();
}
// Add a new contact point into the manifold
void ContactManifoldInfo::addContactPoint(ContactPointInfo* contactPointInfo) {
assert(contactPointInfo->penetrationDepth > decimal(0.0));
// Add it into the linked list of contact points
contactPointInfo->next = mContactPointsList;
mContactPointsList = contactPointInfo;
mNbContactPoints++;
}
// Remove all the contact points
void ContactManifoldInfo::reset() {
// Delete all the contact points in the linked list
ContactPointInfo* element = mContactPointsList;
while(element != nullptr) {
ContactPointInfo* elementToDelete = element;
element = element->next;
// Call the constructor
elementToDelete->~ContactPointInfo();
// Delete the current element
mAllocator.release(elementToDelete, sizeof(ContactPointInfo));
}
mContactPointsList = nullptr;
mNbContactPoints = 0;
}
// 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
// "Contacts Creation" GDC presentation. This method will reduce the number of
// contact points to a maximum of 4 points (but it can be less).
void ContactManifoldInfo::reduce(const Transform& shape1ToWorldTransform) {
assert(mContactPointsList != nullptr);
// The following algorithm only works to reduce to a maximum of 4 contact points
assert(MAX_CONTACT_POINTS_IN_MANIFOLD == 4);
// If there are too many contact points in the manifold
if (mNbContactPoints > MAX_CONTACT_POINTS_IN_MANIFOLD) {
uint nbReducedPoints = 0;
ContactPointInfo* pointsToKeep[MAX_CONTACT_POINTS_IN_MANIFOLD];
for (int i=0; i<MAX_CONTACT_POINTS_IN_MANIFOLD; i++) {
pointsToKeep[i] = nullptr;
}
// Compute the initial contact point we need to keep.
// The first point we keep is always the point in a given
// constant direction (in order to always have same contact points
// between frames for better stability)
const Transform worldToShape1Transform = shape1ToWorldTransform.getInverse();
// Compute the contact normal of the manifold (we use the first contact point)
// in the local-space of the first collision shape
const Vector3 contactNormalShape1Space = worldToShape1Transform.getOrientation() * mContactPointsList->normal;
// Compute a search direction
const Vector3 searchDirection(1, 1, 1);
ContactPointInfo* element = mContactPointsList;
pointsToKeep[0] = element;
decimal maxDotProduct = searchDirection.dot(element->localPoint1);
element = element->next;
nbReducedPoints = 1;
while(element != nullptr) {
decimal dotProduct = searchDirection.dot(element->localPoint1);
if (dotProduct > maxDotProduct) {
maxDotProduct = dotProduct;
pointsToKeep[0] = element;
}
element = element->next;
}
assert(pointsToKeep[0] != nullptr);
assert(nbReducedPoints == 1);
// Compute the second contact point we need to keep.
// The second point we keep is the one farthest away from the first point.
decimal maxDistance = decimal(0.0);
element = mContactPointsList;
while(element != nullptr) {
if (element == pointsToKeep[0]) {
element = element->next;
continue;
}
decimal distance = (pointsToKeep[0]->localPoint1 - element->localPoint1).lengthSquare();
if (distance >= maxDistance) {
maxDistance = distance;
pointsToKeep[1] = element;
nbReducedPoints = 2;
}
element = element->next;
}
assert(pointsToKeep[1] != nullptr);
assert(nbReducedPoints == 2);
// Compute the third contact point we need to keep.
// The second point is the one producing the triangle with the larger area
// with first and second point.
// We compute the most positive or most negative triangle area (depending on winding)
ContactPointInfo* thirdPointMaxArea = nullptr;
ContactPointInfo* thirdPointMinArea = nullptr;
decimal minArea = decimal(0.0);
decimal maxArea = decimal(0.0);
bool isPreviousAreaPositive = true;
element = mContactPointsList;
while(element != nullptr) {
if (element == pointsToKeep[0] || element == pointsToKeep[1]) {
element = element->next;
continue;
}
const Vector3 newToFirst = pointsToKeep[0]->localPoint1 - element->localPoint1;
const Vector3 newToSecond = pointsToKeep[1]->localPoint1 - element->localPoint1;
// Compute the triangle area
decimal area = newToFirst.cross(newToSecond).dot(contactNormalShape1Space);
if (area >= maxArea) {
maxArea = area;
thirdPointMaxArea = element;
}
if (area <= minArea) {
minArea = area;
thirdPointMinArea = element;
}
element = element->next;
}
assert(minArea <= decimal(0.0));
assert(maxArea >= decimal(0.0));
if (maxArea > (-minArea)) {
isPreviousAreaPositive = true;
pointsToKeep[2] = thirdPointMaxArea;
nbReducedPoints = 3;
}
else {
isPreviousAreaPositive = false;
pointsToKeep[2] = thirdPointMinArea;
nbReducedPoints = 3;
}
// Compute the 4th point by choosing the triangle that add the most
// triangle area to the previous triangle and has opposite sign area (opposite winding)
decimal largestArea = decimal(0.0); // Largest area (positive or negative)
element = mContactPointsList;
if (nbReducedPoints == 3) {
// For each remaining point
while(element != nullptr) {
if (element == pointsToKeep[0] || element == pointsToKeep[1] || element == pointsToKeep[2]) {
element = element->next;
continue;
}
// For each edge of the triangle made by the first three points
for (uint i=0; i<3; i++) {
uint edgeVertex1Index = i;
uint edgeVertex2Index = i < 2 ? i + 1 : 0;
const Vector3 newToFirst = pointsToKeep[edgeVertex1Index]->localPoint1 - element->localPoint1;
const Vector3 newToSecond = pointsToKeep[edgeVertex2Index]->localPoint1 - element->localPoint1;
// Compute the triangle area
decimal area = newToFirst.cross(newToSecond).dot(contactNormalShape1Space);
// We are looking at the triangle with maximal area (positive or negative).
// If the previous area is positive, we are looking at negative area now.
// If the previous area is negative, we are looking at the positive area now.
if (isPreviousAreaPositive && area <= largestArea) {
largestArea = area;
pointsToKeep[3] = element;
nbReducedPoints = 4;
}
else if (!isPreviousAreaPositive && area >= largestArea) {
largestArea = area;
pointsToKeep[3] = element;
nbReducedPoints = 4;
}
}
element = element->next;
}
}
// Delete the contact points we do not want to keep from the linked list
element = mContactPointsList;
ContactPointInfo* previousElement = nullptr;
while(element != nullptr) {
bool deletePoint = true;
// Skip the points we want to keep
for (uint i=0; i<nbReducedPoints; i++) {
if (element == pointsToKeep[i]) {
previousElement = element;
element = element->next;
deletePoint = false;
}
}
if (deletePoint) {
ContactPointInfo* elementToDelete = element;
if (previousElement != nullptr) {
previousElement->next = elementToDelete->next;
}
else {
mContactPointsList = elementToDelete->next;
}
element = element->next;
// Call the destructor
elementToDelete->~ContactPointInfo();
// Delete the current element
mAllocator.release(elementToDelete, sizeof(ContactPointInfo));
}
}
assert(nbReducedPoints > 0 && nbReducedPoints <= 4);
mNbContactPoints = nbReducedPoints;
}
}

View File

@ -1,117 +0,0 @@
/********************************************************************************
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
* Copyright (c) 2010-2018 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_CONTACT_MANIFOLD_INFO_H
#define REACTPHYSICS3D_CONTACT_MANIFOLD_INFO_H
// Libraries
#include "configuration.h"
/// ReactPhysics3D namespace
namespace reactphysics3d {
// Declarations
class MemoryAllocator;
struct ContactPointInfo;
class Transform;
// Constants
const int8 MAX_CONTACT_POINTS_IN_MANIFOLD = 4; // Maximum number of contacts in the manifold
// Class ContactManifoldInfo
/**
* This class is used to collect the list of ContactPointInfo that come
* from a collision test between two shapes.
*/
class ContactManifoldInfo {
private:
// -------------------- Attributes -------------------- //
/// Linked list with all the contact points
ContactPointInfo* mContactPointsList;
/// Number of contact points in the manifold
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
MemoryAllocator& mAllocator;
public:
// -------------------- Methods -------------------- //
/// Constructor
ContactManifoldInfo(MemoryAllocator& allocator);
/// Destructor
~ContactManifoldInfo();
/// Deleted Copy-constructor
ContactManifoldInfo(const ContactManifoldInfo& contactManifold) = delete;
/// Deleted assignment operator
ContactManifoldInfo& operator=(const ContactManifoldInfo& contactManifold) = delete;
/// Add a new contact point into the manifold
void addContactPoint(ContactPointInfo* contactPointInfo);
/// Remove all the contact points
void reset();
/// Get the first contact point info of the linked list of contact points
ContactPointInfo* getFirstContactPointInfo() const;
/// 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();
/// Reduce the number of contact points of the currently computed manifold
void reduce(const Transform& shape1ToWorldTransform);
// Friendship
friend class OverlappingPair;
friend class CollisionDetection;
};
// Get the first contact point info of the linked list of contact points
inline ContactPointInfo* ContactManifoldInfo::getFirstContactPointInfo() const {
return mContactPointsList;
}
// Return the pointer to the next manifold info in the linked-list
inline ContactManifoldInfo* ContactManifoldInfo::getNext() {
return mNext;
}
}
#endif

View File

@ -25,8 +25,8 @@
// Libraries
#include "ContactManifoldSet.h"
#include "NarrowPhaseInfo.h"
#include "constraint/ContactPoint.h"
#include "collision/ContactManifoldInfo.h"
#include "ProxyShape.h"
#include "collision/ContactManifold.h"
@ -49,24 +49,56 @@ ContactManifoldSet::~ContactManifoldSet() {
clear();
}
void ContactManifoldSet::addContactManifold(const ContactManifoldInfo* contactManifoldInfo) {
void ContactManifoldSet::addContactPoints(NarrowPhaseInfo* narrowPhaseInfo) {
assert(contactManifoldInfo->getFirstContactPointInfo() != nullptr);
assert(narrowPhaseInfo->contactPoints != nullptr);
// Try to find an existing contact manifold with similar contact normal
ContactManifold* similarManifold = selectManifoldWithSimilarNormal(contactManifoldInfo);
// For each potential contact point to add
ContactPointInfo* contactPoint = narrowPhaseInfo->contactPoints;
while (contactPoint != nullptr) {
// If a similar manifold has been found
if (similarManifold != nullptr) {
// 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)
ContactManifold* manifold = mManifolds;
bool similarManifoldFound = false;
while(manifold != nullptr) {
// Update the old manifold with the new one
updateManifoldWithNewOne(similarManifold, contactManifoldInfo);
// Get the first contact point
const ContactPoint* point = manifold->getContactPoints();
assert(point != nullptr);
// If we have found a corresponding manifold for the new contact point
// (a manifold with a similar contact normal direction)
if (point->getNormal().dot(contactPoint->normal) >= mWorldSettings.cosAngleSimilarContactManifold) {
// Add the contact point to the manifold
manifold->addContactPoint(contactPoint);
similarManifoldFound = true;
break;
}
manifold = manifold->getNext();
}
// If we have not found an existing manifold with a similar contact normal
if (!similarManifoldFound) {
// Create a new contact manifold
ContactManifold* manifold = createManifold();
// Add the contact point to the manifold
manifold->addContactPoint(contactPoint);
}
contactPoint = contactPoint->next;
}
else {
// Create a new contact manifold
createManifold(contactManifoldInfo);
}
// All the contact point info of the narrow-phase info have been moved
// into the potential contacts of the overlapping pair. We can now
// remove the contacts points from the narrow phase info object.
narrowPhaseInfo->resetContactPoints();
}
// Return the total number of contact points in the set of manifolds
@ -96,51 +128,6 @@ int ContactManifoldSet::computeNbMaxContactManifolds(const CollisionShape* shape
}
}
// Update a previous similar manifold with a new one
void ContactManifoldSet::updateManifoldWithNewOne(ContactManifold* oldManifold, const ContactManifoldInfo* newManifold) {
assert(oldManifold != nullptr);
assert(newManifold != nullptr);
// For each contact point of the new manifold
ContactPointInfo* contactPointInfo = newManifold->getFirstContactPointInfo();
assert(contactPointInfo != nullptr);
while (contactPointInfo != nullptr) {
// For each contact point in the old manifold
bool isSimilarPointFound = false;
ContactPoint* oldContactPoint = oldManifold->getContactPoints();
while (oldContactPoint != nullptr) {
assert(oldContactPoint != nullptr);
// If the new contact point is similar (very close) to the old contact point
if (oldContactPoint->isSimilarWithContactPoint(contactPointInfo)) {
// Replace (update) the old contact point with the new one
oldContactPoint->update(contactPointInfo);
isSimilarPointFound = true;
break;
}
oldContactPoint = oldContactPoint->getNext();
}
// If we have not found a similar contact point
if (!isSimilarPointFound) {
// Add the contact point to the manifold
oldManifold->addContactPoint(contactPointInfo);
}
contactPointInfo = contactPointInfo->next;
}
// The old manifold is no longer obsolete
oldManifold->setIsObsolete(false, false);
}
// Remove a contact manifold that is the least optimal (smaller penetration depth)
void ContactManifoldSet::removeNonOptimalManifold() {
@ -171,13 +158,26 @@ void ContactManifoldSet::removeNonOptimalManifold() {
removeManifold(minDepthManifold);
}
// Create a new contact manifold and add it to the set
ContactManifold* ContactManifoldSet::createManifold() {
ContactManifold* manifold = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
ContactManifold(mShape1, mShape2, mMemoryAllocator, mWorldSettings);
manifold->setPrevious(nullptr);
manifold->setNext(mManifolds);
if (mManifolds != nullptr) {
mManifolds->setPrevious(manifold);
}
mManifolds = manifold;
mNbManifolds++;
return manifold;
}
// Return the contact manifold with a similar contact normal.
// If no manifold has close enough contact normal, it returns nullptr
ContactManifold* ContactManifoldSet::selectManifoldWithSimilarNormal(const ContactManifoldInfo* contactManifold) const {
// Get the contact normal of the first point of the manifold
const ContactPointInfo* contactPoint = contactManifold->getFirstContactPointInfo();
assert(contactPoint != nullptr);
ContactManifold* ContactManifoldSet::selectManifoldWithSimilarNormal(const Vector3& contactNormal) const {
ContactManifold* manifold = mManifolds;
@ -189,7 +189,7 @@ ContactManifold* ContactManifoldSet::selectManifoldWithSimilarNormal(const Conta
assert(point != nullptr);
// If the contact normal of the two manifolds are close enough
if (contactPoint->normal.dot(point->getNormal()) >= mWorldSettings.cosAngleSimilarContactManifold) {
if (contactNormal.dot(point->getNormal()) >= mWorldSettings.cosAngleSimilarContactManifold) {
return manifold;
}
@ -216,24 +216,11 @@ void ContactManifoldSet::clear() {
mNbManifolds--;
}
mManifolds = nullptr;
assert(mNbManifolds == 0);
}
// Create a new contact manifold and add it to the set
void ContactManifoldSet::createManifold(const ContactManifoldInfo* manifoldInfo) {
ContactManifold* manifold = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
ContactManifold(manifoldInfo, mShape1, mShape2, mMemoryAllocator, mWorldSettings);
manifold->setPrevious(nullptr);
manifold->setNext(mManifolds);
if (mManifolds != nullptr) {
mManifolds->setPrevious(manifold);
}
mManifolds = manifold;
mNbManifolds++;
}
// Remove a contact manifold from the set
void ContactManifoldSet::removeManifold(ContactManifold* manifold) {
@ -309,7 +296,7 @@ void ContactManifoldSet::reduce() {
// Reduce all the contact manifolds in case they have too many contact points
ContactManifold* manifold = mManifolds;
while (manifold != nullptr) {
manifold->reduce();
manifold->reduce(mShape1->getLocalToWorldTransform());
manifold = manifold->getNext();
}
}

View File

@ -34,7 +34,11 @@ class ContactManifoldInfo;
class ProxyShape;
class MemoryAllocator;
struct WorldSettings;
struct NarrowPhaseInfo;
struct Vector3;
class CollisionShape;
class Transform;
// Constants
const int MAX_MANIFOLDS_IN_CONTACT_MANIFOLD_SET = 3; // Maximum number of contact manifolds in the set
@ -77,17 +81,14 @@ class ContactManifoldSet {
// -------------------- Methods -------------------- //
/// Create a new contact manifold and add it to the set
void createManifold(const ContactManifoldInfo* manifoldInfo);
ContactManifold* createManifold();
// Return the contact manifold with a similar contact normal.
ContactManifold* selectManifoldWithSimilarNormal(const ContactManifoldInfo* contactManifold) const;
ContactManifold* selectManifoldWithSimilarNormal(const Vector3& contactNormal) const;
/// Remove a contact manifold that is the least optimal (smaller penetration depth)
void removeNonOptimalManifold();
/// Update a previous similar manifold with a new one
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);
@ -108,8 +109,8 @@ class ContactManifoldSet {
/// Destructor
~ContactManifoldSet();
/// Add a contact manifold in the set
void addContactManifold(const ContactManifoldInfo* contactManifoldInfo);
/// Add the contact points from the narrow phase
void addContactPoints(NarrowPhaseInfo* narrowPhaseInfo);
/// Return the first proxy shape
ProxyShape* getShape1() const;

View File

@ -78,12 +78,6 @@ void NarrowPhaseInfo::addContactPoint(const Vector3& contactNormal, decimal penD
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() {

View File

@ -83,9 +83,6 @@ struct NarrowPhaseInfo {
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();

View File

@ -42,7 +42,7 @@ namespace reactphysics3d {
* This class represents a simple generic set. This set is implemented
* with a hash table.
*/
template<typename V>
template<typename V, class Hash = std::hash<V>, class KeyEqual = std::equal_to<V>>
class Set {
private:
@ -94,6 +94,12 @@ class Set {
// -------------------- Attributes -------------------- //
/// Object with hash operator
const Hash mHash;
/// Object with equality operator
const KeyEqual mEqual;
/// Current number of used entries in the set
int mNbUsedEntries;
@ -206,11 +212,11 @@ class Set {
if (mCapacity > 0) {
size_t hashCode = std::hash<V>()(value);
size_t hashCode = mHash(value);
int bucket = hashCode % mCapacity;
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
if (mEntries[i].hashCode == hashCode && (*mEntries[i].value) == value) {
if (mEntries[i].hashCode == hashCode && mEqual(*mEntries[i].value, value)) {
return i;
}
}
@ -373,8 +379,9 @@ class Set {
// -------------------- Methods -------------------- //
/// Constructor
Set(MemoryAllocator& allocator, size_t capacity = 0)
: mNbUsedEntries(0), mNbFreeEntries(0), mCapacity(0), mBuckets(nullptr),
Set(MemoryAllocator& allocator, size_t capacity = 0, const Hash& hash = Hash(),
const KeyEqual& equal = KeyEqual())
: mHash(hash), mEqual(equal), mNbUsedEntries(0), mNbFreeEntries(0), mCapacity(0), mBuckets(nullptr),
mEntries(nullptr), mAllocator(allocator), mFreeIndex(-1) {
// If the largest prime has not been computed yet
@ -391,8 +398,8 @@ class Set {
}
/// Copy constructor
Set(const Set<V>& set)
:mNbUsedEntries(set.mNbUsedEntries), mNbFreeEntries(set.mNbFreeEntries), mCapacity(set.mCapacity),
Set(const Set<V, Hash, KeyEqual>& set)
:mHash(set.mHash), mEqual(set.mEqual), mNbUsedEntries(set.mNbUsedEntries), mNbFreeEntries(set.mNbFreeEntries), mCapacity(set.mCapacity),
mBuckets(nullptr), mEntries(nullptr), mAllocator(set.mAllocator), mFreeIndex(set.mFreeIndex) {
if (mCapacity > 0) {
@ -445,15 +452,16 @@ class Set {
return findEntry(value) != -1;
}
/// Add a value into the set
void add(const V& value) {
/// Add a value into the set.
/// Returns true if the item has been inserted and false otherwise.
bool add(const V& value) {
if (mCapacity == 0) {
initialize(0);
}
// Compute the hash code of the value
size_t hashCode = std::hash<V>()(value);
size_t hashCode = mHash(value);
// Compute the corresponding bucket index
int bucket = hashCode % mCapacity;
@ -462,9 +470,9 @@ class Set {
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
// If there is already an item with the same value in the set
if (mEntries[i].hashCode == hashCode && (*mEntries[i].value) == value) {
if (mEntries[i].hashCode == hashCode && mEqual(*mEntries[i].value, value)) {
return;
return false;
}
}
@ -500,6 +508,8 @@ class Set {
assert(mEntries[entryIndex].value != nullptr);
new (mEntries[entryIndex].value) V(value);
mBuckets[bucket] = entryIndex;
return true;
}
/// Remove the element pointed by some iterator
@ -517,12 +527,12 @@ class Set {
if (mCapacity > 0) {
size_t hashcode = std::hash<V>()(value);
size_t hashcode = mHash(value);
int bucket = hashcode % mCapacity;
int last = -1;
for (int i = mBuckets[bucket]; i >= 0; last = i, i = mEntries[i].next) {
if (mEntries[i].hashCode == hashcode && (*mEntries[i].value) == value) {
if (mEntries[i].hashCode == hashcode && mEqual(*mEntries[i].value, value)) {
if (last < 0 ) {
mBuckets[bucket] = mEntries[i].next;
@ -604,11 +614,11 @@ class Set {
if (mCapacity > 0) {
size_t hashCode = std::hash<V>()(value);
size_t hashCode = mHash(value);
bucket = hashCode % mCapacity;
for (int i = mBuckets[bucket]; i >= 0; i = mEntries[i].next) {
if (mEntries[i].hashCode == hashCode && *(mEntries[i].value) == value) {
if (mEntries[i].hashCode == hashCode && mEqual(*(mEntries[i].value), value)) {
entry = i;
break;
}
@ -715,15 +725,15 @@ class Set {
}
};
template<typename V>
const int Set<V>::PRIMES[NB_PRIMES] = {3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
template<typename V, class Hash, class KeyEqual>
const int Set<V, Hash, KeyEqual>::PRIMES[NB_PRIMES] = {3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559};
template<typename V>
int Set<V>::LARGEST_PRIME = -1;
template<typename V, class Hash, class KeyEqual>
int Set<V, Hash, KeyEqual>::LARGEST_PRIME = -1;
}

View File

@ -894,8 +894,7 @@ List<const ContactManifold*> DynamicsWorld::getContactsList() {
List<const ContactManifold*> contactManifolds(mMemoryManager.getPoolAllocator());
// For each currently overlapping pair of bodies
Map<Pair<uint, uint>, OverlappingPair*>::Iterator it;
for (it = mCollisionDetection.mOverlappingPairs.begin();
for (auto it = mCollisionDetection.mOverlappingPairs.begin();
it != mCollisionDetection.mOverlappingPairs.end(); ++it) {
OverlappingPair* pair = it->second;

View File

@ -26,7 +26,6 @@
// Libraries
#include <cassert>
#include "OverlappingPair.h"
#include "collision/ContactManifoldInfo.h"
#include "collision/NarrowPhaseInfo.h"
#include "containers/containers_common.h"
#include "collision/ContactPointInfo.h"
@ -37,7 +36,7 @@ using namespace reactphysics3d;
OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
MemoryAllocator& persistentMemoryAllocator, MemoryAllocator& temporaryMemoryAllocator,
const WorldSettings& worldSettings)
: mContactManifoldSet(shape1, shape2, persistentMemoryAllocator, worldSettings), mPotentialContactManifolds(nullptr),
: mPairID(computeID(shape1, shape2)), mContactManifoldSet(shape1, shape2, persistentMemoryAllocator, worldSettings),
mPersistentAllocator(persistentMemoryAllocator), mTempMemoryAllocator(temporaryMemoryAllocator),
mLastFrameCollisionInfos(mPersistentAllocator), mWorldSettings(worldSettings) {
@ -45,7 +44,6 @@ OverlappingPair::OverlappingPair(ProxyShape* shape1, ProxyShape* shape2,
// Destructor
OverlappingPair::~OverlappingPair() {
assert(mPotentialContactManifolds == nullptr);
// Remove all the remaining last frame collision info
for (auto it = mLastFrameCollisionInfos.begin(); it != mLastFrameCollisionInfos.end(); ++it) {
@ -58,98 +56,6 @@ OverlappingPair::~OverlappingPair() {
}
}
// 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;
// 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) {
// Get the first contact point
const ContactPointInfo* point = manifold->getFirstContactPointInfo();
assert(point != nullptr);
// If we have found a corresponding manifold for the new contact point
// (a manifold with a similar contact normal direction)
if (point->normal.dot(contactPoint->normal) >= mWorldSettings.cosAngleSimilarContactManifold) {
// Add the contact point to the manifold
manifold->addContactPoint(contactPoint);
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);
}
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() {
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();
}
}
// Add a new last frame collision info if it does not exist for the given shapes already
void OverlappingPair::addLastFrameInfoIfNecessary(uint shapeId1, uint shapeId2) {

View File

@ -32,6 +32,7 @@
#include "containers/Map.h"
#include "containers/Pair.h"
#include "containers/containers_common.h"
#include <cstddef>
/// ReactPhysics3D namespace
namespace reactphysics3d {
@ -106,12 +107,12 @@ class OverlappingPair {
// -------------------- Attributes -------------------- //
/// Pair ID
OverlappingPairId mPairID;
/// Set of persistent contact manifolds
ContactManifoldSet mContactManifoldSet;
/// Linked-list of potential contact manifold
ContactManifoldInfo* mPotentialContactManifolds;
/// Persistent memory allocator
MemoryAllocator& mPersistentAllocator;
@ -144,7 +145,7 @@ class OverlappingPair {
/// Deleted assignment operator
OverlappingPair& operator=(const OverlappingPair& pair) = delete;
/// Return the pointer to first proxy collision shape
ProxyShape* getShape1() const;
@ -157,15 +158,9 @@ class OverlappingPair {
/// Return the a reference to the contact manifold set
const ContactManifoldSet& getContactManifoldSet();
/// Clear all the potential contact manifolds
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
MemoryAllocator& getTemporaryAllocator();
@ -175,12 +170,6 @@ class OverlappingPair {
/// Return true if the overlapping pair has contact manifolds with contacts
bool hasContacts() 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 obsolete
void makeContactsObsolete();
@ -223,11 +212,6 @@ inline ProxyShape* OverlappingPair::getShape2() const {
return mContactManifoldSet.getShape2();
}
// Add a contact to the contact manifold
inline void OverlappingPair::addContactManifold(const ContactManifoldInfo* contactManifoldInfo) {
mContactManifoldSet.addContactManifold(contactManifoldInfo);
}
// Return the last frame collision info for a given shape id or nullptr if none is found
inline LastFrameCollisionInfo* OverlappingPair::getLastFrameCollisionInfo(ShapeIdPair& shapeIds) {
Map<ShapeIdPair, LastFrameCollisionInfo*>::Iterator it = mLastFrameCollisionInfos.find(shapeIds);
@ -289,11 +273,6 @@ inline bool OverlappingPair::hasContacts() const {
return mContactManifoldSet.getContactManifolds() != nullptr;
}
// Return a pointer to the first potential contact manifold in the linked-list
inline ContactManifoldInfo* OverlappingPair::getPotentialContactManifolds() {
return mPotentialContactManifolds;
}
// Clear the obsolete contact manifold and contact points
inline void OverlappingPair::clearObsoleteManifoldsAndContactPoints() {
mContactManifoldSet.clearObsoleteManifoldsAndContactPoints();
@ -309,6 +288,11 @@ inline LastFrameCollisionInfo* OverlappingPair::getLastFrameCollisionInfo(uint s
return mLastFrameCollisionInfos[ShapeIdPair(shapeId1, shapeId2)];
}
// Create a new potential contact manifold using contact-points from narrow-phase
inline void OverlappingPair::addPotentialContactPoints(NarrowPhaseInfo* narrowPhaseInfo) {
mContactManifoldSet.addContactPoints(narrowPhaseInfo);
}
}
#endif

View File

@ -149,14 +149,22 @@ class TestSet : public Test {
// ----- Test add() ----- //
Set<int> set1(mAllocator);
set1.add(10);
set1.add(80);
set1.add(130);
bool add1 = set1.add(10);
bool add2 = set1.add(80);
bool add3 = set1.add(130);
test(add1);
test(add2);
test(add3);
test(set1.contains(10));
test(set1.contains(80));
test(set1.contains(130));
test(set1.size() == 3);
bool add4 = set1.add(80);
test(!add4);
test(set1.contains(80));
test(set1.size() == 3);
Set<int> set2(mAllocator, 15);
for (int i = 0; i < 1000000; i++) {
set2.add(i);
@ -168,7 +176,8 @@ class TestSet : public Test {
test(isValid);
set1.remove(10);
set1.add(10);
bool add = set1.add(10);
test(add);
test(set1.size() == 3);
test(set1.contains(10));