DecalTextureArrayFeatureProcessor.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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 <Decals/DecalTextureArrayFeatureProcessor.h>
  9. #include <Atom/RHI/Factory.h>
  10. #include <Atom/RPI.Public/RPISystemInterface.h>
  11. #include <Atom/RPI.Public/Material/Material.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/RPI.Public/View.h>
  14. #include <AzCore/Math/Quaternion.h>
  15. #include <AzCore/std/containers/span.h>
  16. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  17. #include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
  18. #include <AtomCore/Instance/InstanceDatabase.h>
  19. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  20. namespace AZ
  21. {
  22. namespace Render
  23. {
  24. namespace
  25. {
  26. static AZ::RHI::Size GetTextureSizeFromMaterialAsset(AZ::RPI::MaterialAsset* materialAsset)
  27. {
  28. for (const auto& elem : materialAsset->GetPropertyValues())
  29. {
  30. if (elem.Is<Data::Asset<RPI::ImageAsset>>())
  31. {
  32. const auto& imageBinding = elem.GetValue<Data::Asset<RPI::ImageAsset>>();
  33. if (imageBinding && imageBinding.IsReady())
  34. {
  35. return imageBinding->GetImageDescriptor().m_size;
  36. }
  37. }
  38. }
  39. AZ_Error(
  40. "DecalTextureFeatureProcessor",
  41. false,
  42. "GetSizeFromMaterial() unable to load image in material ID '%s'",
  43. materialAsset->GetId().ToString<AZStd::string>().c_str()
  44. );
  45. return {};
  46. }
  47. static AZ::Data::Asset<AZ::RPI::MaterialAsset> QueueMaterialAssetLoad(const AZ::Data::AssetId material)
  48. {
  49. auto asset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::MaterialAsset>(material, AZ::Data::AssetLoadBehavior::QueueLoad);
  50. return asset;
  51. }
  52. }
  53. void DecalTextureArrayFeatureProcessor::Reflect(ReflectContext* context)
  54. {
  55. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  56. {
  57. serializeContext
  58. ->Class<DecalTextureArrayFeatureProcessor, RPI::FeatureProcessor>()
  59. ->Version(0);
  60. }
  61. }
  62. void DecalTextureArrayFeatureProcessor::Activate()
  63. {
  64. GpuBufferHandler::Descriptor desc;
  65. desc.m_bufferName = "DecalBuffer";
  66. desc.m_bufferSrgName = "m_decals";
  67. desc.m_elementCountSrgName = "m_decalCount";
  68. desc.m_elementSize = sizeof(DecalData);
  69. desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
  70. m_decalBufferHandler = GpuBufferHandler(desc);
  71. CacheShaderIndices();
  72. }
  73. void DecalTextureArrayFeatureProcessor::Deactivate()
  74. {
  75. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  76. m_decalData.Clear();
  77. m_decalBufferHandler.Release();
  78. }
  79. DecalTextureArrayFeatureProcessor::DecalHandle DecalTextureArrayFeatureProcessor::AcquireDecal()
  80. {
  81. const uint16_t id = m_decalData.GetFreeSlotIndex();
  82. if (id == IndexedDataVector<DecalData>::NoFreeSlot)
  83. {
  84. return DecalHandle(DecalHandle::NullIndex);
  85. }
  86. else
  87. {
  88. m_deviceBufferNeedsUpdate = true;
  89. DecalData& decalData = m_decalData.GetData(id);
  90. decalData.m_textureArrayIndex = DecalData::UnusedIndex;
  91. return DecalHandle(id);
  92. }
  93. }
  94. bool DecalTextureArrayFeatureProcessor::ReleaseDecal(const DecalHandle decal)
  95. {
  96. if (decal.IsValid())
  97. {
  98. if (m_materialLoadTracker.IsAssetLoading(decal))
  99. {
  100. m_materialLoadTracker.RemoveHandle(decal);
  101. }
  102. DecalLocation decalLocation;
  103. decalLocation.textureArrayIndex = m_decalData.GetData(decal.GetIndex()).m_textureArrayIndex;
  104. decalLocation.textureIndex = m_decalData.GetData(decal.GetIndex()).m_textureIndex;
  105. RemoveDecalFromTextureArrays(decalLocation);
  106. m_decalData.RemoveIndex(decal.GetIndex());
  107. m_deviceBufferNeedsUpdate = true;
  108. return true;
  109. }
  110. return false;
  111. }
  112. DecalTextureArrayFeatureProcessor::DecalHandle DecalTextureArrayFeatureProcessor::CloneDecal(const DecalHandle sourceDecal)
  113. {
  114. AZ_Assert(sourceDecal.IsValid(), "Invalid DecalHandle passed to DecalTextureArrayFeatureProcessor::CloneDecal().");
  115. const DecalHandle decal = AcquireDecal();
  116. if (decal.IsValid())
  117. {
  118. m_decalData.GetData(decal.GetIndex()) = m_decalData.GetData(sourceDecal.GetIndex());
  119. const auto materialAsset = GetMaterialUsedByDecal(sourceDecal);
  120. if (materialAsset.IsValid())
  121. {
  122. m_materialToTextureArrayLookupTable.at(materialAsset).m_useCount++;
  123. }
  124. else
  125. {
  126. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "CloneDecal called on a decal with no material set.");
  127. }
  128. m_deviceBufferNeedsUpdate = true;
  129. }
  130. return decal;
  131. }
  132. void DecalTextureArrayFeatureProcessor::Simulate(const RPI::FeatureProcessor::SimulatePacket& packet)
  133. {
  134. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Simulate");
  135. AZ_UNUSED(packet);
  136. if (m_deviceBufferNeedsUpdate)
  137. {
  138. m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector());
  139. m_deviceBufferNeedsUpdate = false;
  140. }
  141. }
  142. void DecalTextureArrayFeatureProcessor::Render(const RPI::FeatureProcessor::RenderPacket& packet)
  143. {
  144. // Note that decals are rendered as part of the forward shading pipeline. We only need to bind the decal buffers/textures in here.
  145. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Render");
  146. for (const RPI::ViewPtr& view : packet.m_views)
  147. {
  148. m_decalBufferHandler.UpdateSrg(view->GetShaderResourceGroup().get());
  149. SetPackedTexturesToSrg(view);
  150. }
  151. }
  152. void DecalTextureArrayFeatureProcessor::SetDecalData(const DecalHandle handle, const DecalData& data)
  153. {
  154. if (handle.IsValid())
  155. {
  156. m_decalData.GetData(handle.GetIndex()) = data;
  157. m_deviceBufferNeedsUpdate = true;
  158. }
  159. else
  160. {
  161. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalData().");
  162. }
  163. }
  164. const Data::Instance<RPI::Buffer> DecalTextureArrayFeatureProcessor::GetDecalBuffer() const
  165. {
  166. return m_decalBufferHandler.GetBuffer();
  167. }
  168. uint32_t DecalTextureArrayFeatureProcessor::GetDecalCount() const
  169. {
  170. return m_decalBufferHandler.GetElementCount();
  171. }
  172. void DecalTextureArrayFeatureProcessor::SetDecalPosition(const DecalHandle handle, const AZ::Vector3& position)
  173. {
  174. if (handle.IsValid())
  175. {
  176. AZStd::array<float, 3>& writePos = m_decalData.GetData(handle.GetIndex()).m_position;
  177. position.StoreToFloat3(writePos.data());
  178. m_deviceBufferNeedsUpdate = true;
  179. }
  180. else
  181. {
  182. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalPosition().");
  183. }
  184. }
  185. void DecalTextureArrayFeatureProcessor::SetDecalOrientation(DecalHandle handle, const AZ::Quaternion& orientation)
  186. {
  187. if (handle.IsValid())
  188. {
  189. orientation.StoreToFloat4(m_decalData.GetData(handle.GetIndex()).m_quaternion.data());
  190. m_deviceBufferNeedsUpdate = true;
  191. }
  192. else
  193. {
  194. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOrientation().");
  195. }
  196. }
  197. void DecalTextureArrayFeatureProcessor::SetDecalHalfSize(DecalHandle handle, const Vector3& halfSize)
  198. {
  199. if (handle.IsValid())
  200. {
  201. halfSize.StoreToFloat3(m_decalData.GetData(handle.GetIndex()).m_halfSize.data());
  202. m_deviceBufferNeedsUpdate = true;
  203. }
  204. else
  205. {
  206. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalHalfSize().");
  207. }
  208. }
  209. void DecalTextureArrayFeatureProcessor::SetDecalAttenuationAngle(const DecalHandle handle, float angleAttenuation)
  210. {
  211. if (handle.IsValid())
  212. {
  213. m_decalData.GetData(handle.GetIndex()).m_angleAttenuation = angleAttenuation;
  214. m_deviceBufferNeedsUpdate = true;
  215. }
  216. else
  217. {
  218. AZ_Warning("DecalTextureArrayFeatureProcessor", handle.IsValid(), "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalAttenuationAngle().");
  219. }
  220. }
  221. void DecalTextureArrayFeatureProcessor::SetDecalOpacity(const DecalHandle handle, float opacity)
  222. {
  223. if (handle.IsValid())
  224. {
  225. m_decalData.GetData(handle.GetIndex()).m_opacity = opacity;
  226. m_deviceBufferNeedsUpdate = true;
  227. }
  228. else
  229. {
  230. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOpacity().");
  231. }
  232. }
  233. void DecalTextureArrayFeatureProcessor::SetDecalNormalMapOpacity(const DecalHandle handle, float opacity)
  234. {
  235. if (handle.IsValid())
  236. {
  237. m_decalData.GetData(handle.GetIndex()).m_normalMapOpacity = opacity;
  238. m_deviceBufferNeedsUpdate = true;
  239. }
  240. else
  241. {
  242. AZ_Warning(
  243. "DecalTextureArrayFeatureProcessor", false,
  244. "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOpacity().");
  245. }
  246. }
  247. void DecalTextureArrayFeatureProcessor::SetDecalSortKey(DecalHandle handle, uint8_t sortKey)
  248. {
  249. if (handle.IsValid())
  250. {
  251. m_decalData.GetData(handle.GetIndex()).m_sortKey = sortKey;
  252. m_deviceBufferNeedsUpdate = true;
  253. }
  254. else
  255. {
  256. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalSortKey().");
  257. }
  258. }
  259. void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world)
  260. {
  261. SetDecalTransform(handle, world, AZ::Vector3::CreateOne());
  262. }
  263. void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world,
  264. const AZ::Vector3& nonUniformScale)
  265. {
  266. if (handle.IsValid())
  267. {
  268. SetDecalHalfSize(handle, nonUniformScale * world.GetUniformScale());
  269. SetDecalPosition(handle, world.GetTranslation());
  270. SetDecalOrientation(handle, world.GetRotation());
  271. m_deviceBufferNeedsUpdate = true;
  272. }
  273. else
  274. {
  275. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalTransform().");
  276. }
  277. }
  278. void DecalTextureArrayFeatureProcessor::SetDecalMaterial(const DecalHandle handle, const AZ::Data::AssetId material)
  279. {
  280. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: SetDecalMaterial");
  281. if (handle.IsNull())
  282. {
  283. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalMaterial().");
  284. return;
  285. }
  286. if (GetMaterialUsedByDecal(handle) == material)
  287. {
  288. return;
  289. }
  290. const auto decalIndex = handle.GetIndex();
  291. const bool isValidMaterialBeingUsedCurrently = m_decalData.GetData(decalIndex).m_textureArrayIndex != DecalData::UnusedIndex;
  292. if (isValidMaterialBeingUsedCurrently)
  293. {
  294. RemoveMaterialFromDecal(decalIndex);
  295. }
  296. if (!material.IsValid())
  297. {
  298. return;
  299. }
  300. const auto iter = m_materialToTextureArrayLookupTable.find(material);
  301. if (iter != m_materialToTextureArrayLookupTable.end())
  302. {
  303. // This material is already loaded and registered with this feature processor
  304. iter->second.m_useCount++;
  305. SetDecalTextureLocation(handle, iter->second.m_location);
  306. return;
  307. }
  308. // Material not loaded so queue it up for loading.
  309. QueueMaterialLoadForDecal(material, handle);
  310. }
  311. void DecalTextureArrayFeatureProcessor::RemoveMaterialFromDecal(const uint16_t decalIndex)
  312. {
  313. auto& decalData = m_decalData.GetData(decalIndex);
  314. DecalLocation decalLocation;
  315. decalLocation.textureArrayIndex = decalData.m_textureArrayIndex;
  316. decalLocation.textureIndex = decalData.m_textureIndex;
  317. RemoveDecalFromTextureArrays(decalLocation);
  318. decalData.m_textureArrayIndex = DecalData::UnusedIndex;
  319. decalData.m_textureIndex = DecalData::UnusedIndex;
  320. m_deviceBufferNeedsUpdate = true;
  321. }
  322. void DecalTextureArrayFeatureProcessor::CacheShaderIndices()
  323. {
  324. // The azsl shader should define several texture arrays such as:
  325. // Texture2DArray<float4> m_decalTextureArrayDiffuse0;
  326. // Texture2DArray<float4> m_decalTextureArrayDiffuse1;
  327. // Texture2DArray<float4> m_decalTextureArrayDiffuse2;
  328. // and
  329. // Texture2DArray<float2> m_decalTextureArrayNormalMaps0;
  330. // Texture2DArray<float2> m_decalTextureArrayNormalMaps1;
  331. // Texture2DArray<float2> m_decalTextureArrayNormalMaps2;
  332. static constexpr AZStd::array<AZStd::string_view, DecalMapType_Num> ShaderNames = { "m_decalTextureArrayDiffuse",
  333. "m_decalTextureArrayNormalMaps" };
  334. for (int mapType = 0; mapType < DecalMapType_Num; ++mapType)
  335. {
  336. for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx)
  337. {
  338. const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
  339. const AZStd::string baseName = AZStd::string(ShaderNames[mapType]) + AZStd::to_string(texArrayIdx);
  340. m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str()));
  341. AZ_Warning(
  342. "DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[texArrayIdx][mapType].IsValid(),
  343. "Unable to find %s in decal shader.",
  344. baseName.c_str());
  345. }
  346. }
  347. }
  348. AZStd::optional<AZ::Render::DecalTextureArrayFeatureProcessor::DecalLocation> DecalTextureArrayFeatureProcessor::AddMaterialToTextureArrays(AZ::RPI::MaterialAsset* materialAsset)
  349. {
  350. const RHI::Size textureSize = GetTextureSizeFromMaterialAsset(materialAsset);
  351. int textureArrayIndex = FindTextureArrayWithSize(textureSize);
  352. const bool wasExistingTextureArrayFoundForGivenSize = textureArrayIndex != -1;
  353. if (m_textureArrayList.size() == NumTextureArrays && !wasExistingTextureArrayFoundForGivenSize)
  354. {
  355. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Unable to add decal with size %u %u. There are no more texture arrays left to accept a decal with this size permutation.", textureSize.m_width, textureSize.m_height);
  356. return AZStd::nullopt;
  357. }
  358. int textureIndex;
  359. if (!wasExistingTextureArrayFoundForGivenSize)
  360. {
  361. DecalTextureArray decalTextureArray;
  362. textureIndex = decalTextureArray.AddMaterial(materialAsset->GetId());
  363. textureArrayIndex = m_textureArrayList.push_front(AZStd::make_pair(textureSize, decalTextureArray));
  364. }
  365. else
  366. {
  367. textureIndex = m_textureArrayList[textureArrayIndex].second.AddMaterial(materialAsset->GetId());
  368. }
  369. DecalLocation result;
  370. result.textureArrayIndex = textureArrayIndex;
  371. result.textureIndex = textureIndex;
  372. return result;
  373. }
  374. void DecalTextureArrayFeatureProcessor::OnAssetReady(const Data::Asset<Data::AssetData> asset)
  375. {
  376. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: OnAssetReady");
  377. const Data::AssetId& assetId = asset->GetId();
  378. const auto decalsThatUseThisMaterial = m_materialLoadTracker.GetHandlesByAsset(assetId);
  379. m_materialLoadTracker.RemoveAllHandlesWithAsset(assetId);
  380. SetMaterialToDecals(asset.GetAs<AZ::RPI::MaterialAsset>(), decalsThatUseThisMaterial);
  381. AZ::Data::AssetBus::MultiHandler::BusDisconnect(assetId);
  382. }
  383. void DecalTextureArrayFeatureProcessor::SetDecalTextureLocation(const DecalHandle& handle, const DecalLocation location)
  384. {
  385. AZ_Assert(handle.IsValid(), "SetDecalTextureLocation called with invalid handle");
  386. m_decalData.GetData(handle.GetIndex()).m_textureArrayIndex = location.textureArrayIndex;
  387. m_decalData.GetData(handle.GetIndex()).m_textureIndex = location.textureIndex;
  388. m_deviceBufferNeedsUpdate = true;
  389. }
  390. void DecalTextureArrayFeatureProcessor::SetPackedTexturesToSrg(const RPI::ViewPtr& view)
  391. {
  392. int iter = m_textureArrayList.begin();
  393. while (iter != -1)
  394. {
  395. for (int mapType = 0 ; mapType < DecalMapType_Num ; ++mapType)
  396. {
  397. const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(aznumeric_cast<DecalMapType>(mapType));
  398. view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter][mapType], packedTexture);
  399. }
  400. iter = m_textureArrayList.next(iter);
  401. }
  402. }
  403. int DecalTextureArrayFeatureProcessor::FindTextureArrayWithSize(const RHI::Size& size) const
  404. {
  405. int iter = m_textureArrayList.begin();
  406. while (iter != -1)
  407. {
  408. if (m_textureArrayList[iter].first == size)
  409. {
  410. return iter;
  411. }
  412. iter = m_textureArrayList.next(iter);
  413. }
  414. return -1;
  415. }
  416. bool DecalTextureArrayFeatureProcessor::RemoveDecalFromTextureArrays(const DecalLocation decalLocation)
  417. {
  418. if (decalLocation.textureArrayIndex != DecalData::UnusedIndex)
  419. {
  420. auto& textureArray = m_textureArrayList[decalLocation.textureArrayIndex].second;
  421. const AZ::Data::AssetId material = textureArray.GetMaterialAssetId(decalLocation.textureIndex);
  422. auto iter = m_materialToTextureArrayLookupTable.find(material);
  423. AZ_Assert(iter != m_materialToTextureArrayLookupTable.end(), "Bad state");
  424. DecalLocationAndUseCount& decalInformation = iter->second;
  425. decalInformation.m_useCount--;
  426. if (decalInformation.m_useCount == 0)
  427. {
  428. m_materialToTextureArrayLookupTable.erase(iter);
  429. textureArray.RemoveMaterial(decalLocation.textureIndex);
  430. }
  431. if (textureArray.NumMaterials() == 0)
  432. {
  433. m_textureArrayList.erase(decalLocation.textureArrayIndex);
  434. }
  435. }
  436. return false;
  437. }
  438. void DecalTextureArrayFeatureProcessor::PackTexureArrays()
  439. {
  440. int iter = m_textureArrayList.begin();
  441. while (iter != -1)
  442. {
  443. m_textureArrayList[iter].second.Pack();
  444. iter = m_textureArrayList.next(iter);
  445. }
  446. }
  447. AZ::Data::AssetId DecalTextureArrayFeatureProcessor::GetMaterialUsedByDecal(const DecalHandle handle) const
  448. {
  449. AZ::Data::AssetId material;
  450. if (handle.IsValid())
  451. {
  452. const DecalData& decalData = m_decalData.GetData(handle.GetIndex());
  453. if (decalData.m_textureArrayIndex != DecalData::UnusedIndex)
  454. {
  455. const DecalTextureArray& textureArray = m_textureArrayList[decalData.m_textureArrayIndex].second;
  456. material = textureArray.GetMaterialAssetId(decalData.m_textureIndex);
  457. }
  458. }
  459. return material;
  460. }
  461. void DecalTextureArrayFeatureProcessor::QueueMaterialLoadForDecal(const AZ::Data::AssetId materialId, const DecalHandle handle)
  462. {
  463. const auto materialAsset = QueueMaterialAssetLoad(materialId);
  464. if (materialAsset.IsLoading())
  465. {
  466. m_materialLoadTracker.TrackAssetLoad(handle, materialAsset);
  467. AZ::Data::AssetBus::MultiHandler::BusConnect(materialId);
  468. }
  469. else if (materialAsset.IsReady())
  470. {
  471. SetMaterialToDecals(materialAsset.GetAs<AZ::RPI::MaterialAsset>(), { handle });
  472. }
  473. else if (materialAsset.IsError())
  474. {
  475. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Unable to load material for decal. Asset ID: %s", materialId.ToString<AZStd::string>().c_str());
  476. }
  477. else
  478. {
  479. AZ_Assert(false, "DecalTextureArrayFeatureProcessor::QueueMaterialLoadForDecal is in an unhandled state.");
  480. }
  481. }
  482. void DecalTextureArrayFeatureProcessor::SetMaterialToDecals(
  483. RPI::MaterialAsset* materialAsset, const AZStd::vector<DecalHandle>& decalsThatUseThisMaterial)
  484. {
  485. if (!materialAsset)
  486. {
  487. return;
  488. }
  489. const Data::AssetId& assetId = materialAsset->GetId();
  490. const bool validDecalMaterial = materialAsset && DecalTextureArray::IsValidDecalMaterial(*materialAsset);
  491. if (validDecalMaterial)
  492. {
  493. const auto& decalLocation = AddMaterialToTextureArrays(materialAsset);
  494. if (decalLocation)
  495. {
  496. for (const auto& decal : decalsThatUseThisMaterial)
  497. {
  498. m_materialToTextureArrayLookupTable[assetId].m_useCount++;
  499. SetDecalTextureLocation(decal, *decalLocation);
  500. }
  501. m_materialToTextureArrayLookupTable[assetId].m_location = *decalLocation;
  502. }
  503. }
  504. else
  505. {
  506. AZ_Warning(
  507. "DecalTextureArrayFeatureProcessor",
  508. false,
  509. "DecalTextureArray::IsValidDecalMaterial() failed, unable to add this material to the decal");
  510. }
  511. if (!m_materialLoadTracker.AreAnyLoadsInFlight())
  512. {
  513. PackTexureArrays();
  514. }
  515. }
  516. } // namespace Render
  517. } // namespace AZ