3
0

TerrainSurfaceGradientListComponent.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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/TerrainSurfaceGradientListComponent.h>
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <GradientSignal/Ebuses/GradientRequestBus.h>
  13. #include <TerrainSystem/TerrainSystemBus.h>
  14. #include <TerrainProfiler.h>
  15. namespace Terrain
  16. {
  17. void TerrainSurfaceGradientMapping::Reflect(AZ::ReflectContext* context)
  18. {
  19. if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
  20. {
  21. serialize->Class<TerrainSurfaceGradientMapping>()
  22. ->Version(1)
  23. ->Field("Gradient Entity", &TerrainSurfaceGradientMapping::m_gradientEntityId)
  24. ->Field("Surface Tag", &TerrainSurfaceGradientMapping::m_surfaceTag)
  25. ;
  26. }
  27. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  28. {
  29. behaviorContext->Class<TerrainSurfaceGradientMapping>()
  30. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  31. ->Attribute(AZ::Script::Attributes::Category, "Terrain")
  32. ->Attribute(AZ::Script::Attributes::Module, "terrain")
  33. ->Constructor()
  34. ->Property("GradientEntityId", BehaviorValueProperty(&TerrainSurfaceGradientMapping::m_gradientEntityId))
  35. ->Property("SurfaceTag", BehaviorValueProperty(&TerrainSurfaceGradientMapping::m_surfaceTag));
  36. }
  37. }
  38. void TerrainSurfaceGradientListConfig::Reflect(AZ::ReflectContext* context)
  39. {
  40. TerrainSurfaceGradientMapping::Reflect(context);
  41. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  42. if (serialize)
  43. {
  44. serialize->Class<TerrainSurfaceGradientListConfig, AZ::ComponentConfig>()
  45. ->Version(1)
  46. ->Field("Mappings", &TerrainSurfaceGradientListConfig::m_gradientSurfaceMappings)
  47. ;
  48. }
  49. }
  50. void TerrainSurfaceGradientListComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  51. {
  52. services.push_back(AZ_CRC_CE("TerrainSurfaceProviderService"));
  53. }
  54. void TerrainSurfaceGradientListComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  55. {
  56. services.push_back(AZ_CRC_CE("TerrainSurfaceProviderService"));
  57. }
  58. void TerrainSurfaceGradientListComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
  59. {
  60. services.push_back(AZ_CRC("TerrainAreaService"));
  61. }
  62. void TerrainSurfaceGradientListComponent::Reflect(AZ::ReflectContext* context)
  63. {
  64. TerrainSurfaceGradientListConfig::Reflect(context);
  65. AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
  66. if (serialize)
  67. {
  68. serialize->Class<TerrainSurfaceGradientListComponent, AZ::Component>()
  69. ->Version(0)->Field("Configuration", &TerrainSurfaceGradientListComponent::m_configuration)
  70. ;
  71. }
  72. }
  73. TerrainSurfaceGradientListComponent::TerrainSurfaceGradientListComponent(const TerrainSurfaceGradientListConfig& configuration)
  74. : m_configuration(configuration)
  75. {
  76. }
  77. void TerrainSurfaceGradientListComponent::Activate()
  78. {
  79. LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId());
  80. // Make sure we get update notifications whenever this entity or any dependent gradient entity changes in any way.
  81. // We'll use that to notify the terrain system that the surface information needs to be refreshed.
  82. m_dependencyMonitor.Reset();
  83. m_dependencyMonitor.SetRegionChangedEntityNotificationFunction();
  84. m_dependencyMonitor.ConnectOwner(GetEntityId());
  85. m_dependencyMonitor.ConnectDependency(GetEntityId());
  86. for (auto& surfaceMapping : m_configuration.m_gradientSurfaceMappings)
  87. {
  88. if (surfaceMapping.m_gradientEntityId != GetEntityId())
  89. {
  90. m_dependencyMonitor.ConnectDependency(surfaceMapping.m_gradientEntityId);
  91. }
  92. }
  93. Terrain::TerrainAreaSurfaceRequestBus::Handler::BusConnect(GetEntityId());
  94. // Notify that the area has changed.
  95. OnCompositionChanged();
  96. }
  97. void TerrainSurfaceGradientListComponent::Deactivate()
  98. {
  99. // Disconnect before doing any other teardown. This will guarantee that any active queries have finished before we proceed.
  100. Terrain::TerrainAreaSurfaceRequestBus::Handler::BusDisconnect();
  101. m_dependencyMonitor.Reset();
  102. LmbrCentral::DependencyNotificationBus::Handler::BusDisconnect();
  103. // Since this surface data will no longer exist, notify the terrain system to refresh the area.
  104. TerrainSystemServiceRequestBus::Broadcast(
  105. &TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId(),
  106. AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::SurfaceData);
  107. }
  108. bool TerrainSurfaceGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  109. {
  110. if (auto config = azrtti_cast<const TerrainSurfaceGradientListConfig*>(baseConfig))
  111. {
  112. m_configuration = *config;
  113. return true;
  114. }
  115. return false;
  116. }
  117. bool TerrainSurfaceGradientListComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
  118. {
  119. if (auto config = azrtti_cast<TerrainSurfaceGradientListConfig*>(outBaseConfig))
  120. {
  121. *config = m_configuration;
  122. return true;
  123. }
  124. return false;
  125. }
  126. void TerrainSurfaceGradientListComponent::GetSurfaceWeights(
  127. const AZ::Vector3& inPosition,
  128. AzFramework::SurfaceData::SurfaceTagWeightList& outSurfaceWeights) const
  129. {
  130. outSurfaceWeights.clear();
  131. if (Terrain::TerrainAreaSurfaceRequestBus::HasReentrantEBusUseThisThread())
  132. {
  133. AZ_ErrorOnce("Terrain", false, "Detected cyclic dependencies with terrain surface entity references on entity '%s' (%s)",
  134. GetEntity()->GetName().c_str(), GetEntityId().ToString().c_str());
  135. return;
  136. }
  137. const GradientSignal::GradientSampleParams params(inPosition);
  138. for (const auto& mapping : m_configuration.m_gradientSurfaceMappings)
  139. {
  140. float weight = 0.0f;
  141. GradientSignal::GradientRequestBus::EventResult(weight,
  142. mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
  143. outSurfaceWeights.emplace_back(mapping.m_surfaceTag, weight);
  144. }
  145. }
  146. void TerrainSurfaceGradientListComponent::GetSurfaceWeightsFromList(
  147. AZStd::span<const AZ::Vector3> inPositionList,
  148. AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList) const
  149. {
  150. TERRAIN_PROFILE_FUNCTION_VERBOSE
  151. AZ_Assert(
  152. inPositionList.size() == outSurfaceWeightsList.size(), "The position list size doesn't match the outSurfaceWeights list size.");
  153. if (Terrain::TerrainAreaSurfaceRequestBus::HasReentrantEBusUseThisThread())
  154. {
  155. AZ_ErrorOnce(
  156. "Terrain", false, "Detected cyclic dependencies with terrain surface entity references on entity '%s' (%s)",
  157. GetEntity()->GetName().c_str(), GetEntityId().ToString().c_str());
  158. return;
  159. }
  160. AZStd::vector<float> gradientValues;
  161. gradientValues.resize_no_construct(inPositionList.size());
  162. for (const auto& mapping : m_configuration.m_gradientSurfaceMappings)
  163. {
  164. // Clear out the gradient values before every GetValues call to ensure we don't accidentally end up with stale data.
  165. AZStd::fill(gradientValues.begin(), gradientValues.end(), 0.0f);
  166. GradientSignal::GradientRequestBus::Event(
  167. mapping.m_gradientEntityId, &GradientSignal::GradientRequestBus::Events::GetValues, inPositionList, gradientValues);
  168. for (size_t index = 0; index < outSurfaceWeightsList.size(); index++)
  169. {
  170. outSurfaceWeightsList[index].emplace_back(mapping.m_surfaceTag, gradientValues[index]);
  171. }
  172. }
  173. }
  174. void TerrainSurfaceGradientListComponent::OnCompositionChanged()
  175. {
  176. OnCompositionRegionChanged(AZ::Aabb::CreateNull());
  177. }
  178. void TerrainSurfaceGradientListComponent::OnCompositionRegionChanged(const AZ::Aabb& dirtyRegion)
  179. {
  180. if (dirtyRegion.IsValid())
  181. {
  182. TerrainSystemServiceRequestBus::Broadcast(
  183. &TerrainSystemServiceRequestBus::Events::RefreshRegion,
  184. dirtyRegion,
  185. AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::SurfaceData);
  186. }
  187. else
  188. {
  189. TerrainSystemServiceRequestBus::Broadcast(
  190. &TerrainSystemServiceRequestBus::Events::RefreshArea,
  191. GetEntityId(),
  192. AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::SurfaceData);
  193. }
  194. }
  195. } // namespace Terrain