3
0

ColliderCommandTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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 "ActorFixture.h"
  9. #include <MCore/Source/CommandGroup.h>
  10. #include <EMotionFX/Source/Actor.h>
  11. #include <EMotionFX/CommandSystem/Source/CommandManager.h>
  12. #include <EMotionFX/CommandSystem/Source/ColliderCommands.h>
  13. #include <Tests/Printers.h>
  14. #include <Tests/PhysicsSetupUtils.h>
  15. namespace EMotionFX
  16. {
  17. using ColliderCommandTests = ActorFixture;
  18. TEST_F(ColliderCommandTests, AddRemoveColliders)
  19. {
  20. AZStd::string result;
  21. CommandSystem::CommandManager commandManager;
  22. MCore::CommandGroup commandGroup;
  23. const AZ::u32 actorId = GetActor()->GetID();
  24. const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
  25. const size_t jointCount = jointNames.size();
  26. // 1. Add colliders
  27. const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor());
  28. for (const AZStd::string& jointName : jointNames)
  29. {
  30. CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::BoxShapeConfiguration>(), &commandGroup);
  31. CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::CapsuleShapeConfiguration>(), &commandGroup);
  32. CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::SphereShapeConfiguration>(), &commandGroup);
  33. }
  34. EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
  35. const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor());
  36. EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  37. EXPECT_EQ(
  38. jointCount,
  39. PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box));
  40. EXPECT_TRUE(commandManager.Undo(result));
  41. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  42. EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor()));
  43. EXPECT_TRUE(commandManager.Redo(result));
  44. EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  45. EXPECT_EQ(
  46. jointCount,
  47. PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Box));
  48. EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor()));
  49. // 2. Remove colliders
  50. commandGroup.RemoveAllCommands();
  51. const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor());
  52. size_t colliderIndexToRemove = 1;
  53. for (const AZStd::string& jointName : jointNames)
  54. {
  55. CommandColliderHelpers::RemoveCollider(actorId, jointName, PhysicsSetup::HitDetection, colliderIndexToRemove, &commandGroup);
  56. }
  57. EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
  58. const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor());
  59. EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  60. EXPECT_EQ(
  61. 0,
  62. PhysicsSetupUtils::CountColliders(
  63. GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule));
  64. EXPECT_TRUE(commandManager.Undo(result));
  65. EXPECT_EQ(jointCount * 3, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  66. EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor()));
  67. EXPECT_TRUE(commandManager.Redo(result));
  68. EXPECT_EQ(jointCount * 2, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  69. EXPECT_EQ(
  70. 0,
  71. PhysicsSetupUtils::CountColliders(
  72. GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/ false, Physics::ShapeType::Capsule));
  73. EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor()));
  74. }
  75. TEST_F(ColliderCommandTests, AddRemove1000Colliders)
  76. {
  77. AZStd::string result;
  78. CommandSystem::CommandManager commandManager;
  79. MCore::CommandGroup commandGroup;
  80. const AZ::u32 actorId = GetActor()->GetID();
  81. const AZStd::string jointName = "Bip01__pelvis";
  82. // 1. Add colliders
  83. const AZStd::string serializedBeforeAdd = SerializePhysicsSetup(GetActor());
  84. const size_t colliderCount = 1000;
  85. for (AZ::u32 i = 0; i < colliderCount; ++i)
  86. {
  87. CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::BoxShapeConfiguration>(), &commandGroup);
  88. }
  89. EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
  90. const AZStd::string serializedAfterAdd = SerializePhysicsSetup(GetActor());
  91. EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  92. EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
  93. EXPECT_TRUE(commandManager.Undo(result));
  94. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  95. EXPECT_EQ(serializedBeforeAdd, SerializePhysicsSetup(GetActor()));
  96. EXPECT_TRUE(commandManager.Redo(result));
  97. EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  98. EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
  99. EXPECT_EQ(serializedAfterAdd, SerializePhysicsSetup(GetActor()));
  100. // 2. Clear colliders
  101. commandGroup.RemoveAllCommands();
  102. const AZStd::string serializedBeforeRemove = SerializePhysicsSetup(GetActor());
  103. CommandColliderHelpers::ClearColliders(actorId, jointName, PhysicsSetup::HitDetection, &commandGroup);
  104. EXPECT_TRUE(commandManager.ExecuteCommandGroup(commandGroup, result));
  105. const AZStd::string serializedAfterRemove = SerializePhysicsSetup(GetActor());
  106. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  107. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
  108. EXPECT_TRUE(commandManager.Undo(result));
  109. EXPECT_EQ(colliderCount, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  110. EXPECT_EQ(serializedBeforeRemove, SerializePhysicsSetup(GetActor()));
  111. EXPECT_TRUE(commandManager.Redo(result));
  112. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection));
  113. EXPECT_EQ(0, PhysicsSetupUtils::CountColliders(GetActor(), PhysicsSetup::HitDetection, /*ignoreShapeType*/false, Physics::ShapeType::Box));
  114. EXPECT_EQ(serializedAfterRemove, SerializePhysicsSetup(GetActor()));
  115. }
  116. TEST_F(ColliderCommandTests, AutoSizingColliders)
  117. {
  118. CommandSystem::CommandManager commandManager;
  119. const AZ::u32 actorId = GetActor()->GetID();
  120. const AZStd::vector<AZStd::string> jointNames = GetTestJointNames();
  121. ASSERT_TRUE(jointNames.size() > 0) << "The joint names test data needs at least one joint for this test.";
  122. const AZStd::string& jointName = jointNames[0];
  123. CommandColliderHelpers::AddCollider(actorId, jointName, PhysicsSetup::HitDetection, azrtti_typeid<Physics::BoxShapeConfiguration>());
  124. const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = GetActor()->GetPhysicsSetup();
  125. Physics::CharacterColliderConfiguration* colliderConfig = physicsSetup->GetColliderConfigByType(PhysicsSetup::HitDetection);
  126. EXPECT_NE(colliderConfig, nullptr) << "Collider config should be valid after we added a collider to it.";
  127. Physics::CharacterColliderNodeConfiguration* jointConfig = colliderConfig->FindNodeConfigByName(jointName);
  128. EXPECT_NE(jointConfig, nullptr) << "Joint config should be valid after we added a collider to it.";
  129. EXPECT_EQ(jointConfig->m_shapes.size(), 1) << "Joint config should contain one collider.";
  130. Physics::BoxShapeConfiguration* box = azdynamic_cast<Physics::BoxShapeConfiguration*>(jointConfig->m_shapes[0].second.get());
  131. EXPECT_NE(box, nullptr) << "The containing collider should be a box collider.";
  132. EXPECT_TRUE(box->m_dimensions.GetLength() > AZ::Constants::FloatEpsilon)
  133. << "A collider with size zero won't be visible in the viewport. Make sure the auto sizing uses defaults in case of missing data.";
  134. }
  135. ///////////////////////////////////////////////////////////////////////////
  136. struct EditColliderCommandTestParameter
  137. {
  138. AZ::TypeId m_shapeType;
  139. bool m_isTrigger;
  140. AZ::Vector3 m_position;
  141. AZ::Quaternion m_rotation;
  142. std::string m_tag;
  143. float m_radius;
  144. float m_height;
  145. AZ::Vector3 m_dimensions;
  146. };
  147. class EditColliderCommandFixture
  148. : public ActorFixture
  149. , public ::testing::WithParamInterface<EditColliderCommandTestParameter>
  150. {
  151. };
  152. TEST_P(EditColliderCommandFixture, EditColliderCommandTest)
  153. {
  154. AZStd::string result;
  155. CommandSystem::CommandManager commandManager;
  156. const EditColliderCommandTestParameter param = GetParam();
  157. const AZStd::string m_jointName = "l_ankle";
  158. const PhysicsSetup::ColliderConfigType m_configType = PhysicsSetup::ColliderConfigType::HitDetection;
  159. // Add collider to the given joint first.
  160. const AZStd::shared_ptr<PhysicsSetup>& physicsSetup = GetActor()->GetPhysicsSetup();
  161. EXPECT_TRUE(CommandColliderHelpers::AddCollider(GetActor()->GetID(), m_jointName, m_configType, param.m_shapeType));
  162. Physics::CharacterColliderConfiguration* characterColliderConfig = physicsSetup->GetColliderConfigByType(m_configType);
  163. ASSERT_TRUE(characterColliderConfig != nullptr);
  164. Physics::CharacterColliderNodeConfiguration* nodeConfig = CommandColliderHelpers::GetCreateNodeConfig(GetActor(), m_jointName, *characterColliderConfig, result);
  165. ASSERT_TRUE(nodeConfig != nullptr);
  166. EXPECT_EQ(nodeConfig->m_shapes.size(), 1);
  167. AzPhysics::ShapeColliderPair& shapeConfigPair = nodeConfig->m_shapes[0];
  168. Physics::ColliderConfiguration* colliderConfig = shapeConfigPair.first.get();
  169. Physics::ShapeConfiguration* shapeConfig = shapeConfigPair.second.get();
  170. Physics::BoxShapeConfiguration* boxShapeConfig = azdynamic_cast<Physics::BoxShapeConfiguration*>(shapeConfig);
  171. Physics::CapsuleShapeConfiguration* capsuleShapeConfig = azdynamic_cast<Physics::CapsuleShapeConfiguration*>(shapeConfig);
  172. // Create the adjust collider command and using the data from the test parameter.
  173. MCore::Command* orgCommand = CommandSystem::GetCommandManager()->FindCommand(CommandAdjustCollider::s_commandName);
  174. CommandAdjustCollider* command =
  175. aznew CommandAdjustCollider(GetActor()->GetID(), m_jointName, m_configType, /*colliderIndex=*/0, orgCommand);
  176. command->SetOldIsTrigger(colliderConfig->m_isTrigger);
  177. command->SetIsTrigger(param.m_isTrigger);
  178. command->SetOldPosition(colliderConfig->m_position);
  179. command->SetPosition(param.m_position);
  180. command->SetOldRotation(colliderConfig->m_rotation);
  181. command->SetRotation(param.m_rotation);
  182. command->SetOldTag(colliderConfig->m_tag);
  183. command->SetTag(param.m_tag.c_str());
  184. if (capsuleShapeConfig)
  185. {
  186. command->SetOldRadius(capsuleShapeConfig->m_radius);
  187. command->SetRadius(param.m_radius);
  188. command->SetOldHeight(capsuleShapeConfig->m_height);
  189. command->SetHeight(param.m_height);
  190. }
  191. if (boxShapeConfig)
  192. {
  193. command->SetOldDimensions(boxShapeConfig->m_dimensions);
  194. command->SetDimensions(param.m_dimensions);
  195. }
  196. // Check execute.
  197. const AZStd::string serializedBeforeExecute = SerializePhysicsSetup(GetActor());
  198. EXPECT_TRUE(CommandSystem::GetCommandManager()->ExecuteCommand(command, result));
  199. const AZStd::string serializedAfterExecute = SerializePhysicsSetup(GetActor());
  200. EXPECT_EQ(colliderConfig->m_isTrigger, param.m_isTrigger);
  201. EXPECT_EQ(colliderConfig->m_position, param.m_position);
  202. EXPECT_EQ(colliderConfig->m_rotation, param.m_rotation);
  203. EXPECT_EQ(colliderConfig->m_tag, param.m_tag.c_str());
  204. if (capsuleShapeConfig)
  205. {
  206. EXPECT_EQ(capsuleShapeConfig->m_radius, param.m_radius);
  207. EXPECT_EQ(capsuleShapeConfig->m_height, param.m_height);
  208. }
  209. if (boxShapeConfig)
  210. {
  211. EXPECT_EQ(boxShapeConfig->m_dimensions, param.m_dimensions);
  212. }
  213. // Check undo.
  214. EXPECT_TRUE(CommandSystem::GetCommandManager()->Undo(result));
  215. const AZStd::string serializedAfterUndo = SerializePhysicsSetup(GetActor());
  216. EXPECT_EQ(serializedAfterUndo, serializedBeforeExecute);
  217. // Check redo.
  218. EXPECT_TRUE(CommandSystem::GetCommandManager()->Redo(result));
  219. const AZStd::string serializedAfterRedo = SerializePhysicsSetup(GetActor());
  220. EXPECT_EQ(serializedAfterRedo, serializedAfterExecute);
  221. }
  222. std::vector<EditColliderCommandTestParameter> editColliderCommandTestParameters
  223. {
  224. {
  225. azrtti_typeid<Physics::BoxShapeConfiguration>(),
  226. false,
  227. AZ::Vector3::CreateZero(),
  228. AZ::Quaternion::CreateRotationX(0.0f),
  229. "Tag1",
  230. 0.0f,
  231. 0.0f,
  232. AZ::Vector3(1.0f, 2.0f, 3.0f),
  233. },
  234. {
  235. azrtti_typeid<Physics::BoxShapeConfiguration>(),
  236. true,
  237. AZ::Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
  238. AZ::Quaternion::CreateRotationX(180.0f),
  239. "Tag2",
  240. 0.0f,
  241. 0.0f,
  242. AZ::Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()),
  243. },
  244. {
  245. azrtti_typeid<Physics::BoxShapeConfiguration>(),
  246. true,
  247. AZ::Vector3(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
  248. AZ::Quaternion::CreateRotationX(180.0f),
  249. "Tag2",
  250. 0.0f,
  251. 0.0f,
  252. AZ::Vector3(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max()),
  253. },
  254. {
  255. azrtti_typeid<Physics::CapsuleShapeConfiguration>(),
  256. false,
  257. AZ::Vector3::CreateAxisX(99.0f),
  258. AZ::Quaternion::CreateRotationX(45.0f),
  259. "Tag3",
  260. 1.0f,
  261. 3.0f,
  262. AZ::Vector3::CreateZero(),
  263. },
  264. {
  265. azrtti_typeid<Physics::CapsuleShapeConfiguration>(),
  266. true,
  267. AZ::Vector3::CreateAxisY(1.0f),
  268. AZ::Quaternion::CreateRotationX(-90.0f),
  269. "",
  270. FLT_MAX,
  271. FLT_MAX,
  272. AZ::Vector3::CreateZero(),
  273. }
  274. };
  275. INSTANTIATE_TEST_CASE_P(EditColliderCommandTests,
  276. EditColliderCommandFixture,
  277. ::testing::ValuesIn(editColliderCommandTestParameters)
  278. );
  279. } // namespace EMotionFX