TerrainClipmapManager.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  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/TerrainClipmapManager.h>
  9. #include <AzFramework/Terrain/TerrainDataRequestBus.h>
  10. #include <Atom/RPI.Public/Image/AttachmentImagePool.h>
  11. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  12. #include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
  13. #include <Atom/RPI.Public/ViewportContext.h>
  14. #include <Atom/RPI.Public/ViewportContextBus.h>
  15. #include <AzCore/Console/Console.h>
  16. namespace Terrain
  17. {
  18. AZ_CVAR(
  19. uint32_t,
  20. r_terrainClipmapDebugOverlay,
  21. 0,
  22. nullptr,
  23. AZ::ConsoleFunctorFlags::Null,
  24. "The clipmap index to be rendered on the screen.\n"
  25. "0: off\n"
  26. "1: macro clipmap overlay\n"
  27. "2: detail clipmap overlay");
  28. AZ_CVAR(
  29. uint32_t,
  30. r_terrainClipmapDebugClipmapId,
  31. 2,
  32. nullptr,
  33. AZ::ConsoleFunctorFlags::Null,
  34. "The clipmap index to be rendered on the screen.\n"
  35. "0: macro color clipmap\n"
  36. "1: macro normal clipmap\n"
  37. "2: detail color clipmap\n"
  38. "3: detail normal clipmap\n"
  39. "4: detail height clipmap\n"
  40. "5: detail roughness clipmap\n"
  41. "6: detail specularF0 clipmap\n"
  42. "7: detail metalness clipmap\n"
  43. "8: detail occlusion clipmap");
  44. AZ_CVAR(
  45. uint32_t,
  46. r_terrainClipmapDebugClipmapLevel,
  47. 0,
  48. nullptr,
  49. AZ::ConsoleFunctorFlags::Null,
  50. "The clipmap level to be rendered on the screen.");
  51. AZ_CVAR(
  52. float,
  53. r_terrainClipmapDebugScale,
  54. 0.5f,
  55. nullptr,
  56. AZ::ConsoleFunctorFlags::Null,
  57. "The size multiplier of the clipmap texture's debug display.");
  58. AZ_CVAR(
  59. float,
  60. r_terrainClipmapDebugBrightness,
  61. 1.0f,
  62. nullptr,
  63. AZ::ConsoleFunctorFlags::Null,
  64. "A multiplier to the final output of the clipmap texture's debug display.");
  65. namespace
  66. {
  67. [[maybe_unused]] static const char* TerrainClipmapManagerName = "TerrainClipmapManager";
  68. }
  69. //! Calculate how many layers of clipmap is needed.
  70. //! Final result must be less or equal than the MacroClipmapStackSizeMax/DetailClipmapStackSizeMax.
  71. uint32_t ClipmapConfiguration::CalculateMacroClipmapStackSize() const
  72. {
  73. float clipmapSize = aznumeric_cast<float>(m_clipmapSize);
  74. float minRenderDistance = clipmapSize / m_macroClipmapMaxResolution / 2.0f; // Render distance is half of the image.
  75. uint32_t stackSizeNeeded = 1u;
  76. // Add more layers until it meets the max resolution.
  77. for (float radius = m_macroClipmapMaxRenderRadius; radius > minRenderDistance; radius /= m_macroClipmapScaleBase)
  78. {
  79. ++stackSizeNeeded;
  80. }
  81. AZ_Assert(stackSizeNeeded <= MacroClipmapStackSizeMax, "Stack size needed is bigger than max. Consider increasing MacroClipmapStackSizeMax and the same name constant in TerrainSrg.azsli.");
  82. return stackSizeNeeded;
  83. }
  84. uint32_t ClipmapConfiguration::CalculateDetailClipmapStackSize() const
  85. {
  86. float clipmapSize = aznumeric_cast<float>(m_clipmapSize);
  87. float minRenderDistance = clipmapSize / m_detailClipmapMaxResolution / 2.0f; // Render distance is half of the image.
  88. uint32_t stackSizeNeeded = 1u;
  89. // Add more layers until it meets the max resolution.
  90. for (float radius = m_detailClipmapMaxRenderRadius; radius > minRenderDistance; radius /= m_detailClipmapScaleBase)
  91. {
  92. ++stackSizeNeeded;
  93. }
  94. AZ_Assert(stackSizeNeeded <= MacroClipmapStackSizeMax, "Stack size needed is bigger than max. Consider increasing DetailClipmapStackSizeMax and the same name constant in TerrainSrg.azsli.");
  95. return stackSizeNeeded;
  96. }
  97. TerrainClipmapManager::TerrainClipmapManager()
  98. : m_terrainSrgClipmapImageIndex{
  99. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::MacroColor]),
  100. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::MacroNormal]),
  101. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailColor]),
  102. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailNormal]),
  103. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailHeight]),
  104. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailRoughness]),
  105. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailSpecularF0]),
  106. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailMetalness]),
  107. AZ::RHI::ShaderInputNameIndex(ClipmapImageShaderInput[ClipmapName::DetailOcclusion])
  108. }
  109. {
  110. }
  111. void TerrainClipmapManager::SetConfiguration(const ClipmapConfiguration& config)
  112. {
  113. AZ::RPI::ShaderSystemInterface::Get()->SetGlobalShaderOption(AZ::Name{ "o_useClipmap" }, AZ::RPI::ShaderOptionValue{ config.m_clipmapEnabled });
  114. if (!m_isInitialized)
  115. {
  116. m_config = config;
  117. return;
  118. }
  119. if (!config.m_clipmapEnabled)
  120. {
  121. ClearMacroClipmapImages();
  122. ClearMacroClipmapGpuBuffer();
  123. m_config = config;
  124. return;
  125. }
  126. bool macroRecreation = false;
  127. bool detailRecreation = false;
  128. bool macroRefresh = false;
  129. bool detailRefresh = false;
  130. // If clipmap size is changed, everything will be recreated.
  131. if (config.m_clipmapSize != m_config.m_clipmapSize)
  132. {
  133. macroRecreation = true;
  134. detailRecreation = true;
  135. }
  136. // Check if macro or detail stack size has a change, it will need recreation.
  137. if (config.CalculateMacroClipmapStackSize() != m_config.CalculateMacroClipmapStackSize())
  138. {
  139. macroRecreation = true;
  140. }
  141. if (config.CalculateDetailClipmapStackSize() != m_config.CalculateDetailClipmapStackSize())
  142. {
  143. detailRecreation = true;
  144. }
  145. //! Minor changes can be resolved by updating the full clipmap.
  146. if (config.m_macroClipmapMaxRenderRadius != m_config.m_macroClipmapMaxRenderRadius ||
  147. config.m_macroClipmapMaxResolution != m_config.m_macroClipmapMaxResolution ||
  148. config.m_macroClipmapScaleBase != m_config.m_macroClipmapScaleBase ||
  149. config.m_macroClipmapMarginSize != m_config.m_macroClipmapMarginSize)
  150. {
  151. macroRefresh = true;
  152. }
  153. if (config.m_detailClipmapMaxRenderRadius != m_config.m_detailClipmapMaxRenderRadius ||
  154. config.m_detailClipmapMaxResolution != m_config.m_detailClipmapMaxResolution ||
  155. config.m_detailClipmapScaleBase != m_config.m_detailClipmapScaleBase ||
  156. config.m_detailClipmapMarginSize != m_config.m_detailClipmapMarginSize)
  157. {
  158. detailRefresh = true;
  159. }
  160. if (macroRecreation || detailRecreation || macroRefresh || detailRefresh)
  161. {
  162. m_config = config;
  163. TriggerFullRefresh();
  164. if (macroRecreation)
  165. {
  166. ClearMacroClipmapImages();
  167. ClearMacroClipmapGpuBuffer();
  168. QueryMacroClipmapStackSize();
  169. InitializeMacroClipmapData();
  170. InitializeMacroClipmapImages();
  171. InitializeMacroClipmapGpuBuffer();
  172. }
  173. else if (macroRefresh)
  174. {
  175. InitializeMacroClipmapData();
  176. }
  177. if (detailRecreation)
  178. {
  179. ClearDetailClipmapImages();
  180. ClearDetailClipmapGpuBuffer();
  181. QueryDetailClipmapStackSize();
  182. InitializeDetailClipmapData();
  183. InitializeDetailClipmapImages();
  184. InitializeDetailClipmapGpuBuffer();
  185. }
  186. else if (detailRefresh)
  187. {
  188. InitializeDetailClipmapData();
  189. }
  190. return;
  191. }
  192. if (config.m_extendedClipmapMarginSize != m_config.m_extendedClipmapMarginSize ||
  193. config.m_clipmapBlendSize != m_config.m_clipmapBlendSize)
  194. {
  195. m_config = config;
  196. m_clipmapData.m_extendedClipmapMarginSize = aznumeric_cast<float>(m_config.m_extendedClipmapMarginSize);
  197. m_clipmapData.m_clipmapBlendSize = aznumeric_cast<float>(m_config.m_clipmapBlendSize);
  198. }
  199. }
  200. bool TerrainClipmapManager::IsClipmapEnabled() const
  201. {
  202. return m_config.m_clipmapEnabled;
  203. }
  204. void TerrainClipmapManager::Initialize(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  205. {
  206. AZ_Error(TerrainClipmapManagerName, terrainSrg, "terrainSrg must not be null.");
  207. AZ_Error(TerrainClipmapManagerName, !m_isInitialized, "Already initialized.");
  208. if (!terrainSrg || m_isInitialized)
  209. {
  210. return;
  211. }
  212. m_terrainSrg = terrainSrg;
  213. QueryMacroClipmapStackSize();
  214. QueryDetailClipmapStackSize();
  215. InitializeMacroClipmapData();
  216. InitializeDetailClipmapData();
  217. InitializeMacroClipmapImages();
  218. InitializeDetailClipmapImages();
  219. InitializeMacroClipmapGpuBuffer();
  220. InitializeDetailClipmapGpuBuffer();
  221. UpdateSrgIndices(terrainSrg);
  222. TerrainAreaMaterialNotificationBus::Handler::BusConnect();
  223. TerrainMacroMaterialNotificationBus::Handler::BusConnect();
  224. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
  225. m_isInitialized = true;
  226. }
  227. void TerrainClipmapManager::UpdateSrgIndices(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  228. {
  229. for (uint32_t i = 0; i < ClipmapName::Count; ++i)
  230. {
  231. terrainSrg->SetImage(m_terrainSrgClipmapImageIndex[i], m_clipmaps[i]);
  232. }
  233. }
  234. bool TerrainClipmapManager::IsInitialized() const
  235. {
  236. return m_isInitialized;
  237. }
  238. void TerrainClipmapManager::Reset()
  239. {
  240. m_isInitialized = false;
  241. m_fullRefreshClipmaps = true;
  242. m_terrainSrg = nullptr;
  243. ClearMacroClipmapImages();
  244. ClearMacroClipmapGpuBuffer();
  245. ClearDetailClipmapImages();
  246. ClearDetailClipmapGpuBuffer();
  247. TerrainAreaMaterialNotificationBus::Handler::BusDisconnect();
  248. TerrainMacroMaterialNotificationBus::Handler::BusDisconnect();
  249. AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
  250. }
  251. void TerrainClipmapManager::TriggerFullRefresh()
  252. {
  253. m_fullRefreshClipmaps = true;
  254. }
  255. void TerrainClipmapManager::Update(const AZ::Vector3& cameraPosition, const AZ::RPI::Scene* scene, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  256. {
  257. UpdateClipmapData(cameraPosition, scene, terrainSrg);
  258. terrainSrg->SetConstant(m_terrainSrgClipmapDataIndex, m_clipmapData);
  259. }
  260. void TerrainClipmapManager::ImportClipmap(ClipmapName clipmapName, AZ::RHI::FrameGraphAttachmentInterface attachmentDatabase) const
  261. {
  262. auto clipmap = m_clipmaps[clipmapName];
  263. attachmentDatabase.ImportImage(clipmap->GetAttachmentId(), clipmap->GetRHIImage());
  264. }
  265. void TerrainClipmapManager::UseClipmap(ClipmapName clipmapName, AZ::RHI::ScopeAttachmentAccess access, AZ::RHI::FrameGraphInterface frameGraph) const
  266. {
  267. auto clipmap = m_clipmaps[clipmapName];
  268. AZ::RHI::ImageScopeAttachmentDescriptor desc;
  269. desc.m_imageViewDescriptor = clipmap->GetImageView()->GetDescriptor();
  270. desc.m_loadStoreAction.m_loadAction = AZ::RHI::AttachmentLoadAction::Load;
  271. desc.m_attachmentId = clipmap->GetAttachmentId();
  272. frameGraph.UseShaderAttachment(desc, access, AZ::RHI::ScopeAttachmentStage::ComputeShader);
  273. }
  274. void TerrainClipmapManager::QueryMacroClipmapStackSize()
  275. {
  276. m_macroClipmapStackSize = m_config.CalculateMacroClipmapStackSize();
  277. }
  278. void TerrainClipmapManager::QueryDetailClipmapStackSize()
  279. {
  280. m_detailClipmapStackSize = m_config.CalculateDetailClipmapStackSize();
  281. }
  282. void TerrainClipmapManager::InitializeMacroClipmapGpuBuffer()
  283. {
  284. AZ::Render::GpuBufferHandler::Descriptor desc;
  285. desc.m_bufferName = "Macro Clipmap Update Regions";
  286. desc.m_bufferSrgName = "m_macroClipmapUpdateRegions";
  287. desc.m_elementSize = sizeof(ClipmapUpdateRegion);
  288. desc.m_srgLayout = m_terrainSrg->GetLayout();
  289. m_macroClipmapUpdateRegionsBuffer = AZ::Render::GpuBufferHandler(desc);
  290. // Reserve the max possible size.
  291. m_macroClipmapUpdateRegions.reserve(ClipmapBounds::MaxUpdateRegions * m_macroClipmapStackSize);
  292. }
  293. void TerrainClipmapManager::InitializeDetailClipmapGpuBuffer()
  294. {
  295. AZ::Render::GpuBufferHandler::Descriptor desc;
  296. desc.m_bufferName = "Detail Clipmap Update Regions";
  297. desc.m_bufferSrgName = "m_detailClipmapUpdateRegions";
  298. desc.m_elementSize = sizeof(ClipmapUpdateRegion);
  299. desc.m_srgLayout = m_terrainSrg->GetLayout();
  300. m_detailClipmapUpdateRegionsBuffer = AZ::Render::GpuBufferHandler(desc);
  301. // Reserve the max possible size.
  302. m_detailClipmapUpdateRegions.reserve(ClipmapBounds::MaxUpdateRegions * m_detailClipmapStackSize);
  303. }
  304. void TerrainClipmapManager::ClearMacroClipmapGpuBuffer()
  305. {
  306. m_macroClipmapUpdateRegionsBuffer.Release();
  307. }
  308. void TerrainClipmapManager::ClearDetailClipmapGpuBuffer()
  309. {
  310. m_detailClipmapUpdateRegionsBuffer.Release();
  311. }
  312. void TerrainClipmapManager::InitializeMacroClipmapBounds(const AZ::Vector2& center)
  313. {
  314. m_macroClipmapBounds.resize(m_macroClipmapStackSize);
  315. float clipmapToWorldScale = m_config.m_macroClipmapMaxRenderRadius * 2.0f / m_config.m_clipmapSize;
  316. for (int32_t clipmapIndex = m_macroClipmapStackSize - 1; clipmapIndex >= 0; --clipmapIndex)
  317. {
  318. ClipmapBoundsDescriptor desc;
  319. desc.m_size = m_config.m_clipmapSize;
  320. desc.m_worldSpaceCenter = center;
  321. desc.m_clipmapUpdateMultiple = m_config.m_macroClipmapMarginSize;
  322. desc.m_clipmapToWorldScale = clipmapToWorldScale;
  323. m_macroClipmapBounds[clipmapIndex] = ClipmapBounds(desc);
  324. clipmapToWorldScale /= m_config.m_macroClipmapScaleBase;
  325. }
  326. }
  327. void TerrainClipmapManager::InitializeDetailClipmapBounds(const AZ::Vector2& center)
  328. {
  329. m_detailClipmapBounds.resize(m_detailClipmapStackSize);
  330. float clipmapToWorldScale = m_config.m_detailClipmapMaxRenderRadius * 2.0f / m_config.m_clipmapSize;
  331. for (int32_t clipmapIndex = m_detailClipmapStackSize - 1; clipmapIndex >= 0; --clipmapIndex)
  332. {
  333. ClipmapBoundsDescriptor desc;
  334. desc.m_size = m_config.m_clipmapSize;
  335. desc.m_worldSpaceCenter = center;
  336. desc.m_clipmapUpdateMultiple = m_config.m_detailClipmapMarginSize;
  337. desc.m_clipmapToWorldScale = clipmapToWorldScale;
  338. m_detailClipmapBounds[clipmapIndex] = ClipmapBounds(desc);
  339. clipmapToWorldScale /= m_config.m_detailClipmapScaleBase;
  340. }
  341. }
  342. void TerrainClipmapManager::InitializeMacroClipmapData()
  343. {
  344. m_clipmapData.m_extendedClipmapMarginSize = aznumeric_cast<float>(m_config.m_extendedClipmapMarginSize);
  345. m_clipmapData.m_clipmapSizeFloat = aznumeric_cast<float>(m_config.m_clipmapSize);
  346. m_clipmapData.m_clipmapSizeUint = m_config.m_clipmapSize;
  347. m_clipmapData.m_clipmapBlendSize = aznumeric_cast<float>(m_config.m_clipmapBlendSize);
  348. m_clipmapData.m_macroClipmapMaxRenderRadius = m_config.m_macroClipmapMaxRenderRadius;
  349. m_clipmapData.m_macroClipmapScaleBase = m_config.m_macroClipmapScaleBase;
  350. m_clipmapData.m_macroClipmapStackSize = m_macroClipmapStackSize;
  351. m_clipmapData.m_macroClipmapMarginSize = aznumeric_cast<float>(m_config.m_macroClipmapMarginSize);
  352. m_clipmapData.m_validMacroClipmapRadius =
  353. m_clipmapData.m_clipmapSizeFloat / 2.0f - m_clipmapData.m_macroClipmapMarginSize - m_clipmapData.m_extendedClipmapMarginSize;
  354. float clipmapToWorldScale = m_config.m_macroClipmapMaxRenderRadius * 2.0f / m_config.m_clipmapSize;
  355. for (int32_t clipmapIndex = m_macroClipmapStackSize - 1; clipmapIndex >= 0; --clipmapIndex)
  356. {
  357. m_clipmapData.m_clipmapToWorldScale[clipmapIndex].m_macro = clipmapToWorldScale;
  358. clipmapToWorldScale /= m_config.m_macroClipmapScaleBase;
  359. m_clipmapData.m_clipmapCenters[clipmapIndex].m_macro = { 0u, 0u };
  360. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_macro = { 0.0f, 0.0f };
  361. }
  362. }
  363. void TerrainClipmapManager::InitializeDetailClipmapData()
  364. {
  365. m_clipmapData.m_extendedClipmapMarginSize = aznumeric_cast<float>(m_config.m_extendedClipmapMarginSize);
  366. m_clipmapData.m_clipmapSizeFloat = aznumeric_cast<float>(m_config.m_clipmapSize);
  367. m_clipmapData.m_clipmapSizeUint = m_config.m_clipmapSize;
  368. m_clipmapData.m_clipmapBlendSize = aznumeric_cast<float>(m_config.m_clipmapBlendSize);
  369. m_clipmapData.m_detailClipmapMaxRenderRadius = m_config.m_detailClipmapMaxRenderRadius;
  370. m_clipmapData.m_detailClipmapScaleBase = m_config.m_detailClipmapScaleBase;
  371. m_clipmapData.m_detailClipmapStackSize = m_detailClipmapStackSize;
  372. m_clipmapData.m_detailClipmapMarginSize = aznumeric_cast<float>(m_config.m_detailClipmapMarginSize);
  373. m_clipmapData.m_validDetailClipmapRadius =
  374. m_clipmapData.m_clipmapSizeFloat / 2.0f - m_clipmapData.m_detailClipmapMarginSize - m_clipmapData.m_extendedClipmapMarginSize;
  375. float clipmapToWorldScale = m_config.m_detailClipmapMaxRenderRadius * 2.0f / m_config.m_clipmapSize;
  376. for (int32_t clipmapIndex = m_detailClipmapStackSize - 1; clipmapIndex >= 0; --clipmapIndex)
  377. {
  378. m_clipmapData.m_clipmapToWorldScale[clipmapIndex].m_detail = clipmapToWorldScale;
  379. clipmapToWorldScale /= m_config.m_detailClipmapScaleBase;
  380. m_clipmapData.m_clipmapCenters[clipmapIndex].m_detail = { 0u, 0u };
  381. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_detail = { 0.0f, 0.0f };
  382. }
  383. }
  384. void TerrainClipmapManager::InitializeMacroClipmapImages()
  385. {
  386. AZ::Data::Instance<AZ::RPI::AttachmentImagePool> pool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool();
  387. AZ::RHI::ImageDescriptor imageDesc;
  388. imageDesc.m_bindFlags = AZ::RHI::ImageBindFlags::ShaderReadWrite;
  389. imageDesc.m_size = AZ::RHI::Size(m_config.m_clipmapSize, m_config.m_clipmapSize, 1);
  390. imageDesc.m_format = AZ::RHI::Format::R8G8B8A8_UNORM;
  391. imageDesc.m_arraySize = aznumeric_cast<uint16_t>(m_macroClipmapStackSize);
  392. AZ::Name macroColorClipmapName = AZ::Name("MacroColorClipmaps");
  393. m_clipmaps[ClipmapName::MacroColor] =
  394. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, macroColorClipmapName, nullptr, nullptr);
  395. imageDesc.m_format = AZ::RHI::Format::R16G16_SNORM;
  396. imageDesc.m_arraySize = aznumeric_cast<uint16_t>(m_macroClipmapStackSize);
  397. AZ::Name macroNormalClipmapName = AZ::Name("MacroNormalClipmaps");
  398. m_clipmaps[ClipmapName::MacroNormal] =
  399. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, macroNormalClipmapName, nullptr, nullptr);
  400. }
  401. void TerrainClipmapManager::InitializeDetailClipmapImages()
  402. {
  403. AZ::Data::Instance<AZ::RPI::AttachmentImagePool> pool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool();
  404. AZ::RHI::ImageDescriptor imageDesc;
  405. imageDesc.m_bindFlags = AZ::RHI::ImageBindFlags::ShaderReadWrite;
  406. imageDesc.m_size = AZ::RHI::Size(m_config.m_clipmapSize, m_config.m_clipmapSize, 1);
  407. imageDesc.m_format = AZ::RHI::Format::R8G8B8A8_UNORM;
  408. imageDesc.m_arraySize = aznumeric_cast<uint16_t>(m_detailClipmapStackSize);
  409. AZ::Name detailColorClipmapName = AZ::Name("DetailColorClipmaps");
  410. m_clipmaps[ClipmapName::DetailColor] =
  411. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailColorClipmapName, nullptr, nullptr);
  412. imageDesc.m_format = AZ::RHI::Format::R16G16_SNORM;
  413. imageDesc.m_arraySize = aznumeric_cast<uint16_t>(m_detailClipmapStackSize);
  414. AZ::Name detailNormalClipmapName = AZ::Name("DetailNormalClipmaps");
  415. m_clipmaps[ClipmapName::DetailNormal] =
  416. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailNormalClipmapName, nullptr, nullptr);
  417. imageDesc.m_format = AZ::RHI::Format::R16_FLOAT;
  418. AZ::Name detailHeightClipmapName = AZ::Name("DetailHeightClipmaps");
  419. m_clipmaps[ClipmapName::DetailHeight] =
  420. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailHeightClipmapName, nullptr, nullptr);
  421. imageDesc.m_format = AZ::RHI::Format::R8_UNORM;
  422. AZ::Name detailRoughnessClipmapName = AZ::Name("DetailRoughnessClipmaps");
  423. m_clipmaps[ClipmapName::DetailRoughness] =
  424. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailRoughnessClipmapName, nullptr, nullptr);
  425. AZ::Name detailSpecularF0ClipmapName = AZ::Name("DetailSpecularF0Clipmaps");
  426. m_clipmaps[ClipmapName::DetailSpecularF0] =
  427. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailSpecularF0ClipmapName, nullptr, nullptr);
  428. AZ::Name detailMetalnessClipmapName = AZ::Name("DetailMetalnessClipmaps");
  429. m_clipmaps[ClipmapName::DetailMetalness] =
  430. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailMetalnessClipmapName, nullptr, nullptr);
  431. imageDesc.m_format = AZ::RHI::Format::R16_FLOAT;
  432. AZ::Name detailOcclusionClipmapName = AZ::Name("DetailOcclusionClipmaps");
  433. m_clipmaps[ClipmapName::DetailOcclusion] =
  434. AZ::RPI::AttachmentImage::Create(*pool.get(), imageDesc, detailOcclusionClipmapName, nullptr, nullptr);
  435. }
  436. void TerrainClipmapManager::ClearMacroClipmapImages()
  437. {
  438. m_clipmaps[ClipmapName::MacroColor] = nullptr;
  439. m_clipmaps[ClipmapName::MacroNormal] = nullptr;
  440. }
  441. void TerrainClipmapManager::ClearDetailClipmapImages()
  442. {
  443. m_clipmaps[ClipmapName::DetailColor] = nullptr;
  444. m_clipmaps[ClipmapName::DetailNormal] = nullptr;
  445. m_clipmaps[ClipmapName::DetailHeight] = nullptr;
  446. m_clipmaps[ClipmapName::DetailRoughness] = nullptr;
  447. m_clipmaps[ClipmapName::DetailSpecularF0] = nullptr;
  448. m_clipmaps[ClipmapName::DetailMetalness] = nullptr;
  449. m_clipmaps[ClipmapName::DetailOcclusion] = nullptr;
  450. }
  451. void TerrainClipmapManager::UpdateClipmapData(const AZ::Vector3& cameraPosition, const AZ::RPI::Scene* scene, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  452. {
  453. // set new view position
  454. AZ::Vector2 currentViewPosition = AZ::Vector2(cameraPosition.GetX(), cameraPosition.GetY());
  455. // Update debug data
  456. auto viewportContextInterface = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
  457. auto viewportContext = viewportContextInterface->GetViewportContextByScene(scene);
  458. auto viewportWindowSize = viewportContext->GetViewportSize();
  459. m_clipmapData.m_viewportSize[0] = aznumeric_cast<float>(viewportWindowSize.m_width);
  460. m_clipmapData.m_viewportSize[1] = aznumeric_cast<float>(viewportWindowSize.m_height);
  461. m_clipmapData.m_debugClipmapId = uint32_t(r_terrainClipmapDebugClipmapId);
  462. m_clipmapData.m_debugClipmapLevel = aznumeric_cast<float>(uint32_t(r_terrainClipmapDebugClipmapLevel));
  463. m_clipmapData.m_debugScale = float(r_terrainClipmapDebugScale);
  464. m_clipmapData.m_debugBrightness = float(r_terrainClipmapDebugBrightness);
  465. if (r_terrainClipmapDebugOverlay == 0u)
  466. {
  467. m_clipmapData.m_macroClipmapOverlayFactor = 0.0f;
  468. m_clipmapData.m_detailClipmapOverlayFactor = 0.0f;
  469. }
  470. else if (r_terrainClipmapDebugOverlay == 1u)
  471. {
  472. m_clipmapData.m_macroClipmapOverlayFactor = 1.0f;
  473. m_clipmapData.m_detailClipmapOverlayFactor = 0.0f;
  474. }
  475. else
  476. {
  477. m_clipmapData.m_macroClipmapOverlayFactor = 0.0f;
  478. m_clipmapData.m_detailClipmapOverlayFactor = 1.0f;
  479. }
  480. // Update clipmap center
  481. m_macroClipmapUpdateRegions.clear();
  482. m_detailClipmapUpdateRegions.clear();
  483. // First time update will run through the whole clipmap
  484. if (m_fullRefreshClipmaps)
  485. {
  486. m_fullRefreshClipmaps = false;
  487. InitializeMacroClipmapBounds(currentViewPosition);
  488. InitializeDetailClipmapBounds(currentViewPosition);
  489. AZStd::array<uint32_t, 4> aabb = { 0, 0, m_config.m_clipmapSize, m_config.m_clipmapSize };
  490. for (uint32_t clipmapIndex = 0; clipmapIndex < m_macroClipmapStackSize; ++clipmapIndex)
  491. {
  492. m_macroClipmapUpdateRegions.push_back(ClipmapUpdateRegion(clipmapIndex, aabb));
  493. Vector2i center = m_macroClipmapBounds[clipmapIndex].GetModCenter();
  494. AZ::Vector2 centerWorld = m_macroClipmapBounds[clipmapIndex].GetCenterInWorldSpace();
  495. m_clipmapData.m_clipmapCenters[clipmapIndex].m_macro[0] = center.m_x;
  496. m_clipmapData.m_clipmapCenters[clipmapIndex].m_macro[1] = center.m_y;
  497. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_macro[0] = centerWorld.GetX();
  498. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_macro[1] = centerWorld.GetY();
  499. }
  500. for (uint32_t clipmapIndex = 0; clipmapIndex < m_detailClipmapStackSize; ++clipmapIndex)
  501. {
  502. m_detailClipmapUpdateRegions.push_back(ClipmapUpdateRegion(clipmapIndex, aabb));
  503. Vector2i center = m_detailClipmapBounds[clipmapIndex].GetModCenter();
  504. AZ::Vector2 centerWorld = m_detailClipmapBounds[clipmapIndex].GetCenterInWorldSpace();
  505. m_clipmapData.m_clipmapCenters[clipmapIndex].m_detail[0] = center.m_x;
  506. m_clipmapData.m_clipmapCenters[clipmapIndex].m_detail[1] = center.m_y;
  507. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_detail[0] = centerWorld.GetX();
  508. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_detail[1] = centerWorld.GetY();
  509. }
  510. m_clipmapData.m_macroClipmapUpdateRegionCount = aznumeric_cast<uint32_t>(m_macroClipmapUpdateRegions.size());
  511. m_clipmapData.m_detailClipmapUpdateRegionCount = aznumeric_cast<uint32_t>(m_detailClipmapUpdateRegions.size());
  512. m_macroClipmapUpdateRegionsBuffer.UpdateBuffer(m_macroClipmapUpdateRegions.data(), m_clipmapData.m_macroClipmapUpdateRegionCount);
  513. m_detailClipmapUpdateRegionsBuffer.UpdateBuffer(m_detailClipmapUpdateRegions.data(), m_clipmapData.m_detailClipmapUpdateRegionCount);
  514. m_macroClipmapUpdateRegionsBuffer.UpdateSrg(terrainSrg.get());
  515. m_detailClipmapUpdateRegionsBuffer.UpdateSrg(terrainSrg.get());
  516. m_macroTotalDispatchThreadX = 1024;
  517. m_macroTotalDispatchThreadY = 1024;
  518. m_detailTotalDispatchThreadX = 1024;
  519. m_detailTotalDispatchThreadY = 1024;
  520. m_clipmapData.m_macroDispatchGroupCountX = m_macroTotalDispatchThreadX / MacroGroupThreadX;
  521. m_clipmapData.m_macroDispatchGroupCountY = m_macroTotalDispatchThreadY / MacroGroupThreadY;
  522. m_clipmapData.m_detailDispatchGroupCountX = m_detailTotalDispatchThreadX / DetailGroupThreadX;
  523. m_clipmapData.m_detailDispatchGroupCountY = m_detailTotalDispatchThreadY / DetailGroupThreadY;
  524. return;
  525. }
  526. // macro clipmap data:
  527. for (uint32_t clipmapIndex = 0; clipmapIndex < m_macroClipmapStackSize; ++clipmapIndex)
  528. {
  529. ClipmapBounds& clipmapBounds = m_macroClipmapBounds[clipmapIndex];
  530. ClipmapBoundsRegionList updateRegionList = clipmapBounds.UpdateCenter(currentViewPosition);
  531. // write updated center
  532. Vector2i center = clipmapBounds.GetModCenter();
  533. m_clipmapData.m_clipmapCenters[clipmapIndex].m_macro[0] = aznumeric_cast<uint32_t>(center.m_x);
  534. m_clipmapData.m_clipmapCenters[clipmapIndex].m_macro[1] = aznumeric_cast<uint32_t>(center.m_y);
  535. AZ::Vector2 centerWorld = clipmapBounds.GetCenterInWorldSpace();
  536. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_macro[0] = centerWorld.GetX();
  537. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_macro[1] = centerWorld.GetY();
  538. for (uint32_t i = 0; i < updateRegionList.size(); ++i)
  539. {
  540. AZStd::array<uint32_t, 4> aabb = { aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_min.m_x),
  541. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_min.m_y),
  542. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_max.m_x),
  543. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_max.m_y) };
  544. m_macroClipmapUpdateRegions.push_back(ClipmapUpdateRegion(clipmapIndex, aabb));
  545. }
  546. }
  547. uint32_t updateRegionCount = aznumeric_cast<uint32_t>(m_macroClipmapUpdateRegions.size());
  548. if (updateRegionCount)
  549. {
  550. m_macroTotalDispatchThreadX = 64;
  551. m_macroTotalDispatchThreadY = 64;
  552. m_clipmapData.m_macroDispatchGroupCountX = m_macroTotalDispatchThreadX / MacroGroupThreadX;
  553. m_clipmapData.m_macroDispatchGroupCountY = m_macroTotalDispatchThreadY / MacroGroupThreadY;
  554. m_clipmapData.m_macroClipmapUpdateRegionCount = updateRegionCount;
  555. m_macroClipmapUpdateRegionsBuffer.UpdateBuffer(m_macroClipmapUpdateRegions.data(), updateRegionCount);
  556. m_macroClipmapUpdateRegionsBuffer.UpdateSrg(terrainSrg.get());
  557. }
  558. else
  559. {
  560. m_macroTotalDispatchThreadX = 0;
  561. m_macroTotalDispatchThreadY = 0;
  562. m_clipmapData.m_macroDispatchGroupCountX = 1;
  563. m_clipmapData.m_macroDispatchGroupCountY = 1;
  564. }
  565. // detail clipmap data:
  566. for (uint32_t clipmapIndex = 0; clipmapIndex < m_detailClipmapStackSize; ++clipmapIndex)
  567. {
  568. ClipmapBounds& clipmapBounds = m_detailClipmapBounds[clipmapIndex];
  569. ClipmapBoundsRegionList updateRegionList = clipmapBounds.UpdateCenter(currentViewPosition);
  570. // write updated center
  571. Vector2i center = clipmapBounds.GetModCenter();
  572. m_clipmapData.m_clipmapCenters[clipmapIndex].m_detail[0] = aznumeric_cast<uint32_t>(center.m_x);
  573. m_clipmapData.m_clipmapCenters[clipmapIndex].m_detail[1] = aznumeric_cast<uint32_t>(center.m_y);
  574. AZ::Vector2 centerWorld = clipmapBounds.GetCenterInWorldSpace();
  575. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_detail[0] = centerWorld.GetX();
  576. m_clipmapData.m_clipmapWorldCenters[clipmapIndex].m_detail[1] = centerWorld.GetY();
  577. for (uint32_t i = 0; i < updateRegionList.size(); ++i)
  578. {
  579. AZStd::array<uint32_t, 4> aabb = { aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_min.m_x),
  580. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_min.m_y),
  581. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_max.m_x),
  582. aznumeric_cast<uint32_t>(updateRegionList[i].m_localAabb.m_max.m_y) };
  583. m_detailClipmapUpdateRegions.push_back(ClipmapUpdateRegion(clipmapIndex, aabb));
  584. }
  585. }
  586. updateRegionCount = aznumeric_cast<uint32_t>(m_detailClipmapUpdateRegions.size());
  587. if (updateRegionCount)
  588. {
  589. m_detailTotalDispatchThreadX = 64;
  590. m_detailTotalDispatchThreadY = 64;
  591. m_clipmapData.m_detailDispatchGroupCountX = m_detailTotalDispatchThreadX / DetailGroupThreadX;
  592. m_clipmapData.m_detailDispatchGroupCountY = m_detailTotalDispatchThreadY / DetailGroupThreadY;
  593. m_clipmapData.m_detailClipmapUpdateRegionCount = updateRegionCount;
  594. m_detailClipmapUpdateRegionsBuffer.UpdateBuffer(m_detailClipmapUpdateRegions.data(), updateRegionCount);
  595. m_detailClipmapUpdateRegionsBuffer.UpdateSrg(terrainSrg.get());
  596. }
  597. else
  598. {
  599. m_detailTotalDispatchThreadX = 0;
  600. m_detailTotalDispatchThreadY = 0;
  601. m_clipmapData.m_detailDispatchGroupCountX = 1;
  602. m_clipmapData.m_detailDispatchGroupCountY = 1;
  603. }
  604. }
  605. AZ::Data::Instance<AZ::RPI::AttachmentImage> TerrainClipmapManager::GetClipmapImage(ClipmapName clipmapName) const
  606. {
  607. AZ_Assert(clipmapName < ClipmapName::Count, "Must be a valid ClipmapName enum.");
  608. return m_clipmaps[clipmapName];
  609. }
  610. void TerrainClipmapManager::GetMacroDispatchThreadNum(uint32_t& outThreadX, uint32_t& outThreadY, uint32_t& outThreadZ) const
  611. {
  612. outThreadX = m_macroTotalDispatchThreadX;
  613. outThreadY = m_macroTotalDispatchThreadY;
  614. outThreadZ = 1;
  615. }
  616. void TerrainClipmapManager::GetDetailDispatchThreadNum(uint32_t& outThreadX, uint32_t& outThreadY, uint32_t& outThreadZ) const
  617. {
  618. outThreadX = m_detailTotalDispatchThreadX;
  619. outThreadY = m_detailTotalDispatchThreadY;
  620. outThreadZ = 1;
  621. }
  622. uint32_t TerrainClipmapManager::GetClipmapSize() const
  623. {
  624. return m_config.m_clipmapSize;
  625. }
  626. bool TerrainClipmapManager::HasMacroClipmapUpdate() const
  627. {
  628. return m_macroTotalDispatchThreadX != 0 && m_macroTotalDispatchThreadY != 0;
  629. }
  630. bool TerrainClipmapManager::HasDetailClipmapUpdate() const
  631. {
  632. return m_detailTotalDispatchThreadX != 0 && m_detailTotalDispatchThreadY != 0;
  633. }
  634. // AzFramework::Terrain::TerrainDataNotificationBus overrides...
  635. void TerrainClipmapManager::OnTerrainDataChanged(
  636. [[maybe_unused]] const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask)
  637. {
  638. TriggerFullRefresh();
  639. }
  640. // TerrainMacroMaterialNotificationBus overrides...
  641. void TerrainClipmapManager::OnTerrainMacroMaterialCreated(
  642. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const MacroMaterialData& material)
  643. {
  644. TriggerFullRefresh();
  645. }
  646. void TerrainClipmapManager::OnTerrainMacroMaterialChanged(
  647. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const MacroMaterialData& material)
  648. {
  649. TriggerFullRefresh();
  650. }
  651. void TerrainClipmapManager::OnTerrainMacroMaterialRegionChanged(
  652. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, [[maybe_unused]] const AZ::Aabb& newRegion)
  653. {
  654. TriggerFullRefresh();
  655. }
  656. void TerrainClipmapManager::OnTerrainMacroMaterialDestroyed([[maybe_unused]] AZ::EntityId entityId)
  657. {
  658. TriggerFullRefresh();
  659. }
  660. // TerrainAreaMaterialNotificationBus overrides...
  661. void TerrainClipmapManager::OnTerrainDefaultSurfaceMaterialCreated(
  662. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> material)
  663. {
  664. TriggerFullRefresh();
  665. }
  666. void TerrainClipmapManager::OnTerrainDefaultSurfaceMaterialDestroyed([[maybe_unused]] AZ::EntityId entityId)
  667. {
  668. TriggerFullRefresh();
  669. }
  670. void TerrainClipmapManager::OnTerrainDefaultSurfaceMaterialChanged(
  671. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> newMaterial)
  672. {
  673. TriggerFullRefresh();
  674. }
  675. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingCreated(
  676. [[maybe_unused]] AZ::EntityId entityId,
  677. [[maybe_unused]] SurfaceData::SurfaceTag surfaceTag,
  678. [[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> material)
  679. {
  680. TriggerFullRefresh();
  681. }
  682. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingDestroyed(
  683. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] SurfaceData::SurfaceTag surfaceTag)
  684. {
  685. TriggerFullRefresh();
  686. }
  687. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingMaterialChanged(
  688. [[maybe_unused]] AZ::EntityId entityId,
  689. [[maybe_unused]] SurfaceData::SurfaceTag surfaceTag,
  690. [[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> material)
  691. {
  692. TriggerFullRefresh();
  693. }
  694. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingTagChanged(
  695. [[maybe_unused]] AZ::EntityId entityId,
  696. [[maybe_unused]] SurfaceData::SurfaceTag oldSurfaceTag,
  697. [[maybe_unused]] SurfaceData::SurfaceTag newSurfaceTag)
  698. {
  699. TriggerFullRefresh();
  700. }
  701. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingRegionCreated(
  702. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& region)
  703. {
  704. TriggerFullRefresh();
  705. }
  706. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingRegionDestroyed(
  707. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion)
  708. {
  709. TriggerFullRefresh();
  710. }
  711. void TerrainClipmapManager::OnTerrainSurfaceMaterialMappingRegionChanged(
  712. [[maybe_unused]] AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, [[maybe_unused]] const AZ::Aabb& newRegion)
  713. {
  714. TriggerFullRefresh();
  715. }
  716. }