Fix issue with bias in SATAlgorithm and add asserts
This commit is contained in:
parent
b7506013e5
commit
6bcb586d52
|
@ -65,6 +65,7 @@ void NarrowPhaseInfo::addContactPoint(const Vector3& contactNormal, decimal penD
|
||||||
const Vector3& localPt1, const Vector3& localPt2) {
|
const Vector3& localPt1, const Vector3& localPt2) {
|
||||||
|
|
||||||
assert(penDepth > decimal(0.0));
|
assert(penDepth > decimal(0.0));
|
||||||
|
assert(contactNormal.length() > decimal(0.8));
|
||||||
|
|
||||||
// Get the memory allocator
|
// Get the memory allocator
|
||||||
MemoryAllocator& allocator = overlappingPair->getTemporaryAllocator();
|
MemoryAllocator& allocator = overlappingPair->getTemporaryAllocator();
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
using namespace reactphysics3d;
|
using namespace reactphysics3d;
|
||||||
|
|
||||||
// Static variables initialization
|
// Static variables initialization
|
||||||
const decimal SATAlgorithm::SAME_SEPARATING_AXIS_BIAS = decimal(0.001);
|
const decimal SATAlgorithm::SEPARATING_AXIS_RELATIVE_TOLERANCE = decimal(1.02);
|
||||||
|
const decimal SATAlgorithm::SEPARATING_AXIS_ABSOLUTE_TOLERANCE = decimal(0.005);
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
SATAlgorithm::SATAlgorithm(MemoryAllocator& memoryAllocator) : mMemoryAllocator(memoryAllocator) {
|
SATAlgorithm::SATAlgorithm(MemoryAllocator& memoryAllocator) : mMemoryAllocator(memoryAllocator) {
|
||||||
|
@ -478,8 +479,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
uint minSeparatingEdge2Index = 0;
|
uint minSeparatingEdge2Index = 0;
|
||||||
Vector3 separatingEdge1A, separatingEdge1B;
|
Vector3 separatingEdge1A, separatingEdge1B;
|
||||||
Vector3 separatingEdge2A, separatingEdge2B;
|
Vector3 separatingEdge2A, separatingEdge2B;
|
||||||
Vector3 minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
|
const bool isShape1Triangle = polyhedron1->getName() == CollisionShapeName::TRIANGLE;
|
||||||
bool isShape1Triangle = polyhedron1->getName() == CollisionShapeName::TRIANGLE;
|
|
||||||
|
|
||||||
LastFrameCollisionInfo* lastFrameCollisionInfo = narrowPhaseInfo->getLastFrameCollisionInfo();
|
LastFrameCollisionInfo* lastFrameCollisionInfo = narrowPhaseInfo->getLastFrameCollisionInfo();
|
||||||
|
|
||||||
|
@ -633,7 +633,6 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
|
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
|
|
||||||
Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * normal.getUnit();
|
Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * normal.getUnit();
|
||||||
|
|
||||||
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
|
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
|
||||||
|
@ -657,40 +656,58 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minPenetrationDepth = DECIMAL_LARGEST;
|
||||||
|
isMinPenetrationFaceNormal = false;
|
||||||
|
|
||||||
// Test all the face normals of the polyhedron 1 for separating axis
|
// Test all the face normals of the polyhedron 1 for separating axis
|
||||||
uint faceIndex;
|
uint faceIndex1;
|
||||||
decimal penetrationDepth = testFacesDirectionPolyhedronVsPolyhedron(polyhedron1, polyhedron2, polyhedron1ToPolyhedron2, faceIndex);
|
decimal penetrationDepth1 = testFacesDirectionPolyhedronVsPolyhedron(polyhedron1, polyhedron2, polyhedron1ToPolyhedron2, faceIndex1);
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
if (penetrationDepth1 <= decimal(0.0)) {
|
||||||
|
|
||||||
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = true;
|
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = true;
|
||||||
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = false;
|
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = false;
|
||||||
lastFrameCollisionInfo->satMinAxisFaceIndex = faceIndex;
|
lastFrameCollisionInfo->satMinAxisFaceIndex = faceIndex1;
|
||||||
|
|
||||||
// We have found a separating axis
|
// We have found a separating axis
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (penetrationDepth < minPenetrationDepth - SAME_SEPARATING_AXIS_BIAS) {
|
|
||||||
isMinPenetrationFaceNormal = true;
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minFaceIndex = faceIndex;
|
|
||||||
isMinPenetrationFaceNormalPolyhedron1 = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test all the face normals of the polyhedron 2 for separating axis
|
// Test all the face normals of the polyhedron 2 for separating axis
|
||||||
penetrationDepth = testFacesDirectionPolyhedronVsPolyhedron(polyhedron2, polyhedron1, polyhedron2ToPolyhedron1, faceIndex);
|
uint faceIndex2;
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
decimal penetrationDepth2 = testFacesDirectionPolyhedronVsPolyhedron(polyhedron2, polyhedron1, polyhedron2ToPolyhedron1, faceIndex2);
|
||||||
|
if (penetrationDepth2 <= decimal(0.0)) {
|
||||||
|
|
||||||
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = false;
|
lastFrameCollisionInfo->satIsAxisFacePolyhedron1 = false;
|
||||||
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = true;
|
lastFrameCollisionInfo->satIsAxisFacePolyhedron2 = true;
|
||||||
lastFrameCollisionInfo->satMinAxisFaceIndex = faceIndex;
|
lastFrameCollisionInfo->satMinAxisFaceIndex = faceIndex2;
|
||||||
|
|
||||||
// We have found a separating axis
|
// We have found a separating axis
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (penetrationDepth < minPenetrationDepth - SAME_SEPARATING_AXIS_BIAS) {
|
|
||||||
|
// Here we know that we have found penetration along both axis of a face of polyhedron1 and a face of
|
||||||
|
// polyhedron2. If the two penetration depths are almost the same, we need to make sure we always prefer
|
||||||
|
// one axis to the other for consistency between frames. This is to prevent the contact manifolds to switch
|
||||||
|
// from one reference axis to the other for a face to face resting contact for instance. This is better for
|
||||||
|
// stability. To do this, we use a relative and absolute bias to move penetrationDepth2 a little bit to the right.
|
||||||
|
// Now if:
|
||||||
|
// penetrationDepth1 < penetrationDepth2: Nothing happens and we use axis of polygon 1
|
||||||
|
// penetrationDepth1 ~ penetrationDepth2: Until penetrationDepth1 becomes significantly less than penetrationDepth2 we still use axis of polygon 1
|
||||||
|
// penetrationDepth1 >> penetrationDepth2: penetrationDepth2 is now significantly less than penetrationDepth1 and we use polygon 2 axis
|
||||||
|
if (penetrationDepth1 < penetrationDepth2 * SEPARATING_AXIS_RELATIVE_TOLERANCE + SEPARATING_AXIS_ABSOLUTE_TOLERANCE) {
|
||||||
|
|
||||||
|
// We use penetration axis of polygon 1
|
||||||
isMinPenetrationFaceNormal = true;
|
isMinPenetrationFaceNormal = true;
|
||||||
minPenetrationDepth = penetrationDepth;
|
minPenetrationDepth = penetrationDepth1;
|
||||||
minFaceIndex = faceIndex;
|
minFaceIndex = faceIndex1;
|
||||||
|
isMinPenetrationFaceNormalPolyhedron1 = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// We use penetration axis of polygon 2
|
||||||
|
isMinPenetrationFaceNormal = true;
|
||||||
|
minPenetrationDepth = penetrationDepth2;
|
||||||
|
minFaceIndex = faceIndex2;
|
||||||
isMinPenetrationFaceNormalPolyhedron1 = false;
|
isMinPenetrationFaceNormalPolyhedron1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,7 +752,7 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (penetrationDepth < minPenetrationDepth - SAME_SEPARATING_AXIS_BIAS) {
|
if (penetrationDepth < minPenetrationDepth) {
|
||||||
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
minPenetrationDepth = penetrationDepth;
|
||||||
isMinPenetrationFaceNormalPolyhedron1 = false;
|
isMinPenetrationFaceNormalPolyhedron1 = false;
|
||||||
|
@ -746,7 +763,6 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
separatingEdge1B = edge1B;
|
separatingEdge1B = edge1B;
|
||||||
separatingEdge2A = edge2A;
|
separatingEdge2A = edge2A;
|
||||||
separatingEdge2B = edge2B;
|
separatingEdge2B = edge2B;
|
||||||
minEdgeVsEdgeSeparatingAxisPolyhedron2Space = separatingAxisPolyhedron2Space;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,8 +823,10 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
else {
|
else {
|
||||||
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
|
normal = polyhedron1ToPolyhedron2.getOrientation() * ((polyhedron2ToPolyhedron1 * closestPointPolyhedron1Edge) - polyhedron1->getCentroid());
|
||||||
}
|
}
|
||||||
//Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * minEdgeVsEdgeSeparatingAxisPolyhedron2Space;
|
const Vector3 unitNormal = normal.getUnit();
|
||||||
Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * normal.getUnit();
|
assert(unitNormal.length() > decimal(0.7));
|
||||||
|
Vector3 normalWorld = narrowPhaseInfo->shape2ToWorldTransform.getOrientation() * unitNormal;
|
||||||
|
assert(normalWorld.length() > decimal(0.7));
|
||||||
|
|
||||||
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
|
// Compute smooth triangle mesh contact if one of the two collision shapes is a triangle
|
||||||
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfo->collisionShape1, narrowPhaseInfo->collisionShape2,
|
TriangleShape::computeSmoothTriangleMeshContact(narrowPhaseInfo->collisionShape1, narrowPhaseInfo->collisionShape2,
|
||||||
|
@ -816,6 +834,8 @@ bool SATAlgorithm::testCollisionConvexPolyhedronVsConvexPolyhedron(NarrowPhaseIn
|
||||||
narrowPhaseInfo->shape1ToWorldTransform, narrowPhaseInfo->shape2ToWorldTransform,
|
narrowPhaseInfo->shape1ToWorldTransform, narrowPhaseInfo->shape2ToWorldTransform,
|
||||||
minPenetrationDepth, normalWorld);
|
minPenetrationDepth, normalWorld);
|
||||||
|
|
||||||
|
assert(normalWorld.length() > decimal(0.7));
|
||||||
|
|
||||||
// Create the contact point
|
// Create the contact point
|
||||||
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
narrowPhaseInfo->addContactPoint(normalWorld, minPenetrationDepth,
|
||||||
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
|
closestPointPolyhedron1EdgeLocalSpace, closestPointPolyhedron2Edge);
|
||||||
|
|
|
@ -55,10 +55,11 @@ class SATAlgorithm {
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
/// Bias used to make sure the SAT algorithm returns the same penetration axis between frames
|
/// Relative and absolute bias used to make sure the SAT algorithm returns the same penetration axis between frames
|
||||||
/// when there are multiple separating axis with the same penetration depth. The goal is to
|
/// when there are multiple separating axis with almost the same penetration depth. The goal is to
|
||||||
/// make sure the contact manifold does not change too much between frames.
|
/// make sure the contact manifold does not change too much between frames for better stability.
|
||||||
static const decimal SAME_SEPARATING_AXIS_BIAS;
|
static const decimal SEPARATING_AXIS_RELATIVE_TOLERANCE;
|
||||||
|
static const decimal SEPARATING_AXIS_ABSOLUTE_TOLERANCE;
|
||||||
|
|
||||||
/// Memory allocator
|
/// Memory allocator
|
||||||
MemoryAllocator& mMemoryAllocator;
|
MemoryAllocator& mMemoryAllocator;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user