TerrainSurfaceDataSystemComponent.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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 <Components/TerrainSurfaceDataSystemComponent.h>
  9. #include <Terrain/TerrainDataConstants.h>
  10. #include <AzCore/Debug/Profiler.h>
  11. #include <AzCore/Math/MathUtils.h>
  12. #include <AzCore/Serialization/EditContext.h>
  13. #include <AzCore/Serialization/SerializeContext.h>
  14. #include <SurfaceData/SurfaceDataSystemRequestBus.h>
  15. #include <SurfaceData/SurfaceTag.h>
  16. #include <SurfaceData/Utility/SurfaceDataUtility.h>
  17. #include <SurfaceData/SurfaceDataTagProviderRequestBus.h>
  18. namespace Terrain
  19. {
  20. //////////////////////////////////////////////////////////////////////////
  21. // TerrainSurfaceDataSystemConfig
  22. void TerrainSurfaceDataSystemConfig::Reflect(AZ::ReflectContext* context)
  23. {
  24. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  25. {
  26. serializeContext->Class<TerrainSurfaceDataSystemConfig, AZ::ComponentConfig>()
  27. ->Version(0)
  28. ;
  29. if (AZ::EditContext* editContext = serializeContext->GetEditContext())
  30. {
  31. editContext->Class<TerrainSurfaceDataSystemConfig>(
  32. "Terrain Surface Data System", "Configures management of surface data requests against legacy terrain")
  33. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  34. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  35. ;
  36. }
  37. }
  38. }
  39. //////////////////////////////////////////////////////////////////////////
  40. // TerrainSurfaceDataSystemComponent
  41. void TerrainSurfaceDataSystemComponent::Reflect(AZ::ReflectContext* context)
  42. {
  43. TerrainSurfaceDataSystemConfig::Reflect(context);
  44. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  45. if (serialize)
  46. {
  47. serialize->Class<TerrainSurfaceDataSystemComponent, AZ::Component>()
  48. ->Version(0)
  49. ->Field("Configuration", &TerrainSurfaceDataSystemComponent::m_configuration)
  50. ;
  51. if (AZ::EditContext* editContext = serialize->GetEditContext())
  52. {
  53. editContext->Class<TerrainSurfaceDataSystemComponent>("Terrain Surface Data System", "Manages surface data requests against legacy terrain")
  54. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  55. ->Attribute(AZ::Edit::Attributes::Category, "Surface Data")
  56. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  57. ->DataElement(0, &TerrainSurfaceDataSystemComponent::m_configuration, "Configuration", "")
  58. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  59. ;
  60. }
  61. }
  62. }
  63. TerrainSurfaceDataSystemComponent::TerrainSurfaceDataSystemComponent(const TerrainSurfaceDataSystemConfig& configuration)
  64. : m_configuration(configuration)
  65. {
  66. }
  67. TerrainSurfaceDataSystemComponent::TerrainSurfaceDataSystemComponent()
  68. {
  69. }
  70. void TerrainSurfaceDataSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  71. {
  72. services.push_back(AZ_CRC_CE("SurfaceDataProviderService"));
  73. services.push_back(AZ_CRC_CE("TerrainSurfaceDataProviderService"));
  74. }
  75. void TerrainSurfaceDataSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  76. {
  77. services.push_back(AZ_CRC_CE("TerrainSurfaceDataProviderService"));
  78. }
  79. void TerrainSurfaceDataSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  80. {
  81. services.push_back(AZ_CRC_CE("SurfaceDataSystemService"));
  82. }
  83. void TerrainSurfaceDataSystemComponent::Activate()
  84. {
  85. m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle;
  86. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
  87. SurfaceData::SurfaceDataTagProviderRequestBus::Handler::BusConnect();
  88. UpdateTerrainData(AZ::Aabb::CreateNull());
  89. }
  90. void TerrainSurfaceDataSystemComponent::Deactivate()
  91. {
  92. if (m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle)
  93. {
  94. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UnregisterSurfaceDataProvider(m_providerHandle);
  95. m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle;
  96. }
  97. SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect();
  98. SurfaceData::SurfaceDataTagProviderRequestBus::Handler::BusDisconnect();
  99. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
  100. // Clear the cached terrain bounds data
  101. {
  102. m_terrainBounds = AZ::Aabb::CreateNull();
  103. m_terrainBoundsIsValid = false;
  104. }
  105. }
  106. bool TerrainSurfaceDataSystemComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  107. {
  108. if (const auto config = azrtti_cast<const TerrainSurfaceDataSystemConfig*>(baseConfig))
  109. {
  110. m_configuration = *config;
  111. return true;
  112. }
  113. return false;
  114. }
  115. bool TerrainSurfaceDataSystemComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
  116. {
  117. if (auto config = azrtti_cast<TerrainSurfaceDataSystemConfig*>(outBaseConfig))
  118. {
  119. *config = m_configuration;
  120. return true;
  121. }
  122. return false;
  123. }
  124. void TerrainSurfaceDataSystemComponent::GetSurfacePoints(
  125. const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const
  126. {
  127. GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
  128. }
  129. void TerrainSurfaceDataSystemComponent::GetSurfacePointsFromList(
  130. AZStd::span<const AZ::Vector3> inPositions, SurfaceData::SurfacePointList& surfacePointList) const
  131. {
  132. if (!m_terrainBoundsIsValid)
  133. {
  134. return;
  135. }
  136. size_t inPositionIndex = 0;
  137. AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
  138. &AzFramework::Terrain::TerrainDataRequestBus::Events::QueryList, inPositions,
  139. AzFramework::Terrain::TerrainDataRequests::TerrainDataMask::All,
  140. [this, inPositions, &inPositionIndex, &surfacePointList]
  141. (const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
  142. {
  143. AZ_Assert(inPositionIndex < inPositions.size(), "Too many points returned from QueryList");
  144. SurfaceData::SurfaceTagWeights weights(surfacePoint.m_surfaceTags);
  145. // Always add a "terrain" or "terrainHole" tag.
  146. const AZ::Crc32 terrainTag = terrainExists ? Constants::s_terrainTagCrc : Constants::s_terrainHoleTagCrc;
  147. weights.AddSurfaceTagWeight(terrainTag, 1.0f);
  148. surfacePointList.AddSurfacePoint(
  149. GetEntityId(), inPositions[inPositionIndex], surfacePoint.m_position, surfacePoint.m_normal, weights);
  150. inPositionIndex++;
  151. },
  152. AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR);
  153. }
  154. AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const
  155. {
  156. auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
  157. return terrain ? terrain->GetTerrainAabb() : AZ::Aabb::CreateNull();
  158. }
  159. SurfaceData::SurfaceTagVector TerrainSurfaceDataSystemComponent::GetSurfaceTags() const
  160. {
  161. SurfaceData::SurfaceTagVector tags;
  162. tags.push_back(Constants::s_terrainHoleTagCrc);
  163. tags.push_back(Constants::s_terrainTagCrc);
  164. return tags;
  165. }
  166. void TerrainSurfaceDataSystemComponent::UpdateTerrainData(const AZ::Aabb& dirtyRegion)
  167. {
  168. bool terrainValidBeforeUpdate = m_terrainBoundsIsValid;
  169. bool terrainValidAfterUpdate = false;
  170. AZ::Aabb terrainBoundsBeforeUpdate = m_terrainBounds;
  171. SurfaceData::SurfaceDataRegistryEntry registryEntry;
  172. registryEntry.m_entityId = GetEntityId();
  173. registryEntry.m_bounds = GetSurfaceAabb();
  174. registryEntry.m_tags = GetSurfaceTags();
  175. registryEntry.m_maxPointsCreatedPerInput = 1;
  176. m_terrainBounds = registryEntry.m_bounds;
  177. m_terrainBoundsIsValid = m_terrainBounds.IsValid();
  178. terrainValidAfterUpdate = m_terrainBoundsIsValid;
  179. if (terrainValidBeforeUpdate && terrainValidAfterUpdate)
  180. {
  181. AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  182. // Our terrain was valid before and after, it just changed in some way. If we have a valid dirty region, and the terrain
  183. // bounds themselves haven't changed, just notify that our terrain data has changed within the bounds. Otherwise, notify
  184. // that the entire terrain provider needs to be updated, since it either has new bounds or the entire set of data is dirty.
  185. if (dirtyRegion.IsValid() && m_terrainBounds.IsClose(terrainBoundsBeforeUpdate))
  186. {
  187. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->RefreshSurfaceData(m_providerHandle, dirtyRegion);
  188. }
  189. else
  190. {
  191. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UpdateSurfaceDataProvider(m_providerHandle, registryEntry);
  192. }
  193. }
  194. else if (!terrainValidBeforeUpdate && terrainValidAfterUpdate)
  195. {
  196. // Our terrain has become valid, so register as a provider and save off the registry handles
  197. AZ_Assert(
  198. (m_providerHandle == SurfaceData::InvalidSurfaceDataRegistryHandle),
  199. "Surface Provider data handle is initialized before our terrain became valid");
  200. m_providerHandle = AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->RegisterSurfaceDataProvider(registryEntry);
  201. // Start listening for surface data events
  202. AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  203. SurfaceData::SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle);
  204. }
  205. else if (terrainValidBeforeUpdate && !terrainValidAfterUpdate)
  206. {
  207. // Our terrain has stopped being valid, so unregister and stop listening for surface data events
  208. AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle");
  209. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UnregisterSurfaceDataProvider(m_providerHandle);
  210. m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle;
  211. SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect();
  212. }
  213. else
  214. {
  215. // We didn't have a valid terrain before or after running this, so do nothing.
  216. }
  217. }
  218. void TerrainSurfaceDataSystemComponent::OnTerrainDataChanged(
  219. const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask)
  220. {
  221. UpdateTerrainData(dirtyRegion);
  222. }
  223. void TerrainSurfaceDataSystemComponent::GetRegisteredSurfaceTagNames(SurfaceData::SurfaceTagNameSet& names) const
  224. {
  225. names.insert(Constants::s_terrainHoleTagName);
  226. names.insert(Constants::s_terrainTagName);
  227. }
  228. }