1
\$\begingroup\$

I'm using the IntersectMovingAABBAABB implementation from the book Realtime Collision Detection and I'm having a little bit of an issue. When I have two AABBs next to each other (not touching), A being stationnary and B moving up or down, I'm getting a result saying there's a collision. Obviously this is wrong.

 _______     _______
|       |   |       |
|   A   |   |   B   |  B moving up/down
|_______|   |_______|

I've rechecked my code multiple times to make sure I had the same thing as in the book. Stepping through the code, I realized that the check for v[i] < 0 and v[i] > 0 will never be true for either X or Z axis when moving straight up or down. Therefor, no checks for intersections on these axis will be done. I find that quite weird, and I was wondering if I was missing something, or if this code is simply bad.

Here's my implementation for reference:

public static bool IntersectMovingAABBAABB(AABB a, AABB b, Vector3 va, Vector3 vb, out float first, out float last, out BlockFace face)
{
    face = BlockFace.None;
    if (TestAABB(a, b))
    {
        first = last = 0;
        return true;
    }

    Vector3 v = vb - va;
    float current;

    first = 0;
    last = 1;

    for (int i = 0; i < 3; i++)
    {
        if (v[i] < 0)
        {
            if (b.Max[i] < a.Min[i]) return false;
            if (a.Max[i] < b.Min[i]) if ((first = Math.Max(current= (a.Max[i] - b.Min[i]) / v[i], first)) == current) face = (BlockFace)(1 << (i));
            if (b.Max[i] > a.Min[i]) last = Math.Min((a.Min[i] - b.Max[i]) / v[i], last);
        }

        if (v[i] > 0)
        {
            if (a.Max[i] < b.Min[i]) return false;
            if (b.Max[i] < a.Min[i]) if ((first = Math.Max(current = (a.Min[i] - b.Max[i]) / v[i], first)) == current) face = (BlockFace)(1 << (i + 3));
            if (a.Max[i] > b.Min[i]) last = Math.Min((a.Max[i] - b.Min[i]) / v[i], last);
        }

        if (first > last) return false;
    }

    return true;
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Realtime collision detection is a great book, but that code is clearly wrong. If the relative velocity was zero, it would always return true, which is clearly incorrect. I believe the first test in each of the if (v[i] ...) blocks needs to be done if the velocity is <= 0 and >= 0 respectively. Note that you can't just change those tests though, because you could then end up dividing by zero. There may be a more elegant way, but I think this should work:

    if (v[i] < 0)
    {
        if (b.Max[i] < a.Min[i]) return false;
        if (a.Max[i] < b.Min[i]) if ((first = Math.Max(current= (a.Max[i] - b.Min[i]) / v[i], first)) == current) face = (BlockFace)(1 << (i));
        if (b.Max[i] > a.Min[i]) last = Math.Min((a.Min[i] - b.Max[i]) / v[i], last);
    }
    else if (v[i] > 0)
    {
        if (a.Max[i] < b.Min[i]) return false;
        if (b.Max[i] < a.Min[i]) if ((first = Math.Max(current = (a.Min[i] - b.Max[i]) / v[i], first)) == current) face = (BlockFace)(1 << (i + 3));
        if (a.Max[i] > b.Min[i]) last = Math.Min((a.Max[i] - b.Min[i]) / v[i], last);
    }
    else
    {
        if (b.Max[i] < a.Min[i] || a.Max[i] < b.Min[i]) return false;
    }
\$\endgroup\$
1
  • \$\begingroup\$ Amazing! Thanks a lot! I find it kind of weird that such a good book wouldn't have a working implementation. I checked the errata, nothing there! \$\endgroup\$ Commented Jul 16, 2017 at 18:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .