diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-02-07 01:12:31 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-02-07 01:12:31 +0000 |
| commit | 5409a67ee0cb5da5bc35b5b6f755ce09bcface8d (patch) | |
| tree | c97e4f34c3516a48ce02f884f1e608d072b5bba1 | |
| parent | Updated API version and release history (added PRIMITIVE_TOPOLOGY_LINE_STRIP) (diff) | |
| download | DiligentCore-5409a67ee0cb5da5bc35b5b6f755ce09bcface8d.tar.gz DiligentCore-5409a67ee0cb5da5bc35b5b6f755ce09bcface8d.zip | |
MathLib: added IntersectRayAABB, max3 and min3 function
| -rw-r--r-- | Common/interface/AdvancedMath.hpp | 34 | ||||
| -rw-r--r-- | Common/interface/BasicMath.hpp | 14 | ||||
| -rw-r--r-- | Tests/DiligentCoreTest/src/Common/MathLibTest.cpp | 91 |
3 files changed, 139 insertions, 0 deletions
diff --git a/Common/interface/AdvancedMath.hpp b/Common/interface/AdvancedMath.hpp index ee72217b..23160554 100644 --- a/Common/interface/AdvancedMath.hpp +++ b/Common/interface/AdvancedMath.hpp @@ -427,6 +427,40 @@ inline void GetFrustumMinimumBoundingSphere(float Proj_00, // cot(HorzFOV / } } +/// Intersects a ray with the axis-aligned bounding box and returns distances to intersections +inline bool IntersectRayAABB(const float3& RayOrigin, + const float3& RayDirection, + BoundBox AABB, + float& EnterDist, + float& ExitDist) +{ + AABB.Min -= RayOrigin; + AABB.Max -= RayOrigin; + + static constexpr float Epsilon = 1e-20f; + + float3 AbsRayDir = abs(RayDirection); + float3 t_min // + { + AbsRayDir.x > Epsilon ? AABB.Min.x / RayDirection.x : +FLT_MAX, + AbsRayDir.y > Epsilon ? AABB.Min.y / RayDirection.y : +FLT_MAX, + AbsRayDir.z > Epsilon ? AABB.Min.z / RayDirection.z : +FLT_MAX // + }; + float3 t_max // + { + AbsRayDir.x > Epsilon ? AABB.Max.x / RayDirection.x : -FLT_MAX, + AbsRayDir.y > Epsilon ? AABB.Max.y / RayDirection.y : -FLT_MAX, + AbsRayDir.z > Epsilon ? AABB.Max.z / RayDirection.z : -FLT_MAX // + }; + + EnterDist = max3(std::min(t_min.x, t_max.x), std::min(t_min.y, t_max.y), std::min(t_min.z, t_max.z)); + ExitDist = min3(std::max(t_min.x, t_max.x), std::max(t_min.y, t_max.y), std::max(t_min.z, t_max.z)); + + // if ExitDist < 0, the ray intersects AABB, but the whole AABB is behind it + // if EnterDist > ExitDist, the ray doesn't intersect AABB + return ExitDist >= 0 && EnterDist <= ExitDist; +} + } // namespace Diligent namespace std diff --git a/Common/interface/BasicMath.hpp b/Common/interface/BasicMath.hpp index d28ee9ab..81f646fb 100644 --- a/Common/interface/BasicMath.hpp +++ b/Common/interface/BasicMath.hpp @@ -1907,8 +1907,22 @@ T SmoothStep(T Left, T Right, T w) return t * t * (static_cast<T>(3) - static_cast<T>(2) * t); } +template <typename T> +T max3(const T& x, const T& y, const T& z) +{ + return std::max(std::max(x, y), z); +} + +template <typename T> +T min3(const T& x, const T& y, const T& z) +{ + return std::min(std::min(x, y), z); +} + } // namespace Diligent + + namespace std { template <typename T> diff --git a/Tests/DiligentCoreTest/src/Common/MathLibTest.cpp b/Tests/DiligentCoreTest/src/Common/MathLibTest.cpp index 455e9240..a384d667 100644 --- a/Tests/DiligentCoreTest/src/Common/MathLibTest.cpp +++ b/Tests/DiligentCoreTest/src/Common/MathLibTest.cpp @@ -930,4 +930,95 @@ TEST(Common_AdvancedMath, HermiteSpline) EXPECT_NE(HermiteSpline(double3(1, 2, 3), double3(4, 5, 6), double3(7, 8, 9), double3(10, 11, 12), 0.1), double3(0, 0, 0)); } +TEST(Common_AdvancedMath, IntersectRayAABB) +{ + BoundBox AABB{float3(2, 4, 6), float3(4, 8, 12)}; + float3 Center = (AABB.Min + AABB.Max) * 0.5f; + float3 HalfExtent = (AABB.Max - AABB.Min) * 0.5f; + + float Enter = 0, Exit = 0; + + // Intersections along axes + + // +X + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{-2.f, 0.25f, 0.125f}, float3{+1, 0, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.x); + EXPECT_FLOAT_EQ(Exit, HalfExtent.x * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{-2.f, 0.25f, 0.125f}, float3{-1, 0, 0}, AABB, Enter, Exit)); + + // -X + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{+2.f, 0.25f, 0.125f}, float3{-1, 0, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.x); + EXPECT_FLOAT_EQ(Exit, HalfExtent.x * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{+2.f, 0.25f, 0.125f}, float3{+1, 0, 0}, AABB, Enter, Exit)); + + // +Y + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, -2.f, 0.125f}, float3{0, +1, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.y); + EXPECT_FLOAT_EQ(Exit, HalfExtent.y * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, -2.f, 0.125f}, float3{0, -1, 0}, AABB, Enter, Exit)); + + // -Y + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 2.f, 0.125f}, float3{0, -1, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.y); + EXPECT_FLOAT_EQ(Exit, HalfExtent.y * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 2.f, 0.125f}, float3{0, +1, 0}, AABB, Enter, Exit)); + + // +Z + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 0.5f, -2.f}, float3{0, 0, +1}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.z); + EXPECT_FLOAT_EQ(Exit, HalfExtent.z * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 0.5f, -2.f}, float3{0, 0, -1}, AABB, Enter, Exit)); + + // -Z + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 0.5f, 2.f}, float3{0, 0, -1}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, HalfExtent.z); + EXPECT_FLOAT_EQ(Exit, HalfExtent.z * 3); + EXPECT_FALSE(IntersectRayAABB(Center + HalfExtent * float3{0.75f, 0.5f, 2.f}, float3{0, 0, +1}, AABB, Enter, Exit)); + + + // Origin in the box + + // +X + EXPECT_TRUE(IntersectRayAABB(Center, float3{1, 0, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.x); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.x); + + // -X + EXPECT_TRUE(IntersectRayAABB(Center, float3{-1, 0, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.x); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.x); + + // +Y + EXPECT_TRUE(IntersectRayAABB(Center, float3{0, 1, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.y); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.y); + + // -Y + EXPECT_TRUE(IntersectRayAABB(Center, float3{0, -1, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.y); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.y); + + // +Z + EXPECT_TRUE(IntersectRayAABB(Center, float3{0, 0, 1}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.z); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.z); + + // -Z + EXPECT_TRUE(IntersectRayAABB(Center, float3{0, 0, -1}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, -HalfExtent.z); + EXPECT_FLOAT_EQ(Exit, +HalfExtent.z); + + const float rsqrt2 = 1.f / std::sqrt(2.f); + + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{-1.f, -0.5f, -0.125f} + float3{-rsqrt2, 0, 0}, float3{rsqrt2, rsqrt2, 0}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, 1.f); + + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{-0.5f, -1.f, -0.125f} + float3{0, -rsqrt2, 0}, float3{0, rsqrt2, rsqrt2}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, 1.f); + + EXPECT_TRUE(IntersectRayAABB(Center + HalfExtent * float3{-0.125f, -0.5f, -1.f} + float3{0, 0, -rsqrt2}, float3{rsqrt2, 0, rsqrt2}, AABB, Enter, Exit)); + EXPECT_FLOAT_EQ(Enter, 1.f); +} + } // namespace |
