ViewportInteractionTests.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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 <AzFramework/Viewport/ViewportScreen.h>
  9. #include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
  10. #include <AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h>
  11. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  12. #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
  13. #include <AzToolsFramework/Viewport/ViewportMessages.h>
  14. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  15. #include <Tests/BoundsTestComponent.h>
  16. namespace UnitTest
  17. {
  18. class IndirectCallViewportInteractionIntersectionFixture : public ToolsApplicationFixture<>
  19. {
  20. public:
  21. void SetUpEditorFixtureImpl() override
  22. {
  23. auto* app = GetApplication();
  24. // register a simple component implementing BoundsRequestBus and EditorComponentSelectionRequestsBus
  25. app->RegisterComponentDescriptor(BoundsTestComponent::CreateDescriptor());
  26. // register a component implementing RenderGeometry::IntersectionRequestBus
  27. app->RegisterComponentDescriptor(RenderGeometryIntersectionTestComponent::CreateDescriptor());
  28. AZ::Entity* entityGround = nullptr;
  29. m_entityIdGround = CreateDefaultEditorEntity("EntityGround", &entityGround);
  30. entityGround->Deactivate();
  31. auto ground = entityGround->CreateComponent<RenderGeometryIntersectionTestComponent>();
  32. entityGround->Activate();
  33. ground->m_localBounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(-10.0f, -10.0f, -0.5f), AZ::Vector3(10.0f, 10.0f, 0.5f));
  34. }
  35. AZ::EntityId m_entityIdGround;
  36. };
  37. using IndirectCallManipulatorViewportInteractionIntersectionFixture =
  38. IndirectCallManipulatorViewportInteractionFixtureMixin<IndirectCallViewportInteractionIntersectionFixture>;
  39. TEST_F(IndirectCallManipulatorViewportInteractionIntersectionFixture, FindClosestPickIntersectionReturnsExpectedSurfacePoint)
  40. {
  41. // camera - 21.00, 8.00, 11.00, -22.00, 150.00
  42. m_cameraState.m_viewportSize = AzFramework::ScreenSize(1280, 720);
  43. AzFramework::SetCameraTransform(
  44. m_cameraState,
  45. AZ::Transform::CreateFromMatrix3x3AndTranslation(
  46. AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(150.0f)) * AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-22.0f)),
  47. AZ::Vector3(21.0f, 8.0f, 11.0f)));
  48. m_actionDispatcher->CameraState(m_cameraState);
  49. AzToolsFramework::SetWorldTransform(
  50. m_entityIdGround,
  51. AZ::Transform::CreateFromMatrix3x3AndTranslation(
  52. AZ::Matrix3x3::CreateRotationY(AZ::DegToRad(40.0f)) * AZ::Matrix3x3::CreateRotationZ(AZ::DegToRad(60.0f)),
  53. AZ::Vector3(14.0f, -6.0f, 5.0f)));
  54. // expected world position (value taken from editor scenario)
  55. const auto expectedWorldPosition = AZ::Vector3(13.606657f, -2.6753534f, 5.9827675f);
  56. const auto screenPosition = AzFramework::WorldToScreen(expectedWorldPosition, m_cameraState);
  57. // perform ray intersection against mesh
  58. constexpr float defaultPickDistance = 10.0f;
  59. const auto worldIntersectionPoint = AzToolsFramework::FindClosestPickIntersection(
  60. m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(), screenPosition,
  61. AzToolsFramework::EditorPickRayLength, defaultPickDistance);
  62. EXPECT_THAT(worldIntersectionPoint, IsCloseTolerance(expectedWorldPosition, 0.01f));
  63. // Verify that the overloaded version of the API that returns an optional Vector3 also detects the hit correctly.
  64. const auto optionalWorldIntersectionPoint = AzToolsFramework::FindClosestPickIntersection(
  65. m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(),
  66. screenPosition,
  67. AzToolsFramework::EditorPickRayLength);
  68. EXPECT_TRUE(optionalWorldIntersectionPoint.has_value());
  69. EXPECT_THAT(*optionalWorldIntersectionPoint, IsCloseTolerance(expectedWorldPosition, 0.01f));
  70. }
  71. TEST_F(IndirectCallManipulatorViewportInteractionIntersectionFixture, FindClosestPickIntersectionWithNoHitReturnsExpectedResult)
  72. {
  73. const int screenSize = 1000;
  74. const AZ::Vector3 cameraLocation(100.0f);
  75. // Create a simple default camera located at (100,100,100) pointing straight up.
  76. m_cameraState.m_viewportSize = AzFramework::ScreenSize(screenSize, screenSize);
  77. AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(cameraLocation));
  78. m_actionDispatcher->CameraState(m_cameraState);
  79. // Query from the center of the screen.
  80. const AzFramework::ScreenPoint screenPosition(screenSize / 2, screenSize / 2);
  81. // perform ray intersection. With no collision, it should pick a point directly pointing into the camera
  82. // at the default distance, starting from the camera's position + near clip plane distance.
  83. constexpr float defaultPickDistance = 25.0f;
  84. const auto expectedWorldPosition = cameraLocation + AZ::Vector3(0.0f, defaultPickDistance + m_cameraState.m_nearClip, 0.0f);
  85. const auto worldIntersectionPoint = AzToolsFramework::FindClosestPickIntersection(
  86. m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(),
  87. screenPosition,
  88. AzToolsFramework::EditorPickRayLength,
  89. defaultPickDistance);
  90. EXPECT_THAT(worldIntersectionPoint, IsCloseTolerance(expectedWorldPosition, 0.01f));
  91. // Verify that the overloaded version of the API that returns an optional Vector3 doesn't find a hit.
  92. const auto optionalWorldIntersectionPoint = AzToolsFramework::FindClosestPickIntersection(
  93. m_viewportManipulatorInteraction->GetViewportInteraction().GetViewportId(),
  94. screenPosition,
  95. AzToolsFramework::EditorPickRayLength);
  96. EXPECT_FALSE(optionalWorldIntersectionPoint.has_value());
  97. }
  98. } // namespace UnitTest