SurfaceDataMeshComponent.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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 "SurfaceDataMeshComponent.h"
  9. #include <AzCore/Debug/Profiler.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
  13. #include <SurfaceData/SurfaceDataSystemRequestBus.h>
  14. #include <SurfaceData/Utility/SurfaceDataUtility.h>
  15. namespace SurfaceData
  16. {
  17. void SurfaceDataMeshConfig::Reflect(AZ::ReflectContext* context)
  18. {
  19. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  20. if (serialize)
  21. {
  22. serialize->Class<SurfaceDataMeshConfig, AZ::ComponentConfig>()
  23. ->Version(0)
  24. ->Field("SurfaceTags", &SurfaceDataMeshConfig::m_tags)
  25. ;
  26. AZ::EditContext* edit = serialize->GetEditContext();
  27. if (edit)
  28. {
  29. edit->Class<SurfaceDataMeshConfig>(
  30. "Mesh Surface Tag Emitter", "")
  31. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  32. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  33. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  34. ->DataElement(0, &SurfaceDataMeshConfig::m_tags, "Generated Tags", "")
  35. ;
  36. }
  37. }
  38. }
  39. void SurfaceDataMeshComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  40. {
  41. services.push_back(AZ_CRC_CE("SurfaceDataProviderService"));
  42. }
  43. void SurfaceDataMeshComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  44. {
  45. services.push_back(AZ_CRC_CE("SurfaceDataProviderService"));
  46. }
  47. void SurfaceDataMeshComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  48. {
  49. services.push_back(AZ_CRC_CE("MeshService"));
  50. }
  51. void SurfaceDataMeshComponent::Reflect(AZ::ReflectContext* context)
  52. {
  53. SurfaceDataMeshConfig::Reflect(context);
  54. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  55. if (serialize)
  56. {
  57. serialize->Class<SurfaceDataMeshComponent, AZ::Component>()
  58. ->Version(0)
  59. ->Field("Configuration", &SurfaceDataMeshComponent::m_configuration)
  60. ;
  61. }
  62. }
  63. SurfaceDataMeshComponent::SurfaceDataMeshComponent()
  64. : m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
  65. {
  66. }
  67. SurfaceDataMeshComponent::SurfaceDataMeshComponent(const SurfaceDataMeshConfig& configuration)
  68. : m_configuration(configuration)
  69. , m_nonUniformScaleChangedHandler([this]([[maybe_unused]] const AZ::Vector3& scale) { this->OnCompositionChanged(); })
  70. {
  71. }
  72. void SurfaceDataMeshComponent::Activate()
  73. {
  74. AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
  75. AZ::Render::MeshComponentNotificationBus::Handler::BusConnect(GetEntityId());
  76. AZ::NonUniformScaleRequestBus::Event(
  77. GetEntityId(), &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler);
  78. m_providerHandle = InvalidSurfaceDataRegistryHandle;
  79. m_refresh = false;
  80. // Update the cached mesh data and bounds, then register the surface data provider
  81. m_newPointWeights.AssignSurfaceTagWeights(m_configuration.m_tags, 1.0f);
  82. UpdateMeshData();
  83. }
  84. void SurfaceDataMeshComponent::Deactivate()
  85. {
  86. if (m_providerHandle != InvalidSurfaceDataRegistryHandle)
  87. {
  88. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UnregisterSurfaceDataProvider(m_providerHandle);
  89. m_providerHandle = InvalidSurfaceDataRegistryHandle;
  90. }
  91. m_nonUniformScaleChangedHandler.Disconnect();
  92. SurfaceDataProviderRequestBus::Handler::BusDisconnect();
  93. AZ::TickBus::Handler::BusDisconnect();
  94. AZ::TransformNotificationBus::Handler::BusDisconnect();
  95. AZ::Render::MeshComponentNotificationBus::Handler::BusDisconnect();
  96. m_refresh = false;
  97. // Clear the cached mesh data
  98. {
  99. AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
  100. m_meshAssetData = {};
  101. m_meshBounds = AZ::Aabb::CreateNull();
  102. m_meshWorldTM = AZ::Transform::CreateIdentity();
  103. m_meshWorldTMInverse = AZ::Transform::CreateIdentity();
  104. }
  105. }
  106. bool SurfaceDataMeshComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  107. {
  108. if (auto config = azrtti_cast<const SurfaceDataMeshConfig*>(baseConfig))
  109. {
  110. m_configuration = *config;
  111. return true;
  112. }
  113. return false;
  114. }
  115. bool SurfaceDataMeshComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
  116. {
  117. if (auto config = azrtti_cast<SurfaceDataMeshConfig*>(outBaseConfig))
  118. {
  119. *config = m_configuration;
  120. return true;
  121. }
  122. return false;
  123. }
  124. void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
  125. {
  126. GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
  127. }
  128. void SurfaceDataMeshComponent::GetSurfacePointsFromList(
  129. AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
  130. {
  131. AZ::Vector3 hitPosition;
  132. AZ::Vector3 hitNormal;
  133. AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
  134. AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
  135. if (!mesh)
  136. {
  137. return;
  138. }
  139. for (auto& inPosition : inPositions)
  140. {
  141. // test AABB as first pass to claim the point
  142. if (SurfaceData::AabbContains2D(m_meshBounds, inPosition))
  143. {
  144. const AZ::Vector3 rayStart =
  145. AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
  146. const AZ::Vector3 rayEnd =
  147. AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
  148. bool rayHit = GetMeshRayIntersection(
  149. *mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, hitPosition, hitNormal);
  150. if (rayHit)
  151. {
  152. surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
  153. }
  154. }
  155. }
  156. }
  157. AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
  158. {
  159. return m_meshBounds;
  160. }
  161. SurfaceTagVector SurfaceDataMeshComponent::GetSurfaceTags() const
  162. {
  163. return m_configuration.m_tags;
  164. }
  165. void SurfaceDataMeshComponent::OnCompositionChanged()
  166. {
  167. if (!m_refresh)
  168. {
  169. m_refresh = true;
  170. AZ::TickBus::Handler::BusConnect();
  171. }
  172. }
  173. void SurfaceDataMeshComponent::OnModelReady([[maybe_unused]] const AZ::Data::Asset<AZ::RPI::ModelAsset>& modelAsset, [[maybe_unused]] const AZ::Data::Instance<AZ::RPI::Model>& model)
  174. {
  175. OnCompositionChanged();
  176. }
  177. void SurfaceDataMeshComponent::OnTransformChanged(const AZ::Transform & local, const AZ::Transform & world)
  178. {
  179. (void)local;
  180. (void)world;
  181. OnCompositionChanged();
  182. }
  183. void SurfaceDataMeshComponent::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
  184. {
  185. if (m_refresh)
  186. {
  187. UpdateMeshData();
  188. m_refresh = false;
  189. }
  190. AZ::TickBus::Handler::BusDisconnect();
  191. }
  192. void SurfaceDataMeshComponent::UpdateMeshData()
  193. {
  194. AZ_PROFILE_SCOPE(Entity, "SurfaceDataMeshComponent: UpdateMeshData");
  195. bool meshValidBeforeUpdate = false;
  196. bool meshValidAfterUpdate = false;
  197. {
  198. AZStd::unique_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
  199. meshValidBeforeUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
  200. m_meshAssetData = {};
  201. AZ::Render::MeshComponentRequestBus::EventResult(m_meshAssetData, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetModelAsset);
  202. m_meshBounds = AZ::Aabb::CreateNull();
  203. AZ::Render::MeshComponentRequestBus::EventResult(m_meshBounds, GetEntityId(), &AZ::Render::MeshComponentRequestBus::Events::GetWorldBounds);
  204. m_meshWorldTM = AZ::Transform::CreateIdentity();
  205. AZ::TransformBus::EventResult(m_meshWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
  206. m_meshWorldTMInverse = m_meshWorldTM.GetInverse();
  207. m_meshNonUniformScale = AZ::Vector3::CreateOne();
  208. AZ::NonUniformScaleRequestBus::EventResult(m_meshNonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
  209. meshValidAfterUpdate = (m_meshAssetData.GetAs<AZ::RPI::ModelAsset>() != nullptr) && (m_meshBounds.IsValid());
  210. }
  211. SurfaceDataRegistryEntry registryEntry;
  212. registryEntry.m_entityId = GetEntityId();
  213. registryEntry.m_bounds = GetSurfaceAabb();
  214. registryEntry.m_tags = GetSurfaceTags();
  215. registryEntry.m_maxPointsCreatedPerInput = 1;
  216. if (!meshValidBeforeUpdate && !meshValidAfterUpdate)
  217. {
  218. // We didn't have a valid mesh asset before or after running this, so do nothing.
  219. }
  220. else if (!meshValidBeforeUpdate && meshValidAfterUpdate)
  221. {
  222. // Our mesh has become valid, so register as a provider and save off the provider handle
  223. AZ_Assert((m_providerHandle == InvalidSurfaceDataRegistryHandle), "Surface data handle is initialized before our mesh became active");
  224. AZ_Assert(m_meshBounds.IsValid(), "Mesh Geometry isn't correctly initialized.");
  225. m_providerHandle = AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->RegisterSurfaceDataProvider(registryEntry);
  226. // Start listening for surface data events
  227. AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  228. SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle);
  229. }
  230. else if (meshValidBeforeUpdate && !meshValidAfterUpdate)
  231. {
  232. // Our mesh has stopped being valid, so unregister and stop listening for surface data events
  233. AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  234. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UnregisterSurfaceDataProvider(m_providerHandle);
  235. m_providerHandle = InvalidSurfaceDataRegistryHandle;
  236. SurfaceDataProviderRequestBus::Handler::BusDisconnect();
  237. }
  238. else if (meshValidBeforeUpdate && meshValidAfterUpdate)
  239. {
  240. // Our mesh was valid before and after, it just changed in some way, so update our registry entry.
  241. AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  242. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UpdateSurfaceDataProvider(m_providerHandle, registryEntry);
  243. }
  244. }
  245. }