Refactor contact manifold and contact point creation
This commit is contained in:
parent
6a01abfae8
commit
b21a6bb59b
|
@ -60,6 +60,8 @@ SET (REACTPHYSICS3D_SOURCES
|
||||||
"src/body/CollisionBody.cpp"
|
"src/body/CollisionBody.cpp"
|
||||||
"src/body/RigidBody.h"
|
"src/body/RigidBody.h"
|
||||||
"src/body/RigidBody.cpp"
|
"src/body/RigidBody.cpp"
|
||||||
|
"src/collision/ContactPointInfo.h"
|
||||||
|
"src/collision/ContactManifoldInfo.h"
|
||||||
"src/collision/broadphase/BroadPhaseAlgorithm.h"
|
"src/collision/broadphase/BroadPhaseAlgorithm.h"
|
||||||
"src/collision/broadphase/BroadPhaseAlgorithm.cpp"
|
"src/collision/broadphase/BroadPhaseAlgorithm.cpp"
|
||||||
"src/collision/broadphase/DynamicAABBTree.h"
|
"src/collision/broadphase/DynamicAABBTree.h"
|
||||||
|
|
|
@ -72,66 +72,6 @@ void CollisionDetection::computeCollisionDetection() {
|
||||||
mNarrowPhaseInfoList = nullptr;
|
mNarrowPhaseInfoList = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : Remove this method
|
|
||||||
// Report collision between two sets of shapes
|
|
||||||
/*
|
|
||||||
void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callback,
|
|
||||||
const std::set<uint>& shapes1,
|
|
||||||
const std::set<uint>& shapes2) {
|
|
||||||
|
|
||||||
// For each possible collision pair of bodies
|
|
||||||
map<overlappingpairid, OverlappingPair*>::iterator it;
|
|
||||||
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ++it) {
|
|
||||||
|
|
||||||
OverlappingPair* pair = it->second;
|
|
||||||
|
|
||||||
const ProxyShape* shape1 = pair->getShape1();
|
|
||||||
const ProxyShape* shape2 = pair->getShape2();
|
|
||||||
|
|
||||||
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
|
||||||
|
|
||||||
// If both shapes1 and shapes2 sets are non-empty, we check that
|
|
||||||
// shape1 is among on set and shape2 is among the other one
|
|
||||||
if (!shapes1.empty() && !shapes2.empty() &&
|
|
||||||
(shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) &&
|
|
||||||
(shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!shapes1.empty() && shapes2.empty() &&
|
|
||||||
shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!shapes2.empty() && shapes1.empty() &&
|
|
||||||
shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each contact manifold set of the overlapping pair
|
|
||||||
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
|
||||||
for (int j=0; j<manifoldSet.getNbContactManifolds(); j++) {
|
|
||||||
|
|
||||||
const ContactManifold* manifold = manifoldSet.getContactManifold(j);
|
|
||||||
|
|
||||||
// For each contact manifold of the manifold set
|
|
||||||
for (uint i=0; i<manifold->getNbContactPoints(); i++) {
|
|
||||||
|
|
||||||
ContactPoint* contactPoint = manifold->getContactPoint(i);
|
|
||||||
|
|
||||||
// Create the contact info object for the contact
|
|
||||||
ContactPointInfo contactInfo;
|
|
||||||
contactInfo.init(contactPoint->getNormal(), contactPoint->getPenetrationDepth(),
|
|
||||||
contactPoint->getLocalPointOnBody1(), contactPoint->getLocalPointOnBody2());
|
|
||||||
|
|
||||||
// Notify the collision callback about this new contact
|
|
||||||
if (callback != nullptr) callback->notifyContact(contactInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Compute the broad-phase collision detection
|
// Compute the broad-phase collision detection
|
||||||
void CollisionDetection::computeBroadPhase() {
|
void CollisionDetection::computeBroadPhase() {
|
||||||
|
|
||||||
|
@ -191,9 +131,6 @@ void CollisionDetection::computeMiddlePhase() {
|
||||||
CollisionBody* const body1 = shape1->getBody();
|
CollisionBody* const body1 = shape1->getBody();
|
||||||
CollisionBody* const body2 = shape2->getBody();
|
CollisionBody* const body2 = shape2->getBody();
|
||||||
|
|
||||||
// Update the contact cache of the overlapping pair
|
|
||||||
pair->update();
|
|
||||||
|
|
||||||
// Check that at least one body is awake and not static
|
// Check that at least one body is awake and not static
|
||||||
bool isBody1Active = !body1->isSleeping() && body1->getType() != BodyType::STATIC;
|
bool isBody1Active = !body1->isSleeping() && body1->getType() != BodyType::STATIC;
|
||||||
bool isBody2Active = !body2->isSleeping() && body2->getType() != BodyType::STATIC;
|
bool isBody2Active = !body2->isSleeping() && body2->getType() != BodyType::STATIC;
|
||||||
|
@ -308,25 +245,21 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mSingleFrameAllocator);
|
||||||
if (narrowPhaseAlgorithm->testCollision(currentNarrowPhaseInfo, contactPointInfo)) {
|
if (narrowPhaseAlgorithm->testCollision(currentNarrowPhaseInfo, contactManifoldInfo)) {
|
||||||
|
|
||||||
|
// Reduce the number of points in the contact manifold
|
||||||
|
contactManifoldInfo.reduce();
|
||||||
|
|
||||||
// If it is the first contact since the pairs are overlapping
|
// If it is the first contact since the pairs are overlapping
|
||||||
if (currentNarrowPhaseInfo->overlappingPair->getNbContactPoints() == 0) {
|
if (currentNarrowPhaseInfo->overlappingPair->getNbContactPoints() == 0) {
|
||||||
|
|
||||||
// Trigger a callback event
|
// Trigger a callback event
|
||||||
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->beginContact(contactPointInfo);
|
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->beginContact(contactManifoldInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new contact
|
// Add the contact manifold to the corresponding overlapping pair
|
||||||
ContactPoint* contact = new (mWorld->mPoolAllocator.allocate(sizeof(ContactPoint)))
|
currentNarrowPhaseInfo->overlappingPair->addContactManifold(contactManifoldInfo);
|
||||||
ContactPoint(contactPointInfo);
|
|
||||||
|
|
||||||
contact->updateWorldContactPoints(currentNarrowPhaseInfo->shape1ToWorldTransform,
|
|
||||||
currentNarrowPhaseInfo->shape2ToWorldTransform);
|
|
||||||
|
|
||||||
// Add the contact to the contact manifold set of the corresponding overlapping pair
|
|
||||||
currentNarrowPhaseInfo->overlappingPair->addContact(contact);
|
|
||||||
|
|
||||||
// Add the overlapping pair into the set of pairs in contact during narrow-phase
|
// Add the overlapping pair into the set of pairs in contact during narrow-phase
|
||||||
overlappingpairid pairId = OverlappingPair::computeID(currentNarrowPhaseInfo->overlappingPair->getShape1(),
|
overlappingpairid pairId = OverlappingPair::computeID(currentNarrowPhaseInfo->overlappingPair->getShape1(),
|
||||||
|
@ -334,7 +267,7 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
mContactOverlappingPairs[pairId] = currentNarrowPhaseInfo->overlappingPair;
|
mContactOverlappingPairs[pairId] = currentNarrowPhaseInfo->overlappingPair;
|
||||||
|
|
||||||
// Trigger a callback event for the new contact
|
// Trigger a callback event for the new contact
|
||||||
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->newContact(contactPointInfo);
|
if (mWorld->mEventListener != nullptr) mWorld->mEventListener->newContact(contactManifoldInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,111 +278,6 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
addAllContactManifoldsToBodies();
|
addAllContactManifoldsToBodies();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : Remove this method
|
|
||||||
// Compute the narrow-phase collision detection
|
|
||||||
/*
|
|
||||||
void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* callback,
|
|
||||||
const std::set<uint>& shapes1,
|
|
||||||
const std::set<uint>& shapes2) {
|
|
||||||
|
|
||||||
mContactOverlappingPairs.clear();
|
|
||||||
|
|
||||||
// For each possible collision pair of bodies
|
|
||||||
map<overlappingpairid, OverlappingPair*>::iterator it;
|
|
||||||
for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); ) {
|
|
||||||
|
|
||||||
OverlappingPair* pair = it->second;
|
|
||||||
|
|
||||||
ProxyShape* shape1 = pair->getShape1();
|
|
||||||
ProxyShape* shape2 = pair->getShape2();
|
|
||||||
|
|
||||||
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
|
||||||
|
|
||||||
// If both shapes1 and shapes2 sets are non-empty, we check that
|
|
||||||
// shape1 is among on set and shape2 is among the other one
|
|
||||||
if (!shapes1.empty() && !shapes2.empty() &&
|
|
||||||
(shapes1.count(shape1->mBroadPhaseID) == 0 || shapes2.count(shape2->mBroadPhaseID) == 0) &&
|
|
||||||
(shapes1.count(shape2->mBroadPhaseID) == 0 || shapes2.count(shape1->mBroadPhaseID) == 0)) {
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!shapes1.empty() && shapes2.empty() &&
|
|
||||||
shapes1.count(shape1->mBroadPhaseID) == 0 && shapes1.count(shape2->mBroadPhaseID) == 0)
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!shapes2.empty() && shapes1.empty() &&
|
|
||||||
shapes2.count(shape1->mBroadPhaseID) == 0 && shapes2.count(shape2->mBroadPhaseID) == 0)
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the collision filtering allows collision between the two shapes and
|
|
||||||
// that the two shapes are still overlapping. Otherwise, we destroy the
|
|
||||||
// overlapping pair
|
|
||||||
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
|
||||||
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) ||
|
|
||||||
!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
|
||||||
|
|
||||||
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
|
||||||
++it;
|
|
||||||
|
|
||||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
|
||||||
|
|
||||||
// Destroy the overlapping pair
|
|
||||||
itToRemove->second->~OverlappingPair();
|
|
||||||
mWorld->mPoolAllocator.release(itToRemove->second, sizeof(OverlappingPair));
|
|
||||||
mOverlappingPairs.erase(itToRemove);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
CollisionBody* const body1 = shape1->getBody();
|
|
||||||
CollisionBody* const body2 = shape2->getBody();
|
|
||||||
|
|
||||||
// Update the contact cache of the overlapping pair
|
|
||||||
pair->update();
|
|
||||||
|
|
||||||
// Check if the two bodies are allowed to collide, otherwise, we do not test for collision
|
|
||||||
if (body1->getType() != BodyType::DYNAMIC && body2->getType() != BodyType::DYNAMIC) continue;
|
|
||||||
bodyindexpair bodiesIndex = OverlappingPair::computeBodiesIndexPair(body1, body2);
|
|
||||||
if (mNoCollisionPairs.count(bodiesIndex) > 0) continue;
|
|
||||||
|
|
||||||
// Check if the two bodies are sleeping, if so, we do no test collision between them
|
|
||||||
if (body1->isSleeping() && body2->isSleeping()) continue;
|
|
||||||
|
|
||||||
// Select the narrow phase algorithm to use according to the two collision shapes
|
|
||||||
const CollisionShapeType shape1Type = shape1->getCollisionShape()->getType();
|
|
||||||
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
|
|
||||||
const int shape1Index = static_cast<int>(shape1Type);
|
|
||||||
const int shape2Index = static_cast<int>(shape2Type);
|
|
||||||
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = mCollisionMatrix[shape1Index][shape2Index];
|
|
||||||
|
|
||||||
// If there is no collision algorithm between those two kinds of shapes
|
|
||||||
if (narrowPhaseAlgorithm == nullptr) continue;
|
|
||||||
|
|
||||||
// Create the CollisionShapeInfo objects
|
|
||||||
CollisionShapeInfo shape1Info(shape1, shape1->getCollisionShape(), shape1->getLocalToWorldTransform(),
|
|
||||||
pair, shape1->getCachedCollisionData());
|
|
||||||
CollisionShapeInfo shape2Info(shape2, shape2->getCollisionShape(), shape2->getLocalToWorldTransform(),
|
|
||||||
pair, shape2->getCachedCollisionData());
|
|
||||||
|
|
||||||
TestCollisionBetweenShapesCallback narrowPhaseCallback(callback);
|
|
||||||
|
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
|
||||||
// if there really is a collision
|
|
||||||
narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, &narrowPhaseCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all the contact manifolds (between colliding bodies) to the bodies
|
|
||||||
addAllContactManifoldsToBodies();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Allow the broadphase to notify the collision detection about an overlapping pair.
|
// Allow the broadphase to notify the collision detection about an overlapping pair.
|
||||||
/// 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) {
|
||||||
|
@ -698,8 +526,8 @@ bool CollisionDetection::testOverlap(CollisionBody* body1, CollisionBody* body2)
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
||||||
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactPointInfo);
|
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,8 +614,8 @@ void CollisionDetection::testOverlap(CollisionBody* body, OverlapCallback* overl
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
||||||
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactPointInfo);
|
isColliding |= narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,10 +687,10 @@ void CollisionDetection::testCollision(CollisionBody* body1, CollisionBody* body
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactPointInfo)) {
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactPointInfo, body1, body2,
|
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, body1, body2,
|
||||||
body1ProxyShape, body2ProxyShape);
|
body1ProxyShape, body2ProxyShape);
|
||||||
|
|
||||||
// Report the contact to the user
|
// Report the contact to the user
|
||||||
|
@ -937,10 +765,10 @@ void CollisionDetection::testCollision(CollisionBody* body, CollisionCallback* c
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactPointInfo)) {
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactPointInfo, body,
|
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, body,
|
||||||
proxyShape->getBody(), bodyProxyShape,
|
proxyShape->getBody(), bodyProxyShape,
|
||||||
proxyShape);
|
proxyShape);
|
||||||
|
|
||||||
|
@ -1008,10 +836,10 @@ void CollisionDetection::testCollision(CollisionCallback* callback) {
|
||||||
// Use the narrow-phase collision detection algorithm to check
|
// Use the narrow-phase collision detection algorithm to check
|
||||||
// if there really is a collision. If a collision occurs, the
|
// if there really is a collision. If a collision occurs, the
|
||||||
// notifyContact() callback method will be called.
|
// notifyContact() callback method will be called.
|
||||||
ContactPointInfo contactPointInfo;
|
ContactManifoldInfo contactManifoldInfo(mMemoryAllocator);
|
||||||
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactPointInfo)) {
|
if (narrowPhaseAlgorithm->testCollision(narrowPhaseInfo, contactManifoldInfo)) {
|
||||||
|
|
||||||
CollisionCallback::CollisionCallbackInfo collisionInfo(contactPointInfo, shape1->getBody(),
|
CollisionCallback::CollisionCallbackInfo collisionInfo(contactManifoldInfo, shape1->getBody(),
|
||||||
shape2->getBody(), shape1, shape2);
|
shape2->getBody(), shape1, shape2);
|
||||||
|
|
||||||
// Report the contact to the user
|
// Report the contact to the user
|
||||||
|
|
|
@ -30,13 +30,30 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ContactManifold::ContactManifold(ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifold::ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
|
||||||
PoolAllocator& memoryAllocator, short normalDirectionId)
|
PoolAllocator& memoryAllocator, short normalDirectionId)
|
||||||
: mShape1(shape1), mShape2(shape2), mNormalDirectionId(normalDirectionId),
|
: mShape1(shape1), mShape2(shape2), mNormalDirectionId(normalDirectionId),
|
||||||
mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0),
|
mNbContactPoints(0), mFrictionImpulse1(0.0), mFrictionImpulse2(0.0),
|
||||||
mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false),
|
mFrictionTwistImpulse(0.0), mIsAlreadyInIsland(false),
|
||||||
mMemoryAllocator(memoryAllocator) {
|
mMemoryAllocator(memoryAllocator) {
|
||||||
|
|
||||||
|
// For each contact point info in the manifold
|
||||||
|
const ContactPointInfo* pointInfo = manifoldInfo.getFirstContactPointInfo();
|
||||||
|
while(pointInfo != nullptr) {
|
||||||
|
|
||||||
|
// Create the new contact point
|
||||||
|
ContactPoint* contact = new (mMemoryAllocator.allocate(sizeof(ContactPoint)))
|
||||||
|
ContactPoint(pointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
||||||
|
|
||||||
|
// Add the new contact point into the manifold
|
||||||
|
mContactPoints[mNbContactPoints] = contact;
|
||||||
|
mNbContactPoints++;
|
||||||
|
|
||||||
|
pointInfo = pointInfo->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(mNbContactPoints <= MAX_CONTACT_POINTS_IN_MANIFOLD);
|
||||||
|
assert(mNbContactPoints > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
|
@ -44,209 +61,6 @@ ContactManifold::~ContactManifold() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a contact point in the manifold
|
|
||||||
void ContactManifold::addContactPoint(ContactPoint* contact) {
|
|
||||||
|
|
||||||
// For contact already in the manifold
|
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
|
||||||
|
|
||||||
// Check if the new point point does not correspond to a same contact point
|
|
||||||
// already in the manifold.
|
|
||||||
decimal distance = (mContactPoints[i]->getWorldPointOnBody1() -
|
|
||||||
contact->getWorldPointOnBody1()).lengthSquare();
|
|
||||||
if (distance <= PERSISTENT_CONTACT_DIST_THRESHOLD*PERSISTENT_CONTACT_DIST_THRESHOLD) {
|
|
||||||
|
|
||||||
// Delete the new contact
|
|
||||||
contact->~ContactPoint();
|
|
||||||
mMemoryAllocator.release(contact, sizeof(ContactPoint));
|
|
||||||
|
|
||||||
assert(mNbContactPoints > 0);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the contact manifold is full
|
|
||||||
if (mNbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD) {
|
|
||||||
int indexMaxPenetration = getIndexOfDeepestPenetration(contact);
|
|
||||||
int indexToRemove = getIndexToRemove(indexMaxPenetration, contact->getLocalPointOnBody1());
|
|
||||||
removeContactPoint(indexToRemove);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the new contact point in the manifold
|
|
||||||
mContactPoints[mNbContactPoints] = contact;
|
|
||||||
mNbContactPoints++;
|
|
||||||
|
|
||||||
assert(mNbContactPoints > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a contact point from the manifold
|
|
||||||
void ContactManifold::removeContactPoint(uint index) {
|
|
||||||
assert(index < mNbContactPoints);
|
|
||||||
assert(mNbContactPoints > 0);
|
|
||||||
|
|
||||||
// Call the destructor explicitly and tell the memory allocator that
|
|
||||||
// the corresponding memory block is now free
|
|
||||||
mContactPoints[index]->~ContactPoint();
|
|
||||||
mMemoryAllocator.release(mContactPoints[index], sizeof(ContactPoint));
|
|
||||||
|
|
||||||
// If we don't remove the last index
|
|
||||||
if (index < mNbContactPoints - 1) {
|
|
||||||
mContactPoints[index] = mContactPoints[mNbContactPoints - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
mNbContactPoints--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the contact manifold
|
|
||||||
/// First the world space coordinates of the current contacts in the manifold are recomputed from
|
|
||||||
/// the corresponding transforms of the bodies because they have moved. Then we remove the contacts
|
|
||||||
/// with a negative penetration depth (meaning that the bodies are not penetrating anymore) and also
|
|
||||||
/// the contacts with a too large distance between the contact points in the plane orthogonal to the
|
|
||||||
/// contact normal.
|
|
||||||
void ContactManifold::update(const Transform& transform1, const Transform& transform2) {
|
|
||||||
|
|
||||||
if (mNbContactPoints == 0) return;
|
|
||||||
|
|
||||||
// Update the world coordinates and penetration depth of the contact points in the manifold
|
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
|
||||||
|
|
||||||
mContactPoints[i]->updateWorldContactPoints(transform1, transform2);
|
|
||||||
mContactPoints[i]->updatePenetrationDepth();
|
|
||||||
}
|
|
||||||
|
|
||||||
const decimal squarePersistentContactThreshold = PERSISTENT_CONTACT_DIST_THRESHOLD *
|
|
||||||
PERSISTENT_CONTACT_DIST_THRESHOLD;
|
|
||||||
|
|
||||||
// Remove the contact points that don't represent very well the contact manifold
|
|
||||||
for (int i=static_cast<int>(mNbContactPoints)-1; i>=0; i--) {
|
|
||||||
assert(i < static_cast<int>(mNbContactPoints));
|
|
||||||
|
|
||||||
// Compute the distance between contact points in the normal direction
|
|
||||||
decimal distanceNormal = -mContactPoints[i]->getPenetrationDepth();
|
|
||||||
|
|
||||||
// If the contacts points are too far from each other in the normal direction
|
|
||||||
if (distanceNormal > squarePersistentContactThreshold) {
|
|
||||||
removeContactPoint(i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Compute the distance of the two contact points in the plane
|
|
||||||
// orthogonal to the contact normal
|
|
||||||
Vector3 projOfPoint1 = mContactPoints[i]->getWorldPointOnBody1() +
|
|
||||||
mContactPoints[i]->getNormal() * distanceNormal;
|
|
||||||
Vector3 projDifference = mContactPoints[i]->getWorldPointOnBody2() - projOfPoint1;
|
|
||||||
|
|
||||||
// If the orthogonal distance is larger than the valid distance
|
|
||||||
// threshold, we remove the contact
|
|
||||||
if (projDifference.lengthSquare() > squarePersistentContactThreshold) {
|
|
||||||
removeContactPoint(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of the contact point with the larger penetration depth.
|
|
||||||
/// This corresponding contact will be kept in the cache. The method returns -1 is
|
|
||||||
/// the new contact is the deepest.
|
|
||||||
int ContactManifold::getIndexOfDeepestPenetration(ContactPoint* newContact) const {
|
|
||||||
assert(mNbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD);
|
|
||||||
int indexMaxPenetrationDepth = -1;
|
|
||||||
decimal maxPenetrationDepth = newContact->getPenetrationDepth();
|
|
||||||
|
|
||||||
// For each contact in the cache
|
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
|
||||||
|
|
||||||
// If the current contact has a larger penetration depth
|
|
||||||
if (mContactPoints[i]->getPenetrationDepth() > maxPenetrationDepth) {
|
|
||||||
maxPenetrationDepth = mContactPoints[i]->getPenetrationDepth();
|
|
||||||
indexMaxPenetrationDepth = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of largest penetration depth
|
|
||||||
return indexMaxPenetrationDepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index that will be removed.
|
|
||||||
/// The index of the contact point with the larger penetration
|
|
||||||
/// depth is given as a parameter. This contact won't be removed. Given this contact, we compute
|
|
||||||
/// the different area and we want to keep the contacts with the largest area. The new point is also
|
|
||||||
/// kept. In order to compute the area of a quadrilateral, we use the formula :
|
|
||||||
/// Area = 0.5 * | AC x BD | where AC and BD form the diagonals of the quadrilateral. Note that
|
|
||||||
/// when we compute this area, we do not calculate it exactly but we
|
|
||||||
/// only estimate it because we do not compute the actual diagonals of the quadrialteral. Therefore,
|
|
||||||
/// this is only a guess that is faster to compute. This idea comes from the Bullet Physics library
|
|
||||||
/// by Erwin Coumans (http://wwww.bulletphysics.org).
|
|
||||||
int ContactManifold::getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const {
|
|
||||||
|
|
||||||
assert(mNbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD);
|
|
||||||
|
|
||||||
decimal area0 = 0.0; // Area with contact 1,2,3 and newPoint
|
|
||||||
decimal area1 = 0.0; // Area with contact 0,2,3 and newPoint
|
|
||||||
decimal area2 = 0.0; // Area with contact 0,1,3 and newPoint
|
|
||||||
decimal area3 = 0.0; // Area with contact 0,1,2 and newPoint
|
|
||||||
|
|
||||||
if (indexMaxPenetration != 0) {
|
|
||||||
// Compute the area
|
|
||||||
Vector3 vector1 = newPoint - mContactPoints[1]->getLocalPointOnBody1();
|
|
||||||
Vector3 vector2 = mContactPoints[3]->getLocalPointOnBody1() -
|
|
||||||
mContactPoints[2]->getLocalPointOnBody1();
|
|
||||||
Vector3 crossProduct = vector1.cross(vector2);
|
|
||||||
area0 = crossProduct.lengthSquare();
|
|
||||||
}
|
|
||||||
if (indexMaxPenetration != 1) {
|
|
||||||
// Compute the area
|
|
||||||
Vector3 vector1 = newPoint - mContactPoints[0]->getLocalPointOnBody1();
|
|
||||||
Vector3 vector2 = mContactPoints[3]->getLocalPointOnBody1() -
|
|
||||||
mContactPoints[2]->getLocalPointOnBody1();
|
|
||||||
Vector3 crossProduct = vector1.cross(vector2);
|
|
||||||
area1 = crossProduct.lengthSquare();
|
|
||||||
}
|
|
||||||
if (indexMaxPenetration != 2) {
|
|
||||||
// Compute the area
|
|
||||||
Vector3 vector1 = newPoint - mContactPoints[0]->getLocalPointOnBody1();
|
|
||||||
Vector3 vector2 = mContactPoints[3]->getLocalPointOnBody1() -
|
|
||||||
mContactPoints[1]->getLocalPointOnBody1();
|
|
||||||
Vector3 crossProduct = vector1.cross(vector2);
|
|
||||||
area2 = crossProduct.lengthSquare();
|
|
||||||
}
|
|
||||||
if (indexMaxPenetration != 3) {
|
|
||||||
// Compute the area
|
|
||||||
Vector3 vector1 = newPoint - mContactPoints[0]->getLocalPointOnBody1();
|
|
||||||
Vector3 vector2 = mContactPoints[2]->getLocalPointOnBody1() -
|
|
||||||
mContactPoints[1]->getLocalPointOnBody1();
|
|
||||||
Vector3 crossProduct = vector1.cross(vector2);
|
|
||||||
area3 = crossProduct.lengthSquare();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of the contact to remove
|
|
||||||
return getMaxArea(area0, area1, area2, area3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of maximum area
|
|
||||||
int ContactManifold::getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const {
|
|
||||||
if (area0 < area1) {
|
|
||||||
if (area1 < area2) {
|
|
||||||
if (area2 < area3) return 3;
|
|
||||||
else return 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (area1 < area3) return 3;
|
|
||||||
else return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (area0 < area2) {
|
|
||||||
if (area2 < area3) return 3;
|
|
||||||
else return 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (area0 < area3) return 3;
|
|
||||||
else return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the contact manifold
|
// Clear the contact manifold
|
||||||
void ContactManifold::clear() {
|
void ContactManifold::clear() {
|
||||||
for (uint i=0; i<mNbContactPoints; i++) {
|
for (uint i=0; i<mNbContactPoints; i++) {
|
||||||
|
@ -258,3 +72,35 @@ void ContactManifold::clear() {
|
||||||
}
|
}
|
||||||
mNbContactPoints = 0;
|
mNbContactPoints = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a contact point
|
||||||
|
void ContactManifold::addContactPoint(const ContactPointInfo* contactPointInfo) {
|
||||||
|
|
||||||
|
assert(mNbContactPoints < MAX_CONTACT_POINTS_IN_MANIFOLD);
|
||||||
|
|
||||||
|
// Create the new contact point
|
||||||
|
ContactPoint* contactPoint = new (mMemoryAllocator.allocate(sizeof(ContactPoint)))
|
||||||
|
ContactPoint(contactPointInfo, mShape1->getLocalToWorldTransform(), mShape2->getLocalToWorldTransform());
|
||||||
|
|
||||||
|
// Add the new contact point into the manifold
|
||||||
|
mContactPoints[mNbContactPoints] = contactPoint;
|
||||||
|
mNbContactPoints++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a contact point
|
||||||
|
void ContactManifold::removeContactPoint(int index) {
|
||||||
|
|
||||||
|
assert(mNbContactPoints > 0);
|
||||||
|
assert(index >= 0 && index < mNbContactPoints);
|
||||||
|
|
||||||
|
// Delete the contact
|
||||||
|
mContactPoints[index]->~ContactPoint();
|
||||||
|
mMemoryAllocator.release(mContactPoints[index], sizeof(ContactPoint));
|
||||||
|
|
||||||
|
for (int i=index; (i+1) < mNbContactPoints; i++) {
|
||||||
|
mContactPoints[i] = mContactPoints[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
mNbContactPoints--;
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "body/CollisionBody.h"
|
#include "body/CollisionBody.h"
|
||||||
#include "collision/ProxyShape.h"
|
#include "collision/ProxyShape.h"
|
||||||
#include "constraint/ContactPoint.h"
|
#include "constraint/ContactPoint.h"
|
||||||
|
#include "collision/ContactManifoldInfo.h"
|
||||||
#include "memory/PoolAllocator.h"
|
#include "memory/PoolAllocator.h"
|
||||||
|
|
||||||
/// ReactPhysics3D namespace
|
/// ReactPhysics3D namespace
|
||||||
|
@ -130,18 +131,6 @@ class ContactManifold {
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Return the index of maximum area
|
|
||||||
int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const;
|
|
||||||
|
|
||||||
/// Return the index of the contact with the larger penetration depth.
|
|
||||||
int getIndexOfDeepestPenetration(ContactPoint* newContact) const;
|
|
||||||
|
|
||||||
/// Return the index that will be removed.
|
|
||||||
int getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const;
|
|
||||||
|
|
||||||
/// Remove a contact point from the manifold
|
|
||||||
void removeContactPoint(uint index);
|
|
||||||
|
|
||||||
/// Return true if the contact manifold has already been added into an island
|
/// Return true if the contact manifold has already been added into an island
|
||||||
bool isAlreadyInIsland() const;
|
bool isAlreadyInIsland() const;
|
||||||
|
|
||||||
|
@ -150,7 +139,7 @@ class ContactManifold {
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
ContactManifold(ProxyShape* shape1, ProxyShape* shape2,
|
ContactManifold(const ContactManifoldInfo& manifoldInfo, ProxyShape* shape1, ProxyShape* shape2,
|
||||||
PoolAllocator& memoryAllocator, short int normalDirectionId);
|
PoolAllocator& memoryAllocator, short int normalDirectionId);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
|
@ -177,12 +166,6 @@ class ContactManifold {
|
||||||
/// Return the normal direction Id
|
/// Return the normal direction Id
|
||||||
short int getNormalDirectionId() const;
|
short int getNormalDirectionId() const;
|
||||||
|
|
||||||
/// Add a contact point to the manifold
|
|
||||||
void addContactPoint(ContactPoint* contact);
|
|
||||||
|
|
||||||
/// Update the contact manifold.
|
|
||||||
void update(const Transform& transform1, const Transform& transform2);
|
|
||||||
|
|
||||||
/// Clear the contact manifold
|
/// Clear the contact manifold
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
@ -231,6 +214,12 @@ class ContactManifold {
|
||||||
/// Return the largest depth of all the contact points
|
/// Return the largest depth of all the contact points
|
||||||
decimal getLargestContactDepth() const;
|
decimal getLargestContactDepth() const;
|
||||||
|
|
||||||
|
/// Add a contact point
|
||||||
|
void addContactPoint(const ContactPointInfo* contactPointInfo);
|
||||||
|
|
||||||
|
/// Remove a contact point
|
||||||
|
void removeContactPoint(int index);
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
friend class DynamicsWorld;
|
friend class DynamicsWorld;
|
||||||
|
|
130
src/collision/ContactManifoldInfo.h
Normal file
130
src/collision/ContactManifoldInfo.h
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||||
|
*********************************************************************************
|
||||||
|
* *
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. *
|
||||||
|
* In no event will the authors be held liable for any damages arising from the *
|
||||||
|
* use of this software. *
|
||||||
|
* *
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, *
|
||||||
|
* including commercial applications, and to alter it and redistribute it *
|
||||||
|
* freely, subject to the following restrictions: *
|
||||||
|
* *
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||||
|
* that you wrote the original software. If you use this software in a *
|
||||||
|
* product, an acknowledgment in the product documentation would be *
|
||||||
|
* appreciated but is not required. *
|
||||||
|
* *
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||||
|
* misrepresented as being the original software. *
|
||||||
|
* *
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef REACTPHYSICS3D_CONTACT_MANIFOLD_INFO_H
|
||||||
|
#define REACTPHYSICS3D_CONTACT_MANIFOLD_INFO_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "collision/ContactPointInfo.h"
|
||||||
|
#include "memory/Allocator.h"
|
||||||
|
|
||||||
|
/// ReactPhysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
/// Memory allocator used to allocate contact points
|
||||||
|
Allocator& mAllocator;
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
ContactManifoldInfo(Allocator& allocator) : mContactPointsList(nullptr), mAllocator(allocator) {}
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~ContactManifoldInfo() {
|
||||||
|
|
||||||
|
// Delete all the contact points in the linked list
|
||||||
|
ContactPointInfo* element = mContactPointsList;
|
||||||
|
while(element != nullptr) {
|
||||||
|
ContactPointInfo* elementToDelete = element;
|
||||||
|
element = element->next;
|
||||||
|
|
||||||
|
// Delete the current element
|
||||||
|
mAllocator.release(elementToDelete, sizeof(ContactPointInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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(const Vector3& contactNormal, decimal penDepth,
|
||||||
|
const Vector3& localPt1, const Vector3& localPt2) {
|
||||||
|
|
||||||
|
assert(penDepth > decimal(0.0));
|
||||||
|
|
||||||
|
// Create the contact point info
|
||||||
|
ContactPointInfo* contactPointInfo = new (mAllocator.allocate(sizeof(ContactPointInfo)))
|
||||||
|
ContactPointInfo(contactNormal, penDepth, localPt1, localPt2);
|
||||||
|
|
||||||
|
// Add it into the linked list of contact points
|
||||||
|
contactPointInfo->next = mContactPointsList;
|
||||||
|
mContactPointsList = contactPointInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the first contact point info of the linked list of contact points
|
||||||
|
ContactPointInfo* getFirstContactPointInfo() const {
|
||||||
|
return mContactPointsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduce the number of points in the contact manifold
|
||||||
|
void reduce() {
|
||||||
|
|
||||||
|
// TODO : Implement this (do not forget to deallocate removed points)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the largest penetration depth among the contact points
|
||||||
|
decimal getLargestPenetrationDepth() const {
|
||||||
|
|
||||||
|
decimal maxDepth = decimal(0.0);
|
||||||
|
ContactPointInfo* element = mContactPointsList;
|
||||||
|
while(element != nullptr) {
|
||||||
|
|
||||||
|
if (element->penetrationDepth > maxDepth) {
|
||||||
|
maxDepth = element->penetrationDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = element->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxDepth;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -43,92 +43,147 @@ ContactManifoldSet::~ContactManifoldSet() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a contact point to the manifold set
|
void ContactManifoldSet::addContactManifold(const ContactManifoldInfo& contactManifoldInfo) {
|
||||||
void ContactManifoldSet::addContactPoint(ContactPoint* contact) {
|
|
||||||
|
|
||||||
// Compute an Id corresponding to the normal direction (using a cubemap)
|
assert(contactManifoldInfo.getFirstContactPointInfo() != nullptr);
|
||||||
short int normalDirectionId = computeCubemapNormalId(contact->getNormal());
|
|
||||||
|
|
||||||
// If there is no contact manifold yet
|
// If there is no contact manifold yet
|
||||||
if (mNbManifolds == 0) {
|
if (mNbManifolds == 0) {
|
||||||
|
|
||||||
createManifold(normalDirectionId);
|
// If the maximum number of manifold is 1
|
||||||
mManifolds[0]->addContactPoint(contact);
|
if (mNbMaxManifolds == 1) {
|
||||||
assert(mManifolds[mNbManifolds-1]->getNbContactPoints() > 0);
|
createManifold(contactManifoldInfo, 0);
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
}
|
||||||
assert(mManifolds[i]->getNbContactPoints() > 0);
|
else {
|
||||||
|
|
||||||
|
// Compute an Id corresponding to the normal direction (using a cubemap)
|
||||||
|
short int normalDirectionId = computeCubemapNormalId(contactManifoldInfo.getFirstContactPointInfo()->normal);
|
||||||
|
|
||||||
|
createManifold(contactManifoldInfo, normalDirectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // If there is already at least one contact manifold in the set
|
||||||
|
|
||||||
|
// If the maximum number of manifold is 1
|
||||||
|
if (mNbMaxManifolds == 1) {
|
||||||
|
|
||||||
|
// Replace the old manifold with the new one
|
||||||
|
updateManifoldWithNewOne(0, contactManifoldInfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Compute an Id corresponding to the normal direction (using a cubemap)
|
||||||
|
short int normalDirectionId = computeCubemapNormalId(contactManifoldInfo.getFirstContactPointInfo()->normal);
|
||||||
|
|
||||||
|
// Select the manifold with the most similar normal (if exists)
|
||||||
|
int similarManifoldIndex = 0;
|
||||||
|
if (mNbMaxManifolds > 1) {
|
||||||
|
similarManifoldIndex = selectManifoldWithSimilarNormal(normalDirectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a similar manifold has been found
|
||||||
|
if (similarManifoldIndex != -1) {
|
||||||
|
|
||||||
|
// Replace the old manifold with the new one
|
||||||
|
updateManifoldWithNewOne(similarManifoldIndex, contactManifoldInfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// If we have not reach the maximum number of manifolds
|
||||||
|
if (mNbManifolds < mNbMaxManifolds) {
|
||||||
|
|
||||||
|
// Create the new contact manifold
|
||||||
|
createManifold(contactManifoldInfo, normalDirectionId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
decimal newManifoldPenDepth = contactManifoldInfo.getLargestPenetrationDepth();
|
||||||
|
|
||||||
|
// We have reached the maximum number of manifold, we do not
|
||||||
|
// want to keep the manifold with the smallest penetration detph
|
||||||
|
int smallestPenDepthManifoldIndex = getManifoldWithSmallestContactPenetrationDepth(newManifoldPenDepth);
|
||||||
|
|
||||||
|
// If the manifold with the smallest penetration depth is not the new one,
|
||||||
|
// we have to keep the new manifold and remove the one with the smallest depth
|
||||||
|
if (smallestPenDepthManifoldIndex >= 0) {
|
||||||
|
removeManifold(smallestPenDepthManifoldIndex);
|
||||||
|
createManifold(contactManifoldInfo, normalDirectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update a previous similar manifold with a new one
|
||||||
|
void ContactManifoldSet::updateManifoldWithNewOne(int oldManifoldIndex, const ContactManifoldInfo& newManifold) {
|
||||||
|
|
||||||
|
// For each contact point of the previous manifold
|
||||||
|
for (int i=0; i<mManifolds[oldManifoldIndex]->getNbContactPoints(); ) {
|
||||||
|
|
||||||
|
ContactPoint* contactPoint = mManifolds[oldManifoldIndex]->getContactPoint(i);
|
||||||
|
|
||||||
|
// For each contact point in the new manifold
|
||||||
|
ContactPointInfo* newPoint = newManifold.getFirstContactPointInfo();
|
||||||
|
bool needToRemovePoint = true;
|
||||||
|
while (newPoint != nullptr) {
|
||||||
|
|
||||||
|
// If the new contact point is similar (very close) to the old contact point
|
||||||
|
if (!newPoint->isUsed && contactPoint->isSimilarWithContactPoint(newPoint)) {
|
||||||
|
|
||||||
|
// Replace (update) the old contact point with the new one
|
||||||
|
contactPoint->update(newPoint, mManifolds[oldManifoldIndex]->getShape1()->getLocalToWorldTransform(),
|
||||||
|
mManifolds[oldManifoldIndex]->getShape2()->getLocalToWorldTransform());
|
||||||
|
needToRemovePoint = false;
|
||||||
|
newPoint->isUsed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPoint = newPoint->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no new contact point is similar to the old one
|
||||||
|
if (needToRemovePoint) {
|
||||||
|
|
||||||
|
// Remove the old contact point
|
||||||
|
mManifolds[oldManifoldIndex]->removeContactPoint(i);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each point of the new manifold that have not been used yet (to update
|
||||||
|
// an existing point in the previous manifold), add it into the previous manifold
|
||||||
|
const ContactPointInfo* newPointInfo = newManifold.getFirstContactPointInfo();
|
||||||
|
while (newPointInfo != nullptr) {
|
||||||
|
|
||||||
|
if (!newPointInfo->isUsed) {
|
||||||
|
mManifolds[oldManifoldIndex]->addContactPoint(newPointInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
newPointInfo = newPointInfo->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Select the manifold with the most similar normal (if exists)
|
// Return the manifold with the smallest contact penetration depth
|
||||||
int similarManifoldIndex = 0;
|
int ContactManifoldSet::getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const {
|
||||||
if (mNbMaxManifolds > 1) {
|
|
||||||
similarManifoldIndex = selectManifoldWithSimilarNormal(normalDirectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a similar manifold has been found
|
|
||||||
if (similarManifoldIndex != -1) {
|
|
||||||
|
|
||||||
// Add the contact point to that similar manifold
|
|
||||||
mManifolds[similarManifoldIndex]->addContactPoint(contact);
|
|
||||||
assert(mManifolds[similarManifoldIndex]->getNbContactPoints() > 0);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the maximum number of manifold has not been reached yet
|
|
||||||
if (mNbManifolds < mNbMaxManifolds) {
|
|
||||||
|
|
||||||
// Create a new manifold for the contact point
|
|
||||||
createManifold(normalDirectionId);
|
|
||||||
mManifolds[mNbManifolds-1]->addContactPoint(contact);
|
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
|
||||||
assert(mManifolds[i]->getNbContactPoints() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The contact point will be in a new contact manifold, we now have too much
|
// The contact point will be in a new contact manifold, we now have too much
|
||||||
// manifolds condidates. We need to remove one. We choose to keep the manifolds
|
// manifolds condidates. We need to remove one. We choose to remove the manifold
|
||||||
// with the largest contact depth among their points
|
// with the smallest contact depth among their points
|
||||||
int smallestDepthIndex = -1;
|
int smallestDepthManifoldIndex = -1;
|
||||||
decimal minDepth = contact->getPenetrationDepth();
|
decimal minDepth = initDepth;
|
||||||
assert(mNbManifolds == mNbMaxManifolds);
|
assert(mNbManifolds == mNbMaxManifolds);
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
for (int i=0; i<mNbManifolds; i++) {
|
||||||
decimal depth = mManifolds[i]->getLargestContactDepth();
|
decimal depth = mManifolds[i]->getLargestContactDepth();
|
||||||
if (depth < minDepth) {
|
if (depth < minDepth) {
|
||||||
minDepth = depth;
|
minDepth = depth;
|
||||||
smallestDepthIndex = i;
|
smallestDepthManifoldIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we do not want to keep to new manifold (not created yet) with the
|
return smallestDepthManifoldIndex;
|
||||||
// new contact point
|
|
||||||
if (smallestDepthIndex == -1) {
|
|
||||||
|
|
||||||
// Delete the new contact
|
|
||||||
contact->~ContactPoint();
|
|
||||||
mMemoryAllocator.release(contact, sizeof(ContactPoint));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(smallestDepthIndex >= 0 && smallestDepthIndex < mNbManifolds);
|
|
||||||
|
|
||||||
// Here we need to replace an existing manifold with a new one (that contains
|
|
||||||
// the new contact point)
|
|
||||||
removeManifold(smallestDepthIndex);
|
|
||||||
createManifold(normalDirectionId);
|
|
||||||
mManifolds[mNbManifolds-1]->addContactPoint(contact);
|
|
||||||
assert(mManifolds[mNbManifolds-1]->getNbContactPoints() > 0);
|
|
||||||
for (int i=0; i<mNbManifolds; i++) {
|
|
||||||
assert(mManifolds[i]->getNbContactPoints() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the index of the contact manifold with a similar average normal.
|
// Return the index of the contact manifold with a similar average normal.
|
||||||
|
@ -154,7 +209,7 @@ short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) cons
|
||||||
|
|
||||||
int faceNo;
|
int faceNo;
|
||||||
decimal u, v;
|
decimal u, v;
|
||||||
decimal max = max3(fabs(normal.x), fabs(normal.y), fabs(normal.z));
|
decimal max = max3(std::fabs(normal.x), std::fabs(normal.y), std::fabs(normal.z));
|
||||||
Vector3 normalScaled = normal / max;
|
Vector3 normalScaled = normal / max;
|
||||||
|
|
||||||
if (normalScaled.x >= normalScaled.y && normalScaled.x >= normalScaled.z) {
|
if (normalScaled.x >= normalScaled.y && normalScaled.x >= normalScaled.z) {
|
||||||
|
@ -173,8 +228,8 @@ short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) cons
|
||||||
v = normalScaled.y;
|
v = normalScaled.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int indexU = floor(((u + 1)/2) * CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS);
|
int indexU = std::floor(((u + 1)/2) * CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS);
|
||||||
int indexV = floor(((v + 1)/2) * CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS);
|
int indexV = std::floor(((v + 1)/2) * CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS);
|
||||||
if (indexU == CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS) indexU--;
|
if (indexU == CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS) indexU--;
|
||||||
if (indexV == CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS) indexV--;
|
if (indexV == CONTACT_CUBEMAP_FACE_NB_SUBDIVISIONS) indexV--;
|
||||||
|
|
||||||
|
@ -182,22 +237,6 @@ short int ContactManifoldSet::computeCubemapNormalId(const Vector3& normal) cons
|
||||||
return faceNo * 200 + indexU * nbSubDivInFace + indexV;
|
return faceNo * 200 + indexU * nbSubDivInFace + indexV;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the contact manifolds
|
|
||||||
void ContactManifoldSet::update() {
|
|
||||||
|
|
||||||
for (int i=mNbManifolds-1; i>=0; i--) {
|
|
||||||
|
|
||||||
// Update the contact manifold
|
|
||||||
mManifolds[i]->update(mShape1->getBody()->getTransform() * mShape1->getLocalToBodyTransform(),
|
|
||||||
mShape2->getBody()->getTransform() * mShape2->getLocalToBodyTransform());
|
|
||||||
|
|
||||||
// Remove the contact manifold if has no contact points anymore
|
|
||||||
if (mManifolds[i]->getNbContactPoints() == 0) {
|
|
||||||
removeManifold(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the contact manifold set
|
// Clear the contact manifold set
|
||||||
void ContactManifoldSet::clear() {
|
void ContactManifoldSet::clear() {
|
||||||
|
|
||||||
|
@ -210,11 +249,11 @@ void ContactManifoldSet::clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new contact manifold and add it to the set
|
// Create a new contact manifold and add it to the set
|
||||||
void ContactManifoldSet::createManifold(short int normalDirectionId) {
|
void ContactManifoldSet::createManifold(const ContactManifoldInfo& manifoldInfo, short int normalDirectionId) {
|
||||||
assert(mNbManifolds < mNbMaxManifolds);
|
assert(mNbManifolds < mNbMaxManifolds);
|
||||||
|
|
||||||
mManifolds[mNbManifolds] = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
|
mManifolds[mNbManifolds] = new (mMemoryAllocator.allocate(sizeof(ContactManifold)))
|
||||||
ContactManifold(mShape1, mShape2, mMemoryAllocator, normalDirectionId);
|
ContactManifold(manifoldInfo, mShape1, mShape2, mMemoryAllocator, normalDirectionId);
|
||||||
mNbManifolds++;
|
mNbManifolds++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class ContactManifoldSet {
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Create a new contact manifold and add it to the set
|
/// Create a new contact manifold and add it to the set
|
||||||
void createManifold(short normalDirectionId);
|
void createManifold(const ContactManifoldInfo& manifoldInfo, short normalDirectionId);
|
||||||
|
|
||||||
/// Remove a contact manifold from the set
|
/// Remove a contact manifold from the set
|
||||||
void removeManifold(int index);
|
void removeManifold(int index);
|
||||||
|
@ -82,6 +82,12 @@ class ContactManifoldSet {
|
||||||
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
// normal vector into of the of the bucket and returns a unique Id for the bucket
|
||||||
short int computeCubemapNormalId(const Vector3& normal) const;
|
short int computeCubemapNormalId(const Vector3& normal) const;
|
||||||
|
|
||||||
|
/// Return the manifold with the smallest contact penetration depth
|
||||||
|
int getManifoldWithSmallestContactPenetrationDepth(decimal initDepth) const;
|
||||||
|
|
||||||
|
/// Update a previous similar manifold with a new one
|
||||||
|
void updateManifoldWithNewOne(int oldManifoldIndex, const ContactManifoldInfo& newManifold);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
@ -93,18 +99,15 @@ class ContactManifoldSet {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ContactManifoldSet();
|
~ContactManifoldSet();
|
||||||
|
|
||||||
|
/// Add a contact manifold in the set
|
||||||
|
void addContactManifold(const ContactManifoldInfo& contactManifoldInfo);
|
||||||
|
|
||||||
/// Return the first proxy shape
|
/// Return the first proxy shape
|
||||||
ProxyShape* getShape1() const;
|
ProxyShape* getShape1() const;
|
||||||
|
|
||||||
/// Return the second proxy shape
|
/// Return the second proxy shape
|
||||||
ProxyShape* getShape2() const;
|
ProxyShape* getShape2() const;
|
||||||
|
|
||||||
/// Add a contact point to the manifold set
|
|
||||||
void addContactPoint(ContactPoint* contact);
|
|
||||||
|
|
||||||
/// Update the contact manifolds
|
|
||||||
void update();
|
|
||||||
|
|
||||||
/// Clear the contact manifold set
|
/// Clear the contact manifold set
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
88
src/collision/ContactPointInfo.h
Normal file
88
src/collision/ContactPointInfo.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* ReactPhysics3D physics library, http://www.reactphysics3d.com *
|
||||||
|
* Copyright (c) 2010-2016 Daniel Chappuis *
|
||||||
|
*********************************************************************************
|
||||||
|
* *
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty. *
|
||||||
|
* In no event will the authors be held liable for any damages arising from the *
|
||||||
|
* use of this software. *
|
||||||
|
* *
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, *
|
||||||
|
* including commercial applications, and to alter it and redistribute it *
|
||||||
|
* freely, subject to the following restrictions: *
|
||||||
|
* *
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
||||||
|
* that you wrote the original software. If you use this software in a *
|
||||||
|
* product, an acknowledgment in the product documentation would be *
|
||||||
|
* appreciated but is not required. *
|
||||||
|
* *
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
||||||
|
* misrepresented as being the original software. *
|
||||||
|
* *
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef REACTPHYSICS3D_CONTACT_POINT_INFO_H
|
||||||
|
#define REACTPHYSICS3D_CONTACT_POINT_INFO_H
|
||||||
|
|
||||||
|
// Libraries
|
||||||
|
#include "body/CollisionBody.h"
|
||||||
|
#include "mathematics/mathematics.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
/// ReactPhysics3D namespace
|
||||||
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Structure ContactPointInfo
|
||||||
|
/**
|
||||||
|
* This structure contains informations about a collision contact
|
||||||
|
* computed during the narrow-phase collision detection. Those
|
||||||
|
* informations are used to compute the contact set for a contact
|
||||||
|
* between two bodies.
|
||||||
|
*/
|
||||||
|
struct ContactPointInfo {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
|
/// Normalized normal vector of the collision contact in world space
|
||||||
|
Vector3 normal;
|
||||||
|
|
||||||
|
/// Penetration depth of the contact
|
||||||
|
decimal penetrationDepth;
|
||||||
|
|
||||||
|
/// Contact point of body 1 in local space of body 1
|
||||||
|
Vector3 localPoint1;
|
||||||
|
|
||||||
|
/// Contact point of body 2 in local space of body 2
|
||||||
|
Vector3 localPoint2;
|
||||||
|
|
||||||
|
/// Pointer to the next contact point info
|
||||||
|
ContactPointInfo* next;
|
||||||
|
|
||||||
|
/// True if the contact point has already been inserted into a manifold
|
||||||
|
bool isUsed;
|
||||||
|
|
||||||
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
ContactPointInfo(const Vector3& contactNormal, decimal penDepth,
|
||||||
|
const Vector3& localPt1, const Vector3& localPt2)
|
||||||
|
: normal(contactNormal), penetrationDepth(penDepth),
|
||||||
|
localPoint1(localPt1), localPoint2(localPt2), next(nullptr), isUsed(false) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~ContactPointInfo() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -30,8 +30,11 @@
|
||||||
// We want to use the ReactPhysics3D namespace
|
// We want to use the ReactPhysics3D namespace
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactPointInfo& contactPointInfo) {
|
bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::CAPSULE);
|
||||||
|
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CAPSULE);
|
||||||
|
|
||||||
const decimal parallelEpsilon = decimal(0.001);
|
const decimal parallelEpsilon = decimal(0.001);
|
||||||
|
|
||||||
// Get the capsule collision shapes
|
// Get the capsule collision shapes
|
||||||
|
@ -39,7 +42,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
const CapsuleShape* capsuleShape2 = static_cast<const CapsuleShape*>(narrowPhaseInfo->collisionShape2);
|
const CapsuleShape* capsuleShape2 = static_cast<const CapsuleShape*>(narrowPhaseInfo->collisionShape2);
|
||||||
|
|
||||||
// Get the transform from capsule 1 local-space to capsule 2 local-space
|
// Get the transform from capsule 1 local-space to capsule 2 local-space
|
||||||
const Transform capsule1ToCapsule2SpaceTransform = narrowPhaseInfo->shape1ToWorldTransform * narrowPhaseInfo->shape2ToWorldTransform.getInverse();
|
const Transform capsule1ToCapsule2SpaceTransform = narrowPhaseInfo->shape2ToWorldTransform.getInverse() * narrowPhaseInfo->shape1ToWorldTransform;
|
||||||
|
|
||||||
// Compute the end-points of the inner segment of the first capsule
|
// Compute the end-points of the inner segment of the first capsule
|
||||||
Vector3 capsule1SegA(0, -capsuleShape1->getHeight() * decimal(0.5), 0);
|
Vector3 capsule1SegA(0, -capsuleShape1->getHeight() * decimal(0.5), 0);
|
||||||
|
@ -63,7 +66,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
|
|
||||||
// If the distance between the two segments is larger than the sum of the capsules radius (we do not have overlapping)
|
// If the distance between the two segments is larger than the sum of the capsules radius (we do not have overlapping)
|
||||||
const decimal segmentsDistance = computeDistancePointToLineDistance(capsule1SegA, capsule1SegB, capsule2SegA);
|
const decimal segmentsDistance = computeDistancePointToLineDistance(capsule1SegA, capsule1SegB, capsule2SegA);
|
||||||
if (segmentsDistance > sumRadius || segmentsDistance < MACHINE_EPSILON) {
|
if (segmentsDistance >= sumRadius || segmentsDistance < MACHINE_EPSILON) {
|
||||||
|
|
||||||
// The capsule are parallel but their inner segment distance is larger than the sum of the capsules radius.
|
// The capsule are parallel but their inner segment distance is larger than the sum of the capsules radius.
|
||||||
// Therefore, we do not have overlap. If the inner segments overlap, we do not report any collision.
|
// Therefore, we do not have overlap. If the inner segments overlap, we do not report any collision.
|
||||||
|
@ -102,8 +105,9 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
Vector3 segment1ToSegment2 = (capsule2SegA - capsule1SegA);
|
Vector3 segment1ToSegment2 = (capsule2SegA - capsule1SegA);
|
||||||
Vector3 segment1ToSegment2Normalized = segment1ToSegment2.getUnit();
|
Vector3 segment1ToSegment2Normalized = segment1ToSegment2.getUnit();
|
||||||
|
|
||||||
const Vector3 contactPointACapsule1Local = capsule1ToCapsule2SpaceTransform.getInverse() * (clipPointA - segment1ToSegment2 + segment1ToSegment2Normalized * capsuleShape1->getRadius());
|
Transform capsule2ToCapsule1SpaceTransform = capsule1ToCapsule2SpaceTransform.getInverse();
|
||||||
const Vector3 contactPointBCapsule1Local = capsule1ToCapsule2SpaceTransform.getInverse() * (clipPointB - segment1ToSegment2 + segment1ToSegment2Normalized * capsuleShape1->getRadius());
|
const Vector3 contactPointACapsule1Local = capsule2ToCapsule1SpaceTransform * (clipPointA - segment1ToSegment2 + segment1ToSegment2Normalized * capsuleShape1->getRadius());
|
||||||
|
const Vector3 contactPointBCapsule1Local = capsule2ToCapsule1SpaceTransform * (clipPointB - segment1ToSegment2 + segment1ToSegment2Normalized * capsuleShape1->getRadius());
|
||||||
const Vector3 contactPointACapsule2Local = clipPointA - segment1ToSegment2Normalized * capsuleShape2->getRadius();
|
const Vector3 contactPointACapsule2Local = clipPointA - segment1ToSegment2Normalized * capsuleShape2->getRadius();
|
||||||
const Vector3 contactPointBCapsule2Local = clipPointB - segment1ToSegment2Normalized * capsuleShape2->getRadius();
|
const Vector3 contactPointBCapsule2Local = clipPointB - segment1ToSegment2Normalized * capsuleShape2->getRadius();
|
||||||
|
|
||||||
|
@ -112,9 +116,10 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
decimal penetrationDepth = sumRadius - segmentsDistance;
|
decimal penetrationDepth = sumRadius - segmentsDistance;
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
// TODO : Make sure we create two contact points at the same time (same method here)
|
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointACapsule1Local, contactPointACapsule2Local);
|
||||||
contactPointInfo.init(normalWorld, penetrationDepth, contactPointACapsule1Local, contactPointBCapsule1Local);
|
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointBCapsule1Local, contactPointBCapsule2Local);
|
||||||
contactPointInfo.init(normalWorld, penetrationDepth, contactPointACapsule2Local, contactPointBCapsule2Local);
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +134,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
const decimal closestPointsDistanceSquare = closestPointsSeg1ToSeg2.lengthSquare();
|
const decimal closestPointsDistanceSquare = closestPointsSeg1ToSeg2.lengthSquare();
|
||||||
|
|
||||||
// If the collision shapes overlap
|
// If the collision shapes overlap
|
||||||
if (closestPointsDistanceSquare <= sumRadius * sumRadius && closestPointsDistanceSquare > MACHINE_EPSILON) {
|
if (closestPointsDistanceSquare < sumRadius * sumRadius && closestPointsDistanceSquare > MACHINE_EPSILON) {
|
||||||
|
|
||||||
decimal closestPointsDistance = std::sqrt(closestPointsDistanceSquare);
|
decimal closestPointsDistance = std::sqrt(closestPointsDistanceSquare);
|
||||||
closestPointsSeg1ToSeg2 /= closestPointsDistance;
|
closestPointsSeg1ToSeg2 /= closestPointsDistance;
|
||||||
|
@ -142,7 +147,7 @@ bool CapsuleVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhase
|
||||||
decimal penetrationDepth = sumRadius - closestPointsDistance;
|
decimal penetrationDepth = sumRadius - closestPointsDistance;
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactPointInfo.init(normalWorld, penetrationDepth, contactPointCapsule1Local, contactPointCapsule2Local);
|
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointCapsule1Local, contactPointCapsule2Local);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class CapsuleVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) override;
|
ContactManifoldInfo& contactManifoldInfo) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ NarrowPhaseAlgorithm* DefaultCollisionDispatch::selectAlgorithm(int type1, int t
|
||||||
return &mSphereVsSphereAlgorithm;
|
return &mSphereVsSphereAlgorithm;
|
||||||
}
|
}
|
||||||
// Sphere vs Capsule algorithm
|
// Sphere vs Capsule algorithm
|
||||||
if (shape1Type == CollisionShapeType::CAPSULE && shape2Type == CollisionShapeType::SPHERE) {
|
if (shape1Type == CollisionShapeType::SPHERE && shape2Type == CollisionShapeType::CAPSULE) {
|
||||||
return &mSphereVsCapsuleAlgorithm;
|
return &mSphereVsCapsuleAlgorithm;
|
||||||
}
|
}
|
||||||
// Capsule vs Capsule algorithm
|
// Capsule vs Capsule algorithm
|
||||||
|
|
|
@ -47,7 +47,7 @@ using namespace reactphysics3d;
|
||||||
/// origin, they we give that simplex polytope to the EPA algorithm which will compute
|
/// origin, they we give that simplex polytope to the EPA algorithm which will compute
|
||||||
/// the correct penetration depth and contact points between the enlarged objects.
|
/// the correct penetration depth and contact points between the enlarged objects.
|
||||||
GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) {
|
ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
PROFILE("GJKAlgorithm::testCollision()");
|
PROFILE("GJKAlgorithm::testCollision()");
|
||||||
|
|
||||||
|
@ -201,8 +201,8 @@ GJKAlgorithm::GJKResult GJKAlgorithm::testCollision(const NarrowPhaseInfo* narro
|
||||||
return GJKResult::INTERPENETRATE;
|
return GJKResult::INTERPENETRATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the contact info object
|
// Add a new contact point
|
||||||
contactPointInfo.init(normal, penetrationDepth, pA, pB);
|
contactManifoldInfo.addContactPoint(normal, penetrationDepth, pA, pB);
|
||||||
|
|
||||||
return GJKResult::COLLIDE_IN_MARGIN;
|
return GJKResult::COLLIDE_IN_MARGIN;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
#define REACTPHYSICS3D_GJK_ALGORITHM_H
|
#define REACTPHYSICS3D_GJK_ALGORITHM_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "constraint/ContactPoint.h"
|
#include "collision/ContactManifoldInfo.h"
|
||||||
|
#include "collision/NarrowPhaseInfo.h"
|
||||||
#include "collision/shapes/ConvexShape.h"
|
#include "collision/shapes/ConvexShape.h"
|
||||||
#include "VoronoiSimplex.h"
|
#include "VoronoiSimplex.h"
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ class GJKAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volumes collide.
|
/// Compute a contact info if the two bounding volumes collide.
|
||||||
GJKResult testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
GJKResult testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo);
|
ContactManifoldInfo& contactManifoldInfo);
|
||||||
|
|
||||||
/// Use the GJK Algorithm to find if a point is inside a convex collision shape
|
/// Use the GJK Algorithm to find if a point is inside a convex collision shape
|
||||||
bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape);
|
bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "body/Body.h"
|
#include "body/Body.h"
|
||||||
#include "constraint/ContactPoint.h"
|
#include "collision/ContactManifoldInfo.h"
|
||||||
#include "memory/PoolAllocator.h"
|
#include "memory/PoolAllocator.h"
|
||||||
#include "engine/OverlappingPair.h"
|
#include "engine/OverlappingPair.h"
|
||||||
#include "collision/NarrowPhaseInfo.h"
|
#include "collision/NarrowPhaseInfo.h"
|
||||||
|
@ -84,7 +84,7 @@ class NarrowPhaseAlgorithm {
|
||||||
NarrowPhaseAlgorithm& operator=(const NarrowPhaseAlgorithm& algorithm) = delete;
|
NarrowPhaseAlgorithm& operator=(const NarrowPhaseAlgorithm& algorithm) = delete;
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactPointInfo& contactPointInfo)=0;
|
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool SATAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SATAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) {
|
ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
#define REACTPHYSICS3D_SAT_ALGORITHM_H
|
#define REACTPHYSICS3D_SAT_ALGORITHM_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "constraint/ContactPoint.h"
|
#include "collision/ContactManifoldInfo.h"
|
||||||
|
#include "collision/NarrowPhaseInfo.h"
|
||||||
|
|
||||||
/// ReactPhysics3D namespace
|
/// ReactPhysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
@ -59,7 +60,7 @@ class SATAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volumes collide.
|
/// Compute a contact info if the two bounding volumes collide.
|
||||||
bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo);
|
ContactManifoldInfo& contactManifoldInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,17 @@
|
||||||
// We want to use the ReactPhysics3D namespace
|
// We want to use the ReactPhysics3D namespace
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactPointInfo& contactPointInfo) {
|
bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo, ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE);
|
||||||
|
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::CAPSULE);
|
||||||
|
|
||||||
// Get the collision shapes
|
// Get the collision shapes
|
||||||
const SphereShape* sphereShape = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape1);
|
const SphereShape* sphereShape = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape1);
|
||||||
const CapsuleShape* capsuleShape = static_cast<const CapsuleShape*>(narrowPhaseInfo->collisionShape2);
|
const CapsuleShape* capsuleShape = static_cast<const CapsuleShape*>(narrowPhaseInfo->collisionShape2);
|
||||||
|
|
||||||
// Get the transform from sphere local-space to capsule local-space
|
// Get the transform from sphere local-space to capsule local-space
|
||||||
const Transform sphereToCapsuleSpaceTransform = narrowPhaseInfo->shape1ToWorldTransform * narrowPhaseInfo->shape2ToWorldTransform.getInverse();
|
const Transform sphereToCapsuleSpaceTransform = narrowPhaseInfo->shape2ToWorldTransform.getInverse() * narrowPhaseInfo->shape1ToWorldTransform;
|
||||||
|
|
||||||
// Transform the center of the sphere into the local-space of the capsule shape
|
// Transform the center of the sphere into the local-space of the capsule shape
|
||||||
const Vector3 sphereCenter = sphereToCapsuleSpaceTransform.getPosition();
|
const Vector3 sphereCenter = sphereToCapsuleSpaceTransform.getPosition();
|
||||||
|
@ -58,7 +61,7 @@ bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseI
|
||||||
decimal sumRadius = sphereShape->getRadius() + capsuleShape->getRadius();
|
decimal sumRadius = sphereShape->getRadius() + capsuleShape->getRadius();
|
||||||
|
|
||||||
// If the collision shapes overlap
|
// If the collision shapes overlap
|
||||||
if (sphereSegmentDistanceSquare <= sumRadius * sumRadius && sphereSegmentDistanceSquare > MACHINE_EPSILON) {
|
if (sphereSegmentDistanceSquare < sumRadius * sumRadius && sphereSegmentDistanceSquare > MACHINE_EPSILON) {
|
||||||
|
|
||||||
decimal sphereSegmentDistance = std::sqrt(sphereSegmentDistanceSquare);
|
decimal sphereSegmentDistance = std::sqrt(sphereSegmentDistanceSquare);
|
||||||
sphereCenterToSegment /= sphereSegmentDistance;
|
sphereCenterToSegment /= sphereSegmentDistance;
|
||||||
|
@ -71,7 +74,7 @@ bool SphereVsCapsuleAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseI
|
||||||
decimal penetrationDepth = sumRadius - sphereSegmentDistance;
|
decimal penetrationDepth = sumRadius - sphereSegmentDistance;
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactPointInfo.init(normalWorld, penetrationDepth, contactPointSphereLocal, contactPointCapsuleLocal);
|
contactManifoldInfo.addContactPoint(normalWorld, penetrationDepth, contactPointSphereLocal, contactPointCapsuleLocal);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class SphereVsCapsuleAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) override;
|
ContactManifoldInfo& contactManifoldInfo) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool SphereVsConvexMeshAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SphereVsConvexMeshAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) {
|
ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
// Get the local-space to world-space transforms
|
// Get the local-space to world-space transforms
|
||||||
const Transform& transform1 = narrowPhaseInfo->shape1ToWorldTransform;
|
const Transform& transform1 = narrowPhaseInfo->shape1ToWorldTransform;
|
||||||
|
@ -41,7 +41,7 @@ bool SphereVsConvexMeshAlgorithm::testCollision(const NarrowPhaseInfo* narrowPha
|
||||||
|
|
||||||
// First, we run the GJK algorithm
|
// First, we run the GJK algorithm
|
||||||
GJKAlgorithm gjkAlgorithm;
|
GJKAlgorithm gjkAlgorithm;
|
||||||
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, contactPointInfo);
|
GJKAlgorithm::GJKResult result = gjkAlgorithm.testCollision(narrowPhaseInfo, contactManifoldInfo);
|
||||||
|
|
||||||
// If we have found a contact point inside the margins (shallow penetration)
|
// If we have found a contact point inside the margins (shallow penetration)
|
||||||
if (result == GJKAlgorithm::GJKResult::COLLIDE_IN_MARGIN) {
|
if (result == GJKAlgorithm::GJKResult::COLLIDE_IN_MARGIN) {
|
||||||
|
@ -55,7 +55,7 @@ bool SphereVsConvexMeshAlgorithm::testCollision(const NarrowPhaseInfo* narrowPha
|
||||||
|
|
||||||
// Run the SAT algorithm to find the separating axis and compute contact point
|
// Run the SAT algorithm to find the separating axis and compute contact point
|
||||||
SATAlgorithm satAlgorithm;
|
SATAlgorithm satAlgorithm;
|
||||||
return satAlgorithm.testCollision(narrowPhaseInfo, contactPointInfo);
|
return satAlgorithm.testCollision(narrowPhaseInfo, contactManifoldInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -62,7 +62,7 @@ class SphereVsConvexMeshAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) override;
|
ContactManifoldInfo& contactManifoldInfo) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,11 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) {
|
ContactManifoldInfo& contactManifoldInfo) {
|
||||||
|
|
||||||
|
assert(narrowPhaseInfo->collisionShape1->getType() == CollisionShapeType::SPHERE);
|
||||||
|
assert(narrowPhaseInfo->collisionShape2->getType() == CollisionShapeType::SPHERE);
|
||||||
|
|
||||||
// Get the sphere collision shapes
|
// Get the sphere collision shapes
|
||||||
const SphereShape* sphereShape1 = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape1);
|
const SphereShape* sphereShape1 = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape1);
|
||||||
const SphereShape* sphereShape2 = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape2);
|
const SphereShape* sphereShape2 = static_cast<const SphereShape*>(narrowPhaseInfo->collisionShape2);
|
||||||
|
@ -49,7 +52,7 @@ bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseIn
|
||||||
decimal sumRadius = sphereShape1->getRadius() + sphereShape2->getRadius();
|
decimal sumRadius = sphereShape1->getRadius() + sphereShape2->getRadius();
|
||||||
|
|
||||||
// If the sphere collision shapes intersect
|
// If the sphere collision shapes intersect
|
||||||
if (squaredDistanceBetweenCenters <= sumRadius * sumRadius) {
|
if (squaredDistanceBetweenCenters < sumRadius * sumRadius) {
|
||||||
Vector3 centerSphere2InBody1LocalSpace = transform1.getInverse() * transform2.getPosition();
|
Vector3 centerSphere2InBody1LocalSpace = transform1.getInverse() * transform2.getPosition();
|
||||||
Vector3 centerSphere1InBody2LocalSpace = transform2.getInverse() * transform1.getPosition();
|
Vector3 centerSphere1InBody2LocalSpace = transform2.getInverse() * transform1.getPosition();
|
||||||
Vector3 intersectionOnBody1 = sphereShape1->getRadius() *
|
Vector3 intersectionOnBody1 = sphereShape1->getRadius() *
|
||||||
|
@ -59,8 +62,8 @@ bool SphereVsSphereAlgorithm::testCollision(const NarrowPhaseInfo* narrowPhaseIn
|
||||||
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
|
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
|
||||||
|
|
||||||
// Create the contact info object
|
// Create the contact info object
|
||||||
contactPointInfo.init(vectorBetweenCenters.getUnit(), penetrationDepth,
|
contactManifoldInfo.addContactPoint(vectorBetweenCenters.getUnit(), penetrationDepth,
|
||||||
intersectionOnBody1, intersectionOnBody2);
|
intersectionOnBody1, intersectionOnBody2);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
|
|
||||||
/// Compute a contact info if the two bounding volume collide
|
/// Compute a contact info if the two bounding volume collide
|
||||||
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
virtual bool testCollision(const NarrowPhaseInfo* narrowPhaseInfo,
|
||||||
ContactPointInfo& contactPointInfo) override;
|
ContactManifoldInfo& contactManifoldInfo) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
/// Type of the collision shape
|
/// Type of the collision shape
|
||||||
enum class CollisionShapeType {TRIANGLE, BOX, CAPSULE, SPHERE, CONVEX_MESH, CONCAVE_MESH, HEIGHTFIELD};
|
enum class CollisionShapeType {TRIANGLE, SPHERE, CAPSULE, BOX, CONVEX_MESH, CONCAVE_MESH, HEIGHTFIELD};
|
||||||
const int NB_COLLISION_SHAPE_TYPES = 9;
|
const int NB_COLLISION_SHAPE_TYPES = 9;
|
||||||
|
|
||||||
// Declarations
|
// Declarations
|
||||||
|
|
|
@ -31,13 +31,35 @@ using namespace reactphysics3d;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
ContactPoint::ContactPoint(const ContactPointInfo& contactInfo)
|
ContactPoint::ContactPoint(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
||||||
: mNormal(contactInfo.normal),
|
const Transform& body2Transform)
|
||||||
mPenetrationDepth(contactInfo.penetrationDepth),
|
: mNormal(contactInfo->normal),
|
||||||
mLocalPointOnBody1(contactInfo.localPoint1),
|
mPenetrationDepth(contactInfo->penetrationDepth),
|
||||||
mLocalPointOnBody2(contactInfo.localPoint2),
|
mLocalPointOnBody1(contactInfo->localPoint1),
|
||||||
|
mLocalPointOnBody2(contactInfo->localPoint2),
|
||||||
mIsRestingContact(false) {
|
mIsRestingContact(false) {
|
||||||
|
|
||||||
assert(mPenetrationDepth > decimal(0.0));
|
assert(mPenetrationDepth > decimal(0.0));
|
||||||
|
|
||||||
|
// Compute the world position of the contact points
|
||||||
|
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
||||||
|
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the contact point with a new one that is similar (very close)
|
||||||
|
/// The idea is to keep the cache impulse (for warm starting the contact solver)
|
||||||
|
void ContactPoint::update(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
||||||
|
const Transform& body2Transform) {
|
||||||
|
|
||||||
|
assert(isSimilarWithContactPoint(contactInfo));
|
||||||
|
assert(contactInfo->penetrationDepth > decimal(0.0));
|
||||||
|
|
||||||
|
mNormal = contactInfo->normal;
|
||||||
|
mPenetrationDepth = contactInfo->penetrationDepth;
|
||||||
|
mLocalPointOnBody1 = contactInfo->localPoint1;
|
||||||
|
mLocalPointOnBody2 = contactInfo->localPoint2;
|
||||||
|
|
||||||
|
// Compute the world position of the contact points
|
||||||
|
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
||||||
|
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,60 +29,13 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "body/CollisionBody.h"
|
#include "body/CollisionBody.h"
|
||||||
#include "collision/NarrowPhaseInfo.h"
|
#include "collision/NarrowPhaseInfo.h"
|
||||||
|
#include "collision/ContactPointInfo.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "mathematics/mathematics.h"
|
#include "mathematics/mathematics.h"
|
||||||
#include "configuration.h"
|
|
||||||
|
|
||||||
/// ReactPhysics3D namespace
|
/// ReactPhysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
// Structure ContactPointInfo
|
|
||||||
/**
|
|
||||||
* This structure contains informations about a collision contact
|
|
||||||
* computed during the narrow-phase collision detection. Those
|
|
||||||
* informations are used to compute the contact set for a contact
|
|
||||||
* between two bodies.
|
|
||||||
*/
|
|
||||||
struct ContactPointInfo {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
|
||||||
|
|
||||||
/// Normalized normal vector of the collision contact in world space
|
|
||||||
Vector3 normal;
|
|
||||||
|
|
||||||
/// Penetration depth of the contact
|
|
||||||
decimal penetrationDepth;
|
|
||||||
|
|
||||||
/// Contact point of body 1 in local space of body 1
|
|
||||||
Vector3 localPoint1;
|
|
||||||
|
|
||||||
/// Contact point of body 2 in local space of body 2
|
|
||||||
Vector3 localPoint2;
|
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
|
||||||
|
|
||||||
/// Constructor
|
|
||||||
ContactPointInfo() = default;
|
|
||||||
|
|
||||||
/// Destructor
|
|
||||||
~ContactPointInfo() = default;
|
|
||||||
|
|
||||||
/// Initialize the contact point info
|
|
||||||
void init(const Vector3& contactNormal, decimal penDepth,
|
|
||||||
const Vector3& localPt1, const Vector3& localPt2) {
|
|
||||||
normal = contactNormal;
|
|
||||||
penetrationDepth = penDepth;
|
|
||||||
localPoint1 = localPt1;
|
|
||||||
localPoint2 = localPt2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Class ContactPoint
|
// Class ContactPoint
|
||||||
/**
|
/**
|
||||||
* This class represents a collision contact point between two
|
* This class represents a collision contact point between two
|
||||||
|
@ -95,16 +48,16 @@ class ContactPoint {
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
/// Normalized normal vector of the contact (from body1 toward body2) in world space
|
/// Normalized normal vector of the contact (from body1 toward body2) in world space
|
||||||
const Vector3 mNormal;
|
Vector3 mNormal;
|
||||||
|
|
||||||
/// Penetration depth
|
/// Penetration depth
|
||||||
decimal mPenetrationDepth;
|
decimal mPenetrationDepth;
|
||||||
|
|
||||||
/// Contact point on body 1 in local space of body 1
|
/// Contact point on body 1 in local space of body 1
|
||||||
const Vector3 mLocalPointOnBody1;
|
Vector3 mLocalPointOnBody1;
|
||||||
|
|
||||||
/// Contact point on body 2 in local space of body 2
|
/// Contact point on body 2 in local space of body 2
|
||||||
const Vector3 mLocalPointOnBody2;
|
Vector3 mLocalPointOnBody2;
|
||||||
|
|
||||||
/// Contact point on body 1 in world space
|
/// Contact point on body 1 in world space
|
||||||
Vector3 mWorldPointOnBody1;
|
Vector3 mWorldPointOnBody1;
|
||||||
|
@ -123,7 +76,8 @@ class ContactPoint {
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
ContactPoint(const ContactPointInfo& contactInfo);
|
ContactPoint(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
||||||
|
const Transform& body2Transform);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ContactPoint() = default;
|
~ContactPoint() = default;
|
||||||
|
@ -134,11 +88,9 @@ class ContactPoint {
|
||||||
/// Deleted assignment operator
|
/// Deleted assignment operator
|
||||||
ContactPoint& operator=(const ContactPoint& contact) = delete;
|
ContactPoint& operator=(const ContactPoint& contact) = delete;
|
||||||
|
|
||||||
/// Update the world contact points
|
/// Update the contact point with a new one that is similar (very close)
|
||||||
void updateWorldContactPoints(const Transform& body1Transform, const Transform& body2Transform);
|
void update(const ContactPointInfo* contactInfo, const Transform& body1Transform,
|
||||||
|
const Transform& body2Transform);
|
||||||
/// Update the penetration depth
|
|
||||||
void updatePenetrationDepth();
|
|
||||||
|
|
||||||
/// Return the normal vector of the contact
|
/// Return the normal vector of the contact
|
||||||
Vector3 getNormal() const;
|
Vector3 getNormal() const;
|
||||||
|
@ -158,6 +110,9 @@ class ContactPoint {
|
||||||
/// Return the cached penetration impulse
|
/// Return the cached penetration impulse
|
||||||
decimal getPenetrationImpulse() const;
|
decimal getPenetrationImpulse() const;
|
||||||
|
|
||||||
|
/// Return true if the contact point is similar (close enougth) to another given contact point
|
||||||
|
bool isSimilarWithContactPoint(const ContactPointInfo* contactPoint) const;
|
||||||
|
|
||||||
/// Set the cached penetration impulse
|
/// Set the cached penetration impulse
|
||||||
void setPenetrationImpulse(decimal impulse);
|
void setPenetrationImpulse(decimal impulse);
|
||||||
|
|
||||||
|
@ -174,17 +129,6 @@ class ContactPoint {
|
||||||
size_t getSizeInBytes() const;
|
size_t getSizeInBytes() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update the world contact points
|
|
||||||
inline void ContactPoint::updateWorldContactPoints(const Transform& body1Transform, const Transform& body2Transform) {
|
|
||||||
mWorldPointOnBody1 = body1Transform * mLocalPointOnBody1;
|
|
||||||
mWorldPointOnBody2 = body2Transform * mLocalPointOnBody2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the penetration depth
|
|
||||||
inline void ContactPoint::updatePenetrationDepth() {
|
|
||||||
mPenetrationDepth = (mWorldPointOnBody1 - mWorldPointOnBody2).dot(mNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the normal vector of the contact
|
// Return the normal vector of the contact
|
||||||
inline Vector3 ContactPoint::getNormal() const {
|
inline Vector3 ContactPoint::getNormal() const {
|
||||||
return mNormal;
|
return mNormal;
|
||||||
|
@ -215,6 +159,12 @@ inline decimal ContactPoint::getPenetrationImpulse() const {
|
||||||
return mPenetrationImpulse;
|
return mPenetrationImpulse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the contact point is similar (close enougth) to another given contact point
|
||||||
|
inline bool ContactPoint::isSimilarWithContactPoint(const ContactPointInfo* localContactPointBody1) const {
|
||||||
|
return (localContactPointBody1->localPoint1 - mLocalPointOnBody1).lengthSquare() <= (PERSISTENT_CONTACT_DIST_THRESHOLD *
|
||||||
|
PERSISTENT_CONTACT_DIST_THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
// Set the cached penetration impulse
|
// Set the cached penetration impulse
|
||||||
inline void ContactPoint::setPenetrationImpulse(decimal impulse) {
|
inline void ContactPoint::setPenetrationImpulse(decimal impulse) {
|
||||||
mPenetrationImpulse = impulse;
|
mPenetrationImpulse = impulse;
|
||||||
|
|
|
@ -247,16 +247,16 @@ class CollisionCallback {
|
||||||
struct CollisionCallbackInfo {
|
struct CollisionCallbackInfo {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const ContactPointInfo& contactPoint;
|
const ContactManifoldInfo& contactManifold;
|
||||||
CollisionBody* body1;
|
CollisionBody* body1;
|
||||||
CollisionBody* body2;
|
CollisionBody* body2;
|
||||||
const ProxyShape* proxyShape1;
|
const ProxyShape* proxyShape1;
|
||||||
const ProxyShape* proxyShape2;
|
const ProxyShape* proxyShape2;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
CollisionCallbackInfo(const ContactPointInfo& point, CollisionBody* b1, CollisionBody* b2,
|
CollisionCallbackInfo(const ContactManifoldInfo& manifold, CollisionBody* b1, CollisionBody* b2,
|
||||||
const ProxyShape* proxShape1, const ProxyShape* proxShape2) :
|
const ProxyShape* proxShape1, const ProxyShape* proxShape2) :
|
||||||
contactPoint(point), body1(b1), body2(b2),
|
contactManifold(manifold), body1(b1), body2(b2),
|
||||||
proxyShape1(proxShape1), proxyShape2(proxShape2) {
|
proxyShape1(proxShape1), proxyShape2(proxShape2) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define REACTPHYSICS3D_EVENT_LISTENER_H
|
#define REACTPHYSICS3D_EVENT_LISTENER_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "constraint/ContactPoint.h"
|
#include "collision/ContactManifoldInfo.h"
|
||||||
|
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
@ -53,13 +53,13 @@ class EventListener {
|
||||||
/**
|
/**
|
||||||
* @param contact Information about the contact
|
* @param contact Information about the contact
|
||||||
*/
|
*/
|
||||||
virtual void beginContact(const ContactPointInfo& contact) {}
|
virtual void beginContact(const ContactManifoldInfo& contactManifold) {}
|
||||||
|
|
||||||
/// Called when a new contact point is found between two bodies
|
/// Called when a new contact point is found between two bodies
|
||||||
/**
|
/**
|
||||||
* @param contact Information about the contact
|
* @param contact Information about the contact
|
||||||
*/
|
*/
|
||||||
virtual void newContact(const ContactPointInfo& contact) {}
|
virtual void newContact(const ContactManifoldInfo& contactManifold) {}
|
||||||
|
|
||||||
/// Called at the beginning of an internal tick of the simulation step.
|
/// Called at the beginning of an internal tick of the simulation step.
|
||||||
/// Each time the DynamicsWorld::update() method is called, the physics
|
/// Each time the DynamicsWorld::update() method is called, the physics
|
||||||
|
|
|
@ -80,11 +80,8 @@ class OverlappingPair {
|
||||||
/// Return the pointer to second body
|
/// Return the pointer to second body
|
||||||
ProxyShape* getShape2() const;
|
ProxyShape* getShape2() const;
|
||||||
|
|
||||||
/// Add a contact to the contact cache
|
/// Add a contact manifold
|
||||||
void addContact(ContactPoint* contact);
|
void addContactManifold(const ContactManifoldInfo& contactManifoldInfo);
|
||||||
|
|
||||||
/// Update the contact cache
|
|
||||||
void update();
|
|
||||||
|
|
||||||
/// Return the cached separating axis
|
/// Return the cached separating axis
|
||||||
Vector3 getCachedSeparatingAxis() const;
|
Vector3 getCachedSeparatingAxis() const;
|
||||||
|
@ -123,13 +120,8 @@ inline ProxyShape* OverlappingPair::getShape2() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a contact to the contact manifold
|
// Add a contact to the contact manifold
|
||||||
inline void OverlappingPair::addContact(ContactPoint* contact) {
|
inline void OverlappingPair::addContactManifold(const ContactManifoldInfo& contactManifoldInfo) {
|
||||||
mContactManifoldSet.addContactPoint(contact);
|
mContactManifoldSet.addContactManifold(contactManifoldInfo);
|
||||||
}
|
|
||||||
|
|
||||||
// Update the contact manifold
|
|
||||||
inline void OverlappingPair::update() {
|
|
||||||
mContactManifoldSet.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the cached separating axis
|
// Return the cached separating axis
|
||||||
|
|
Loading…
Reference in New Issue
Block a user