TerrainFeatureProcessor.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 <TerrainRenderer/TerrainFeatureProcessor.h>
  9. #include <Atom/Utils/Utils.h>
  10. #include <Atom/RHI/RHISystemInterface.h>
  11. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  12. #include <Atom/RPI.Public/RPIUtils.h>
  13. #include <Atom/RPI.Public/Scene.h>
  14. #include <Atom/RPI.Public/View.h>
  15. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  16. #include <Atom/RPI.Public/Image/AttachmentImagePool.h>
  17. #include <Atom/RPI.Public/Material/Material.h>
  18. #include <Atom/RPI.Public/Pass/PassFilter.h>
  19. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  20. #include <Atom/RPI.Public/Pass/RasterPass.h>
  21. #include <Atom/RPI.Public/RenderPipeline.h>
  22. #include <Atom/Feature/RenderCommon.h>
  23. #include <SurfaceData/SurfaceDataSystemRequestBus.h>
  24. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  25. #include <Atom/RPI.Reflect/Material/MaterialAssetCreator.h>
  26. namespace Terrain
  27. {
  28. namespace
  29. {
  30. [[maybe_unused]] const char* TerrainFPName = "TerrainFeatureProcessor";
  31. }
  32. void TerrainFeatureProcessor::Reflect(AZ::ReflectContext* context)
  33. {
  34. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  35. {
  36. serialize->Class<TerrainFeatureProcessor, AZ::RPI::FeatureProcessor>()
  37. ->Version(0)
  38. ;
  39. }
  40. }
  41. void TerrainFeatureProcessor::Activate()
  42. {
  43. EnableSceneNotification();
  44. Initialize();
  45. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
  46. }
  47. void TerrainFeatureProcessor::Initialize()
  48. {
  49. auto sceneSrgLayout = AZ::RPI::RPISystemInterface::Get()->GetSceneSrgLayout();
  50. // Load the terrain material asynchronously
  51. static constexpr const char* materialFilePath = "Materials/Terrain/DefaultPbrTerrain.azmaterial";
  52. const AZ::Data::AssetId materialAssetId =
  53. AZ::RPI::AssetUtils::GetAssetIdForProductPath(materialFilePath, AZ::RPI::AssetUtils::TraceLevel::Error);
  54. if (materialAssetId.IsValid())
  55. {
  56. m_materialAsset.Create(materialAssetId);
  57. m_materialAsset.QueueLoad();
  58. AZ::Data::AssetBus::Handler::BusConnect(materialAssetId);
  59. }
  60. OnTerrainDataChanged(
  61. AZ::Aabb::CreateNull(), TerrainDataChangedMask::HeightData | TerrainDataChangedMask::Settings);
  62. m_meshManager.Initialize(*GetParentScene());
  63. }
  64. void TerrainFeatureProcessor::Deactivate()
  65. {
  66. AZ::Data::AssetBus::Handler::BusDisconnect();
  67. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
  68. DisableSceneNotification();
  69. OnTerrainDataDestroyBegin();
  70. m_materialAsset = {};
  71. m_materialInstance = {};
  72. m_meshManager.Reset();
  73. m_macroMaterialManager.Reset();
  74. m_detailMaterialManager.Reset();
  75. if (m_clipmapManager.IsClipmapEnabled())
  76. {
  77. m_clipmapManager.Reset();
  78. }
  79. }
  80. void TerrainFeatureProcessor::Render(const AZ::RPI::FeatureProcessor::RenderPacket& packet)
  81. {
  82. ProcessSurfaces(packet);
  83. }
  84. void TerrainFeatureProcessor::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
  85. {
  86. m_materialAsset = asset;
  87. if (!m_materialAsset->GetObjectSrgLayout())
  88. {
  89. AZ_Error("TerrainFeatureProcessor", false, "No per-object ShaderResourceGroup found on terrain material.");
  90. }
  91. else
  92. {
  93. m_materialInstance = AZ::RPI::Material::FindOrCreate(m_materialAsset);
  94. PrepareMaterialData();
  95. m_terrainBoundsNeedUpdate = true;
  96. }
  97. }
  98. void TerrainFeatureProcessor::OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset)
  99. {
  100. OnAssetReady(asset);
  101. }
  102. void TerrainFeatureProcessor::OnTerrainDataDestroyBegin()
  103. {
  104. m_zBounds = {};
  105. }
  106. void TerrainFeatureProcessor::OnTerrainDataChanged([[maybe_unused]] const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask)
  107. {
  108. if ((dataChangedMask & TerrainDataChangedMask::Settings) == TerrainDataChangedMask::Settings)
  109. {
  110. AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
  111. m_zBounds, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightBounds);
  112. m_terrainBoundsNeedUpdate = true;
  113. }
  114. }
  115. void TerrainFeatureProcessor::OnRenderPipelineChanged([[maybe_unused]] AZ::RPI::RenderPipeline* renderPipeline,
  116. [[maybe_unused]] AZ::RPI::SceneNotification::RenderPipelineChangeType changeType)
  117. {
  118. CachePasses();
  119. if (changeType == RenderPipelineChangeType::Added || changeType == RenderPipelineChangeType::PassChanged)
  120. {
  121. m_meshManager.SetRebuildDrawPackets();
  122. }
  123. }
  124. void TerrainFeatureProcessor::AddRenderPasses(AZ::RPI::RenderPipeline* renderPipeline)
  125. {
  126. // Get the pass requests to create passes from the asset
  127. AddPassRequestToRenderPipeline(renderPipeline, "Passes/TerrainPassRequest.azasset", "DepthPrePass", true);
  128. // Only add debug pass if the DebugOverlayPass exists
  129. if (renderPipeline->FindFirstPass(AZ::Name("DebugOverlayPass")))
  130. {
  131. AddPassRequestToRenderPipeline(renderPipeline, "Passes/TerrainDebugPassRequest.azasset", "DebugOverlayPass", false);
  132. }
  133. }
  134. void TerrainFeatureProcessor::PrepareMaterialData()
  135. {
  136. m_terrainSrg = {};
  137. m_materialInstance->ForAllShaderItems(
  138. [&](const AZ::Name&, const AZ::RPI::ShaderCollection::Item& shaderItem)
  139. {
  140. if (shaderItem.GetShaderAsset()->GetDrawListName() == AZ::Name("forward"))
  141. {
  142. const auto& shaderAsset = shaderItem.GetShaderAsset();
  143. m_terrainSrg = AZ::RPI::ShaderResourceGroup::Create(
  144. shaderItem.GetShaderAsset(), shaderAsset->GetSupervariantIndex(AZ::Name()), AZ::Name{ "TerrainSrg" });
  145. AZ_Error(TerrainFPName, m_terrainSrg, "Failed to create Terrain shader resource group");
  146. // skip the rest of shader items
  147. return false;
  148. }
  149. return true;
  150. });
  151. AZ_Error(TerrainFPName, m_terrainSrg, "Terrain Srg not found on any shader in the terrain material");
  152. if (m_terrainSrg)
  153. {
  154. if (m_macroMaterialManager.IsInitialized())
  155. {
  156. m_macroMaterialManager.UpdateSrgIndices(m_terrainSrg);
  157. }
  158. else
  159. {
  160. m_macroMaterialManager.Initialize(m_terrainSrg);
  161. }
  162. if (m_detailMaterialManager.IsInitialized())
  163. {
  164. m_detailMaterialManager.UpdateSrgIndices(m_terrainSrg);
  165. }
  166. else if(m_materialInstance)
  167. {
  168. m_detailMaterialManager.Initialize(m_terrainSrg, m_materialInstance);
  169. }
  170. if (m_clipmapManager.IsClipmapEnabled())
  171. {
  172. if (m_clipmapManager.IsInitialized())
  173. {
  174. m_clipmapManager.UpdateSrgIndices(m_terrainSrg);
  175. }
  176. else
  177. {
  178. m_clipmapManager.Initialize(m_terrainSrg);
  179. }
  180. }
  181. m_meshManager.SetMaterial(m_materialInstance);
  182. }
  183. else
  184. {
  185. m_macroMaterialManager.Reset();
  186. m_detailMaterialManager.Reset();
  187. if (m_clipmapManager.IsClipmapEnabled())
  188. {
  189. m_clipmapManager.Reset();
  190. }
  191. }
  192. }
  193. void TerrainFeatureProcessor::ProcessSurfaces(const FeatureProcessor::RenderPacket& process)
  194. {
  195. AZ_PROFILE_FUNCTION(AzRender);
  196. if (m_zBounds.m_min == 0.0f && m_zBounds.m_max == 0.0f)
  197. {
  198. return;
  199. }
  200. if (m_materialInstance && m_materialInstance->CanCompile())
  201. {
  202. AZ::Vector3 cameraPosition = AZ::Vector3::CreateZero();
  203. AZ::RPI::ViewPtr mainView;
  204. for (auto& view : process.m_views)
  205. {
  206. if ((view->GetUsageFlags() & AZ::RPI::View::UsageFlags::UsageCamera) > 0)
  207. {
  208. mainView = view;
  209. cameraPosition = view->GetCameraTransform().GetTranslation();
  210. break;
  211. }
  212. }
  213. if (m_terrainSrg)
  214. {
  215. if (m_meshManager.IsInitialized())
  216. {
  217. m_meshManager.Update(mainView, m_terrainSrg);
  218. }
  219. if (m_macroMaterialManager.IsInitialized())
  220. {
  221. m_macroMaterialManager.Update(mainView, m_terrainSrg);
  222. }
  223. if (m_detailMaterialManager.IsInitialized())
  224. {
  225. m_detailMaterialManager.Update(cameraPosition, m_terrainSrg);
  226. }
  227. if (m_clipmapManager.IsClipmapEnabled())
  228. {
  229. if (m_clipmapManager.IsInitialized())
  230. {
  231. m_clipmapManager.Update(cameraPosition, GetParentScene(), m_terrainSrg);
  232. }
  233. }
  234. }
  235. if (m_meshManager.IsInitialized())
  236. {
  237. m_meshManager.DrawMeshes(process, mainView);
  238. }
  239. }
  240. if (m_terrainBoundsNeedUpdate)
  241. {
  242. m_terrainBoundsNeedUpdate = false;
  243. WorldShaderData worldData;
  244. worldData.m_zMin = m_zBounds.m_min;
  245. worldData.m_zMax = m_zBounds.m_max;
  246. worldData.m_zExtents = worldData.m_zMax - worldData.m_zMin;
  247. auto sceneSrg = GetParentScene()->GetShaderResourceGroup();
  248. sceneSrg->SetConstant(m_worldDataIndex, worldData);
  249. }
  250. if (m_materialInstance)
  251. {
  252. m_materialInstance->Compile();
  253. }
  254. if (m_terrainSrg && m_passes.size() > 0)
  255. {
  256. m_terrainSrg->Compile();
  257. for (auto* pass : m_passes)
  258. {
  259. pass->BindSrg(m_terrainSrg->GetRHIShaderResourceGroup());
  260. }
  261. }
  262. }
  263. void TerrainFeatureProcessor::SetDetailMaterialConfiguration(const DetailMaterialConfiguration& config)
  264. {
  265. m_detailMaterialManager.SetDetailMaterialConfiguration(config);
  266. }
  267. void TerrainFeatureProcessor::SetMeshConfiguration(const MeshConfiguration& config)
  268. {
  269. m_meshManager.SetConfiguration(config);
  270. m_macroMaterialManager.SetRenderDistance(config.m_renderDistance);
  271. }
  272. void TerrainFeatureProcessor::SetClipmapConfiguration(const ClipmapConfiguration& config)
  273. {
  274. m_clipmapManager.SetConfiguration(config);
  275. }
  276. void TerrainFeatureProcessor::CachePasses()
  277. {
  278. m_passes.clear();
  279. auto rasterPassFilter = AZ::RPI::PassFilter::CreateWithPassClass<AZ::RPI::RasterPass>();
  280. rasterPassFilter.SetOwnerScene(GetParentScene());
  281. AZ::RHI::RHISystemInterface* rhiSystem = AZ::RHI::RHISystemInterface::Get();
  282. const AZ::RHI::DrawListTag forwardTag = rhiSystem->GetDrawListTagRegistry()->AcquireTag(AZ::Name("forward"));
  283. const AZ::RHI::DrawListTag depthTag = rhiSystem->GetDrawListTagRegistry()->AcquireTag(AZ::Name("depth"));
  284. const AZ::RHI::DrawListTag shadowTag = rhiSystem->GetDrawListTagRegistry()->AcquireTag(AZ::Name("shadow"));
  285. AZ::RPI::PassSystemInterface::Get()->ForEachPass(rasterPassFilter,
  286. [&](AZ::RPI::Pass* pass) -> AZ::RPI::PassFilterExecutionFlow
  287. {
  288. auto* rasterPass = azrtti_cast<AZ::RPI::RasterPass*>(pass);
  289. if (rasterPass && rasterPass->GetPassState() != AZ::RPI::PassState::Orphaned)
  290. {
  291. if (rasterPass->GetDrawListTag() == forwardTag ||
  292. rasterPass->GetDrawListTag() == depthTag ||
  293. rasterPass->GetDrawListTag() == shadowTag)
  294. {
  295. m_passes.push_back(rasterPass);
  296. }
  297. }
  298. return AZ::RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
  299. }
  300. );
  301. }
  302. const AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> TerrainFeatureProcessor::GetTerrainShaderResourceGroup() const
  303. {
  304. return m_terrainSrg;
  305. }
  306. const AZ::Data::Instance<AZ::RPI::Material> TerrainFeatureProcessor::GetMaterial() const
  307. {
  308. return m_materialInstance;
  309. }
  310. const TerrainClipmapManager& TerrainFeatureProcessor::GetClipmapManager() const
  311. {
  312. return m_clipmapManager;
  313. }
  314. }