summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-02-07 01:12:31 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-02-07 01:12:31 +0000
commit5409a67ee0cb5da5bc35b5b6f755ce09bcface8d (patch)
treec97e4f34c3516a48ce02f884f1e608d072b5bba1
parentUpdated API version and release history (added PRIMITIVE_TOPOLOGY_LINE_STRIP) (diff)
downloadDiligentCore-5409a67ee0cb5da5bc35b5b6f755ce09bcface8d.tar.gz
DiligentCore-5409a67ee0cb5da5bc35b5b6f755ce09bcface8d.zip
MathLib: added IntersectRayAABB, max3 and min3 function
-rw-r--r--Common/interface/AdvancedMath.hpp34
-rw-r--r--Common/interface/BasicMath.hpp14
-rw-r--r--Tests/DiligentCoreTest/src/Common/MathLibTest.cpp91
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