SphereShape.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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 "SphereShapeComponent.h"
  9. #include <AzCore/Math/IntersectPoint.h>
  10. #include <AzCore/Math/Transform.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzCore/Math/IntersectSegment.h>
  14. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  15. #include <Shape/ShapeDisplay.h>
  16. namespace LmbrCentral
  17. {
  18. void SphereShape::Reflect(AZ::ReflectContext* context)
  19. {
  20. SphereShapeConfig::Reflect(context);
  21. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  22. {
  23. serializeContext->Class<SphereShape>()
  24. ->Version(1)
  25. ->Field("Configuration", &SphereShape::m_sphereShapeConfig)
  26. ;
  27. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  28. {
  29. editContext->Class<SphereShape>("Sphere Shape", "Sphere shape configuration parameters")
  30. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  31. ->DataElement(AZ::Edit::UIHandlers::Default, &SphereShape::m_sphereShapeConfig, "Sphere Configuration", "Sphere shape configuration")
  32. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  33. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  34. ;
  35. }
  36. }
  37. }
  38. void SphereShape::Activate(AZ::EntityId entityId)
  39. {
  40. m_entityId = entityId;
  41. m_currentTransform = AZ::Transform::CreateIdentity();
  42. AZ::TransformBus::EventResult(m_currentTransform, m_entityId, &AZ::TransformBus::Events::GetWorldTM);
  43. m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::ShapeChange);
  44. AZ::TransformNotificationBus::Handler::BusConnect(m_entityId);
  45. ShapeComponentRequestsBus::Handler::BusConnect(m_entityId);
  46. SphereShapeComponentRequestsBus::Handler::BusConnect(m_entityId);
  47. }
  48. void SphereShape::Deactivate()
  49. {
  50. SphereShapeComponentRequestsBus::Handler::BusDisconnect();
  51. ShapeComponentRequestsBus::Handler::BusDisconnect();
  52. AZ::TransformNotificationBus::Handler::BusDisconnect();
  53. }
  54. void SphereShape::InvalidateCache(InvalidateShapeCacheReason reason)
  55. {
  56. AZStd::unique_lock lock(m_mutex);
  57. m_intersectionDataCache.InvalidateCache(reason);
  58. }
  59. void SphereShape::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
  60. {
  61. {
  62. AZStd::unique_lock lock(m_mutex);
  63. m_currentTransform = world;
  64. m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::TransformChange);
  65. }
  66. ShapeComponentNotificationsBus::Event(
  67. m_entityId, &ShapeComponentNotificationsBus::Events::OnShapeChanged,
  68. ShapeComponentNotifications::ShapeChangeReasons::TransformChanged);
  69. }
  70. void SphereShape::SetRadius(float radius)
  71. {
  72. {
  73. AZStd::unique_lock lock(m_mutex);
  74. m_sphereShapeConfig.m_radius = radius;
  75. m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::ShapeChange);
  76. }
  77. ShapeComponentNotificationsBus::Event(
  78. m_entityId, &ShapeComponentNotificationsBus::Events::OnShapeChanged,
  79. ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged);
  80. }
  81. float SphereShape::GetRadius() const
  82. {
  83. AZStd::shared_lock lock(m_mutex);
  84. return m_sphereShapeConfig.m_radius;
  85. }
  86. AZ::Aabb SphereShape::GetEncompassingAabb() const
  87. {
  88. AZStd::shared_lock lock(m_mutex);
  89. m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_sphereShapeConfig, &m_mutex);
  90. return AZ::Aabb::CreateCenterRadius(
  91. m_currentTransform.TransformPoint(m_sphereShapeConfig.m_translationOffset), m_intersectionDataCache.m_radius);
  92. }
  93. void SphereShape::GetTransformAndLocalBounds(AZ::Transform& transform, AZ::Aabb& bounds) const
  94. {
  95. AZStd::shared_lock lock(m_mutex);
  96. bounds = AZ::Aabb::CreateCenterRadius(m_sphereShapeConfig.m_translationOffset, m_sphereShapeConfig.m_radius);
  97. transform = m_currentTransform;
  98. }
  99. bool SphereShape::IsPointInside(const AZ::Vector3& point) const
  100. {
  101. AZStd::shared_lock lock(m_mutex);
  102. m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_sphereShapeConfig, &m_mutex);
  103. return AZ::Intersect::PointSphere(
  104. m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius * m_intersectionDataCache.m_radius, point);
  105. }
  106. float SphereShape::DistanceSquaredFromPoint(const AZ::Vector3& point) const
  107. {
  108. AZStd::shared_lock lock(m_mutex);
  109. m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_sphereShapeConfig, &m_mutex);
  110. const AZ::Vector3 pointToSphereCenter = m_intersectionDataCache.m_position - point;
  111. const float distance = pointToSphereCenter.GetLength() - m_intersectionDataCache.m_radius;
  112. const float clampedDistance = AZStd::max(distance, 0.0f);
  113. return clampedDistance * clampedDistance;
  114. }
  115. bool SphereShape::IntersectRay(const AZ::Vector3& src, const AZ::Vector3& dir, float& distance) const
  116. {
  117. AZStd::shared_lock lock(m_mutex);
  118. m_intersectionDataCache.UpdateIntersectionParams(m_currentTransform, m_sphereShapeConfig, &m_mutex);
  119. return AZ::Intersect::IntersectRaySphere(
  120. src, dir, m_intersectionDataCache.m_position, m_intersectionDataCache.m_radius, distance) > 0;
  121. }
  122. AZ::Vector3 SphereShape::GetTranslationOffset() const
  123. {
  124. return m_sphereShapeConfig.m_translationOffset;
  125. }
  126. void SphereShape::SetTranslationOffset(const AZ::Vector3& translationOffset)
  127. {
  128. bool shapeChanged = false;
  129. {
  130. AZStd::unique_lock lock(m_mutex);
  131. if (!m_sphereShapeConfig.m_translationOffset.IsClose(translationOffset))
  132. {
  133. m_sphereShapeConfig.m_translationOffset = translationOffset;
  134. m_intersectionDataCache.InvalidateCache(InvalidateShapeCacheReason::ShapeChange);
  135. shapeChanged = true;
  136. }
  137. }
  138. if (shapeChanged)
  139. {
  140. ShapeComponentNotificationsBus::Event(
  141. m_entityId, &ShapeComponentNotificationsBus::Events::OnShapeChanged,
  142. ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged);
  143. }
  144. }
  145. void SphereShape::SphereIntersectionDataCache::UpdateIntersectionParamsImpl(
  146. const AZ::Transform& currentTransform, const SphereShapeConfig& configuration,
  147. [[maybe_unused]] const AZ::Vector3& currentNonUniformScale)
  148. {
  149. m_position = currentTransform.TransformPoint(configuration.m_translationOffset);
  150. m_radius = configuration.m_radius * currentTransform.GetUniformScale();
  151. }
  152. void DrawSphereShape(
  153. const ShapeDrawParams& shapeDrawParams, const SphereShapeConfig& sphereConfig,
  154. AzFramework::DebugDisplayRequests& debugDisplay)
  155. {
  156. if (shapeDrawParams.m_filled)
  157. {
  158. debugDisplay.SetColor(shapeDrawParams.m_shapeColor.GetAsVector4());
  159. debugDisplay.DrawBall(sphereConfig.m_translationOffset, sphereConfig.m_radius, false);
  160. }
  161. debugDisplay.SetColor(shapeDrawParams.m_wireColor.GetAsVector4());
  162. debugDisplay.DrawWireSphere(sphereConfig.m_translationOffset, sphereConfig.m_radius);
  163. }
  164. } // namespace LmbrCentral