3
0

ActorClothColliders.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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 <Integration/ActorComponentBus.h>
  9. #include <Components/ClothComponentMesh/ActorClothColliders.h>
  10. namespace NvCloth
  11. {
  12. namespace Internal
  13. {
  14. extern const size_t NvClothMaxNumSphereColliders = 32;
  15. extern const size_t NvClothMaxNumCapsuleColliders = 32;
  16. SphereCollider CreateSphereCollider(
  17. const Physics::ColliderConfiguration* colliderConfig,
  18. const Physics::SphereShapeConfiguration* sphereShapeConfig,
  19. int jointIndex, int sphereIndex)
  20. {
  21. SphereCollider sphereCollider;
  22. sphereCollider.m_jointIndex = jointIndex;
  23. sphereCollider.m_offsetTransform =
  24. AZ::Transform::CreateFromQuaternionAndTranslation(
  25. colliderConfig->m_rotation,
  26. colliderConfig->m_position);
  27. sphereCollider.m_radius = sphereShapeConfig->m_radius;
  28. sphereCollider.m_nvSphereIndex = sphereIndex;
  29. return sphereCollider;
  30. }
  31. CapsuleCollider CreateCapsuleCollider(
  32. const Physics::ColliderConfiguration* colliderConfig,
  33. const Physics::CapsuleShapeConfiguration* capsuleShapeConfig,
  34. int jointIndex, int capsuleIndex, int sphereAIndex, int sphereBIndex)
  35. {
  36. CapsuleCollider capsuleCollider;
  37. capsuleCollider.m_jointIndex = jointIndex;
  38. capsuleCollider.m_offsetTransform =
  39. AZ::Transform::CreateFromQuaternionAndTranslation(
  40. colliderConfig->m_rotation,
  41. colliderConfig->m_position);
  42. capsuleCollider.m_radius = capsuleShapeConfig->m_radius;
  43. capsuleCollider.m_height = capsuleShapeConfig->m_height;
  44. capsuleCollider.m_capsuleIndex = capsuleIndex;
  45. capsuleCollider.m_sphereAIndex = sphereAIndex;
  46. capsuleCollider.m_sphereBIndex = sphereBIndex;
  47. return capsuleCollider;
  48. }
  49. }
  50. AZStd::unique_ptr<ActorClothColliders> ActorClothColliders::Create(AZ::EntityId entityId)
  51. {
  52. Physics::AnimationConfiguration* actorPhysicsConfig = nullptr;
  53. EMotionFX::Integration::ActorComponentRequestBus::EventResult(
  54. actorPhysicsConfig, entityId, &EMotionFX::Integration::ActorComponentRequestBus::Events::GetPhysicsConfig);
  55. if (!actorPhysicsConfig)
  56. {
  57. return nullptr;
  58. }
  59. const Physics::CharacterColliderConfiguration& clothConfig = actorPhysicsConfig->m_clothConfig;
  60. // Maximum number of spheres and capsules is imposed by NvCloth library
  61. size_t sphereCount = 0;
  62. size_t capsuleCount = 0;
  63. [[maybe_unused]] bool maxSphereCountReachedWarned = false;
  64. [[maybe_unused]] bool maxCapsuleCountReachedWarned = false;
  65. AZStd::vector<SphereCollider> sphereColliders;
  66. AZStd::vector<CapsuleCollider> capsuleColliders;
  67. for (const Physics::CharacterColliderNodeConfiguration& clothNodeConfig : clothConfig.m_nodes)
  68. {
  69. size_t jointIndex = EMotionFX::Integration::ActorComponentRequests::s_invalidJointIndex;
  70. EMotionFX::Integration::ActorComponentRequestBus::EventResult(
  71. jointIndex, entityId,
  72. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetJointIndexByName,
  73. clothNodeConfig.m_name.c_str());
  74. if (jointIndex == EMotionFX::Integration::ActorComponentRequests::s_invalidJointIndex)
  75. {
  76. AZ_Warning("ActorAssetHelper", false, "Joint '%s' not found", clothNodeConfig.m_name.c_str());
  77. continue;
  78. }
  79. for (const AzPhysics::ShapeColliderPair& shapeConfigPair : clothNodeConfig.m_shapes)
  80. {
  81. const auto& colliderConfig = shapeConfigPair.first;
  82. switch (shapeConfigPair.second->GetShapeType())
  83. {
  84. case Physics::ShapeType::Sphere:
  85. {
  86. if (sphereCount >= Internal::NvClothMaxNumSphereColliders)
  87. {
  88. AZ_Warning("ActorAssetHelper", maxSphereCountReachedWarned,
  89. "Maximum number of cloth sphere colliders (%zu) reached",
  90. Internal::NvClothMaxNumSphereColliders);
  91. maxSphereCountReachedWarned = true;
  92. continue;
  93. }
  94. SphereCollider sphereCollider = Internal::CreateSphereCollider(
  95. colliderConfig.get(),
  96. static_cast<const Physics::SphereShapeConfiguration*>(shapeConfigPair.second.get()),
  97. static_cast<int>(jointIndex),
  98. static_cast<int>(sphereCount));
  99. sphereColliders.push_back(sphereCollider);
  100. ++sphereCount;
  101. }
  102. break;
  103. case Physics::ShapeType::Capsule:
  104. {
  105. if (capsuleCount >= Internal::NvClothMaxNumCapsuleColliders)
  106. {
  107. AZ_Warning("ActorAssetHelper", maxCapsuleCountReachedWarned,
  108. "Maximum number of cloth capsule colliders (%zu) reached",
  109. Internal::NvClothMaxNumCapsuleColliders);
  110. maxCapsuleCountReachedWarned = true;
  111. continue;
  112. }
  113. // If there is only 1 sphere left to reach the maximum number
  114. // of spheres the capsule won't fit as each capsule is formed of 2 spheres.
  115. if (sphereCount >= Internal::NvClothMaxNumSphereColliders - 1)
  116. {
  117. AZ_Warning("ActorAssetHelper", maxCapsuleCountReachedWarned,
  118. "Maximum number of cloth capsule colliders reached");
  119. maxCapsuleCountReachedWarned = true;
  120. continue;
  121. }
  122. CapsuleCollider capsuleCollider = Internal::CreateCapsuleCollider(
  123. colliderConfig.get(),
  124. static_cast<const Physics::CapsuleShapeConfiguration*>(shapeConfigPair.second.get()),
  125. static_cast<int>(jointIndex),
  126. static_cast<int>(capsuleCount * 2), // Each capsule holds 2 sphere indices
  127. static_cast<int>(sphereCount + 0), // First sphere index
  128. static_cast<int>(sphereCount + 1)); // Second sphere index
  129. capsuleColliders.push_back(capsuleCollider);
  130. ++capsuleCount;
  131. sphereCount += 2; // Adds 2 spheres per capsule
  132. }
  133. break;
  134. default:
  135. AZ_Warning("ActorAssetHelper", false, "Joint '%s' has an unexpected shape type (%u) for cloth collider.",
  136. clothNodeConfig.m_name.c_str(), static_cast<AZ::u8>(shapeConfigPair.second->GetShapeType()));
  137. break;
  138. }
  139. }
  140. }
  141. if (sphereCount == 0 && capsuleCount == 0)
  142. {
  143. return nullptr;
  144. }
  145. AZStd::unique_ptr<ActorClothColliders> actorClothColliders = AZStd::make_unique<ActorClothColliders>(entityId);
  146. actorClothColliders->m_sphereColliders = AZStd::move(sphereColliders);
  147. actorClothColliders->m_capsuleColliders = AZStd::move(capsuleColliders);
  148. actorClothColliders->m_spheres.resize(sphereCount);
  149. actorClothColliders->m_capsuleIndices.resize(capsuleCount * 2); // 2 sphere indices per capsule
  150. for (const auto& capsuleCollider : actorClothColliders->m_capsuleColliders)
  151. {
  152. actorClothColliders->m_capsuleIndices[capsuleCollider.m_capsuleIndex + 0] = capsuleCollider.m_sphereAIndex;
  153. actorClothColliders->m_capsuleIndices[capsuleCollider.m_capsuleIndex + 1] = capsuleCollider.m_sphereBIndex;
  154. }
  155. // Calculates the current transforms for the colliders
  156. // and fills the data as nvcloth needs them, ready to be
  157. // queried by the cloth component.
  158. actorClothColliders->Update();
  159. return actorClothColliders;
  160. }
  161. ActorClothColliders::ActorClothColliders(AZ::EntityId entityId)
  162. : m_entityId(entityId)
  163. {
  164. }
  165. void ActorClothColliders::Update()
  166. {
  167. for (auto& sphereCollider : m_sphereColliders)
  168. {
  169. AZ::Transform jointModelSpaceTransform = AZ::Transform::Identity();
  170. EMotionFX::Integration::ActorComponentRequestBus::EventResult(
  171. jointModelSpaceTransform, m_entityId,
  172. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetJointTransform,
  173. static_cast<size_t>(sphereCollider.m_jointIndex), EMotionFX::Integration::Space::ModelSpace);
  174. sphereCollider.m_currentModelSpaceTransform = jointModelSpaceTransform * sphereCollider.m_offsetTransform;
  175. UpdateSphere(sphereCollider);
  176. }
  177. for (auto& capsuleCollider : m_capsuleColliders)
  178. {
  179. AZ::Transform jointModelSpaceTransform = AZ::Transform::Identity();
  180. EMotionFX::Integration::ActorComponentRequestBus::EventResult(
  181. jointModelSpaceTransform, m_entityId,
  182. &EMotionFX::Integration::ActorComponentRequestBus::Events::GetJointTransform,
  183. static_cast<size_t>(capsuleCollider.m_jointIndex), EMotionFX::Integration::Space::ModelSpace);
  184. capsuleCollider.m_currentModelSpaceTransform = jointModelSpaceTransform * capsuleCollider.m_offsetTransform;
  185. UpdateCapsule(capsuleCollider);
  186. }
  187. }
  188. void ActorClothColliders::UpdateSphere(const SphereCollider& sphere)
  189. {
  190. const AZ::Vector3 spherePosition = sphere.m_currentModelSpaceTransform.GetTranslation();
  191. AZ_Assert(sphere.m_nvSphereIndex != InvalidIndex, "Sphere collider has invalid index");
  192. m_spheres[sphere.m_nvSphereIndex].Set(spherePosition, sphere.m_radius);
  193. }
  194. void ActorClothColliders::UpdateCapsule(const CapsuleCollider& capsule)
  195. {
  196. const float halfHeightExclusive = 0.5f * capsule.m_height - capsule.m_radius;
  197. const AZ::Vector3 basisZ = capsule.m_currentModelSpaceTransform.GetBasisZ() * halfHeightExclusive;
  198. const AZ::Vector3 capsulePosition = capsule.m_currentModelSpaceTransform.GetTranslation();
  199. const AZ::Vector3 sphereAPosition = capsulePosition + basisZ;
  200. const AZ::Vector3 sphereBPosition = capsulePosition - basisZ;
  201. AZ_Assert(capsule.m_sphereAIndex != InvalidIndex, "Capsule collider has an invalid index for its first sphere");
  202. AZ_Assert(capsule.m_sphereBIndex != InvalidIndex, "Capsule collider has an invalid index for its second sphere");
  203. m_spheres[capsule.m_sphereAIndex].Set(sphereAPosition, capsule.m_radius);
  204. m_spheres[capsule.m_sphereBIndex].Set(sphereBPosition, capsule.m_radius);
  205. }
  206. const AZStd::vector<SphereCollider>& ActorClothColliders::GetSphereColliders() const
  207. {
  208. return m_sphereColliders;
  209. }
  210. const AZStd::vector<CapsuleCollider>& ActorClothColliders::GetCapsuleColliders() const
  211. {
  212. return m_capsuleColliders;
  213. }
  214. const AZStd::vector<AZ::Vector4>& ActorClothColliders::GetSpheres() const
  215. {
  216. return m_spheres;
  217. }
  218. const AZStd::vector<uint32_t>& ActorClothColliders::GetCapsuleIndices() const
  219. {
  220. return m_capsuleIndices;
  221. }
  222. } // namespace NvCloth