Remove temporal coherence from SAT for sphere vs polyhedron and capsule vs polyhedron
This commit is contained in:
parent
9b89f66667
commit
673e487f14
|
@ -74,69 +74,23 @@ bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfo* narrow
|
||||||
decimal minPenetrationDepth = DECIMAL_LARGEST;
|
decimal minPenetrationDepth = DECIMAL_LARGEST;
|
||||||
uint minFaceIndex = 0;
|
uint minFaceIndex = 0;
|
||||||
|
|
||||||
// True if the shapes were overlapping in the previous frame and are
|
|
||||||
// still overlapping on the same axis in this frame
|
|
||||||
bool isTemporalCoherenceValid = false;
|
|
||||||
|
|
||||||
LastFrameCollisionInfo& lastFrameInfo = narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo();
|
// For each face of the convex mesh
|
||||||
|
for (uint f = 0; f < polyhedron->getNbFaces(); f++) {
|
||||||
|
|
||||||
// If the shapes are not triangles (no temporal coherence for triangle collision because we do not store previous
|
// Compute the penetration depth of the shapes along the face normal direction
|
||||||
// frame collision data per triangle)
|
decimal penetrationDepth = computePolyhedronFaceVsSpherePenetrationDepth(f, polyhedron, sphere, sphereCenter);
|
||||||
if (polyhedron->getName() != CollisionShapeName::TRIANGLE) {
|
|
||||||
|
|
||||||
// If the last frame collision info is valid and was also using SAT algorithm
|
// If the penetration depth is negative, we have found a separating axis
|
||||||
if (lastFrameInfo.isValid && lastFrameInfo.wasUsingSAT) {
|
if (penetrationDepth <= decimal(0.0)) {
|
||||||
|
|
||||||
// We perform temporal coherence, we check if there is still an overlapping along the previous minimum separating
|
return false;
|
||||||
// axis. If it is the case, we directly report the collision without executing the whole SAT algorithm again. If
|
|
||||||
// the shapes are still separated along this axis, we directly exit with no collision.
|
|
||||||
|
|
||||||
// Compute the penetration depth of the shapes along the face normal direction
|
|
||||||
decimal penetrationDepth = computePolyhedronFaceVsSpherePenetrationDepth(lastFrameInfo.satMinAxisFaceIndex, polyhedron,
|
|
||||||
sphere, sphereCenter);
|
|
||||||
|
|
||||||
// If the previous axis is a separating axis
|
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
|
||||||
|
|
||||||
// Return no collision
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The two shapes are overlapping as in the previous frame and on the same axis, therefore
|
|
||||||
// we will skip the entire SAT algorithm because the minimum separating axis did not change
|
|
||||||
isTemporalCoherenceValid = lastFrameInfo.wasColliding;
|
|
||||||
|
|
||||||
if (isTemporalCoherenceValid) {
|
|
||||||
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minFaceIndex = lastFrameInfo.satMinAxisFaceIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// We the shapes are still overlapping in the same axis as in
|
// Check if we have found a new minimum penetration axis
|
||||||
// the previous frame, we skip the whole SAT algorithm
|
if (penetrationDepth < minPenetrationDepth) {
|
||||||
if (!isTemporalCoherenceValid) {
|
minPenetrationDepth = penetrationDepth;
|
||||||
|
minFaceIndex = f;
|
||||||
// For each face of the convex mesh
|
|
||||||
for (uint f = 0; f < polyhedron->getNbFaces(); f++) {
|
|
||||||
|
|
||||||
// Compute the penetration depth of the shapes along the face normal direction
|
|
||||||
decimal penetrationDepth = computePolyhedronFaceVsSpherePenetrationDepth(f, polyhedron, sphere, sphereCenter);
|
|
||||||
|
|
||||||
// If the penetration depth is negative, we have found a separating axis
|
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
|
||||||
|
|
||||||
lastFrameInfo.satMinAxisFaceIndex = f;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have found a new minimum penetration axis
|
|
||||||
if (penetrationDepth < minPenetrationDepth) {
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minFaceIndex = f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,8 +115,6 @@ bool SATAlgorithm::testCollisionSphereVsConvexPolyhedron(NarrowPhaseInfo* narrow
|
||||||
isSphereShape1 ? contactPointPolyhedronLocal : contactPointSphereLocal);
|
isSphereShape1 ? contactPointPolyhedronLocal : contactPointSphereLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFrameInfo.satMinAxisFaceIndex = minFaceIndex;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,171 +169,72 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfo* narro
|
||||||
Vector3 separatingPolyhedronEdgeVertex1;
|
Vector3 separatingPolyhedronEdgeVertex1;
|
||||||
Vector3 separatingPolyhedronEdgeVertex2;
|
Vector3 separatingPolyhedronEdgeVertex2;
|
||||||
|
|
||||||
// True if the shapes were overlapping in the previous frame and are
|
// For each face of the convex mesh
|
||||||
// still overlapping on the same axis in this frame
|
for (uint f = 0; f < polyhedron->getNbFaces(); f++) {
|
||||||
bool isTemporalCoherenceValid = false;
|
|
||||||
|
|
||||||
LastFrameCollisionInfo& lastFrameInfo = narrowPhaseInfo->overlappingPair->getLastFrameCollisionInfo();
|
Vector3 outFaceNormalCapsuleSpace;
|
||||||
|
|
||||||
// If the shapes are not triangles (no temporal coherence for triangle collision because we do not store previous
|
// Compute the penetration depth
|
||||||
// frame collision data per triangle)
|
const decimal penetrationDepth = computePolyhedronFaceVsCapsulePenetrationDepth(f, polyhedron, capsuleShape,
|
||||||
if (polyhedron->getName() != CollisionShapeName::TRIANGLE) {
|
polyhedronToCapsuleTransform,
|
||||||
|
outFaceNormalCapsuleSpace);
|
||||||
|
|
||||||
// If the last frame collision info is valid and was also using SAT algorithm
|
// If the penetration depth is negative, we have found a separating axis
|
||||||
if (lastFrameInfo.isValid && lastFrameInfo.wasUsingSAT) {
|
if (penetrationDepth <= decimal(0.0)) {
|
||||||
|
|
||||||
// We perform temporal coherence, we check if there is still an overlapping along the previous minimum separating
|
return false;
|
||||||
// axis. If it is the case, we directly report the collision without executing the whole SAT algorithm again. If
|
}
|
||||||
// the shapes are still separated along this axis, we directly exit with no collision.
|
|
||||||
|
|
||||||
// If the previous minimum separation axis was a face normal of the polyhedron
|
// Check if we have found a new minimum penetration axis
|
||||||
if (lastFrameInfo.satIsAxisFacePolyhedron1) {
|
if (penetrationDepth < minPenetrationDepth) {
|
||||||
|
minPenetrationDepth = penetrationDepth;
|
||||||
Vector3 outFaceNormalCapsuleSpace;
|
minFaceIndex = f;
|
||||||
|
isMinPenetrationFaceNormal = true;
|
||||||
// Compute the penetration depth along the polyhedron face normal direction
|
separatingAxisCapsuleSpace = outFaceNormalCapsuleSpace;
|
||||||
const decimal penetrationDepth = computePolyhedronFaceVsCapsulePenetrationDepth(lastFrameInfo.satMinAxisFaceIndex, polyhedron,
|
|
||||||
capsuleShape, polyhedronToCapsuleTransform,
|
|
||||||
outFaceNormalCapsuleSpace);
|
|
||||||
|
|
||||||
// If the previous axis is a separating axis
|
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
|
||||||
|
|
||||||
// Return no collision
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The two shapes are overlapping as in the previous frame and on the same axis, therefore
|
|
||||||
// we will skip the entire SAT algorithm because the minimum separating axis did not change
|
|
||||||
isTemporalCoherenceValid = lastFrameInfo.wasColliding;
|
|
||||||
|
|
||||||
if (isTemporalCoherenceValid) {
|
|
||||||
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minFaceIndex = lastFrameInfo.satMinAxisFaceIndex;
|
|
||||||
isMinPenetrationFaceNormal = true;
|
|
||||||
separatingAxisCapsuleSpace = outFaceNormalCapsuleSpace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // If the previous minimum separation axis the cross product of the capsule inner segment and an edge of the polyhedron
|
|
||||||
|
|
||||||
// Get an edge from the polyhedron (convert it into the capsule local-space)
|
|
||||||
HalfEdgeStructure::Edge edge = polyhedron->getHalfEdge(lastFrameInfo.satMinEdge1Index);
|
|
||||||
const Vector3 edgeVertex1 = polyhedron->getVertexPosition(edge.vertexIndex);
|
|
||||||
const Vector3 edgeVertex2 = polyhedron->getVertexPosition(polyhedron->getHalfEdge(edge.nextEdgeIndex).vertexIndex);
|
|
||||||
const Vector3 edgeDirectionCapsuleSpace = polyhedronToCapsuleTransform.getOrientation() * (edgeVertex2 - edgeVertex1);
|
|
||||||
|
|
||||||
Vector3 outAxis;
|
|
||||||
|
|
||||||
// Compute the penetration depth along this axis
|
|
||||||
const decimal penetrationDepth = computeEdgeVsCapsuleInnerSegmentPenetrationDepth(polyhedron, capsuleShape,
|
|
||||||
capsuleSegmentAxis, edgeVertex1,
|
|
||||||
edgeDirectionCapsuleSpace,
|
|
||||||
polyhedronToCapsuleTransform,
|
|
||||||
outAxis);
|
|
||||||
|
|
||||||
// If the previous axis is a separating axis
|
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
|
||||||
|
|
||||||
// Return no collision
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The two shapes are overlapping as in the previous frame and on the same axis, therefore
|
|
||||||
// we will skip the entire SAT algorithm because the minimum separating axis did not change
|
|
||||||
isTemporalCoherenceValid = lastFrameInfo.wasColliding;
|
|
||||||
|
|
||||||
if (isTemporalCoherenceValid) {
|
|
||||||
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minEdgeIndex = lastFrameInfo.satMinEdge1Index;
|
|
||||||
isMinPenetrationFaceNormal = false;
|
|
||||||
separatingAxisCapsuleSpace = outAxis;
|
|
||||||
separatingPolyhedronEdgeVertex1 = edgeVertex1;
|
|
||||||
separatingPolyhedronEdgeVertex2 = edgeVertex2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the shapes are still overlapping in the same axis as in the previous frame
|
// For each direction that is the cross product of the capsule inner segment and an edge of the polyhedron
|
||||||
// the previous frame, we skip the whole SAT algorithm
|
for (uint e = 0; e < polyhedron->getNbHalfEdges(); e += 2) {
|
||||||
if (!isTemporalCoherenceValid) {
|
|
||||||
|
|
||||||
// For each face of the convex mesh
|
// Get an edge from the polyhedron (convert it into the capsule local-space)
|
||||||
for (uint f = 0; f < polyhedron->getNbFaces(); f++) {
|
HalfEdgeStructure::Edge edge = polyhedron->getHalfEdge(e);
|
||||||
|
const Vector3 edgeVertex1 = polyhedron->getVertexPosition(edge.vertexIndex);
|
||||||
|
const Vector3 edgeVertex2 = polyhedron->getVertexPosition(polyhedron->getHalfEdge(edge.nextEdgeIndex).vertexIndex);
|
||||||
|
const Vector3 edgeDirectionCapsuleSpace = polyhedronToCapsuleTransform.getOrientation() * (edgeVertex2 - edgeVertex1);
|
||||||
|
|
||||||
Vector3 outFaceNormalCapsuleSpace;
|
HalfEdgeStructure::Edge twinEdge = polyhedron->getHalfEdge(edge.twinEdgeIndex);
|
||||||
|
const Vector3 adjacentFace1Normal = polyhedronToCapsuleTransform.getOrientation() * polyhedron->getFaceNormal(edge.faceIndex);
|
||||||
|
const Vector3 adjacentFace2Normal = polyhedronToCapsuleTransform.getOrientation() * polyhedron->getFaceNormal(twinEdge.faceIndex);
|
||||||
|
|
||||||
|
// Check using the Gauss Map if this edge cross product can be as separating axis
|
||||||
|
if (isMinkowskiFaceCapsuleVsEdge(capsuleSegmentAxis, adjacentFace1Normal, adjacentFace2Normal)) {
|
||||||
|
|
||||||
|
Vector3 outAxis;
|
||||||
|
|
||||||
// Compute the penetration depth
|
// Compute the penetration depth
|
||||||
const decimal penetrationDepth = computePolyhedronFaceVsCapsulePenetrationDepth(f, polyhedron, capsuleShape,
|
const decimal penetrationDepth = computeEdgeVsCapsuleInnerSegmentPenetrationDepth(polyhedron, capsuleShape,
|
||||||
polyhedronToCapsuleTransform,
|
capsuleSegmentAxis, edgeVertex1,
|
||||||
outFaceNormalCapsuleSpace);
|
edgeDirectionCapsuleSpace,
|
||||||
|
polyhedronToCapsuleTransform,
|
||||||
|
outAxis);
|
||||||
|
|
||||||
// If the penetration depth is negative, we have found a separating axis
|
// If the penetration depth is negative, we have found a separating axis
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
if (penetrationDepth <= decimal(0.0)) {
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = true;
|
|
||||||
lastFrameInfo.satMinAxisFaceIndex = f;
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have found a new minimum penetration axis
|
// Check if we have found a new minimum penetration axis
|
||||||
if (penetrationDepth < minPenetrationDepth) {
|
if (penetrationDepth < minPenetrationDepth) {
|
||||||
minPenetrationDepth = penetrationDepth;
|
minPenetrationDepth = penetrationDepth;
|
||||||
minFaceIndex = f;
|
minEdgeIndex = e;
|
||||||
isMinPenetrationFaceNormal = true;
|
isMinPenetrationFaceNormal = false;
|
||||||
separatingAxisCapsuleSpace = outFaceNormalCapsuleSpace;
|
separatingAxisCapsuleSpace = outAxis;
|
||||||
|
separatingPolyhedronEdgeVertex1 = edgeVertex1;
|
||||||
|
separatingPolyhedronEdgeVertex2 = edgeVertex2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each direction that is the cross product of the capsule inner segment and an edge of the polyhedron
|
|
||||||
for (uint e = 0; e < polyhedron->getNbHalfEdges(); e += 2) {
|
|
||||||
|
|
||||||
// Get an edge from the polyhedron (convert it into the capsule local-space)
|
|
||||||
HalfEdgeStructure::Edge edge = polyhedron->getHalfEdge(e);
|
|
||||||
const Vector3 edgeVertex1 = polyhedron->getVertexPosition(edge.vertexIndex);
|
|
||||||
const Vector3 edgeVertex2 = polyhedron->getVertexPosition(polyhedron->getHalfEdge(edge.nextEdgeIndex).vertexIndex);
|
|
||||||
const Vector3 edgeDirectionCapsuleSpace = polyhedronToCapsuleTransform.getOrientation() * (edgeVertex2 - edgeVertex1);
|
|
||||||
|
|
||||||
HalfEdgeStructure::Edge twinEdge = polyhedron->getHalfEdge(edge.twinEdgeIndex);
|
|
||||||
const Vector3 adjacentFace1Normal = polyhedronToCapsuleTransform.getOrientation() * polyhedron->getFaceNormal(edge.faceIndex);
|
|
||||||
const Vector3 adjacentFace2Normal = polyhedronToCapsuleTransform.getOrientation() * polyhedron->getFaceNormal(twinEdge.faceIndex);
|
|
||||||
|
|
||||||
// Check using the Gauss Map if this edge cross product can be as separating axis
|
|
||||||
if (isMinkowskiFaceCapsuleVsEdge(capsuleSegmentAxis, adjacentFace1Normal, adjacentFace2Normal)) {
|
|
||||||
|
|
||||||
Vector3 outAxis;
|
|
||||||
|
|
||||||
// Compute the penetration depth
|
|
||||||
const decimal penetrationDepth = computeEdgeVsCapsuleInnerSegmentPenetrationDepth(polyhedron, capsuleShape,
|
|
||||||
capsuleSegmentAxis, edgeVertex1,
|
|
||||||
edgeDirectionCapsuleSpace,
|
|
||||||
polyhedronToCapsuleTransform,
|
|
||||||
outAxis);
|
|
||||||
|
|
||||||
// If the penetration depth is negative, we have found a separating axis
|
|
||||||
if (penetrationDepth <= decimal(0.0)) {
|
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = false;
|
|
||||||
lastFrameInfo.satMinEdge1Index = e;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have found a new minimum penetration axis
|
|
||||||
if (penetrationDepth < minPenetrationDepth) {
|
|
||||||
minPenetrationDepth = penetrationDepth;
|
|
||||||
minEdgeIndex = e;
|
|
||||||
isMinPenetrationFaceNormal = false;
|
|
||||||
separatingAxisCapsuleSpace = outAxis;
|
|
||||||
separatingPolyhedronEdgeVertex1 = edgeVertex1;
|
|
||||||
separatingPolyhedronEdgeVertex2 = edgeVertex2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the inner capsule segment points into the polyhedron local-space
|
// Convert the inner capsule segment points into the polyhedron local-space
|
||||||
|
@ -404,8 +257,6 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfo* narro
|
||||||
narrowPhaseInfo, isCapsuleShape1);
|
narrowPhaseInfo, isCapsuleShape1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = true;
|
|
||||||
lastFrameInfo.satMinAxisFaceIndex = minFaceIndex;
|
|
||||||
}
|
}
|
||||||
else { // The separating axis is the cross product of a polyhedron edge and the inner capsule segment
|
else { // The separating axis is the cross product of a polyhedron edge and the inner capsule segment
|
||||||
|
|
||||||
|
@ -433,9 +284,6 @@ bool SATAlgorithm::testCollisionCapsuleVsConvexPolyhedron(NarrowPhaseInfo* narro
|
||||||
isCapsuleShape1 ? contactPointCapsule : closestPointPolyhedronEdge,
|
isCapsuleShape1 ? contactPointCapsule : closestPointPolyhedronEdge,
|
||||||
isCapsuleShape1 ? closestPointPolyhedronEdge : contactPointCapsule);
|
isCapsuleShape1 ? closestPointPolyhedronEdge : contactPointCapsule);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFrameInfo.satIsAxisFacePolyhedron1 = false;
|
|
||||||
lastFrameInfo.satMinEdge1Index = minEdgeIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user