Added untested contact point derivation
Left with reducing manifold with more than 4 contact points
This commit is contained in:
parent
8ca4045d55
commit
57498bb8b8
|
@ -11,6 +11,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Project Headers
|
// Project Headers
|
||||||
|
#include "Math/Geometry/SHPlane.h"
|
||||||
#include "Physics/Collision/Contacts/SHManifold.h"
|
#include "Physics/Collision/Contacts/SHManifold.h"
|
||||||
#include "Physics/Collision/Contacts/SHCollisionKey.h"
|
#include "Physics/Collision/Contacts/SHCollisionKey.h"
|
||||||
#include "Physics/Collision/Shapes/SHHalfEdgeStructure.h"
|
#include "Physics/Collision/Shapes/SHHalfEdgeStructure.h"
|
||||||
|
@ -101,29 +102,22 @@ namespace SHADE
|
||||||
|
|
||||||
// Convex VS Convex
|
// Convex VS Convex
|
||||||
|
|
||||||
static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
|
||||||
static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
|
||||||
|
|
||||||
static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
|
||||||
static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept;
|
|
||||||
static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
|
||||||
static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
|
||||||
static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO:
|
* References
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* static uint32_t clip [sutherland-hodgemann clipping]
|
|
||||||
*
|
|
||||||
* ! References
|
|
||||||
* https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf
|
* https://ia801303.us.archive.org/30/items/GDC2013Gregorius/GDC2013-Gregorius.pdf
|
||||||
* https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp
|
* https://github.com/RandyGaul/qu3e/blob/master/src/collision/q3Collide.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static FaceQuery queryFaceDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
||||||
|
static EdgeQuery queryEdgeDirections (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B) noexcept;
|
||||||
|
|
||||||
|
static bool buildMinkowskiFace (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
||||||
|
static bool isMinkowskiFace (const SHVec3& a, const SHVec3& b, const SHVec3& c, const SHVec3& d) noexcept;
|
||||||
|
static float distanceBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
||||||
|
static SHVec3 findClosestPointBetweenEdges (const SHConvexPolyhedron& A, const SHConvexPolyhedron& B, int32_t edgeA, int32_t edgeB) noexcept;
|
||||||
|
static int32_t findIncidentFace (const SHConvexPolyhedron& poly, const SHVec3& normal) noexcept;
|
||||||
|
static std::vector<SHContact> clipsPolygonAgainstPlane (const std::vector<SHContact>& in, const SHPlane& plane) noexcept;
|
||||||
|
|
||||||
|
// TODO: Reduce Manifold
|
||||||
};
|
};
|
||||||
} // namespace SHADE
|
} // namespace SHADE
|
|
@ -128,25 +128,87 @@ namespace SHADE
|
||||||
const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace);
|
const SHVec3 REFERENCE_NORMAL = referencePoly->GetNormal(minFaceQuery.closestFace);
|
||||||
const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL);
|
const int32_t INCIDENT_FACE_IDX = findIncidentFace(*incidentPoly, REFERENCE_NORMAL);
|
||||||
|
|
||||||
|
// Create initial set of contacts as the entire incident face
|
||||||
|
const SHHalfEdgeStructure::Face& INCIDENT_FACE = incidentPoly->GetFace(INCIDENT_FACE_IDX);
|
||||||
|
const int32_t MAX_NUM_CONTACTS = static_cast<int32_t>(INCIDENT_FACE.vertexIndices.size());
|
||||||
|
|
||||||
/*
|
std::vector<SHContact> incidentPolygon;
|
||||||
* TODO:
|
for (const int32_t i : std::views::iota(0, MAX_NUM_CONTACTS))
|
||||||
*
|
{
|
||||||
* !!
|
const int32_t VERTEX_INDEX = INCIDENT_FACE.vertexIndices[i].index;
|
||||||
* 4. From above, save the axis of minimum penetration (reference face)
|
|
||||||
* 5. Find the most anti-parallel face on other shape (incident face)
|
|
||||||
* 6. Clip incident face against side planes of reference face. (Sutherland-Hodgeman Clipping).
|
|
||||||
* Keep all vertices below reference face.
|
|
||||||
* 7. Reduce manifold to 4 contact points. We only need 4 contact points for a stable manifold.
|
|
||||||
*
|
|
||||||
* Remember to save IDs in queries.
|
|
||||||
* During generation of incident face, store IDs of face.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
incidentPolygon[i].position = incidentPoly->GetVertex(VERTEX_INDEX);
|
||||||
|
|
||||||
|
incidentPolygon[i].featurePair.indexA = minFaceQuery.closestFace;
|
||||||
|
incidentPolygon[i].featurePair.indexB = VERTEX_INDEX;
|
||||||
|
incidentPolygon[i].featurePair.typeA = SHUtilities::ConvertEnum(SHContactFeatures::Type::FACE);
|
||||||
|
incidentPolygon[i].featurePair.typeB = SHUtilities::ConvertEnum(SHContactFeatures::Type::VERTEX);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
// Number of vertices == number of edges on face
|
||||||
|
// Clip against each edge of face
|
||||||
|
|
||||||
|
const SHHalfEdgeStructure::Face& REFERENCE_FACE = referencePoly->GetFace(minFaceQuery.closestFace);
|
||||||
|
const int32_t NUM_EDGES = static_cast<int32_t>(INCIDENT_FACE.vertexIndices.size());
|
||||||
|
|
||||||
|
const size_t COPY_SIZE = sizeof(SHContact) * MAX_NUM_CONTACTS;
|
||||||
|
for (const int32_t i : std::views::iota(0, NUM_EDGES))
|
||||||
|
{
|
||||||
|
// Build a plane on the reference poly normal X tangent and the tail of the tangent
|
||||||
|
const int32_t V1_IDX = REFERENCE_FACE.vertexIndices[i].index;
|
||||||
|
const int32_t V2_IDX = REFERENCE_FACE.vertexIndices[(i + 1) % NUM_EDGES].index;
|
||||||
|
|
||||||
|
const SHVec3 V1 = referencePoly->GetVertex(V1_IDX);
|
||||||
|
const SHVec3 V2 = referencePoly->GetVertex(V2_IDX);
|
||||||
|
|
||||||
|
const SHVec3 TANGENT = SHVec3::Normalise(V2 - V1);
|
||||||
|
const SHPlane PLANE{ V1, SHVec3::Cross(REFERENCE_NORMAL, TANGENT) };
|
||||||
|
|
||||||
|
auto clipped = clipsPolygonAgainstPlane(incidentPolygon, PLANE);
|
||||||
|
memcpy_s(incidentPolygon.data(), COPY_SIZE, clipped.data(), COPY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From clipped polygon, only keep points that are below the reference face
|
||||||
|
// The penetration is the signed distance to the plane formed by the reference face.
|
||||||
|
const SHPlane REFERENCE_PLANE{ referencePoly->GetVertex(REFERENCE_FACE.vertexIndices[0].index), REFERENCE_NORMAL };
|
||||||
|
|
||||||
|
std::vector<SHContact> finalContacts;
|
||||||
|
|
||||||
|
for (const auto& cp : incidentPolygon)
|
||||||
|
{
|
||||||
|
const float DEPTH = REFERENCE_PLANE.SignedDistance(cp.position);
|
||||||
|
if (DEPTH <= 0.0f)
|
||||||
|
{
|
||||||
|
SHContact contact;
|
||||||
|
contact.position = cp.position;
|
||||||
|
contact.penetration = -DEPTH;
|
||||||
|
|
||||||
|
if (flipNormal)
|
||||||
|
{
|
||||||
|
contact.featurePair.indexA = cp.featurePair.indexB;
|
||||||
|
contact.featurePair.indexB = cp.featurePair.indexA;
|
||||||
|
contact.featurePair.typeA = cp.featurePair.typeB;
|
||||||
|
contact.featurePair.typeB = cp.featurePair.typeA;
|
||||||
|
}
|
||||||
|
|
||||||
|
finalContacts.emplace_back(contact);
|
||||||
|
++numContacts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numContacts > 4)
|
||||||
|
{
|
||||||
|
// TODO: Reduce the manifold
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy_s(manifold.contacts, sizeof(SHContact) * numContacts, finalContacts.data(), sizeof(SHContact) * numContacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
manifold.normal = flipNormal ? -REFERENCE_NORMAL : REFERENCE_NORMAL;
|
||||||
|
manifold.numContacts = numContacts;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -324,6 +386,7 @@ namespace SHADE
|
||||||
const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA;
|
const float A2_OVER_A1 = VB_DOT_VB / VB_DOT_VA;
|
||||||
const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB;
|
const float NUMERATOR = C_DOT_VA * A2_OVER_A1 - C_DOT_VB;
|
||||||
const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1;
|
const float DENOMINATOR = AV_DOT_VB - AV_DOT_VA * A2_OVER_A1;
|
||||||
|
|
||||||
const float R = NUMERATOR / DENOMINATOR;
|
const float R = NUMERATOR / DENOMINATOR;
|
||||||
|
|
||||||
// Just take a point from A since it's A -> B
|
// Just take a point from A since it's A -> B
|
||||||
|
@ -352,5 +415,80 @@ namespace SHADE
|
||||||
return bestFace;
|
return bestFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SHContact> SHCollision::clipsPolygonAgainstPlane(const std::vector<SHContact>& in, const SHPlane& plane) noexcept
|
||||||
|
{
|
||||||
|
std::vector<SHContact> out;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If both are in front of the plane, keep the head.
|
||||||
|
// If both are behind the plane, ignore both.
|
||||||
|
// If they are on different sides, find the position in between that lies on the plane. Keep the head and interpolation position.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For sutherland-hodgman clipping, we check where any two sets of points lie with respect to the plane
|
||||||
|
* This variation is has 4 scenarios:
|
||||||
|
*
|
||||||
|
* 1. Both behind: ignore
|
||||||
|
* 2. Head behind, tail in-front: Keep interpolated position
|
||||||
|
* 3. Both in-front: Keep tail
|
||||||
|
* 4. Head in-front, tail behind: Keep head & interpolated position
|
||||||
|
*/
|
||||||
|
|
||||||
|
const size_t NUM_POINTS = in.size();
|
||||||
|
for (size_t i = 0; i < NUM_POINTS; ++i)
|
||||||
|
{
|
||||||
|
const SHContact& HEAD = in[i];
|
||||||
|
const SHContact& TAIL = in[(i + 1) % NUM_POINTS];
|
||||||
|
|
||||||
|
const float HEAD_DISTANCE = plane.SignedDistance(HEAD.position);
|
||||||
|
const float TAIL_DISTANCE = plane.SignedDistance(TAIL.position);
|
||||||
|
|
||||||
|
// Scenario 1: Both Behind
|
||||||
|
if (HEAD_DISTANCE < 0.0f && TAIL_DISTANCE < 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Scenario 2: Tail In-Front, Head Behind
|
||||||
|
if (HEAD_DISTANCE >= 0.0f && TAIL_DISTANCE < 0.0f)
|
||||||
|
{
|
||||||
|
SHContact interpolated;
|
||||||
|
|
||||||
|
interpolated.featurePair.indexA = TAIL.featurePair.indexA;
|
||||||
|
interpolated.featurePair.indexB = TAIL.featurePair.indexB;
|
||||||
|
interpolated.featurePair.typeA = TAIL.featurePair.typeB;
|
||||||
|
interpolated.featurePair.typeB = TAIL.featurePair.typeA;
|
||||||
|
|
||||||
|
const SHVec3 DIR = SHVec3::Normalise(HEAD.position - TAIL.position);
|
||||||
|
interpolated.position = TAIL.position + DIR * std::fabs(TAIL_DISTANCE);
|
||||||
|
|
||||||
|
out.emplace_back(interpolated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scenario 3: Both In-Front
|
||||||
|
if (HEAD_DISTANCE >= 0.0f && TAIL_DISTANCE >= 0.0f)
|
||||||
|
{
|
||||||
|
out.emplace_back(TAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scenario 4: Head Behind, Tail In-Front
|
||||||
|
if (HEAD_DISTANCE < 0.0f && TAIL_DISTANCE >= 0.0f)
|
||||||
|
{
|
||||||
|
out.emplace_back(HEAD);
|
||||||
|
|
||||||
|
SHContact interpolated;
|
||||||
|
|
||||||
|
interpolated.featurePair.indexA = TAIL.featurePair.indexA;
|
||||||
|
interpolated.featurePair.indexB = TAIL.featurePair.indexB;
|
||||||
|
interpolated.featurePair.typeA = TAIL.featurePair.typeB;
|
||||||
|
interpolated.featurePair.typeB = TAIL.featurePair.typeA;
|
||||||
|
|
||||||
|
const SHVec3 DIR = SHVec3::Normalise(HEAD.position - TAIL.position);
|
||||||
|
interpolated.position = TAIL.position + DIR * std::fabs(TAIL_DISTANCE);
|
||||||
|
|
||||||
|
out.emplace_back(interpolated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace SHADE
|
} // namespace SHADE
|
Loading…
Reference in New Issue