Skip to content

Commit 883653d

Browse files
committed
GJK floating point fixes
gotta love when 0.0000001f is the difference between working and not!
1 parent bb7ea96 commit 883653d

2 files changed

Lines changed: 79 additions & 5 deletions

File tree

src/include/sndx/collision/gjk.hpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,15 @@ namespace sndx::collision {
287287
auto ac = points[2].out - points[0].out;
288288
auto ao = -points[0].out;
289289

290+
if (glm::length2(ab) <= 0.00001f || glm::length2(ac) <= 0.00001f) {
291+
// keep b and c
292+
size = 2;
293+
points[0] = points[1];
294+
points[1] = points[2];
295+
lineOrigin(newDirection);
296+
return false;
297+
}
298+
290299
auto cross = glm::cross(ab, ac);
291300

292301
if (detail::similarDir(glm::cross(cross, ac), ao)) {
@@ -386,10 +395,14 @@ namespace sndx::collision {
386395
support = detail::gjkMinkowski(supportA, supportB, dir);
387396

388397
// it is okay for the 2nd point to have a negative dot product.
389-
if (!detail::similarDir(support.out, dir) && iterations > 0) {
398+
auto alignment = glm::dot(glm::normalize(support.out), glm::normalize(dir));
399+
if (alignment < -0.05f && iterations > 0) {
390400
return std::nullopt;
391401
}
392402

403+
assert(!std::isnan(support.out.x));
404+
405+
393406
simplex.push_front(support);
394407
if (simplex.gjkOrigin(dir)) {
395408
return simplex;
@@ -473,8 +486,14 @@ namespace sndx::collision {
473486
glm::vec3 b = polytope[faces[i + 1]].out;
474487
glm::vec3 c = polytope[faces[i + 2]].out;
475488

476-
glm::vec3 normal = glm::normalize(glm::cross(b - a, c - a));
477-
float distance = dot(normal, a);
489+
glm::vec3 normal = glm::cross(b - a, c - a);
490+
auto l = glm::length(normal);
491+
492+
float distance = 0.0f;
493+
if (l > 0.000001f) {
494+
normal /= l;
495+
distance = dot(normal, a);
496+
}
478497

479498
if (distance < 0) {
480499
normal *= -1;
@@ -528,13 +547,20 @@ namespace sndx::collision {
528547
minNormal = glm::vec3(normals[minFace]);
529548
minDistance = normals[minFace].w;
530549

531-
if (i >= 1024) {
550+
if (i >= 64) {
532551
break;
533552
}
534553

535554
auto support = detail::gjkMinkowski(supportA, supportB, minNormal);
536555
float sDistance = glm::dot(minNormal, support.out);
537556

557+
for (const auto& pnt : polytope) {
558+
if (glm::distance2(pnt.out, support.out) < 0.000001f) {
559+
sDistance = minDistance;
560+
break;
561+
}
562+
}
563+
538564
if (abs(sDistance - minDistance) > 0.0001f) {
539565
std::vector<std::pair<size_t, size_t>> uniqueEdges;
540566

src/tests/collision/gjk.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ TEST(GJK, circleAndTriangleCollide2) {
118118
EXPECT_TRUE(result);
119119
}
120120

121+
TEST(GJK, circleAndTriangleCollide3) {
122+
Circle3D circle{ glm::vec3{7.22956371f, 0.65463f, -0.94764f}, 0.5f };
123+
Tri3D triangle{
124+
glm::vec3{1.0f, -1.0f, -1.0f},
125+
glm::vec3{1.0f, 1.0f, 1.0f},
126+
glm::vec3{1.0f, -1.0f, 1.0f}
127+
};
128+
129+
glm::mat4 transform = glm::translate(glm::mat4{ 1.0f }, glm::vec3(5.0, 1.5, 0.0));
130+
transform = glm::scale(transform, glm::vec3(2.0, 1.5, 5.0));
131+
auto inv = glm::inverse(transform);
132+
133+
auto ttri = transformSupportFn(getSupportFn(triangle), transform, inv);
134+
135+
auto result = gjk(getSupportFn(circle), ttri);
136+
EXPECT_TRUE(result);
137+
138+
result = gjk(ttri, getSupportFn(circle));
139+
EXPECT_TRUE(result);
140+
}
141+
121142
// because EXPECT_FLOAT_EQ is WAYYYYY too strict.
122143
bool floatEq(float a, float b) {
123144
return std::abs(a - b) <= 0.00005f;
@@ -218,7 +239,7 @@ TEST(EPA, simpleBoxesGiveCorrectDirection) {
218239
auto result = epa(*simplex, getSupportFn(boxA), getSupportFn(boxB));
219240
ASSERT_LE(std::abs(result.depth - 0.50001f), 0.0001f);
220241

221-
boxB.translate(result.normal * (result.depth + 0.0001f));
242+
boxB.translate(result.normal * (result.depth + 0.004f));
222243
EXPECT_FALSE(gjk(getSupportFn(boxA), getSupportFn(boxB)));
223244
}
224245

@@ -248,4 +269,31 @@ TEST(EPA, mixedShapesGiveCorrectDirection) {
248269

249270
auto result = epa(*simplex, sptA, sptB);
250271
EXPECT_TRUE(floatEq(result.depth, 0.5));
272+
}
273+
274+
TEST(EPA, mixedShapesGiveCorrectDirection2) {
275+
Circle3D circle{ glm::vec3{-6.91016197f, 0.49365893f, 1.70220768f}, 0.5f };
276+
Tri3D tri{
277+
glm::vec3{-1.0, -1.0f, 1.0f},
278+
glm::vec3{-1.0f, 1.0f, 1.0f},
279+
glm::vec3{-1.0f, 1.0f, -1.0f}
280+
};
281+
282+
glm::mat4 t = glm::translate(glm::mat4{ 1.0f }, glm::vec3(-5.0, 0.5, 1.0));
283+
t = glm::rotate(t, glm::radians(45.0f), glm::vec3(0.0, 0.0, 1.0));
284+
285+
auto sptA = getSupportFn(circle);
286+
auto sptB = transformSupportFn(getSupportFn(tri), t, glm::inverse(t));
287+
288+
auto simplex = gjk(sptA, sptB);
289+
ASSERT_TRUE(simplex);
290+
291+
auto result = epa(*simplex, sptA, sptB);
292+
EXPECT_LE(result.depth, 0.004f);
293+
294+
simplex = gjk(sptB, sptA);
295+
ASSERT_TRUE(simplex);
296+
297+
result = epa(*simplex, sptB, sptA);
298+
EXPECT_LE(result.depth, 0.004f);
251299
}

0 commit comments

Comments
 (0)