1 #include "hx3d/physics/2d/collisions.hpp" 3 #include "hx3d/math/vector_utils.hpp" 10 bool gt(
float a,
float b) {
11 return a >= b * 0.95f + a * 0.01f;
14 float findAxisLeastPenetration(
unsigned int* face, Ptr<colliders::Polygon>& a, Ptr<colliders::Polygon>& b) {
15 float bestDistance = -FLT_MAX;
16 unsigned int bestIndex = 0;
18 for (
unsigned int i = 0; i < a->vertexCount; ++i) {
19 glm::vec2 n = a->normals[i];
20 glm::vec2 nw = a->u * n;
22 glm::mat2 buT = glm::transpose(b->u);
25 glm::vec2 s = b->getSupport(-n);
27 glm::vec2 v = a->vertices[i];
28 v = a->u * v + a->position;
32 float d = glm::dot(n, s - v);
33 if (d > bestDistance) {
43 void findIncidentFace(std::vector<glm::vec2>& v,
const Ptr<colliders::Polygon>& ref,
const Ptr<colliders::Polygon>& inc,
int refIndex) {
44 glm::vec2 refNormal = ref->normals[refIndex];
45 refNormal = ref->u * refNormal;
46 refNormal = glm::transpose(inc->u) * refNormal;
48 unsigned int incidentFace = 0;
49 float minDot = FLT_MAX;
50 for (
unsigned int i = 0; i < inc->vertexCount; ++i) {
51 float dot = glm::dot(refNormal, inc->normals[i]);
58 v[0] = inc->u * inc->vertices[incidentFace] + inc->position;
59 v[1] = inc->u * inc->vertices[(incidentFace + 1) % inc->vertexCount] + inc->position;
62 int clip(
const glm::vec2 n,
const float c, std::vector<glm::vec2>& face) {
64 std::vector<glm::vec2> out = {face[0], face[1]};
66 float d1 = glm::dot(n, face[0]) - c;
67 float d2 = glm::dot(n, face[1]) - c;
69 if (d1 <= 0.f) out[sp++] = face[0];
70 if (d2 <= 0.f) out[sp++] = face[1];
73 float alpha = d1 / (d1 - d2);
74 out[sp++] = (face[1] - face[0]) * alpha + face[0];
91 unsigned int faceA = 0;
92 float penetrationA = findAxisLeastPenetration(&faceA, a, b);
93 if (penetrationA >= 0.f)
96 unsigned int faceB = 0;
97 float penetrationB = findAxisLeastPenetration(&faceB, b, a);
98 if (penetrationB >= 0.f)
101 unsigned int refIndex = 0;
107 if (gt(penetrationA, penetrationB)) {
121 std::vector<glm::vec2> incidentFace = {{0, 0}, {0, 0}};
122 findIncidentFace(incidentFace, ref, inc, refIndex);
124 glm::vec2 v1 = ref->vertices[refIndex];
125 glm::vec2 v2 = ref->vertices[(refIndex + 1) % ref->vertexCount];
127 v1 = ref->u * v1 + ref->position;
128 v2 = ref->u * v2 + ref->position;
131 glm::vec2 refFaceNormal = {sidePlaneNormal.y, -sidePlaneNormal.x};
133 float refC = glm::dot(refFaceNormal, v1);
134 float negSide = -glm::dot(sidePlaneNormal, v1);
135 float posSide = glm::dot(sidePlaneNormal, v2);
137 if (clip(-sidePlaneNormal, negSide, incidentFace) < 2)
140 if (clip(sidePlaneNormal, posSide, incidentFace) < 2)
143 m.
normal = flip ? -refFaceNormal : refFaceNormal;
146 float separation = glm::dot(refFaceNormal, incidentFace[0]) - refC;
147 if (separation <= 0.f) {
148 m.
contacts.push_back(incidentFace[0]);
157 separation = glm::dot(refFaceNormal, incidentFace[1]) - refC;
158 if (separation <= 0.f) {
159 m.
contacts.push_back(incidentFace[1]);
171 glm::vec2 normal = b->position - a->position;
173 float radius = (a->radius + b->radius) / 2;
175 if (squareLength >= radius*radius) {
182 float distance = std::sqrt(squareLength);
183 if (distance == 0.f) {
185 m.
normal = glm::vec2(1, 0);
191 m.
normal = normal / distance;
std::vector< glm::vec2 > contacts
Contact points.
float squareLength(glm::vec2 vec)
Compute the square length of a 2D vector.
float penetration
Penetration coefficient.
Contact manifold definition.
bool checkCollisions(Manifold &m, Ptr< colliders::Circle > a, Ptr< colliders::Circle > b)
Collision test between two circles.
glm::vec2 normalize(glm::vec2 vec)
Normalize a 2D vector.
std::shared_ptr< T > Ptr
Quick-typing shared ptr.
glm::vec2 normal
Normal vector.