diff --git a/include/bounce/collision/shapes/aabb3.h b/include/bounce/collision/shapes/aabb3.h index 46f9c5a..1ffd8b4 100644 --- a/include/bounce/collision/shapes/aabb3.h +++ b/include/bounce/collision/shapes/aabb3.h @@ -146,40 +146,70 @@ struct b3AABB3 } // Test if a ray intersects this AABB. - // Output the minimum and maximum intersection fractions to derive the minimum and maximum intersection points. - bool TestRay(const b3Vec3& p1, const b3Vec3& p2, float32& min_t, float32& max_t) const + bool TestRay(float32& minFraction, const b3Vec3& p1, const b3Vec3& p2, float32 maxFraction) const { b3Vec3 d = p2 - p1; - float32 t = d.Normalize(); - B3_ASSERT(t > B3_EPSILON); - - b3Vec3 inv_d; - inv_d.x = 1.0f / d.x; - inv_d.y = 1.0f / d.y; - inv_d.z = 1.0f / d.z; - - b3Vec3 t1; - t1.x = (m_lower.x - p1.x) * inv_d.x; - t1.y = (m_lower.y - p1.y) * inv_d.y; - t1.z = (m_lower.z - p1.z) * inv_d.z; - - b3Vec3 t2; - t2.x = (m_upper.x - p1.x) * inv_d.x; - t2.y = (m_upper.y - p1.y) * inv_d.y; - t2.z = (m_upper.z - p1.z) * inv_d.z; - + + float32 lower = 0.0f; + float32 upper = maxFraction; + for (u32 i = 0; i < 3; ++i) { - min_t = b3Max(min_t, b3Min(t1[i], t2[i])); - max_t = b3Min(max_t, b3Max(t1[i], t2[i])); + float32 numerators[2], denominators[2]; + + numerators[0] = p1[i] - m_lower[i]; + numerators[1] = m_upper[i] - p1[i]; + + denominators[0] = -d[i]; + denominators[1] = d[i]; + + for (u32 j = 0; j < 2; ++j) + { + float32 numerator = numerators[j]; + float32 denominator = denominators[j]; + + if (denominator == 0.0f) + { + // s is parallel to this half-space. + if (numerator < 0.0f) + { + // s is outside of this half-space. + // dot(n, p1) and dot(n, p2) < 0. + return false; + } + } + else + { + if (denominator < 0.0f) + { + // s enters this half-space. + if (numerator < lower * denominator) + { + // Increase lower. + lower = numerator / denominator; + } + } + else + { + // s exits the half-space. + if (numerator < upper * denominator) + { + // Decrease upper. + upper = numerator / denominator; + } + } + // Exit if intersection becomes empty. + if (upper < lower) + { + return false; + } + } + } } - if (min_t >= 0.0f && min_t >= max_t && max_t <= t) - { - return true; - } - - return false; + B3_ASSERT(lower >= 0.0f && lower <= maxFraction); + minFraction = lower; + return true; } }; diff --git a/include/bounce/collision/trees/dynamic_tree.h b/include/bounce/collision/trees/dynamic_tree.h index 227d68b..761c28c 100644 --- a/include/bounce/collision/trees/dynamic_tree.h +++ b/include/bounce/collision/trees/dynamic_tree.h @@ -211,8 +211,8 @@ inline void b3DynamicTree::RayCast(T* callback, const b3RayCastInput& input) con const b3Node* node = m_nodes + nodeIndex; - float32 minFraction = 0.0f; - if (node->aabb.TestRay(p1, p2, maxFraction, minFraction) == true) + float32 minFraction; + if (node->aabb.TestRay(minFraction, p1, p2, maxFraction) == true) { if (node->IsLeaf() == true) { diff --git a/include/bounce/collision/trees/static_tree.h b/include/bounce/collision/trees/static_tree.h index 1af50ad..069b855 100644 --- a/include/bounce/collision/trees/static_tree.h +++ b/include/bounce/collision/trees/static_tree.h @@ -174,8 +174,8 @@ inline void b3StaticTree::RayCast(T* callback, const b3RayCastInput& input) cons const b3Node* node = m_nodes + nodeIndex; - float32 minFraction = 0.0f; - if (node->aabb.TestRay(p1, p2, maxFraction, minFraction) == true) + float32 minFraction; + if (node->aabb.TestRay(minFraction, p1, p2, maxFraction) == true) { if (node->IsLeaf() == true) {