Fix issue in SAT with edge-edge contact (wrong contact normal) and favor face contacts over edge-edge contacts in polyhedron vs polyhedron collision in SAT algorithm for better stability

This commit is contained in:
Daniel Chappuis 2020-06-27 23:48:19 +02:00
parent fc5ccdbe4d
commit 4283e3f408
2 changed files with 13 additions and 24 deletions

View File

@ -10,6 +10,7 @@ do not hesitate to take a look at the user manual.
- Method RigidBody::resetForce() to reset the accumulated external force on a rigid body has beend added
- Method RigidBody::resetTorque() to reset the accumulated external torque on a rigid body has beend added
- Constructors with local-space anchor/axis have been added to BallAndSocketJointInfo, HingeJointInfo, FixedJointInfo and SliderJointInfo classes
- Robustness of polyhedron vs polyhedron collision detection has been improved in SAT algorithm (face contacts are favored over edge-edge contacts for better stability)
### Changed
@ -18,6 +19,7 @@ do not hesitate to take a look at the user manual.
### Fixed
- Issue with concave vs convex shape collision detection has been fixed
- Issue with edge vs edge collision has been fixed in SAT algorithm (wrong contact normal was computed)
## Version 0.8.0 (May 31, 2020)

View File

@ -657,18 +657,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
Vector3 closestPointPolyhedron1EdgeLocalSpace = polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge;
// Compute the world normal
// We use the direction from the centroid to the edge of the shape that is not a triangle
// to avoid possible degeneracies when axis direction is orthogonal to triangle normal
Vector3 normal;
if (isShape1Triangle) {
normal = polyhedron2->getCentroid() - closestPointPolyhedron2Edge;
}
else {
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
}
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * normal.getUnit();
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * separatingAxisPolyhedron2Space;
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],
@ -794,7 +783,15 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
break;
}
if (penetrationDepth < minPenetrationDepth) {
// If the current minimum penetration depth is along a face normal axis (isMinPenetrationFaceNormal=true) and we have found a new
// smaller pentration depth along an edge-edge cross-product axis we want to favor the face normal axis because contact manifolds between
// faces have more contact points and therefore more stable than the single contact point of an edge-edge collision. It means that if the new minimum
// penetration depth from the edge-edge contact is only a little bit smaller than the current minPenetrationDepth (from a face contact), we favor
// the face contact and do not generate an edge-edge contact. However, if the new penetration depth from the edge-edge contact is really smaller than
// the current one, we generate an edge-edge contact.
// To do this, we use a relative and absolute bias to increase a little bit the new penetration depth from the edge-edge contact during the comparison test
if ((isMinPenetrationFaceNormal && penetrationDepth1 * SEPARATING_AXIS_RELATIVE_TOLERANCE + SEPARATING_AXIS_ABSOLUTE_TOLERANCE < minPenetrationDepth) ||
(!isMinPenetrationFaceNormal && penetrationDepth < minPenetrationDepth)) {
minPenetrationDepth = penetrationDepth;
isMinPenetrationFaceNormalPolyhedron1 = false;
@ -862,17 +859,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
Vector3 closestPointPolyhedron1EdgeLocalSpace = polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge;
// Compute the world normal
// We use the direction from the centroid to the edge of the shape that is not a triangle
// to avoid possible degeneracies when axis direction is orthogonal to triangle normal
Vector3 normal;
if (isShape1Triangle) {
normal = polyhedron2->getCentroid() - closestPointPolyhedron2Edge;
}
else {
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
}
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * normal.getUnit();
Vector3 normalWorld = narrowPhaseInfoBatch.shape2ToWorldTransforms[batchIndex].getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfoBatch.collisionShapes1[batchIndex], narrowPhaseInfoBatch.collisionShapes2[batchIndex],