TerrainMacroMaterialManager.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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/TerrainMacroMaterialManager.h>
  9. #include <Atom/RHI/RHISystemInterface.h>
  10. #include <Atom/RPI.Public/View.h>
  11. namespace Terrain
  12. {
  13. namespace
  14. {
  15. [[maybe_unused]] static const char* TerrainMacroMaterialManagerName = "TerrainMacroMaterialManager";
  16. }
  17. namespace TerrainSrgInputs
  18. {
  19. static const char* const MacroMaterialData("m_macroMaterialData");
  20. static const char* const MacroMaterialGridRefs("m_macroMaterialGridRefs");
  21. }
  22. bool TerrainMacroMaterialManager::MacroMaterialShaderData::Overlaps(const AZ::Vector2& min, const AZ::Vector2& max) const
  23. {
  24. return AZ::Vector2::CreateFromFloat2(m_boundsMin.data()).IsLessThan(max) &&
  25. AZ::Vector2::CreateFromFloat2(m_boundsMax.data()).IsGreaterThan(min);
  26. }
  27. void TerrainMacroMaterialManager::Initialize(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  28. {
  29. AZ_Error(TerrainMacroMaterialManagerName, terrainSrg, "terrainSrg must not be null.");
  30. AZ_Error(TerrainMacroMaterialManagerName, !m_isInitialized, "Already initialized.");
  31. if (!terrainSrg || m_isInitialized)
  32. {
  33. return;
  34. }
  35. auto deviceCount = AZ::RHI::RHISystemInterface::Get()->GetDeviceCount();
  36. for (auto deviceIndex{0}; deviceIndex < deviceCount; ++deviceIndex)
  37. {
  38. if (terrainSrg->GetRHIShaderResourceGroup()->IsDeviceSet(deviceIndex))
  39. {
  40. m_materialShaderData[deviceIndex] = {};
  41. }
  42. }
  43. if (UpdateSrgIndices(terrainSrg))
  44. {
  45. TerrainMacroMaterialNotificationBus::Handler::BusConnect();
  46. m_terrainSizeChanged = true;
  47. m_isInitialized = true;
  48. }
  49. }
  50. void TerrainMacroMaterialManager::Reset()
  51. {
  52. m_isInitialized = false;
  53. RemoveAllImages();
  54. m_materialDataBuffer = {};
  55. m_materialRefGridDataBuffer = {};
  56. for (auto& [deviceIndex, data] : m_materialShaderData)
  57. {
  58. data.clear();
  59. }
  60. m_materialPriorityData.Clear();
  61. m_materialRefGridShaderData.clear();
  62. m_entityToMaterialHandle.clear();
  63. TerrainMacroMaterialNotificationBus::Handler::BusDisconnect();
  64. }
  65. bool TerrainMacroMaterialManager::IsInitialized()
  66. {
  67. return m_isInitialized;
  68. }
  69. bool TerrainMacroMaterialManager::UpdateSrgIndices(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  70. {
  71. const AZ::RHI::ShaderResourceGroupLayout* terrainSrgLayout = terrainSrg->GetLayout();
  72. AZ::Render::GpuBufferHandler::Descriptor desc;
  73. desc.m_srgLayout = terrainSrgLayout;
  74. // Set up the gpu buffer for macro material data
  75. desc.m_bufferName = "Macro Material Data";
  76. desc.m_bufferSrgName = TerrainSrgInputs::MacroMaterialData;
  77. desc.m_elementSize = sizeof(MacroMaterialShaderData);
  78. m_materialDataBuffer = AZ::Render::GpuBufferHandler(desc);
  79. desc.m_bufferName = "Macro Material Ref Grid";
  80. desc.m_bufferSrgName = TerrainSrgInputs::MacroMaterialGridRefs;
  81. desc.m_elementSize = sizeof(TileMaterials);
  82. m_materialRefGridDataBuffer = AZ::Render::GpuBufferHandler(desc);
  83. m_bufferNeedsUpdate = true;
  84. return m_materialDataBuffer.IsValid() && m_materialRefGridDataBuffer.IsValid();
  85. }
  86. void TerrainMacroMaterialManager::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& newMaterialData)
  87. {
  88. // If terrainSizeChanged, everything will rebuild later, so don't do any work here.
  89. if (m_terrainSizeChanged)
  90. {
  91. return;
  92. }
  93. AZ_Assert(
  94. !m_entityToMaterialHandle.contains(entityId),
  95. "OnTerrainMacroMaterialCreated called for a macro material that already exists. This indicates that either the bus is incorrectly sending out "
  96. "OnCreated announcements for existing materials, or the terrain feature processor isn't properly cleaning up macro materials.");
  97. AZ_Assert(m_materialPriorityData.GetSize() < AZStd::numeric_limits<uint16_t>::max(), "No more room for terrain macro materials.");
  98. MaterialHandle materialHandle = MaterialHandle(m_materialPriorityData.Reserve());
  99. for (auto& [deviceIndex, data] : m_materialShaderData)
  100. {
  101. data.resize(m_materialPriorityData.GetSize());
  102. }
  103. m_entityToMaterialHandle[entityId] = materialHandle;
  104. UpdateMacroMaterialShaderEntry(materialHandle, newMaterialData);
  105. ForMacroMaterialsInBounds(newMaterialData.m_bounds,
  106. [&](TileHandle tileHandle, [[maybe_unused]] const AZ::Vector2& corner)
  107. {
  108. AddMacroMaterialToTile(materialHandle, tileHandle);
  109. }
  110. );
  111. }
  112. void TerrainMacroMaterialManager::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& newMaterialData)
  113. {
  114. // If terrainSizeChanged, everything will rebuild later, so don't do any work here.
  115. if (m_terrainSizeChanged)
  116. {
  117. return;
  118. }
  119. AZ_Assert(
  120. m_entityToMaterialHandle.contains(entityId),
  121. "OnTerrainMacroMaterialChanged called for a macro material that TerrainFeatureProcessor isn't tracking. This indicates that either the bus is sending out "
  122. "Changed announcements for materials that haven't had a OnCreated event sent, or the terrain feature processor isn't properly tracking macro materials.");
  123. MaterialHandle materialHandle = m_entityToMaterialHandle[entityId];
  124. UpdateMacroMaterialShaderEntry(materialHandle, newMaterialData);
  125. }
  126. void TerrainMacroMaterialManager::OnTerrainMacroMaterialRegionChanged(
  127. AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion)
  128. {
  129. // If terrainSizeChanged, everything will rebuild later, so don't do any work here.
  130. if (m_terrainSizeChanged)
  131. {
  132. return;
  133. }
  134. AZ_Assert(
  135. m_entityToMaterialHandle.contains(entityId),
  136. "OnTerrainMacroMaterialChanged called for a macro material that TerrainFeatureProcessor isn't tracking. This indicates that either the bus is sending out "
  137. "Changed announcements for materials that haven't had a OnCreated event sent, or the terrain feature processor isn't properly tracking macro materials.");
  138. MaterialHandle materialHandle = m_entityToMaterialHandle[entityId];
  139. const AZ::Vector2 boundsMin = AZ::Vector2(newRegion.GetMin());
  140. const AZ::Vector2 boundsMax = AZ::Vector2(newRegion.GetMax());
  141. for (auto& [deviceIndex, data] : m_materialShaderData)
  142. {
  143. MacroMaterialShaderData& shaderData = data.at(materialHandle.GetIndex());
  144. boundsMin.StoreToFloat2(shaderData.m_boundsMin.data());
  145. boundsMax.StoreToFloat2(shaderData.m_boundsMax.data());
  146. }
  147. AZ::Aabb changedRegion = oldRegion;
  148. changedRegion.AddAabb(newRegion);
  149. ForMacroMaterialsInBounds(changedRegion,
  150. [&](TileHandle tileHandle, const AZ::Vector2& tileMin)
  151. {
  152. AZ::Vector2 tileMax = tileMin + AZ::Vector2(MacroMaterialGridSize);
  153. bool overlapsNew =
  154. tileMin.IsLessThan(boundsMax) &&
  155. tileMax.IsGreaterThan(boundsMin);
  156. if (overlapsNew)
  157. {
  158. AddMacroMaterialToTile(materialHandle, tileHandle);
  159. }
  160. else
  161. {
  162. RemoveMacroMaterialFromTile(materialHandle, tileHandle, tileMin);
  163. }
  164. }
  165. );
  166. m_bufferNeedsUpdate = true;
  167. }
  168. void TerrainMacroMaterialManager::OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId)
  169. {
  170. // If terrainSizeChanged, everything will rebuild later, so don't do any work here.
  171. if (m_terrainSizeChanged)
  172. {
  173. return;
  174. }
  175. AZ_Assert(
  176. m_entityToMaterialHandle.contains(entityId),
  177. "OnTerrainMacroMaterialChanged called for a macro material that TerrainFeatureProcessor isn't tracking. This indicates that either the bus is sending out "
  178. "Changed announcements for materials that haven't had a OnCreated event sent, or the terrain feature processor isn't properly tracking macro materials.");
  179. MaterialHandle materialHandle = m_entityToMaterialHandle[entityId];
  180. MacroMaterialShaderData& shaderData = m_materialShaderData.begin()->second.at(materialHandle.GetIndex());
  181. ForMacroMaterialsInBounds(shaderData.m_boundsMin, shaderData.m_boundsMax,
  182. [&](TileHandle tileHandle, [[maybe_unused]] const AZ::Vector2& corner)
  183. {
  184. RemoveMacroMaterialFromTile(materialHandle, tileHandle, corner);
  185. }
  186. );
  187. m_materialPriorityData.Release(materialHandle.GetIndex());
  188. m_entityToMaterialHandle.erase(entityId);
  189. m_bufferNeedsUpdate = true;
  190. }
  191. void TerrainMacroMaterialManager::UpdateMacroMaterialShaderEntry(MaterialHandle materialHandle, const MacroMaterialData& macroMaterialData)
  192. {
  193. auto UpdateImageIndex = [&](uint32_t& indexRef, const AZ::Data::Instance<AZ::RPI::Image>& imageView, int deviceIndex)
  194. {
  195. indexRef = imageView ? imageView->GetImageView()->GetDeviceImageView(deviceIndex)->GetBindlessReadIndex() : InvalidImageIndex;
  196. };
  197. for (auto& [deviceIndex, data] : m_materialShaderData)
  198. {
  199. MacroMaterialShaderData& shaderData = data.at(materialHandle.GetIndex());
  200. shaderData.m_flags = (MacroMaterialShaderFlags)(
  201. (macroMaterialData.m_normalFlipX ? MacroMaterialShaderFlags::FlipMacroNormalX : 0) |
  202. (macroMaterialData.m_normalFlipY ? MacroMaterialShaderFlags::FlipMacroNormalY : 0)
  203. );
  204. shaderData.m_normalFactor = macroMaterialData.m_normalFactor;
  205. AZ::Vector2(macroMaterialData.m_bounds.GetMin()).StoreToFloat2(shaderData.m_boundsMin.data());
  206. AZ::Vector2(macroMaterialData.m_bounds.GetMax()).StoreToFloat2(shaderData.m_boundsMax.data());
  207. UpdateImageIndex(shaderData.m_colorMapId, macroMaterialData.m_colorImage, deviceIndex);
  208. UpdateImageIndex(shaderData.m_normalMapId, macroMaterialData.m_normalImage, deviceIndex);
  209. }
  210. MacroMaterialPriority& priority = m_materialPriorityData.GetElement(materialHandle.GetIndex());
  211. priority.m_priority = macroMaterialData.m_priority;
  212. priority.m_hash = uint32_t(AZ::u64(macroMaterialData.m_entityId) >> 32) ^ uint32_t(AZ::u64(macroMaterialData.m_entityId) & 0xFFFFFFFF);
  213. m_bufferNeedsUpdate = true;
  214. }
  215. void TerrainMacroMaterialManager::AddMacroMaterialToTile(MaterialHandle newMaterialHandle, TileHandle tileHandle)
  216. {
  217. TileMaterials& tileMaterials = m_materialRefGridShaderData.at(tileHandle.GetIndex());
  218. MacroMaterialPriority& newPriority = m_materialPriorityData.GetElement(newMaterialHandle.GetIndex());
  219. for (uint16_t materialIndex = 0; materialIndex < MacroMaterialsPerTile; ++materialIndex)
  220. {
  221. MaterialHandle& materialHandle = tileMaterials.at(materialIndex);
  222. if (materialHandle == MaterialHandle::Null)
  223. {
  224. // Empty spot, just add the material
  225. materialHandle = newMaterialHandle;
  226. return;
  227. }
  228. else if (materialHandle == newMaterialHandle)
  229. {
  230. return;
  231. }
  232. else
  233. {
  234. // Check the priority. If the new material's priority is greater, insert.
  235. MacroMaterialPriority& priority = m_materialPriorityData.GetElement(materialHandle.GetIndex());
  236. if (newPriority > priority)
  237. {
  238. MaterialHandle temphandle = newMaterialHandle;
  239. for (; materialIndex < MacroMaterialsPerTile; ++materialIndex)
  240. {
  241. MaterialHandle& materialHandle2 = tileMaterials.at(materialIndex);
  242. AZStd::swap(materialHandle2, temphandle);
  243. }
  244. return;
  245. }
  246. }
  247. }
  248. }
  249. void TerrainMacroMaterialManager::RemoveMacroMaterialFromTile(MaterialHandle materialHandleToRemove, TileHandle tileHandle, const AZ::Vector2& tileMin)
  250. {
  251. TileMaterials& tileMaterials = m_materialRefGridShaderData.at(tileHandle.GetIndex());
  252. for (uint16_t materialIndex = 0; materialIndex < MacroMaterialsPerTile; ++materialIndex)
  253. {
  254. if (tileMaterials.at(materialIndex) == materialHandleToRemove)
  255. {
  256. // Remove the macro material entry from this tile by copying the remaining entries on top.
  257. for (++materialIndex; materialIndex < MacroMaterialsPerTile; ++materialIndex)
  258. {
  259. tileMaterials.at(materialIndex - 1) = tileMaterials.at(materialIndex);
  260. }
  261. break;
  262. }
  263. }
  264. // Disable or replace the last entry.
  265. MaterialHandle& lastEntry = tileMaterials.at(MacroMaterialsPerTile - 1);
  266. if (lastEntry != MaterialHandle::Null)
  267. {
  268. lastEntry = MaterialHandle::Null;
  269. MacroMaterialPriority lastPriority;
  270. // Check all the macro materials to see if any overlap this tile. Since the tile was full, when a macro material
  271. // was removed, there may be a macro material that can be placed in the empty spot.
  272. // Create a list of macro materials to ignore when searching for possible entries to add at the end.
  273. // This is basically all the materials except the last one, plus the material currently being removed.
  274. AZStd::array<MaterialHandle, MacroMaterialsPerTile> alreadyUsedMaterials;
  275. AZStd::copy(tileMaterials.begin(), tileMaterials.end(), alreadyUsedMaterials.begin());
  276. alreadyUsedMaterials.at(MacroMaterialsPerTile - 1) = materialHandleToRemove;
  277. AZ::Vector2 tileMax = tileMin + AZ::Vector2(MacroMaterialGridSize);
  278. for (auto& [entityId, materialHandle] : m_entityToMaterialHandle)
  279. {
  280. if (AZStd::find(alreadyUsedMaterials.begin(), alreadyUsedMaterials.end(), materialHandle) != nullptr)
  281. {
  282. continue;
  283. }
  284. MacroMaterialShaderData& shaderData = m_materialShaderData.begin()->second.at(materialHandle.GetIndex());
  285. MacroMaterialPriority priority = m_materialPriorityData.GetElement(materialHandle.GetIndex());
  286. if (shaderData.Overlaps(tileMin, tileMax) && (lastEntry == MaterialHandle::Null || priority > lastPriority))
  287. {
  288. lastEntry = materialHandle;
  289. lastPriority = priority;
  290. }
  291. }
  292. }
  293. }
  294. template<typename Callback>
  295. void TerrainMacroMaterialManager::ForMacroMaterialsInRegion(const ClipmapBoundsRegion& region, Callback callback)
  296. {
  297. AZ::Vector2 regionCorner = AZ::Vector2(region.m_worldAabb.GetMin());
  298. Vector2i extents = region.m_localAabb.m_max - region.m_localAabb.m_min;
  299. for (int32_t y = 0; y < extents.m_y; ++y)
  300. {
  301. for (int32_t x = 0; x < extents.m_x; ++x)
  302. {
  303. const Vector2i local = region.m_localAabb.m_min + Vector2i(x, y);
  304. TileHandle tileHandle = TileHandle(local.m_y * m_tiles1D + local.m_x);
  305. const AZ::Vector2 corner = regionCorner + AZ::Vector2(x * MacroMaterialGridSize, y * MacroMaterialGridSize);
  306. callback(tileHandle, corner);
  307. }
  308. }
  309. }
  310. template<typename Callback>
  311. void TerrainMacroMaterialManager::ForMacroMaterialsInBounds(const AZ::Vector2& minBounds, const AZ::Vector2& maxBounds, Callback callback)
  312. {
  313. auto updateRegionsList = m_macroMaterialTileBounds.TransformRegion(minBounds, maxBounds);
  314. for (const auto& region : updateRegionsList)
  315. {
  316. ForMacroMaterialsInRegion(region, callback);
  317. }
  318. }
  319. template<typename Callback>
  320. void TerrainMacroMaterialManager::ForMacroMaterialsInBounds(const AZ::Aabb& bounds, Callback callback)
  321. {
  322. ForMacroMaterialsInBounds(AZ::Vector2(bounds.GetMin()), AZ::Vector2(bounds.GetMax()), callback);
  323. }
  324. template<typename Callback>
  325. void TerrainMacroMaterialManager::ForMacroMaterialsInBounds(const AZStd::array<float, 2>& minBounds, const AZStd::array<float, 2>& maxBounds, Callback callback)
  326. {
  327. ForMacroMaterialsInBounds(AZ::Vector2::CreateFromFloat2(minBounds.data()), AZ::Vector2::CreateFromFloat2(maxBounds.data()), callback);
  328. }
  329. void TerrainMacroMaterialManager::SetRenderDistance(float distance)
  330. {
  331. uint16_t newTiles1D = aznumeric_cast<uint16_t>(AZStd::ceilf((distance) / MacroMaterialGridSize)) + 1;
  332. newTiles1D *= 2; // distance is radius, grid covers diameter.
  333. if (newTiles1D != m_tiles1D)
  334. {
  335. m_tiles1D = newTiles1D;
  336. m_terrainSizeChanged = true;
  337. }
  338. }
  339. void TerrainMacroMaterialManager::Update(const AZ::RPI::ViewPtr mainView, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg)
  340. {
  341. AZ::Vector3 mainCameraPosition = mainView->GetCameraTransform().GetTranslation();
  342. if (m_terrainSizeChanged)
  343. {
  344. m_terrainSizeChanged = false;
  345. m_bufferNeedsUpdate = true;
  346. ClipmapBoundsDescriptor desc;
  347. desc.m_clipmapToWorldScale = MacroMaterialGridSize;
  348. desc.m_clipmapUpdateMultiple = 1;
  349. desc.m_size = m_tiles1D;
  350. desc.m_worldSpaceCenter = AZ::Vector2(mainCameraPosition);
  351. m_macroMaterialTileBounds = ClipmapBounds(desc);
  352. // Rebuild the macro material tiles from scratch when the world size changes. This could be made more efficient
  353. // but is fine for now since world resizes are rare.
  354. RemoveAllImages();
  355. m_entityToMaterialHandle.clear();
  356. m_materialPriorityData.Clear();
  357. m_materialRefGridShaderData.clear();
  358. for (auto& [deviceIndex, data] : m_materialShaderData)
  359. {
  360. data.clear();
  361. }
  362. const uint32_t macroMaterialTileCount = m_tiles1D * m_tiles1D;
  363. m_materialRefGridShaderData.resize(macroMaterialTileCount);
  364. AZStd::fill(m_materialRefGridShaderData.begin(), m_materialRefGridShaderData.end(), DefaultTileMaterials);
  365. TerrainMacroMaterialRequestBus::EnumerateHandlers(
  366. [&](TerrainMacroMaterialRequests* handler)
  367. {
  368. MacroMaterialData macroMaterial = handler->GetTerrainMacroMaterialData();
  369. AZ::EntityId entityId = *(Terrain::TerrainMacroMaterialRequestBus::GetCurrentBusId());
  370. OnTerrainMacroMaterialCreated(entityId, macroMaterial);
  371. return true;
  372. }
  373. );
  374. }
  375. else
  376. {
  377. auto updateRegionList = m_macroMaterialTileBounds.UpdateCenter(AZ::Vector2(mainCameraPosition));
  378. for (const auto& updateRegion : updateRegionList)
  379. {
  380. AZStd::vector<MaterialHandle> affectedMaterials;
  381. affectedMaterials.reserve(AZStd::GetMin(m_entityToMaterialHandle.size(), size_t(128)));
  382. AZ::Vector2 regionMin = AZ::Vector2(updateRegion.m_worldAabb.GetMin());
  383. AZ::Vector2 regionMax = AZ::Vector2(updateRegion.m_worldAabb.GetMax());
  384. // Do a coarse check of which materials might affect this region's tiles by gathering all
  385. // macro materials that overlap the region. This should reduce the number of checks that need
  386. // to be done per-tile.
  387. for (auto& [entityId, materialHandle] : m_entityToMaterialHandle)
  388. {
  389. MacroMaterialShaderData& shaderData = m_materialShaderData.begin()->second.at(materialHandle.GetIndex());
  390. if (shaderData.Overlaps(regionMin, regionMax))
  391. {
  392. affectedMaterials.push_back(materialHandle);
  393. }
  394. }
  395. // Check the list of macro materials against all the tiles in this region.
  396. ForMacroMaterialsInRegion(updateRegion,
  397. [&](TileHandle tileHandle, const AZ::Vector2& tileMin)
  398. {
  399. AZ::Vector2 tileMax = tileMin + AZ::Vector2(MacroMaterialGridSize);
  400. m_materialRefGridShaderData.at(tileHandle.GetIndex()) = DefaultTileMaterials; // clear out current materials
  401. for (MaterialHandle materialHandle : affectedMaterials)
  402. {
  403. MacroMaterialShaderData& shaderData = m_materialShaderData.begin()->second.at(materialHandle.GetIndex());
  404. if (shaderData.Overlaps(tileMin, tileMax))
  405. {
  406. AddMacroMaterialToTile(materialHandle, tileHandle);
  407. }
  408. }
  409. }
  410. );
  411. m_bufferNeedsUpdate = true;
  412. }
  413. }
  414. if (m_bufferNeedsUpdate && terrainSrg)
  415. {
  416. m_bufferNeedsUpdate = false;
  417. AZStd::unordered_map<int, const void*> rawData;
  418. for (auto& [deviceIndex, data] : m_materialShaderData)
  419. {
  420. rawData[deviceIndex] = data.data();
  421. }
  422. m_materialDataBuffer.UpdateBuffer(rawData, aznumeric_cast<uint32_t>(m_materialPriorityData.GetSize()));
  423. m_materialRefGridDataBuffer.UpdateBuffer(m_materialRefGridShaderData.data(), aznumeric_cast<uint32_t>(m_materialRefGridShaderData.size()));
  424. MacroMaterialGridShaderData macroMaterialGridShaderData;
  425. macroMaterialGridShaderData.m_tileCount1D = m_tiles1D;
  426. macroMaterialGridShaderData.m_tileSize = MacroMaterialGridSize;
  427. m_materialDataBuffer.UpdateSrg(terrainSrg.get());
  428. m_materialRefGridDataBuffer.UpdateSrg(terrainSrg.get());
  429. terrainSrg->SetConstant(m_macroMaterialGridIndex, macroMaterialGridShaderData);
  430. }
  431. }
  432. void TerrainMacroMaterialManager::RemoveAllImages()
  433. {
  434. for (const auto& [entity, materialRef] : m_entityToMaterialHandle)
  435. {
  436. RemoveImagesForMaterial(materialRef);
  437. }
  438. }
  439. void TerrainMacroMaterialManager::RemoveImagesForMaterial(MaterialHandle materialHandle)
  440. {
  441. for (auto& [deviceIndex, data] : m_materialShaderData)
  442. {
  443. MacroMaterialShaderData& shaderData = data.at(materialHandle.GetIndex());
  444. shaderData.m_colorMapId = InvalidImageIndex;
  445. shaderData.m_normalMapId = InvalidImageIndex;
  446. }
  447. }
  448. }