ManipulatorViewTests.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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/Serialization/SerializeContext.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
  11. #include <AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h>
  12. #include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
  13. #include <AzTest/AzTest.h>
  14. #include <AzToolsFramework/Application/ToolsApplication.h>
  15. #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
  16. #include <AzToolsFramework/Manipulators/ManipulatorView.h>
  17. #include <AzToolsFramework/Manipulators/RotationManipulators.h>
  18. #include <AzToolsFramework/Manipulators/TranslationManipulators.h>
  19. #include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
  20. #include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
  21. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  22. namespace UnitTest
  23. {
  24. using namespace AzToolsFramework;
  25. class ManipulatorViewTest : public LeakDetectionFixture
  26. {
  27. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  28. public:
  29. void SetUp() override
  30. {
  31. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  32. AZ::ComponentApplication::StartupParameters startupParameters;
  33. startupParameters.m_loadSettingsRegistry = false;
  34. m_app.Start(AzFramework::Application::Descriptor(), startupParameters);
  35. // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
  36. // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
  37. // in the unit tests.
  38. AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
  39. }
  40. void TearDown() override
  41. {
  42. m_app.Stop();
  43. m_serializeContext.reset();
  44. }
  45. ToolsTestApplication m_app{ "ManipulatorViewTest" };
  46. };
  47. TEST_F(ManipulatorViewTest, ViewDirectionForCameraAlignedManipulatorFacesCameraInManipulatorSpace)
  48. {
  49. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  50. // Given
  51. const AZ::Transform orientation =
  52. AZ::Transform::CreateFromQuaternion(AZ::Quaternion::CreateRotationX(AZ::DegToRad(-90.0f)));
  53. const AZ::Transform translation = AZ::Transform::CreateTranslation(AZ::Vector3(5.0f, 0.0f, 10.0f));
  54. const AZ::Transform manipulatorSpace = translation * orientation;
  55. // create a rotation manipulator in an arbitrary space
  56. RotationManipulators rotationManipulators(manipulatorSpace);
  57. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. // When
  60. const AZ::Vector3 worldCameraPosition = AZ::Vector3(5.0f, -10.0f, 10.0f);
  61. // transform the view direction to the space of the manipulator (space + local transform)
  62. const AZ::Vector3 viewDirection = CalculateViewDirection(rotationManipulators, worldCameraPosition);
  63. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  64. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. // Then
  66. // check the view direction is in the same space as the manipulator (space + local transform)
  67. EXPECT_THAT(viewDirection, IsClose(AZ::Vector3::CreateAxisZ()));
  68. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
  69. }
  70. TEST(Manipulator, ScaleBasedOnCameraDistanceInFront)
  71. {
  72. AzFramework::CameraState cameraState{};
  73. cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
  74. cameraState.m_forward = -AZ::Vector3::CreateAxisY();
  75. const float scale = AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateZero(), cameraState);
  76. EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
  77. }
  78. TEST(Manipulator, ScaleBasedOnCameraDistanceToTheSide)
  79. {
  80. AzFramework::CameraState cameraState{};
  81. cameraState.m_position = AZ::Vector3::CreateAxisY(20.0f);
  82. cameraState.m_forward = -AZ::Vector3::CreateAxisY();
  83. const float scale = AzToolsFramework::CalculateScreenToWorldMultiplier(AZ::Vector3::CreateAxisX(-10.0f), cameraState);
  84. EXPECT_NEAR(scale, 2.0f, std::numeric_limits<float>::epsilon());
  85. }
  86. TEST_F(ManipulatorViewTest, ManipulatorViewQuadDrawsAtCorrectPositionWhenManipulatorSpaceIsScaledUniformlyAndNonUniformly)
  87. {
  88. // Given
  89. // simulate a custom manipulator space (e.g. entity transform) and a local offset within that space (e.g. spline vertex position)
  90. const AZ::Transform space =
  91. AZ::Transform::CreateTranslation(AZ::Vector3(2.0f, -3.0f, -4.0f)) * AZ::Transform::CreateUniformScale(2.0f);
  92. const AZ::Vector3 localPosition = AZ::Vector3(2.0f, -2.0f, 0.0f);
  93. const AZ::Vector3 nonUniformScale = AZ::Vector3(2.0f, 3.0f, 4.0f);
  94. const AZ::Transform combinedTransform =
  95. AzToolsFramework::ApplySpace(AZ::Transform::CreateTranslation(localPosition), space, nonUniformScale);
  96. // create a manipulator state based on the space and local position
  97. AzToolsFramework::ManipulatorState manipulatorState{};
  98. manipulatorState.m_worldFromLocal = combinedTransform;
  99. manipulatorState.m_nonUniformScale = nonUniformScale;
  100. // note: This is zero as the localPosition is already encoded in the combinedTransform
  101. manipulatorState.m_localPosition = AZ::Vector3::CreateZero();
  102. // camera (go to position format) - 10.00, -15.00, 6.00, -90.00, 0.00
  103. const AzFramework::CameraState cameraState = AzFramework::CreateDefaultCamera(
  104. AZ::Transform::CreateFromMatrix3x3AndTranslation(
  105. AZ::Matrix3x3::CreateRotationX(AZ::DegToRad(-90.0f)), AZ::Vector3(10.0f, -15.0f, 6.0f)),
  106. AzFramework::ScreenSize(1280, 720));
  107. // test debug display instance to record vertices that were output
  108. auto testDebugDisplayRequests = AZStd::make_shared<TestDebugDisplayRequests>();
  109. auto planarTranslationViewQuad = CreateManipulatorViewQuadForPlanarTranslationManipulator(
  110. AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Color::CreateZero(), AZ::Color::CreateZero(), 2.2f, 0.2f, 1.0f);
  111. // When
  112. // draw the quad as it would be for a manipulator
  113. planarTranslationViewQuad->Draw(
  114. AzToolsFramework::ManipulatorManagerId(1), AzToolsFramework::ManipulatorManagerState{ false },
  115. AzToolsFramework::ManipulatorId(1), manipulatorState, *testDebugDisplayRequests, cameraState,
  116. AzToolsFramework::ViewportInteraction::MouseInteraction{});
  117. const AZStd::vector<AZ::Vector3> expectedDisplayPositions = {
  118. AZ::Vector3(10.5f, -13.5f, -4.0f), AZ::Vector3(11.5f, -13.5f, -4.0f), AZ::Vector3(10.5f, -14.5f, -4.0f),
  119. AZ::Vector3(11.5f, -14.5f, -4.0f), AZ::Vector3(10.5f, -13.5f, -4.0f), AZ::Vector3(10.5f, -14.5f, -4.0f),
  120. AZ::Vector3(11.5f, -14.5f, -4.0f), AZ::Vector3(11.5f, -13.5f, -4.0f)
  121. };
  122. // Then
  123. const auto points = testDebugDisplayRequests->GetPoints();
  124. // quad vertices appear in the expected position (not offset or scaled incorrectly by space scale)
  125. using ::testing::UnorderedPointwise;
  126. EXPECT_THAT(points, UnorderedPointwise(ContainerIsClose(), expectedDisplayPositions));
  127. }
  128. } // namespace UnitTest