3
0

DecalTextureArrayFeatureProcessor.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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/Feature/CoreLights/LightCommon.h>
  10. #include <Atom/Feature/Mesh/MeshCommon.h>
  11. #include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
  12. #include <Atom/RHI/Factory.h>
  13. #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
  14. #include <Atom/RPI.Public/RPISystemInterface.h>
  15. #include <Atom/RPI.Public/Material/Material.h>
  16. #include <Atom/RPI.Public/RenderPipeline.h>
  17. #include <Atom/RPI.Public/Scene.h>
  18. #include <Atom/RPI.Public/View.h>
  19. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  20. #include <Atom/RPI.Reflect/Image/StreamingImageAssetHandler.h>
  21. #include <AtomCore/Instance/InstanceDatabase.h>
  22. #include <AzCore/Math/Frustum.h>
  23. #include <AzCore/Math/Quaternion.h>
  24. #include <AzCore/Math/ShapeIntersection.h>
  25. #include <AzCore/std/containers/span.h>
  26. #include <numeric>
  27. //! If modified, ensure that r_maxVisibleDecals is equal to or lower than ENABLE_DECALS_CAP which is the limit set by the shader on GPU.
  28. AZ_CVAR(int, r_maxVisibleDecals, -1, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Maximum number of visible decals to use when culling is not available. -1 means no limit");
  29. namespace AZ
  30. {
  31. namespace Render
  32. {
  33. namespace
  34. {
  35. static AZ::RHI::Size GetTextureSizeFromMaterialAsset(AZ::RPI::MaterialAsset* materialAsset)
  36. {
  37. for (const auto& elem : materialAsset->GetPropertyValues())
  38. {
  39. if (elem.Is<Data::Asset<RPI::ImageAsset>>())
  40. {
  41. const auto& imageBinding = elem.GetValue<Data::Asset<RPI::ImageAsset>>();
  42. if (imageBinding && imageBinding.IsReady())
  43. {
  44. return imageBinding->GetImageDescriptor().m_size;
  45. }
  46. }
  47. }
  48. AZ_Error(
  49. "DecalTextureFeatureProcessor",
  50. false,
  51. "GetSizeFromMaterial() unable to load image in material ID '%s'",
  52. materialAsset->GetId().ToString<AZStd::string>().c_str()
  53. );
  54. return {};
  55. }
  56. static AZ::Data::Asset<AZ::RPI::MaterialAsset> QueueMaterialAssetLoad(const AZ::Data::AssetId material)
  57. {
  58. auto asset = AZ::Data::AssetManager::Instance().GetAsset<AZ::RPI::MaterialAsset>(material, AZ::Data::AssetLoadBehavior::QueueLoad);
  59. return asset;
  60. }
  61. }
  62. void DecalTextureArrayFeatureProcessor::Reflect(ReflectContext* context)
  63. {
  64. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  65. {
  66. serializeContext
  67. ->Class<DecalTextureArrayFeatureProcessor, RPI::FeatureProcessor>()
  68. ->Version(0);
  69. }
  70. }
  71. void DecalTextureArrayFeatureProcessor::Activate()
  72. {
  73. GpuBufferHandler::Descriptor desc;
  74. desc.m_bufferName = "DecalBuffer";
  75. desc.m_bufferSrgName = "m_decals";
  76. desc.m_elementCountSrgName = "m_decalCount";
  77. desc.m_elementSize = sizeof(DecalData);
  78. desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
  79. m_decalBufferHandler = GpuBufferHandler(desc);
  80. CacheShaderIndices();
  81. EnableSceneNotification();
  82. }
  83. void DecalTextureArrayFeatureProcessor::Deactivate()
  84. {
  85. DisableSceneNotification();
  86. AZ::Data::AssetBus::MultiHandler::BusDisconnect();
  87. m_decalData.Clear();
  88. m_decalBufferHandler.Release();
  89. for (auto& handler : m_visibleDecalBufferHandlers)
  90. {
  91. handler.Release();
  92. }
  93. m_visibleDecalBufferHandlers.clear();
  94. }
  95. DecalTextureArrayFeatureProcessor::DecalHandle DecalTextureArrayFeatureProcessor::AcquireDecal()
  96. {
  97. const uint16_t id = m_decalData.GetFreeSlotIndex();
  98. if (id == IndexedDataVector<DecalData>::NoFreeSlot)
  99. {
  100. return DecalHandle(DecalHandle::NullIndex);
  101. }
  102. else
  103. {
  104. m_deviceBufferNeedsUpdate = true;
  105. DecalData& decalData = m_decalData.GetData<0>(id);
  106. decalData.m_textureArrayIndex = DecalData::UnusedIndex;
  107. return DecalHandle(id);
  108. }
  109. }
  110. bool DecalTextureArrayFeatureProcessor::ReleaseDecal(const DecalHandle decal)
  111. {
  112. if (decal.IsValid())
  113. {
  114. if (m_materialLoadTracker.IsAssetLoading(decal))
  115. {
  116. m_materialLoadTracker.RemoveHandle(decal);
  117. }
  118. DecalLocation decalLocation;
  119. decalLocation.textureArrayIndex = m_decalData.GetData<0>(decal.GetIndex()).m_textureArrayIndex;
  120. decalLocation.textureIndex = m_decalData.GetData<0>(decal.GetIndex()).m_textureIndex;
  121. RemoveDecalFromTextureArrays(decalLocation);
  122. m_decalData.RemoveIndex(decal.GetIndex());
  123. m_deviceBufferNeedsUpdate = true;
  124. return true;
  125. }
  126. return false;
  127. }
  128. DecalTextureArrayFeatureProcessor::DecalHandle DecalTextureArrayFeatureProcessor::CloneDecal(const DecalHandle sourceDecal)
  129. {
  130. AZ_Assert(sourceDecal.IsValid(), "Invalid DecalHandle passed to DecalTextureArrayFeatureProcessor::CloneDecal().");
  131. const DecalHandle decal = AcquireDecal();
  132. if (decal.IsValid())
  133. {
  134. m_decalData.GetData<0>(decal.GetIndex()) = m_decalData.GetData<0>(sourceDecal.GetIndex());
  135. const auto materialAsset = GetMaterialUsedByDecal(sourceDecal);
  136. if (materialAsset.IsValid())
  137. {
  138. m_materialToTextureArrayLookupTable.at(materialAsset).m_useCount++;
  139. }
  140. else
  141. {
  142. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "CloneDecal called on a decal with no material set.");
  143. }
  144. m_deviceBufferNeedsUpdate = true;
  145. }
  146. return decal;
  147. }
  148. void DecalTextureArrayFeatureProcessor::Simulate(const RPI::FeatureProcessor::SimulatePacket& packet)
  149. {
  150. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Simulate");
  151. AZ_UNUSED(packet);
  152. if (m_deviceBufferNeedsUpdate)
  153. {
  154. m_decalBufferHandler.UpdateBuffer(m_decalData.GetDataVector<0>());
  155. m_deviceBufferNeedsUpdate = false;
  156. }
  157. if (r_enablePerMeshShaderOptionFlags)
  158. {
  159. auto decalFilter = [&](const AZ::Aabb& aabb) -> bool
  160. {
  161. DecalHandle::IndexType index = m_decalData.GetIndexForData<1>(&aabb);
  162. return index != IndexedDataVector<int>::NoFreeSlot;
  163. };
  164. // Mark meshes that have decals
  165. MeshCommon::MarkMeshesWithFlag(
  166. GetParentScene(), AZStd::span(m_decalData.GetDataVector<1>()), m_decalMeshFlag.GetIndex(), decalFilter);
  167. }
  168. }
  169. void DecalTextureArrayFeatureProcessor::Render(const RPI::FeatureProcessor::RenderPacket& packet)
  170. {
  171. // Note that decals are rendered as part of the forward shading pipeline. We only need to bind the decal buffers/textures in here.
  172. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: Render");
  173. m_visibleDecalBufferUsedCount = 0;
  174. for (const RPI::ViewPtr& view : packet.m_views)
  175. {
  176. m_decalBufferHandler.UpdateSrg(view->GetShaderResourceGroup().get());
  177. SetPackedTexturesToSrg(view);
  178. CullDecals(view);
  179. }
  180. }
  181. void DecalTextureArrayFeatureProcessor::SetDecalData(const DecalHandle handle, const DecalData& data)
  182. {
  183. if (handle.IsValid())
  184. {
  185. m_decalData.GetData<0>(handle.GetIndex()) = data;
  186. m_deviceBufferNeedsUpdate = true;
  187. }
  188. else
  189. {
  190. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalData().");
  191. }
  192. }
  193. const Data::Instance<RPI::Buffer> DecalTextureArrayFeatureProcessor::GetDecalBuffer() const
  194. {
  195. return m_decalBufferHandler.GetBuffer();
  196. }
  197. uint32_t DecalTextureArrayFeatureProcessor::GetDecalCount() const
  198. {
  199. return m_decalBufferHandler.GetElementCount();
  200. }
  201. void DecalTextureArrayFeatureProcessor::SetDecalPosition(const DecalHandle handle, const AZ::Vector3& position)
  202. {
  203. if (handle.IsValid())
  204. {
  205. AZStd::array<float, 3>& writePos = m_decalData.GetData<0>(handle.GetIndex()).m_position;
  206. position.StoreToFloat3(writePos.data());
  207. UpdateBounds(handle);
  208. m_deviceBufferNeedsUpdate = true;
  209. }
  210. else
  211. {
  212. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalPosition().");
  213. }
  214. }
  215. void DecalTextureArrayFeatureProcessor::SetDecalOrientation(DecalHandle handle, const AZ::Quaternion& orientation)
  216. {
  217. if (handle.IsValid())
  218. {
  219. orientation.StoreToFloat4(m_decalData.GetData<0>(handle.GetIndex()).m_quaternion.data());
  220. m_deviceBufferNeedsUpdate = true;
  221. }
  222. else
  223. {
  224. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOrientation().");
  225. }
  226. }
  227. void DecalTextureArrayFeatureProcessor::SetDecalColor(const DecalHandle handle, const AZ::Vector3& color)
  228. {
  229. if (handle.IsValid())
  230. {
  231. AZStd::array<float, 3>& writeColor = m_decalData.GetData<0>(handle.GetIndex()).m_decalColor;
  232. color.StoreToFloat3(writeColor.data());
  233. m_deviceBufferNeedsUpdate = true;
  234. }
  235. else
  236. {
  237. AZ_Warning(
  238. "DecalTextureArrayFeatureProcessor",
  239. false,
  240. "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalColor().");
  241. }
  242. }
  243. void DecalTextureArrayFeatureProcessor::SetDecalColorFactor(const DecalHandle handle, float colorFactor)
  244. {
  245. if (handle.IsValid())
  246. {
  247. m_decalData.GetData<0>(handle.GetIndex()).m_decalColorFactor = colorFactor;
  248. m_deviceBufferNeedsUpdate = true;
  249. }
  250. else
  251. {
  252. AZ_Warning(
  253. "DecalTextureArrayFeatureProcessor",
  254. false,
  255. "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalColorFactor().");
  256. }
  257. }
  258. void DecalTextureArrayFeatureProcessor::SetDecalHalfSize(DecalHandle handle, const Vector3& halfSize)
  259. {
  260. if (handle.IsValid())
  261. {
  262. halfSize.StoreToFloat3(m_decalData.GetData<0>(handle.GetIndex()).m_halfSize.data());
  263. UpdateBounds(handle);
  264. m_deviceBufferNeedsUpdate = true;
  265. }
  266. else
  267. {
  268. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalHalfSize().");
  269. }
  270. }
  271. void DecalTextureArrayFeatureProcessor::SetDecalAttenuationAngle(const DecalHandle handle, float angleAttenuation)
  272. {
  273. if (handle.IsValid())
  274. {
  275. m_decalData.GetData<0>(handle.GetIndex()).m_angleAttenuation = angleAttenuation;
  276. m_deviceBufferNeedsUpdate = true;
  277. }
  278. else
  279. {
  280. AZ_Warning("DecalTextureArrayFeatureProcessor", handle.IsValid(), "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalAttenuationAngle().");
  281. }
  282. }
  283. void DecalTextureArrayFeatureProcessor::SetDecalOpacity(const DecalHandle handle, float opacity)
  284. {
  285. if (handle.IsValid())
  286. {
  287. m_decalData.GetData<0>(handle.GetIndex()).m_opacity = opacity;
  288. m_deviceBufferNeedsUpdate = true;
  289. }
  290. else
  291. {
  292. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOpacity().");
  293. }
  294. }
  295. void DecalTextureArrayFeatureProcessor::SetDecalNormalMapOpacity(const DecalHandle handle, float opacity)
  296. {
  297. if (handle.IsValid())
  298. {
  299. m_decalData.GetData<0>(handle.GetIndex()).m_normalMapOpacity = opacity;
  300. m_deviceBufferNeedsUpdate = true;
  301. }
  302. else
  303. {
  304. AZ_Warning(
  305. "DecalTextureArrayFeatureProcessor", false,
  306. "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalOpacity().");
  307. }
  308. }
  309. void DecalTextureArrayFeatureProcessor::SetDecalSortKey(DecalHandle handle, uint8_t sortKey)
  310. {
  311. if (handle.IsValid())
  312. {
  313. m_decalData.GetData<0>(handle.GetIndex()).m_sortKey = sortKey;
  314. m_deviceBufferNeedsUpdate = true;
  315. }
  316. else
  317. {
  318. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalSortKey().");
  319. }
  320. }
  321. void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world)
  322. {
  323. SetDecalTransform(handle, world, AZ::Vector3::CreateOne());
  324. }
  325. void DecalTextureArrayFeatureProcessor::SetDecalTransform(DecalHandle handle, const AZ::Transform& world,
  326. const AZ::Vector3& nonUniformScale)
  327. {
  328. if (handle.IsValid())
  329. {
  330. SetDecalHalfSize(handle, nonUniformScale * world.GetUniformScale());
  331. SetDecalPosition(handle, world.GetTranslation());
  332. SetDecalOrientation(handle, world.GetRotation());
  333. m_deviceBufferNeedsUpdate = true;
  334. }
  335. else
  336. {
  337. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalTransform().");
  338. }
  339. }
  340. void DecalTextureArrayFeatureProcessor::SetDecalMaterial(const DecalHandle handle, const AZ::Data::AssetId material)
  341. {
  342. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: SetDecalMaterial");
  343. if (handle.IsNull())
  344. {
  345. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Invalid handle passed to DecalTextureArrayFeatureProcessor::SetDecalMaterial().");
  346. return;
  347. }
  348. if (GetMaterialUsedByDecal(handle) == material)
  349. {
  350. return;
  351. }
  352. const auto decalIndex = handle.GetIndex();
  353. const bool isValidMaterialBeingUsedCurrently = m_decalData.GetData<0>(decalIndex).m_textureArrayIndex != DecalData::UnusedIndex;
  354. if (isValidMaterialBeingUsedCurrently)
  355. {
  356. RemoveMaterialFromDecal(decalIndex);
  357. }
  358. if (!material.IsValid())
  359. {
  360. return;
  361. }
  362. const auto iter = m_materialToTextureArrayLookupTable.find(material);
  363. if (iter != m_materialToTextureArrayLookupTable.end())
  364. {
  365. // This material is already loaded and registered with this feature processor
  366. iter->second.m_useCount++;
  367. SetDecalTextureLocation(handle, iter->second.m_location);
  368. return;
  369. }
  370. // Material not loaded so queue it up for loading.
  371. QueueMaterialLoadForDecal(material, handle);
  372. }
  373. void DecalTextureArrayFeatureProcessor::OnRenderPipelinePersistentViewChanged(
  374. RPI::RenderPipeline* renderPipeline, [[maybe_unused]] RPI::PipelineViewTag viewTag, RPI::ViewPtr newView, RPI::ViewPtr previousView)
  375. {
  376. Render::LightCommon::CacheCPUCulledPipelineInfo(renderPipeline, newView, previousView, m_cpuCulledPipelinesPerView);
  377. }
  378. void DecalTextureArrayFeatureProcessor::RemoveMaterialFromDecal(const uint16_t decalIndex)
  379. {
  380. auto& decalData = m_decalData.GetData<0>(decalIndex);
  381. DecalLocation decalLocation;
  382. decalLocation.textureArrayIndex = decalData.m_textureArrayIndex;
  383. decalLocation.textureIndex = decalData.m_textureIndex;
  384. RemoveDecalFromTextureArrays(decalLocation);
  385. decalData.m_textureArrayIndex = DecalData::UnusedIndex;
  386. decalData.m_textureIndex = DecalData::UnusedIndex;
  387. m_deviceBufferNeedsUpdate = true;
  388. }
  389. void DecalTextureArrayFeatureProcessor::CacheShaderIndices()
  390. {
  391. // The azsl shader should define several texture arrays such as:
  392. // Texture2DArray<float4> m_decalTextureArrayDiffuse0;
  393. // Texture2DArray<float4> m_decalTextureArrayDiffuse1;
  394. // Texture2DArray<float4> m_decalTextureArrayDiffuse2;
  395. // and
  396. // Texture2DArray<float2> m_decalTextureArrayNormalMaps0;
  397. // Texture2DArray<float2> m_decalTextureArrayNormalMaps1;
  398. // Texture2DArray<float2> m_decalTextureArrayNormalMaps2;
  399. static constexpr AZStd::array<AZStd::string_view, DecalMapType_Num> ShaderNames = { "m_decalTextureArrayDiffuse",
  400. "m_decalTextureArrayNormalMaps" };
  401. const RHI::ShaderResourceGroupLayout* viewSrgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
  402. for (int mapType = 0; mapType < DecalMapType_Num; ++mapType)
  403. {
  404. for (int texArrayIdx = 0; texArrayIdx < NumTextureArrays; ++texArrayIdx)
  405. {
  406. const AZStd::string baseName = AZStd::string(ShaderNames[mapType]) + AZStd::to_string(texArrayIdx);
  407. m_decalTextureArrayIndices[texArrayIdx][mapType] = viewSrgLayout->FindShaderInputImageIndex(Name(baseName.c_str()));
  408. AZ_Warning(
  409. "DecalTextureArrayFeatureProcessor", m_decalTextureArrayIndices[texArrayIdx][mapType].IsValid(),
  410. "Unable to find %s in decal shader.",
  411. baseName.c_str());
  412. }
  413. }
  414. MeshFeatureProcessor* meshFeatureProcessor = GetParentScene()->GetFeatureProcessor<MeshFeatureProcessor>();
  415. if (meshFeatureProcessor)
  416. {
  417. m_decalMeshFlag = meshFeatureProcessor->GetShaderOptionFlagRegistry()->AcquireTag(AZ::Name("o_enableDecals"));
  418. }
  419. }
  420. AZStd::optional<AZ::Render::DecalTextureArrayFeatureProcessor::DecalLocation> DecalTextureArrayFeatureProcessor::AddMaterialToTextureArrays(AZ::RPI::MaterialAsset* materialAsset)
  421. {
  422. const RHI::Size textureSize = GetTextureSizeFromMaterialAsset(materialAsset);
  423. int textureArrayIndex = FindTextureArrayWithSize(textureSize);
  424. const bool wasExistingTextureArrayFoundForGivenSize = textureArrayIndex != -1;
  425. if (m_textureArrayList.size() == NumTextureArrays && !wasExistingTextureArrayFoundForGivenSize)
  426. {
  427. 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);
  428. return AZStd::nullopt;
  429. }
  430. int textureIndex;
  431. if (!wasExistingTextureArrayFoundForGivenSize)
  432. {
  433. DecalTextureArray decalTextureArray;
  434. textureIndex = decalTextureArray.AddMaterial(materialAsset->GetId());
  435. textureArrayIndex = m_textureArrayList.push_front(AZStd::make_pair(textureSize, decalTextureArray));
  436. }
  437. else
  438. {
  439. textureIndex = m_textureArrayList[textureArrayIndex].second.AddMaterial(materialAsset->GetId());
  440. }
  441. DecalLocation result;
  442. result.textureArrayIndex = textureArrayIndex;
  443. result.textureIndex = textureIndex;
  444. return result;
  445. }
  446. void DecalTextureArrayFeatureProcessor::OnAssetReady(const Data::Asset<Data::AssetData> asset)
  447. {
  448. AZ_PROFILE_SCOPE(AzRender, "DecalTextureArrayFeatureProcessor: OnAssetReady");
  449. const Data::AssetId& assetId = asset->GetId();
  450. const auto decalsThatUseThisMaterial = m_materialLoadTracker.GetHandlesByAsset(assetId);
  451. m_materialLoadTracker.RemoveAllHandlesWithAsset(assetId);
  452. SetMaterialToDecals(asset.GetAs<AZ::RPI::MaterialAsset>(), decalsThatUseThisMaterial);
  453. AZ::Data::AssetBus::MultiHandler::BusDisconnect(assetId);
  454. }
  455. void DecalTextureArrayFeatureProcessor::SetDecalTextureLocation(const DecalHandle& handle, const DecalLocation location)
  456. {
  457. AZ_Assert(handle.IsValid(), "SetDecalTextureLocation called with invalid handle");
  458. m_decalData.GetData<0>(handle.GetIndex()).m_textureArrayIndex = location.textureArrayIndex;
  459. m_decalData.GetData<0>(handle.GetIndex()).m_textureIndex = location.textureIndex;
  460. m_deviceBufferNeedsUpdate = true;
  461. }
  462. void DecalTextureArrayFeatureProcessor::SetPackedTexturesToSrg(const RPI::ViewPtr& view)
  463. {
  464. int iter = m_textureArrayList.begin();
  465. while (iter != -1)
  466. {
  467. for (int mapType = 0 ; mapType < DecalMapType_Num ; ++mapType)
  468. {
  469. const auto& packedTexture = m_textureArrayList[iter].second.GetPackedTexture(aznumeric_cast<DecalMapType>(mapType));
  470. view->GetShaderResourceGroup()->SetImage(m_decalTextureArrayIndices[iter][mapType], packedTexture);
  471. }
  472. iter = m_textureArrayList.next(iter);
  473. }
  474. }
  475. int DecalTextureArrayFeatureProcessor::FindTextureArrayWithSize(const RHI::Size& size) const
  476. {
  477. int iter = m_textureArrayList.begin();
  478. while (iter != -1)
  479. {
  480. if (m_textureArrayList[iter].first == size)
  481. {
  482. return iter;
  483. }
  484. iter = m_textureArrayList.next(iter);
  485. }
  486. return -1;
  487. }
  488. bool DecalTextureArrayFeatureProcessor::RemoveDecalFromTextureArrays(const DecalLocation decalLocation)
  489. {
  490. if (decalLocation.textureArrayIndex != DecalData::UnusedIndex)
  491. {
  492. auto& textureArray = m_textureArrayList[decalLocation.textureArrayIndex].second;
  493. const AZ::Data::AssetId material = textureArray.GetMaterialAssetId(decalLocation.textureIndex);
  494. auto iter = m_materialToTextureArrayLookupTable.find(material);
  495. AZ_Assert(iter != m_materialToTextureArrayLookupTable.end(), "Bad state");
  496. DecalLocationAndUseCount& decalInformation = iter->second;
  497. decalInformation.m_useCount--;
  498. if (decalInformation.m_useCount == 0)
  499. {
  500. m_materialToTextureArrayLookupTable.erase(iter);
  501. textureArray.RemoveMaterial(decalLocation.textureIndex);
  502. }
  503. if (textureArray.NumMaterials() == 0)
  504. {
  505. m_textureArrayList.erase(decalLocation.textureArrayIndex);
  506. }
  507. }
  508. return false;
  509. }
  510. void DecalTextureArrayFeatureProcessor::PackTexureArrays()
  511. {
  512. int iter = m_textureArrayList.begin();
  513. while (iter != -1)
  514. {
  515. m_textureArrayList[iter].second.Pack();
  516. iter = m_textureArrayList.next(iter);
  517. }
  518. }
  519. void DecalTextureArrayFeatureProcessor::CullDecals(const RPI::ViewPtr& view)
  520. {
  521. if (!AZ::RHI::CheckBitsAll(view->GetUsageFlags(), RPI::View::UsageFlags::UsageCamera) ||
  522. !Render::LightCommon::NeedsCPUCulling(view, m_cpuCulledPipelinesPerView))
  523. {
  524. return;
  525. }
  526. const auto& dataVector = m_decalData.GetDataVector<0>();
  527. size_t numVisibleDecals =
  528. r_maxVisibleDecals < 0 ? dataVector.size() : AZStd::min(dataVector.size(), static_cast<size_t>(r_maxVisibleDecals));
  529. AZStd::vector<uint32_t> sortedDecals(dataVector.size());
  530. // Initialize with all the decals indices
  531. std::iota(sortedDecals.begin(), sortedDecals.end(), 0);
  532. // Only sort if we are going to limit the number of visible decals
  533. if (numVisibleDecals < dataVector.size())
  534. {
  535. AZ::Vector3 viewPos = view->GetViewToWorldMatrix().GetTranslation();
  536. AZStd::sort(
  537. sortedDecals.begin(),
  538. sortedDecals.end(),
  539. [&dataVector, &viewPos](uint32_t lhs, uint32_t rhs)
  540. {
  541. float d1 = (AZ::Vector3::CreateFromFloat3(dataVector[lhs].m_position.data()) - viewPos).GetLengthSq();
  542. float d2 = (AZ::Vector3::CreateFromFloat3(dataVector[rhs].m_position.data()) - viewPos).GetLengthSq();
  543. return d1 < d2;
  544. });
  545. }
  546. const AZ::Frustum viewFrustum = AZ::Frustum::CreateFromMatrixColumnMajor(view->GetWorldToClipMatrix());
  547. AZStd::vector<uint32_t> visibilityBuffer;
  548. visibilityBuffer.reserve(numVisibleDecals);
  549. for (uint32_t i = 0; i < sortedDecals.size() && visibilityBuffer.size() < numVisibleDecals; ++i)
  550. {
  551. uint32_t dataIndex = sortedDecals[i];
  552. const auto& decalData = dataVector[dataIndex];
  553. AZ::Obb obb = AZ::Obb::CreateFromPositionRotationAndHalfLengths(
  554. AZ::Vector3::CreateFromFloat3(decalData.m_position.data()),
  555. AZ::Quaternion::CreateFromFloat4(decalData.m_quaternion.data()),
  556. AZ::Vector3::CreateFromFloat3(decalData.m_halfSize.data()));
  557. // Do the actual culling per decal and only add the indices for the visible ones.
  558. if (AZ::ShapeIntersection::Overlaps(viewFrustum, obb))
  559. {
  560. visibilityBuffer.push_back(dataIndex);
  561. }
  562. }
  563. // Create the appropriate buffer handlers for the visibility data
  564. Render::LightCommon::UpdateVisibleBuffers(
  565. "DecalVisibilityBuffer",
  566. "m_visibleDecalIndices",
  567. "m_visibleDecalCount",
  568. m_visibleDecalBufferUsedCount,
  569. m_visibleDecalBufferHandlers);
  570. // Update buffer and View SRG
  571. GpuBufferHandler& bufferHandler = m_visibleDecalBufferHandlers[m_visibleDecalBufferUsedCount++];
  572. bufferHandler.UpdateBuffer(visibilityBuffer);
  573. bufferHandler.UpdateSrg(view->GetShaderResourceGroup().get());
  574. }
  575. AZ::Data::AssetId DecalTextureArrayFeatureProcessor::GetMaterialUsedByDecal(const DecalHandle handle) const
  576. {
  577. AZ::Data::AssetId material;
  578. if (handle.IsValid())
  579. {
  580. const DecalData& decalData = m_decalData.GetData<0>(handle.GetIndex());
  581. if (decalData.m_textureArrayIndex != DecalData::UnusedIndex)
  582. {
  583. const DecalTextureArray& textureArray = m_textureArrayList[decalData.m_textureArrayIndex].second;
  584. material = textureArray.GetMaterialAssetId(decalData.m_textureIndex);
  585. }
  586. }
  587. return material;
  588. }
  589. void DecalTextureArrayFeatureProcessor::QueueMaterialLoadForDecal(const AZ::Data::AssetId materialId, const DecalHandle handle)
  590. {
  591. const auto materialAsset = QueueMaterialAssetLoad(materialId);
  592. if (materialAsset.IsLoading())
  593. {
  594. m_materialLoadTracker.TrackAssetLoad(handle, materialAsset);
  595. AZ::Data::AssetBus::MultiHandler::BusConnect(materialId);
  596. }
  597. else if (materialAsset.IsReady())
  598. {
  599. SetMaterialToDecals(materialAsset.GetAs<AZ::RPI::MaterialAsset>(), { handle });
  600. }
  601. else if (materialAsset.IsError())
  602. {
  603. AZ_Warning("DecalTextureArrayFeatureProcessor", false, "Unable to load material for decal. Asset ID: %s", materialId.ToString<AZStd::string>().c_str());
  604. }
  605. else
  606. {
  607. AZ_Assert(false, "DecalTextureArrayFeatureProcessor::QueueMaterialLoadForDecal is in an unhandled state.");
  608. }
  609. }
  610. void DecalTextureArrayFeatureProcessor::SetMaterialToDecals(
  611. RPI::MaterialAsset* materialAsset, const AZStd::vector<DecalHandle>& decalsThatUseThisMaterial)
  612. {
  613. if (!materialAsset)
  614. {
  615. return;
  616. }
  617. const Data::AssetId& assetId = materialAsset->GetId();
  618. const bool validDecalMaterial = materialAsset && DecalTextureArray::IsValidDecalMaterial(*materialAsset);
  619. if (validDecalMaterial)
  620. {
  621. const auto& decalLocation = AddMaterialToTextureArrays(materialAsset);
  622. if (decalLocation)
  623. {
  624. for (const auto& decal : decalsThatUseThisMaterial)
  625. {
  626. m_materialToTextureArrayLookupTable[assetId].m_useCount++;
  627. SetDecalTextureLocation(decal, *decalLocation);
  628. }
  629. m_materialToTextureArrayLookupTable[assetId].m_location = *decalLocation;
  630. }
  631. }
  632. else
  633. {
  634. AZ_Warning(
  635. "DecalTextureArrayFeatureProcessor",
  636. false,
  637. "DecalTextureArray::IsValidDecalMaterial() failed, unable to add this material to the decal");
  638. }
  639. if (!m_materialLoadTracker.AreAnyLoadsInFlight())
  640. {
  641. PackTexureArrays();
  642. }
  643. }
  644. void DecalTextureArrayFeatureProcessor::UpdateBounds(const DecalHandle handle)
  645. {
  646. const DecalData& data = m_decalData.GetData<0>(handle.GetIndex());
  647. m_decalData.GetData<1>(handle.GetIndex()) = Aabb::CreateCenterHalfExtents(
  648. AZ::Vector3(data.m_position[0], data.m_position[1], data.m_position[2]),
  649. AZ::Vector3(data.m_halfSize[0], data.m_halfSize[1], data.m_halfSize[2]));
  650. }
  651. } // namespace Render
  652. } // namespace AZ