Fix issue with ProxyShape::mBroadPhaseId not set when body was sleeping or inactive

This commit is contained in:
Daniel Chappuis 2017-11-01 23:07:56 +01:00
parent 5da57a96c8
commit 6a69ef76c5
7 changed files with 178 additions and 124 deletions

View File

@ -111,7 +111,7 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) {
if (current == proxyShape) { if (current == proxyShape) {
mProxyCollisionShapes = current->mNext; mProxyCollisionShapes = current->mNext;
if (mIsActive) { if (mIsActive && proxyShape->mBroadPhaseID != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(current); mWorld.mCollisionDetection.removeProxyCollisionShape(current);
} }
@ -131,7 +131,7 @@ void CollisionBody::removeCollisionShape(const ProxyShape* proxyShape) {
ProxyShape* elementToRemove = current->mNext; ProxyShape* elementToRemove = current->mNext;
current->mNext = elementToRemove->mNext; current->mNext = elementToRemove->mNext;
if (mIsActive) { if (mIsActive && proxyShape->mBroadPhaseID != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove); mWorld.mCollisionDetection.removeProxyCollisionShape(elementToRemove);
} }
@ -157,7 +157,7 @@ void CollisionBody::removeAllCollisionShapes() {
// Remove the proxy collision shape // Remove the proxy collision shape
ProxyShape* nextElement = current->mNext; ProxyShape* nextElement = current->mNext;
if (mIsActive) { if (mIsActive && current->mBroadPhaseID != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(current); mWorld.mCollisionDetection.removeProxyCollisionShape(current);
} }
@ -202,12 +202,15 @@ void CollisionBody::updateBroadPhaseState() const {
// Update the broad-phase state of a proxy collision shape of the body // Update the broad-phase state of a proxy collision shape of the body
void CollisionBody::updateProxyShapeInBroadPhase(ProxyShape* proxyShape, bool forceReinsert) const { void CollisionBody::updateProxyShapeInBroadPhase(ProxyShape* proxyShape, bool forceReinsert) const {
// Recompute the world-space AABB of the collision shape if (proxyShape->mBroadPhaseID != -1) {
AABB aabb;
proxyShape->getCollisionShape()->computeAABB(aabb, mTransform * proxyShape->getLocalToBodyTransform());
// Update the broad-phase state for the proxy collision shape // Recompute the world-space AABB of the collision shape
mWorld.mCollisionDetection.updateProxyCollisionShape(proxyShape, aabb, Vector3(0, 0, 0), forceReinsert); AABB aabb;
proxyShape->getCollisionShape()->computeAABB(aabb, mTransform * proxyShape->getLocalToBodyTransform());
// Update the broad-phase state for the proxy collision shape
mWorld.mCollisionDetection.updateProxyCollisionShape(proxyShape, aabb, Vector3(0, 0, 0), forceReinsert) ;
}
} }
// Set whether or not the body is active // Set whether or not the body is active
@ -240,8 +243,11 @@ void CollisionBody::setIsActive(bool isActive) {
// For each proxy shape of the body // For each proxy shape of the body
for (ProxyShape* shape = mProxyCollisionShapes; shape != nullptr; shape = shape->mNext) { for (ProxyShape* shape = mProxyCollisionShapes; shape != nullptr; shape = shape->mNext) {
// Remove the proxy shape from the collision detection if (shape->mBroadPhaseID != -1) {
mWorld.mCollisionDetection.removeProxyCollisionShape(shape);
// Remove the proxy shape from the collision detection
mWorld.mCollisionDetection.removeProxyCollisionShape(shape);
}
} }
// Reset the contact manifold list of the body // Reset the contact manifold list of the body

View File

@ -109,6 +109,8 @@ void CollisionDetection::computeMiddlePhase() {
ProxyShape* shape1 = pair->getShape1(); ProxyShape* shape1 = pair->getShape1();
ProxyShape* shape2 = pair->getShape2(); ProxyShape* shape2 = pair->getShape2();
assert(shape1->mBroadPhaseID != -1);
assert(shape2->mBroadPhaseID != -1);
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
// Check if the two shapes are still overlapping. Otherwise, we destroy the // Check if the two shapes are still overlapping. Otherwise, we destroy the
@ -282,6 +284,8 @@ void CollisionDetection::computeNarrowPhase() {
/// This method is called by the broad-phase collision detection algorithm /// This method is called by the broad-phase collision detection algorithm
void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) { void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) {
assert(shape1->mBroadPhaseID != -1);
assert(shape2->mBroadPhaseID != -1);
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID); assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
// Check if the collision filtering allows collision between the two shapes // Check if the collision filtering allows collision between the two shapes
@ -313,6 +317,8 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro
// Remove a body from the collision detection // Remove a body from the collision detection
void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) { void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) {
assert(proxyShape->mBroadPhaseID != -1);
// Remove all the overlapping pairs involving this proxy shape // Remove all the overlapping pairs involving this proxy shape
std::map<overlappingpairid, OverlappingPair*>::iterator it; std::map<overlappingpairid, OverlappingPair*>::iterator it;
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) { for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
@ -683,87 +689,90 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
ProxyShape* bodyProxyShape = body->getProxyShapesList(); ProxyShape* bodyProxyShape = body->getProxyShapesList();
while (bodyProxyShape != nullptr) { while (bodyProxyShape != nullptr) {
// Get the AABB of the shape if (bodyProxyShape->mBroadPhaseID != -1) {
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
// Ask the broad-phase to get all the overlapping shapes // Get the AABB of the shape
LinkedList<int> overlappingNodes(mPoolAllocator); const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
const bodyindex bodyId = body->getID(); // Ask the broad-phase to get all the overlapping shapes
LinkedList<int> overlappingNodes(mPoolAllocator);
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
// For each overlaping proxy shape const bodyindex bodyId = body->getID();
LinkedList<int>::ListElement* element = overlappingNodes.getListHead();
while (element != nullptr) {
// Get the overlapping proxy shape // For each overlaping proxy shape
int broadPhaseId = element->data; LinkedList<int>::ListElement* element = overlappingNodes.getListHead();
ProxyShape* proxyShape = mBroadPhaseAlgorithm.getProxyShapeForBroadPhaseId(broadPhaseId); while (element != nullptr) {
// If the proxy shape is from a body that we have not already reported collision and the // Get the overlapping proxy shape
// two proxy collision shapes are not from the same body int broadPhaseId = element->data;
if (reportedBodies.find(proxyShape->getBody()->getID()) == reportedBodies.end() && ProxyShape* proxyShape = mBroadPhaseAlgorithm.getProxyShapeForBroadPhaseId(broadPhaseId);
proxyShape->getBody()->getID() != bodyId) {
// Check if the collision filtering allows collision between the two shapes // If the proxy shape is from a body that we have not already reported collision and the
if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) { // two proxy collision shapes are not from the same body
if (reportedBodies.find(proxyShape->getBody()->getID()) == reportedBodies.end() &&
proxyShape->getBody()->getID() != bodyId) {
// Create a temporary overlapping pair // Check if the collision filtering allows collision between the two shapes
OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator); if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) {
// Compute the middle-phase collision detection between the two shapes // Create a temporary overlapping pair
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair); OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator);
bool isColliding = false; // Compute the middle-phase collision detection between the two shapes
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
// For each narrow-phase info object bool isColliding = false;
while (narrowPhaseInfo != nullptr) {
// If we have not found a collision yet // For each narrow-phase info object
if (!isColliding) { while (narrowPhaseInfo != nullptr) {
const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType(); // If we have not found a collision yet
const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType(); if (!isColliding) {
// Select the narrow phase algorithm to use according to the two collision shapes const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType();
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(shape1Type, shape2Type); const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType();
// If there is a collision algorithm for those two kinds of shapes // Select the narrow phase algorithm to use according to the two collision shapes
if (narrowPhaseAlgorithm != nullptr) { NarrowPhaseAlgorithm* narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(shape1Type, shape2Type);
// Use the narrow-phase collision detection algorithm to check // If there is a collision algorithm for those two kinds of shapes
// if there really is a collision. If a collision occurs, the if (narrowPhaseAlgorithm != nullptr) {
// notifyContact() callback method will be called.
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, false); // 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.
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, false);
}
} }
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
narrowPhaseInfo = narrowPhaseInfo->next;
// Call the destructor
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
} }
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo; // Return if we have found a narrow-phase collision
narrowPhaseInfo = narrowPhaseInfo->next; if (isColliding) {
// Call the destructor CollisionBody* overlapBody = proxyShape->getBody();
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory // Add the body into the set of reported bodies
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo)); reportedBodies.insert(overlapBody->getID());
}
// Return if we have found a narrow-phase collision // Notify the overlap to the user
if (isColliding) { overlapCallback->notifyOverlap(overlapBody);
}
CollisionBody* overlapBody = proxyShape->getBody();
// Add the body into the set of reported bodies
reportedBodies.insert(overlapBody->getID());
// Notify the overlap to the user
overlapCallback->notifyOverlap(overlapBody);
} }
} }
}
// Go to the next overlapping proxy shape // Go to the next overlapping proxy shape
element = element->next; element = element->next;
}
} }
// Go to the next proxy shape // Go to the next proxy shape
@ -858,85 +867,88 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
ProxyShape* bodyProxyShape = body->getProxyShapesList(); ProxyShape* bodyProxyShape = body->getProxyShapesList();
while (bodyProxyShape != nullptr) { while (bodyProxyShape != nullptr) {
// Get the AABB of the shape if (bodyProxyShape->mBroadPhaseID != -1) {
const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
// Ask the broad-phase to get all the overlapping shapes // Get the AABB of the shape
LinkedList<int> overlappingNodes(mPoolAllocator); const AABB& shapeAABB = mBroadPhaseAlgorithm.getFatAABB(bodyProxyShape->mBroadPhaseID);
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
const bodyindex bodyId = body->getID(); // Ask the broad-phase to get all the overlapping shapes
LinkedList<int> overlappingNodes(mPoolAllocator);
mBroadPhaseAlgorithm.reportAllShapesOverlappingWithAABB(shapeAABB, overlappingNodes);
// For each overlaping proxy shape const bodyindex bodyId = body->getID();
LinkedList<int>::ListElement* element = overlappingNodes.getListHead();
while (element != nullptr) {
// Get the overlapping proxy shape // For each overlaping proxy shape
int broadPhaseId = element->data; LinkedList<int>::ListElement* element = overlappingNodes.getListHead();
ProxyShape* proxyShape = mBroadPhaseAlgorithm.getProxyShapeForBroadPhaseId(broadPhaseId); while (element != nullptr) {
// If the two proxy collision shapes are not from the same body // Get the overlapping proxy shape
if (proxyShape->getBody()->getID() != bodyId) { int broadPhaseId = element->data;
ProxyShape* proxyShape = mBroadPhaseAlgorithm.getProxyShapeForBroadPhaseId(broadPhaseId);
// Check if the collision filtering allows collision between the two shapes // If the two proxy collision shapes are not from the same body
if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) { if (proxyShape->getBody()->getID() != bodyId) {
// Create a temporary overlapping pair // Check if the collision filtering allows collision between the two shapes
OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator); if ((proxyShape->getCollisionCategoryBits() & categoryMaskBits) != 0) {
// Compute the middle-phase collision detection between the two shapes // Create a temporary overlapping pair
NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair); OverlappingPair pair(bodyProxyShape, proxyShape, mPoolAllocator, mPoolAllocator);
// For each narrow-phase info object // Compute the middle-phase collision detection between the two shapes
while (narrowPhaseInfo != nullptr) { NarrowPhaseInfo* narrowPhaseInfo = computeMiddlePhaseForProxyShapes(&pair);
const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType(); // For each narrow-phase info object
const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType(); while (narrowPhaseInfo != nullptr) {
// Select the narrow phase algorithm to use according to the two collision shapes const CollisionShapeType shape1Type = narrowPhaseInfo->collisionShape1->getType();
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(shape1Type, shape2Type); const CollisionShapeType shape2Type = narrowPhaseInfo->collisionShape2->getType();
// If there is a collision algorithm for those two kinds of shapes // Select the narrow phase algorithm to use according to the two collision shapes
if (narrowPhaseAlgorithm != nullptr) { NarrowPhaseAlgorithm* narrowPhaseAlgorithm = selectNarrowPhaseAlgorithm(shape1Type, shape2Type);
// Use the narrow-phase collision detection algorithm to check // If there is a collision algorithm for those two kinds of shapes
// if there really is a collision. If a collision occurs, the if (narrowPhaseAlgorithm != nullptr) {
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true)) {
// Add the contact points as a potential contact manifold into the pair // Use the narrow-phase collision detection algorithm to check
narrowPhaseInfo->addContactPointsAsPotentialContactManifold(); // if there really is a collision. If a collision occurs, the
// notifyContact() callback method will be called.
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, true)) {
// Add the contact points as a potential contact manifold into the pair
narrowPhaseInfo->addContactPointsAsPotentialContactManifold();
}
} }
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo;
narrowPhaseInfo = narrowPhaseInfo->next;
// Call the destructor
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo));
} }
NarrowPhaseInfo* currentNarrowPhaseInfo = narrowPhaseInfo; // Process the potential contacts
narrowPhaseInfo = narrowPhaseInfo->next; processPotentialContacts(&pair);
// Call the destructor if (pair.hasContacts()) {
currentNarrowPhaseInfo->~NarrowPhaseInfo();
// Release the allocated memory // Report the contacts to the user
mPoolAllocator.release(currentNarrowPhaseInfo, sizeof(NarrowPhaseInfo)); CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mPoolAllocator);
callback->notifyContact(collisionInfo);
}
} }
// Process the potential contacts
processPotentialContacts(&pair);
if (pair.hasContacts()) {
// Report the contacts to the user
CollisionCallback::CollisionCallbackInfo collisionInfo(&pair, mPoolAllocator);
callback->notifyContact(collisionInfo);
}
} }
// Go to the next overlapping proxy shape
element = element->next;
} }
// Go to the next overlapping proxy shape // Go to the next proxy shape
element = element->next; bodyProxyShape = bodyProxyShape->getNext();
} }
// Go to the next proxy shape
bodyProxyShape = bodyProxyShape->getNext();
} }
} }
@ -1031,7 +1043,14 @@ EventListener* CollisionDetection::getWorldEventListener() {
return mWorld->mEventListener; return mWorld->mEventListener;
} }
/// Return a reference to the world memory allocator // Return a reference to the world memory allocator
PoolAllocator& CollisionDetection::getWorldMemoryAllocator() { PoolAllocator& CollisionDetection::getWorldMemoryAllocator() {
return mWorld->mPoolAllocator; return mWorld->mPoolAllocator;
} }
// Return the world-space AABB of a given proxy shape
const AABB CollisionDetection::getWorldAABB(const ProxyShape* proxyShape) const {
assert(proxyShape->mBroadPhaseID > -1);
return mBroadPhaseAlgorithm.getFatAABB(proxyShape->mBroadPhaseID);
}

