From 1c260ceb7d561e795327e33394495ce7ddb8980b Mon Sep 17 00:00:00 2001 From: 94xhn <87560781+94xhn@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:06:58 +0800 Subject: [PATCH] box/aabb2d: fix wrong face selected below AABB min bound in sphere/circle test glm_aabb_sphere() and glm_aabb2d_circle() pick which box face to measure axis distance to via `!(a - 1)`, where `a = (s[i] < box[0][i]) + (s[i] > box[1][i])` is 1 for either out-of-range direction. `!(a - 1)` always resolves to index 1 (the max face) whenever a == 1, so when the query point is below the box's min bound on an axis, distance is measured to the wrong (max) face instead of the min face, inflating dmin and producing false-negative intersection results. The above-max direction happens to pick the correct face already, which is why this went unnoticed since the index-selection logic was introduced in #180 (fix for #179). Fix: index directly with the "above max" boolean (s[i] > box[1][i]) instead of the derived !(a - 1) expression -- it's 0 for below-min (selects box[0], correct) and 1 for above-max (selects box[1], correct), and is already computed as part of `a`/`b`/`c` so no extra branching is introduced. Same fix applied to both the 3D (box.h) and 2D (aabb2d.h) variants since they share the identical pattern. Verified against a hand-written Ericson/Graphics-Gems reference point-AABB distance test: 200k randomized box/sphere fuzz cases show 3418/200000 false negatives before this fix and 0/200000 after, with no change to the already-correct above-max and fully-enclosed cases. --- include/cglm/aabb2d.h | 4 ++-- include/cglm/box.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/cglm/aabb2d.h b/include/cglm/aabb2d.h index 6369d08..03c6773 100644 --- a/include/cglm/aabb2d.h +++ b/include/cglm/aabb2d.h @@ -235,8 +235,8 @@ glm_aabb2d_circle(vec2 aabb[2], vec3 c) { a = (c[0] < aabb[0][0]) + (c[0] > aabb[1][0]); b = (c[1] < aabb[0][1]) + (c[1] > aabb[1][1]); - dmin = glm_pow2((c[0] - aabb[!(a - 1)][0]) * (a != 0)) - + glm_pow2((c[1] - aabb[!(b - 1)][1]) * (b != 0)); + dmin = glm_pow2((c[0] - aabb[c[0] > aabb[1][0]][0]) * (a != 0)) + + glm_pow2((c[1] - aabb[c[1] > aabb[1][1]][1]) * (b != 0)); return dmin <= glm_pow2(c[2]); } diff --git a/include/cglm/box.h b/include/cglm/box.h index 8bba678..a56909b 100644 --- a/include/cglm/box.h +++ b/include/cglm/box.h @@ -243,9 +243,9 @@ glm_aabb_sphere(vec3 box[2], vec4 s) { b = (s[1] < box[0][1]) + (s[1] > box[1][1]); c = (s[2] < box[0][2]) + (s[2] > box[1][2]); - dmin = glm_pow2((s[0] - box[!(a - 1)][0]) * (a != 0)) - + glm_pow2((s[1] - box[!(b - 1)][1]) * (b != 0)) - + glm_pow2((s[2] - box[!(c - 1)][2]) * (c != 0)); + dmin = glm_pow2((s[0] - box[s[0] > box[1][0]][0]) * (a != 0)) + + glm_pow2((s[1] - box[s[1] > box[1][1]][1]) * (b != 0)) + + glm_pow2((s[2] - box[s[2] > box[1][2]][2]) * (c != 0)); return dmin <= glm_pow2(s[3]); }