ManipulatorBoundsTests.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Math/Quaternion.h>
  9. #include <AzCore/Math/Spline.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzTest/AzTest.h>
  12. #include <AzToolsFramework/Picking/Manipulators/ManipulatorBounds.h>
  13. #include <AzCore/UnitTest/TestTypes.h>
  14. namespace UnitTest
  15. {
  16. const float g_epsilon = 1e-4f;
  17. using namespace AzToolsFramework::Picking;
  18. TEST(ManipulatorBounds, Sphere)
  19. {
  20. ManipulatorBoundSphere manipulatorBoundSphere(RegisteredBoundId{});
  21. manipulatorBoundSphere.m_center = AZ::Vector3::CreateZero();
  22. manipulatorBoundSphere.m_radius = 2.0f;
  23. float intersectionDistance;
  24. bool intersection = manipulatorBoundSphere.IntersectRay(
  25. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  26. EXPECT_NEAR(intersectionDistance, 8.0f, g_epsilon);
  27. EXPECT_TRUE(intersection);
  28. }
  29. TEST(ManipulatorBounds, Box)
  30. {
  31. ManipulatorBoundBox manipulatorBoundBox(RegisteredBoundId{});
  32. manipulatorBoundBox.m_center = AZ::Vector3::CreateZero();
  33. manipulatorBoundBox.m_halfExtents = AZ::Vector3(1.0f);
  34. manipulatorBoundBox.m_axis1 = AZ::Vector3::CreateAxisX();
  35. manipulatorBoundBox.m_axis2 = AZ::Vector3::CreateAxisY();
  36. manipulatorBoundBox.m_axis3 = AZ::Vector3::CreateAxisZ();
  37. float intersectionDistance;
  38. bool intersection = manipulatorBoundBox.IntersectRay(
  39. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  40. EXPECT_NEAR(intersectionDistance, 9.0f, g_epsilon);
  41. EXPECT_TRUE(intersection);
  42. }
  43. TEST(ManipulatorBounds, Cylinder)
  44. {
  45. ManipulatorBoundCylinder manipulatorCylinder(RegisteredBoundId{});
  46. manipulatorCylinder.m_base = AZ::Vector3::CreateAxisZ(-5.0f);
  47. manipulatorCylinder.m_axis = AZ::Vector3::CreateAxisZ();
  48. manipulatorCylinder.m_height = 10.0f;
  49. manipulatorCylinder.m_radius = 2.0f;
  50. float intersectionDistance;
  51. bool intersection = manipulatorCylinder.IntersectRay(
  52. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  53. EXPECT_NEAR(intersectionDistance, 8.0f, g_epsilon);
  54. EXPECT_TRUE(intersection);
  55. }
  56. TEST(ManipulatorBounds, Cone)
  57. {
  58. ManipulatorBoundCone manipulatorCone(RegisteredBoundId{});
  59. manipulatorCone.m_apexPosition = AZ::Vector3::CreateAxisZ(-5.0f);
  60. manipulatorCone.m_height = 10.0f;
  61. manipulatorCone.m_dir = AZ::Vector3::CreateAxisZ();
  62. manipulatorCone.m_radius = 4.0f;
  63. float intersectionDistance;
  64. bool intersection = manipulatorCone.IntersectRay(
  65. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  66. EXPECT_NEAR(intersectionDistance, 8.0f, g_epsilon);
  67. EXPECT_TRUE(intersection);
  68. }
  69. TEST(ManipulatorBounds, Quad)
  70. {
  71. ManipulatorBoundQuad manipulatorQuad(RegisteredBoundId{});
  72. manipulatorQuad.m_corner1 = AZ::Vector3(-1.0f, 0.0f, 1.0f);
  73. manipulatorQuad.m_corner2 = AZ::Vector3(1.0f, 0.0f, 1.0f);
  74. manipulatorQuad.m_corner3 = AZ::Vector3(1.0f, 0.0f, -1.0f);
  75. manipulatorQuad.m_corner4 = AZ::Vector3(-1.0f, 0.0f, -1.0f);
  76. float intersectionDistance;
  77. bool intersection = manipulatorQuad.IntersectRay(
  78. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  79. EXPECT_NEAR(intersectionDistance, 10.0f, g_epsilon);
  80. EXPECT_TRUE(intersection);
  81. }
  82. TEST(ManipulatorBounds, Torus)
  83. {
  84. ManipulatorBoundTorus manipulatorTorus(RegisteredBoundId{});
  85. manipulatorTorus.m_axis = AZ::Vector3::CreateAxisY();
  86. manipulatorTorus.m_center = AZ::Vector3::CreateZero();
  87. manipulatorTorus.m_majorRadius = 5.0f;
  88. manipulatorTorus.m_minorRadius = 0.5f;
  89. float _;
  90. bool intersectionCenter = manipulatorTorus.IntersectRay(
  91. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), _);
  92. // miss - through center
  93. EXPECT_TRUE(!intersectionCenter);
  94. float intersectionDistance;
  95. bool intersectionOutside = manipulatorTorus.IntersectRay(
  96. AZ::Vector3(5.0f, 10.0f, 0.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  97. EXPECT_NEAR(intersectionDistance, 9.5f, g_epsilon);
  98. EXPECT_TRUE(intersectionOutside);
  99. }
  100. TEST(ManipulatorBounds, RayIntersectsTorusAtAcuteAngle)
  101. {
  102. // torus approximation is side-on to ray
  103. ManipulatorBoundTorus manipulatorTorus(RegisteredBoundId{});
  104. manipulatorTorus.m_axis = AZ::Vector3::CreateAxisX();
  105. manipulatorTorus.m_center = AZ::Vector3::CreateZero();
  106. manipulatorTorus.m_majorRadius = 5.0f;
  107. manipulatorTorus.m_minorRadius = 0.5f;
  108. // calculation used to orientate the ray to hit
  109. // the inside edge of the cylinder
  110. //
  111. // tan @ = opp / adj
  112. // tan @ = 0.5 / 5.0 = 0.1
  113. // @ = atan(0.1) = 5.71 degrees
  114. //
  115. // tan 5.71 = x / 15
  116. // x = 15 * tan 5.71 = ~1.5
  117. const AZ::Vector3 orientatedPickRay =
  118. AZ::Quaternion::CreateRotationZ(AZ::DegToRad(5.7f)).TransformVector(-AZ::Vector3::CreateAxisY());
  119. float _;
  120. bool intersection = manipulatorTorus.IntersectRay(
  121. AZ::Vector3(-1.5f, 10.0f, 0.0f), orientatedPickRay, _);
  122. // ensure we get a valid intersection (even if the first hit
  123. // might have happened in the 'hollow' part of the cylinder)
  124. EXPECT_TRUE(intersection);
  125. }
  126. TEST(ManipulatorBounds, Line)
  127. {
  128. ManipulatorBoundLineSegment manipulatorLine(RegisteredBoundId{});
  129. manipulatorLine.m_worldStart = AZ::Vector3(-5.0f, 0.0f, 0.0f);
  130. manipulatorLine.m_worldEnd = AZ::Vector3(5.0f, 0.0f, 0.0f);
  131. manipulatorLine.m_width = 0.2f;
  132. float intersectionDistance;
  133. bool intersection = manipulatorLine.IntersectRay(
  134. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  135. EXPECT_NEAR(intersectionDistance, 10.0f, g_epsilon);
  136. EXPECT_TRUE(intersection);
  137. }
  138. TEST(ManipulatorBounds, Spline)
  139. {
  140. AZStd::shared_ptr<AZ::BezierSpline> bezierSpline = AZStd::make_shared<AZ::BezierSpline>();
  141. bezierSpline->m_vertexContainer.AddVertex(AZ::Vector3(-10.0f, 0.0f, 0.0f));
  142. bezierSpline->m_vertexContainer.AddVertex(AZ::Vector3(-5.0f, 0.0f, 0.0f));
  143. bezierSpline->m_vertexContainer.AddVertex(AZ::Vector3(5.0f, 0.0f, 0.0f));
  144. bezierSpline->m_vertexContainer.AddVertex(AZ::Vector3(10.0f, 0.0f, 0.0f));
  145. ManipulatorBoundSpline manipulatorSpline(RegisteredBoundId{});
  146. manipulatorSpline.m_spline = bezierSpline;
  147. manipulatorSpline.m_transform = AZ::Transform::CreateIdentity();
  148. manipulatorSpline.m_width = 0.2f;
  149. float intersectionDistance;
  150. bool intersection = manipulatorSpline.IntersectRay(
  151. AZ::Vector3::CreateAxisY(10.0f), -AZ::Vector3::CreateAxisY(), intersectionDistance);
  152. EXPECT_NEAR(intersectionDistance, 10.0f, g_epsilon);
  153. EXPECT_TRUE(intersection);
  154. }
  155. // replicates a scenario in the Editor using a cone and a pick ray which should have failed but passed with Intersect::IntersectRayCone
  156. TEST(ManipulatorIntersectRayConeTest, RayConeEditorScenarioTest)
  157. {
  158. auto rayOrigin = AZ::Vector3(0.0f, -0.808944702f, 0.0f);
  159. auto rayDir = AZ::Vector3(0.301363617f, 0.939044654f, 0.165454566f);
  160. float t = 0.0f;
  161. bool hit = AzToolsFramework::Picking::IntersectRayCone(
  162. rayOrigin, rayDir, AZ::Vector3(0.0f, 0.0f, 0.161788940f), AZ::Vector3(0.0f, 0.0f, -1.0f), 0.0453009047, 0.0113252262, t);
  163. EXPECT_FALSE(hit);
  164. }
  165. // cone lying flat, ray going towards base of cone
  166. TEST(ManipulatorIntersectRayConeTest, RayIntersectsConeBase)
  167. {
  168. auto rayOrigin = AZ::Vector3::CreateZero();
  169. auto rayDir = AZ::Vector3::CreateAxisY();
  170. float t = 0.0f;
  171. bool hit = AzToolsFramework::Picking::IntersectRayCone(
  172. rayOrigin, rayDir, AZ::Vector3::CreateAxisY(10.0f), AZ::Vector3::CreateAxisY(-1.0f), 5.0f, 1.0f, t);
  173. EXPECT_TRUE(hit);
  174. EXPECT_THAT(t, ::testing::FloatNear(5.0f, 0.0001f));
  175. }
  176. // cone standing up, ray going towards mid side of cone
  177. TEST(ManipulatorIntersectRayConeTest, RayIntersectsConeSide)
  178. {
  179. auto rayOrigin = AZ::Vector3::CreateZero();
  180. auto rayDir = AZ::Vector3::CreateAxisY();
  181. float t = 0.0f;
  182. bool hit = AzToolsFramework::Picking::IntersectRayCone(
  183. rayOrigin, rayDir, AZ::Vector3(0.0f, 10.0f, 5.0f), AZ::Vector3::CreateAxisZ(-1.0f), 10.0f, 5.0f, t);
  184. EXPECT_TRUE(hit);
  185. EXPECT_THAT(t, ::testing::FloatNear(7.5f, 0.0001f));
  186. }
  187. // cone standing up, ray going towards mid side of cone
  188. TEST(ManipulatorIntersectRayConeTest, RayIntersectsConeApex)
  189. {
  190. auto rayOrigin = AZ::Vector3::CreateZero();
  191. auto rayDir = AZ::Vector3::CreateAxisY();
  192. float t = 0.0f;
  193. bool hit = AzToolsFramework::Picking::IntersectRayCone(
  194. rayOrigin, rayDir, AZ::Vector3::CreateAxisY(2.5f), AZ::Vector3::CreateAxisY(1.0f), 5.0f, 1.0f, t);
  195. EXPECT_TRUE(hit);
  196. EXPECT_THAT(t, ::testing::FloatNear(2.5f, 0.0001f));
  197. }
  198. } // namespace UnitTest