View File

@ -219,6 +219,9 @@ class CollisionDetection {
/// Return a reference to the world memory allocator /// Return a reference to the world memory allocator
PoolAllocator& getWorldMemoryAllocator(); PoolAllocator& getWorldMemoryAllocator();
/// Return the world-space AABB of a given proxy shape
const AABB getWorldAABB(const ProxyShape* proxyShape) const;
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class DynamicsWorld; friend class DynamicsWorld;
@ -259,7 +262,10 @@ inline void CollisionDetection::removeNoCollisionPair(CollisionBody* body1,
/// We simply put the shape in the list of collision shape that have moved in the /// We simply put the shape in the list of collision shape that have moved in the
/// previous frame so that it is tested for collision again in the broad-phase. /// previous frame so that it is tested for collision again in the broad-phase.
inline void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* shape) { inline void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* shape) {
mBroadPhaseAlgorithm.addMovedCollisionShape(shape->mBroadPhaseID);
if (shape->mBroadPhaseID != -1) {
mBroadPhaseAlgorithm.addMovedCollisionShape(shape->mBroadPhaseID);
}
} }
// Update a proxy collision shape (that has moved for instance) // Update a proxy collision shape (that has moved for instance)

View File

@ -117,6 +117,8 @@ void BroadPhaseAlgorithm::removeMovedCollisionShape(int broadPhaseID) {
// Add a proxy collision shape into the broad-phase collision detection // Add a proxy collision shape into the broad-phase collision detection
void BroadPhaseAlgorithm::addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb) { void BroadPhaseAlgorithm::addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb) {
assert(proxyShape->mBroadPhaseID == -1);
// Add the collision shape into the dynamic AABB tree and get its broad-phase ID // Add the collision shape into the dynamic AABB tree and get its broad-phase ID
int nodeId = mDynamicAABBTree.addObject(aabb, proxyShape); int nodeId = mDynamicAABBTree.addObject(aabb, proxyShape);
@ -131,8 +133,12 @@ void BroadPhaseAlgorithm::addProxyCollisionShape(ProxyShape* proxyShape, const A
// Remove a proxy collision shape from the broad-phase collision detection // Remove a proxy collision shape from the broad-phase collision detection
void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) { void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) {
assert(proxyShape->mBroadPhaseID != -1);
int broadPhaseID = proxyShape->mBroadPhaseID; int broadPhaseID = proxyShape->mBroadPhaseID;
proxyShape->mBroadPhaseID = -1;
// Remove the collision shape from the dynamic AABB tree // Remove the collision shape from the dynamic AABB tree
mDynamicAABBTree.removeObject(broadPhaseID); mDynamicAABBTree.removeObject(broadPhaseID);

View File

@ -232,6 +232,9 @@ inline bool BroadPhasePair::smallerThan(const BroadPhasePair& pair1, const Broad
// Return true if the two broad-phase collision shapes are overlapping // Return true if the two broad-phase collision shapes are overlapping
inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1, inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1,
const ProxyShape* shape2) const { const ProxyShape* shape2) const {
if (shape1->mBroadPhaseID == -1 || shape2->mBroadPhaseID == -1) return false;
// Get the two AABBs of the collision shapes // Get the two AABBs of the collision shapes
const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1->mBroadPhaseID); const AABB& aabb1 = mDynamicAABBTree.getFatAABB(shape1->mBroadPhaseID);
const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID); const AABB& aabb2 = mDynamicAABBTree.getFatAABB(shape2->mBroadPhaseID);

View File

@ -164,3 +164,14 @@ bool CollisionWorld::testOverlap(CollisionBody* body1, CollisionBody* body2) {
return mCollisionDetection.testOverlap(body1, body2); return mCollisionDetection.testOverlap(body1, body2);
} }
// Return the current world-space AABB of given proxy shape
AABB CollisionWorld::getWorldAABB(const ProxyShape* proxyShape) const {
if (proxyShape->mBroadPhaseID == -1) {
return AABB();
}
return mCollisionDetection.getWorldAABB(proxyShape);
}

View File

@ -147,6 +147,9 @@ class CollisionWorld {
/// Test and report collisions between all shapes of the world /// Test and report collisions between all shapes of the world
void testCollision(CollisionCallback* callback); void testCollision(CollisionCallback* callback);
/// Return the current world-space AABB of given proxy shape
AABB getWorldAABB(const ProxyShape* proxyShape) const;
// -------------------- Friendship -------------------- // // -------------------- Friendship -------------------- //
friend class CollisionDetection; friend class CollisionDetection;