/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #include #include #include #include #include #include #include using namespace AZ; namespace UnitTest { TEST(MATH_Aabb, TestCreateNull) { Aabb aabb = Aabb::CreateNull(); EXPECT_FALSE(aabb.IsValid()); EXPECT_TRUE(aabb.GetMin().IsGreaterThan(aabb.GetMax())); } TEST(MATH_Aabb, TestCreateFromPoint) { Aabb aabb = Aabb::CreateFromPoint(Vector3(0.0f)); EXPECT_TRUE(aabb.IsValid()); EXPECT_TRUE(aabb.IsFinite()); EXPECT_THAT(aabb.GetMin(), IsClose(aabb.GetMax())); } TEST(MATH_Aabb, TestCreateFromMinMax) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f)); EXPECT_TRUE(aabb.IsValid()); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f))); } TEST(MATH_Aabb, TestCreateCenterHalfExtents) { Aabb aabb = Aabb::CreateCenterHalfExtents(Vector3(1.0f), Vector3(1.0f)); EXPECT_TRUE(aabb.IsValid()); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f))); EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f))); } TEST(MATH_Aabb, TestCreateCenterRadius) { Aabb aabb = Aabb::CreateCenterRadius(Vector3(4.0f), 2.0f); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(2.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(6.0f))); EXPECT_THAT(aabb.GetExtents(), IsClose(Vector3(4.0f))); } TEST(MATH_Aabb, TestCreatePoints) { const int numPoints = 3; Vector3 points[numPoints] = { Vector3(10.0f, 0.0f, -10.0f), Vector3(-10.0f, 10.0f, 0.0f), Vector3(0.0f, -10.0f, 10.0f) }; Aabb aabb = Aabb::CreatePoints(points, numPoints); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f))); } TEST(MATH_Aabb, TestCreatePointsSlice) { Vector3 points[] = { Vector3(10.0f, 0.0f, -10.0f), Vector3(-10.0f, 10.0f, 0.0f), Vector3(0.0f, -10.0f, 10.0f) }; Aabb aabb = Aabb::CreatePoints(points); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f))); } TEST(MATH_Aabb, TestCreatePointsEmpty) { Aabb aabb = Aabb::CreatePoints(nullptr, 0); EXPECT_FALSE(aabb.IsValid()); } TEST(MATH_Aabb, TestCreatePointsEmptySlice) { AZStd::span points = {}; Aabb aabb = Aabb::CreatePoints(points); EXPECT_FALSE(aabb.IsValid()); } TEST(MATH_Aabb, TestCreateFromObb) { const Vector3 position(1.0f, 1.0f, 1.0f); const Quaternion rotation = Quaternion::CreateRotationZ(Constants::QuarterPi); const Vector3 halfLengths = Vector3::CreateOne(); const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths); Aabb aabb = Aabb::CreateFromObb(obb); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-0.414f, -0.414f, 0.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.414f, 2.414f, 2.0f))); EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f, 1.0f, 1.0f))); } TEST(MATH_Aabb, TestSetters) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(4.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(4.0f))); aabb.SetMin(Vector3(0.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f))); EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(2.0f))); aabb.SetMax(Vector3(6.0f)); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(6.0f))); EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(3.0f))); } TEST(MATH_Aabb, TestGetExtents) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f, 2.0f, 3.0f)); EXPECT_NEAR(aabb.GetXExtent(), 1.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetYExtent(), 2.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetZExtent(), 3.0f, AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestSupport) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f)); EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774f, 0.5774f, 0.5774f)), IsClose(Vector3(0.0f, 0.0f, 0.0f))); EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774f, 0.5774f, -0.5774f)), IsClose(Vector3(0.0f, 0.0f, 1.0f))); EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774f, -0.5774f, 0.5774f)), IsClose(Vector3(0.0f, 1.0f, 0.0f))); EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774f, -0.5774f, -0.5774f)), IsClose(Vector3(0.0f, 1.0f, 1.0f))); EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774f, 0.5774f, 0.5774f)), IsClose(Vector3(1.0f, 0.0f, 0.0f))); EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774f, 0.5774f, -0.5774f)), IsClose(Vector3(1.0f, 0.0f, 1.0f))); EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774f, -0.5774f, 0.5774f)), IsClose(Vector3(1.0f, 1.0f, 0.0f))); EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774f, -0.5774f, -0.5774f)), IsClose(Vector3(1.0f, 1.0f, 1.0f))); } TEST(MATH_Aabb, TestGetAsSphere) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f, 0.0f, 0.0f), Vector3(2.0f, 0.0f, 0.0f)); Vector3 center; float radius; aabb.GetAsSphere(center, radius); EXPECT_THAT(center, IsClose(Vector3(0.0f))); EXPECT_NEAR(radius, 2.0f, AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestContains) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(2.0f)); //Contains(Vector3) EXPECT_TRUE(aabb.Contains(Vector3(1.0f))); //Contains(Aabb) EXPECT_TRUE(aabb.Contains(aabb2)); EXPECT_FALSE(aabb2.Contains(aabb)); } TEST(MATH_Aabb, TestOverlaps) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(3.0f)); EXPECT_TRUE(aabb.Overlaps(aabb2)); aabb2.Set(Vector3(5.0f), Vector3(6.0f)); EXPECT_FALSE(aabb.Overlaps(aabb2)); } TEST(MATH_Aabb, TestDisjoint) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(2.0f)); Aabb aabb3 = Aabb::CreateFromMinMax(Vector3(3.0f), Vector3(4.0f)); //Disjoint(Aabb) EXPECT_FALSE(aabb.Disjoint(aabb2)); EXPECT_FALSE(aabb2.Disjoint(aabb)); EXPECT_TRUE(aabb3.Disjoint(aabb)); EXPECT_TRUE(aabb3.Disjoint(aabb2)); EXPECT_TRUE(aabb.Disjoint(aabb3)); EXPECT_TRUE(aabb2.Disjoint(aabb3)); } TEST(MATH_Aabb, TestExpand) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f)); aabb.Expand(Vector3(1.0f)); EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f))); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f))); } TEST(MATH_Aabb, TestGetExpanded) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); aabb = aabb.GetExpanded(Vector3(9.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f))); } TEST(MATH_Aabb, TestAddPoint) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); aabb.AddPoint(Vector3(1.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f))); aabb.AddPoint(Vector3(2.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f))); } TEST(MATH_Aabb, TestAddAabb) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(0.0f)); aabb.AddAabb(aabb2); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-2.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f))); } TEST(MATH_Aabb, TestGetDistance) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); EXPECT_NEAR(aabb.GetDistance(Vector3(2.0f, 0.0f, 0.0f)), 1.0f, AZ::Constants::Tolerance); // make sure a point inside the box returns zero, even if that point isn't the center. EXPECT_NEAR(aabb.GetDistance(Vector3(0.5f, 0.0f, 0.0f)), 0.0f, AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestGetDistanceSq) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); EXPECT_NEAR(aabb.GetDistanceSq(Vector3(0.0f, 3.0f, 0.0f)), 4.0f, AZ::Constants::Tolerance); // make sure a point inside the box returns zero, even if that point isn't the center. EXPECT_NEAR(aabb.GetDistanceSq(Vector3(0.0f, 0.5f, 0.0f)), 0.0f, AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestGetMaxDistance) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); // The max distance for all of the following should be the square root of (4^2 + 3^2 + 2^2) EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, 2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, 2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, -2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, -2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, 2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, 2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, -2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, -2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance); // make sure points inside the box return a correct max distance as well - sqrt of (1.5^2 + 1.5^2 + 1.5^2) EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, 0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, 0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, -0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, -0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, 0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, 0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, -0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, -0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance); // make sure the center returns our minimal max distance (1^2 + 1^2 + 1^2) EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.0f, 0.0f, 0.0f)), sqrtf(1.0f + 1.0f + 1.0f), AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestGetMaxDistanceSq) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); // The max distance for all of the following should be (4^2 + 3^2 + 2^2) EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, 2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, 2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, -2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, -2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, 2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, 2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, -2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, -2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance); // make sure points inside the box return a correct max distance as well: (1.5^2 + 1.5^2 + 1.5^2) EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, 0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, 0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, -0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, -0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, 0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, 0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, -0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, -0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance); // make sure the center returns our minimal max distance (1^2 + 1^2 + 1^2) EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.0f, 0.0f, 0.0f)), 1.0f + 1.0f + 1.0f, AZ::Constants::Tolerance); } TEST(MATH_Aabb, TestGetClamped) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(4.0f)); aabb = aabb.GetClamped(aabb2); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f))); } TEST(MATH_Aabb, TestClamp) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f)); Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(1.0f)); aabb.Clamp(aabb2); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f))); } TEST(MATH_Aabb, TestSetNull) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f)); aabb.SetNull(); EXPECT_FALSE(aabb.IsValid()); } TEST(MATH_Aabb, TestTranslate) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f)); aabb.Translate(Vector3(2.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f))); } TEST(MATH_Aabb, TestGetTranslated) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(3.0f)); aabb = aabb.GetTranslated(Vector3(-2.0f)); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f))); } TEST(MATH_Aabb, TestGetSurfaceArea) { Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f)); EXPECT_NEAR(aabb.GetSurfaceArea(), 6.0f, 0.002f); } TEST(MATH_Aabb, TestIsClose) { const Aabb aabb1 = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f)); const Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(0.1f), Vector3(0.9f)); const Aabb aabb3 = Aabb::CreateFromMinMax(Vector3(0.3f), Vector3(0.7f)); EXPECT_TRUE(aabb1.IsClose(aabb2, 0.2f)); EXPECT_FALSE(aabb1.IsClose(aabb3, 0.2f)); EXPECT_TRUE(aabb2.IsClose(aabb3, 0.3f)); } // use of infinity with fast math is simply not supported #if !defined(O3DE_USING_FAST_MATH) TEST(MATH_Aabb, TestIsFinite) { Aabb aabb = Aabb::CreateNull(); const float infinity = std::numeric_limits::infinity(); const Vector3 infiniteV3 = Vector3(infinity); aabb.Set(Vector3(0), infiniteV3); // A bounding box is only invalid if the min is greater than the max. // A bounding box with an infinite min or max is valid as long as this is true. EXPECT_TRUE(aabb.IsValid()); EXPECT_FALSE(aabb.IsFinite()); } #endif // Check if both aabb transform functions give the same result TEST(MATH_AabbTransform, CompareTest) { // create aabb Vector3 min(-100.0f, 50.0f, 0.0f); Vector3 max(120.0f, 300.0f, 50.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); // make the transformation matrix Transform tm = Transform::CreateRotationX(1.0f); tm.SetTranslation(100.0f, 0.0f, -50.0f); // transform Obb obb = aabb.GetTransformedObb(tm); Aabb transAabb = aabb.GetTransformedAabb(tm); Aabb transAabb2 = Aabb::CreateFromObb(obb); aabb.ApplyTransform(tm); // compare the transformations EXPECT_THAT(transAabb.GetMin(), IsClose(transAabb2.GetMin())); EXPECT_THAT(transAabb.GetMax(), IsClose(transAabb2.GetMax())); EXPECT_THAT(aabb.GetMin(), IsClose(transAabb.GetMin())); EXPECT_THAT(aabb.GetMax(), IsClose(transAabb.GetMax())); } TEST(MATH_AabbTransform, GetTransformedAabbCorrectResult) { // create aabb const Vector3 min(20.0f, 30.0f, 40.0f); const Vector3 max(50.0f, 80.0f, 60.0f); const Aabb aabb = Aabb::CreateFromMinMax(min, max); const Transform transform(Vector3(10.0f, 15.0f, 25.0f), Quaternion(0.08f, 0.44f, 0.16f, 0.88f), 0.5f); const Aabb transformedAabb = aabb.GetTransformedAabb(transform); EXPECT_THAT(transformedAabb.GetMin(), IsClose(Vector3(23.168f, 32.56f, 22.504f))); EXPECT_THAT(transformedAabb.GetMax(), IsClose(Vector3(44.872f, 61.24f, 46.776f))); } TEST(MATH_AabbTransform, GetTransformedObbMatrix3x4) { Vector3 min(-1.0f, -2.0f, -3.0f); Vector3 max(4.0f, 3.0f, 2.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); Quaternion rotation(0.46f, 0.26f, 0.58f, 0.62f); Vector3 translation(5.0f, 7.0f, 9.0f); Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation); matrix3x4.MultiplyByScale(Vector3(0.5f, 1.5f, 2.0f)); Obb obb = aabb.GetTransformedObb(matrix3x4); EXPECT_THAT(obb.GetRotation(), IsClose(rotation)); EXPECT_THAT(obb.GetHalfLengths(), IsClose(Vector3(1.25f, 3.75f, 5.0f))); EXPECT_THAT(obb.GetPosition(), IsClose(Vector3(3.928f, 7.9156f, 9.3708f))); } TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4) { Vector3 min(2.0f, 3.0f, 5.0f); Vector3 max(6.0f, 5.0f, 11.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); Quaternion rotation(0.34f, 0.46f, 0.58f, 0.58f); Vector3 translation(-3.0f, -4.0f, -5.0f); Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation); matrix3x4.MultiplyByScale(Vector3(1.2f, 0.8f, 2.0f)); Aabb transformedAabb = aabb.GetTransformedAabb(matrix3x4); EXPECT_THAT(transformedAabb.GetMin(), IsClose(Vector3(4.1488f, -0.01216f, -0.31904f))); EXPECT_THAT(transformedAabb.GetMax(), IsClose(Vector3(16.3216f, 6.54272f, 5.98112f))); } TEST(MATH_AabbTransform, GetTransformedObbFitsInsideTransformedAabb) { Vector3 min(4.0f, 3.0f, 1.0f); Vector3 max(7.0f, 6.0f, 8.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); Quaternion rotation(0.40f, 0.40f, 0.64f, 0.52f); Vector3 translation(-2.0f, 4.0f, -3.0f); Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation); matrix3x4.MultiplyByScale(Vector3(2.2f, 0.6f, 1.4f)); Aabb transformedAabb = aabb.GetTransformedAabb(matrix3x4); Obb transformedObb = aabb.GetTransformedObb(matrix3x4); Aabb aabbContainingTransformedObb = Aabb::CreateFromObb(transformedObb); EXPECT_THAT(transformedAabb.GetMin(), IsClose(aabbContainingTransformedObb.GetMin())); EXPECT_THAT(transformedAabb.GetMax(), IsClose(aabbContainingTransformedObb.GetMax())); } TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4EqualsGetTransformedAabbTransform) { Vector3 min(2.0f, 3.0f, 5.0f); Vector3 max(6.0f, 5.0f, 11.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); Quaternion rotation(0.34f, 0.46f, 0.58f, 0.58f); Vector3 translation(-3.0f, -4.0f, -5.0f); Transform transform = Transform::CreateFromQuaternionAndTranslation(rotation, translation); transform.MultiplyByUniformScale(1.5f); Aabb aabbFromTransform = aabb.GetTransformedAabb(transform); Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation); matrix3x4.MultiplyByScale(Vector3(1.5f)); Aabb aabbFromMatrix = aabb.GetTransformedAabb(matrix3x4); EXPECT_THAT(aabbFromTransform.GetMin(), IsClose(aabbFromMatrix.GetMin())); EXPECT_THAT(aabbFromTransform.GetMax(), IsClose(aabbFromMatrix.GetMax())); } TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4WorksWithLargeBounds) { // Create an AABB with really large bounds on the Y axis. const Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f, AZStd::numeric_limits::lowest(), -10.0f), Vector3(100.0f, 100.0f, 10.0f)); // Set up a 45 degree rotation around Z so that the X and Y bounds are rotated. const Quaternion rotation = Quaternion::CreateFromEulerDegreesXYZ(AZ::Vector3(0.0f, 0.0f, 45.0f)); // Set up a translation with detectable numbers in X and Y. const Vector3 translation(1000.0f, 2000.0f, 0.0f); // Transform the AABB using the given rotation and translation const Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation); const Aabb aabbFromMatrix = aabb.GetTransformedAabb(matrix3x4); // The expected results on the X axis should go from < 1000 to a really large number, // on the Y axis should go from a negative really large number to > 2000, // and on the Z axis should remain -10 to 10. // If this isn't working, the min on the X axis will be 0, and the max on the Y axis will be 0, because the really large // numbers will destroy the precision needed to pick up the translation and the small X bounds. const Vector3 expectedMin(929.289307f, -2.40615924e+38f, -10.0f); const Vector3 expectedMax(2.40615965e+38f, 2141.42139f, 10.0f); EXPECT_NEAR(aabbFromMatrix.GetMin().GetX(), expectedMin.GetX(), AZ::Constants::Tolerance); EXPECT_TRUE(IsCloseMag(aabbFromMatrix.GetMin().GetY(), expectedMin.GetY(), AZ::Constants::Tolerance)); EXPECT_NEAR(aabbFromMatrix.GetMin().GetZ(), expectedMin.GetZ(), AZ::Constants::Tolerance); EXPECT_TRUE(IsCloseMag(aabbFromMatrix.GetMax().GetX(), expectedMax.GetX(), AZ::Constants::Tolerance)); EXPECT_NEAR(aabbFromMatrix.GetMax().GetY(), expectedMax.GetY(), AZ::Constants::Tolerance); EXPECT_NEAR(aabbFromMatrix.GetMax().GetZ(), expectedMax.GetZ(), AZ::Constants::Tolerance); } TEST(MATH_AabbTransform, GetTransformedAabbTransformWorksWithLargeBounds) { // Create an AABB with really large bounds on the Y axis. const Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f, AZStd::numeric_limits::lowest(), -10.0f), Vector3(100.0f, 100.0f, 10.0f)); // Set up a 45 degree rotation around Z so that the X and Y bounds are rotated. const Quaternion rotation = Quaternion::CreateFromEulerDegreesXYZ(AZ::Vector3(0.0f, 0.0f, 45.0f)); // Set up a translation with detectable numbers in X and Y. const Vector3 translation(1000.0f, 2000.0f, 0.0f); // Transform the AABB using the given rotation and translation const Transform transform = Transform::CreateFromQuaternionAndTranslation(rotation, translation); const Aabb aabbFromTransform = aabb.GetTransformedAabb(transform); // The expected results on the X axis should go from < 1000 to a really large number, // on the Y axis should go from a negative really large number to > 2000, // and on the Z axis should remain -10 to 10. // If this isn't working, the min on the X axis will be 0, and the max on the Y axis will be 0, because the really large // numbers will destroy the precision needed to pick up the translation and the small X bounds. const Vector3 expectedMin(929.289307f, -2.40615924e+38f, -10.0f); const Vector3 expectedMax(2.40615965e+38f, 2141.42139f, 10.0f); EXPECT_NEAR(aabbFromTransform.GetMin().GetX(), expectedMin.GetX(), AZ::Constants::Tolerance); EXPECT_TRUE(IsCloseMag(aabbFromTransform.GetMin().GetY(), expectedMin.GetY(), AZ::Constants::Tolerance)); EXPECT_NEAR(aabbFromTransform.GetMin().GetZ(), expectedMin.GetZ(), AZ::Constants::Tolerance); EXPECT_TRUE(IsCloseMag(aabbFromTransform.GetMax().GetX(), expectedMax.GetX(), AZ::Constants::Tolerance)); EXPECT_NEAR(aabbFromTransform.GetMax().GetY(), expectedMax.GetY(), AZ::Constants::Tolerance); EXPECT_NEAR(aabbFromTransform.GetMax().GetZ(), expectedMax.GetZ(), AZ::Constants::Tolerance); } TEST(MATH_AabbTransform, MultiplyByScale) { Vector3 min(2.0f, 6.0f, 8.0f); Vector3 max(6.0f, 9.0f, 10.0f); Aabb aabb = Aabb::CreateFromMinMax(min, max); Vector3 scale(0.5f, 2.0f, 1.5f); aabb.MultiplyByScale(scale); EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f, 12.0f, 12.0f))); EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f, 18.0f, 15.0f))); } }