AssetLoadTestComponent.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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 <AssetLoadTestComponent.h>
  9. #include <SampleComponentManager.h>
  10. #include <SampleComponentConfig.h>
  11. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  12. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  13. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  14. #include <Automation/ScriptRunnerBus.h>
  15. #include <AzCore/Serialization/SerializeContext.h>
  16. #include <RHI/BasicRHIComponent.h>
  17. AZ_DECLARE_BUDGET(AtomSampleViewer);
  18. namespace AtomSampleViewer
  19. {
  20. using namespace AZ;
  21. void AssetLoadTestComponent::Reflect(AZ::ReflectContext* context)
  22. {
  23. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  24. {
  25. serializeContext->Class<AssetLoadTestComponent, EntityLatticeTestComponent>()
  26. ->Version(0)
  27. ;
  28. }
  29. }
  30. AssetLoadTestComponent::AssetLoadTestComponent()
  31. : m_materialBrowser("@user@/AssetLoadTestComponent/material_browser.xml")
  32. , m_modelBrowser("@user@/AssetLoadTestComponent/model_browser.xml")
  33. , m_imguiSidebar("@user@/AssetLoadTestComponent/sidebar.xml")
  34. {
  35. m_sampleName = "AssetLoadTestComponent";
  36. m_materialBrowser.SetFilter([](const AZ::Data::AssetInfo& assetInfo)
  37. {
  38. return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::MaterialAsset>();
  39. });
  40. m_modelBrowser.SetFilter([](const AZ::Data::AssetInfo& assetInfo)
  41. {
  42. return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::ModelAsset>();
  43. });
  44. const AZStd::vector<AZStd::string> defaultMaterialAllowlist =
  45. {
  46. "materials/defaultpbr.azmaterial",
  47. "materials/presets/pbr/metal_aluminum_polished.azmaterial",
  48. "shaders/staticmesh_colorr.azmaterial",
  49. "shaders/staticmesh_colorg.azmaterial",
  50. "shaders/staticmesh_colorb.azmaterial"
  51. };
  52. m_materialBrowser.SetDefaultPinnedAssets(defaultMaterialAllowlist);
  53. m_pinnedMaterialCount = static_cast<uint32_t>(m_materialBrowser.GetPinnedAssets().size());
  54. const AZStd::vector<AZStd::string> defaultModelAllowist =
  55. {
  56. "Objects/bunny.azmodel",
  57. "Objects/Shaderball_simple.azmodel",
  58. "Objects/suzanne.azmodel",
  59. };
  60. m_modelBrowser.SetDefaultPinnedAssets(defaultModelAllowist);
  61. }
  62. void AssetLoadTestComponent::Activate()
  63. {
  64. AZ::TickBus::Handler::BusConnect();
  65. m_imguiSidebar.Activate();
  66. m_materialBrowser.Activate();
  67. m_modelBrowser.Activate();
  68. if (!m_materialBrowser.IsConfigFileLoaded())
  69. {
  70. AZ_TracePrintf("AssetLoadTestComponent", "Material allow list not loaded. Defaulting to built in list.\n");
  71. m_materialBrowser.ResetPinnedAssetsToDefault();
  72. }
  73. if (!m_modelBrowser.IsConfigFileLoaded())
  74. {
  75. AZ_TracePrintf("AssetLoadTestComponent", "Model allow list not loaded. Defaulting to built in list.\n");
  76. m_modelBrowser.ResetPinnedAssetsToDefault();
  77. }
  78. Base::Activate();
  79. }
  80. void AssetLoadTestComponent::Deactivate()
  81. {
  82. m_materialBrowser.Deactivate();
  83. m_modelBrowser.Deactivate();
  84. AZ::TickBus::Handler::BusDisconnect();
  85. m_imguiSidebar.Deactivate();
  86. Base::Deactivate();
  87. }
  88. void AssetLoadTestComponent::PrepareCreateLatticeInstances(uint32_t instanceCount)
  89. {
  90. m_modelInstanceData.reserve(instanceCount);
  91. }
  92. void AssetLoadTestComponent::CreateLatticeInstance(const AZ::Transform& transform)
  93. {
  94. m_modelInstanceData.emplace_back<ModelInstanceData>({});
  95. ModelInstanceData& data = m_modelInstanceData.back();
  96. data.m_modelAssetId = GetRandomModelId();
  97. data.m_materialAssetId = GetRandomMaterialId();
  98. data.m_transform = transform;
  99. }
  100. void AssetLoadTestComponent::FinalizeLatticeInstances()
  101. {
  102. AZStd::set<AZ::Data::AssetId> assetIds;
  103. for (ModelInstanceData& instanceData : m_modelInstanceData)
  104. {
  105. if (instanceData.m_materialAssetId.IsValid())
  106. {
  107. assetIds.insert(instanceData.m_materialAssetId);
  108. }
  109. if (instanceData.m_modelAssetId.IsValid())
  110. {
  111. assetIds.insert(instanceData.m_modelAssetId);
  112. }
  113. }
  114. AZStd::vector<AZ::AssetCollectionAsyncLoader::AssetToLoadInfo> assetList;
  115. for (auto& assetId : assetIds)
  116. {
  117. AZ::Data::AssetInfo assetInfo;
  118. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId);
  119. if (assetInfo.m_assetId.IsValid())
  120. {
  121. AZ::AssetCollectionAsyncLoader::AssetToLoadInfo info;
  122. info.m_assetPath = assetInfo.m_relativePath;
  123. info.m_assetType = assetInfo.m_assetType;
  124. assetList.push_back(info);
  125. }
  126. }
  127. PreloadAssets(assetList);
  128. // pause script and tick until assets are ready
  129. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 120.0f);
  130. AZ::TickBus::Handler::BusDisconnect();
  131. }
  132. void AssetLoadTestComponent::OnAllAssetsReadyActivate()
  133. {
  134. AZ::Render::MaterialAssignmentMap materials;
  135. for (ModelInstanceData& instanceData : m_modelInstanceData)
  136. {
  137. AZ::Render::MaterialAssignment& defaultAssignment = materials[AZ::Render::DefaultMaterialAssignmentId];
  138. defaultAssignment = {};
  139. if (instanceData.m_materialAssetId.IsValid())
  140. {
  141. defaultAssignment.m_materialAsset.Create(instanceData.m_materialAssetId);
  142. defaultAssignment.m_materialInstance = AZ::RPI::Material::FindOrCreate(defaultAssignment.m_materialAsset);
  143. // cache the material when its loaded
  144. m_cachedMaterials.insert(defaultAssignment.m_materialAsset);
  145. }
  146. if (instanceData.m_modelAssetId.IsValid())
  147. {
  148. AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
  149. modelAsset.Create(instanceData.m_modelAssetId);
  150. instanceData.m_meshHandle = GetMeshFeatureProcessor()->AcquireMesh(AZ::Render::MeshHandleDescriptor{ modelAsset }, materials);
  151. GetMeshFeatureProcessor()->SetTransform(instanceData.m_meshHandle, instanceData.m_transform);
  152. }
  153. }
  154. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  155. AZ::TickBus::Handler::BusConnect();
  156. }
  157. void AssetLoadTestComponent::DestroyLatticeInstances()
  158. {
  159. DestroyHandles();
  160. m_modelInstanceData.clear();
  161. }
  162. void AssetLoadTestComponent::DestroyHandles()
  163. {
  164. for (ModelInstanceData& instanceData : m_modelInstanceData)
  165. {
  166. GetMeshFeatureProcessor()->ReleaseMesh(instanceData.m_meshHandle);
  167. instanceData.m_meshHandle = {};
  168. }
  169. }
  170. AZ::Data::AssetId AssetLoadTestComponent::GetRandomModelId() const
  171. {
  172. auto& modelAllowlist = m_modelBrowser.GetPinnedAssets();
  173. if (modelAllowlist.size())
  174. {
  175. const size_t randomModelIndex = rand() % modelAllowlist.size();
  176. return modelAllowlist[randomModelIndex].m_assetId;
  177. }
  178. else
  179. {
  180. return AZ::RPI::AssetUtils::GetAssetIdForProductPath("testdata/objects/cube/cube.azmodel", AZ::RPI::AssetUtils::TraceLevel::Error);
  181. }
  182. }
  183. AZ::Data::AssetId AssetLoadTestComponent::GetRandomMaterialId() const
  184. {
  185. auto& materialAllowlist = m_materialBrowser.GetPinnedAssets();
  186. if (materialAllowlist.size())
  187. {
  188. const size_t randomMaterialIndex = rand() % materialAllowlist.size();
  189. return materialAllowlist[randomMaterialIndex].m_assetId;
  190. }
  191. else
  192. {
  193. return AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultPbrMaterialPath, AZ::RPI::AssetUtils::TraceLevel::Error);
  194. }
  195. }
  196. void AssetLoadTestComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint scriptTime)
  197. {
  198. AZ_PROFILE_FUNCTION(AtomSampleViewer);
  199. const float timeSeconds = static_cast<float>(scriptTime.GetSeconds());
  200. if (m_lastMaterialSwitchInSeconds == 0 || m_lastModelSwitchInSeconds == 0)
  201. {
  202. m_lastMaterialSwitchInSeconds = timeSeconds;
  203. m_lastModelSwitchInSeconds = timeSeconds;
  204. return;
  205. }
  206. bool materialSwitchRequested = m_materialSwitchEnabled && timeSeconds - m_lastMaterialSwitchInSeconds >= m_materialSwitchTimeInSeconds;
  207. bool modelSwitchRequested = m_modelSwitchEnabled && timeSeconds - m_lastModelSwitchInSeconds >= m_modelSwitchTimeInSeconds;
  208. if (m_updateTransformEnabled)
  209. {
  210. float radians = static_cast<float>(fmod(scriptTime.GetSeconds(), AZ::Constants::TwoPi));
  211. AZ::Vector3 rotation(radians, radians, radians);
  212. AZ::Transform rotationTransform;
  213. rotationTransform.SetFromEulerRadians(rotation);
  214. for (ModelInstanceData& instanceData : m_modelInstanceData)
  215. {
  216. GetMeshFeatureProcessor()->SetTransform(instanceData.m_meshHandle, instanceData.m_transform * rotationTransform);
  217. }
  218. }
  219. bool materialsChanged = false;
  220. bool modelsChanged = false;
  221. if (m_imguiSidebar.Begin())
  222. {
  223. ImGui::Checkbox("Switch Materials Every N Seconds", &m_materialSwitchEnabled);
  224. ImGui::SliderFloat("##MaterialSwitchTime", &m_materialSwitchTimeInSeconds, 0.1f, 10.0f);
  225. ImGui::Spacing();
  226. ImGui::Checkbox("Switch Models Every N Seconds", &m_modelSwitchEnabled);
  227. ImGui::SliderFloat("##ModelSwitchTime", &m_modelSwitchTimeInSeconds, 0.1f, 10.0f);
  228. ImGui::Spacing();
  229. ImGui::Checkbox("Update Transforms Every Frame", &m_updateTransformEnabled);
  230. ImGui::Spacing();
  231. ImGui::Separator();
  232. ImGui::Spacing();
  233. RenderImGuiLatticeControls();
  234. ImGui::Spacing();
  235. ImGui::Separator();
  236. ImGui::Spacing();
  237. ImGuiAssetBrowser::WidgetSettings assetBrowserSettings;
  238. assetBrowserSettings.m_labels.m_pinnedAssetList = "Allow List";
  239. assetBrowserSettings.m_labels.m_pinButton = "Add To Allow List";
  240. assetBrowserSettings.m_labels.m_unpinButton = "Remove From Allow List";
  241. assetBrowserSettings.m_labels.m_root = "Materials";
  242. m_materialBrowser.Tick(assetBrowserSettings);
  243. auto& pinnedMaterials = m_materialBrowser.GetPinnedAssets();
  244. materialsChanged = pinnedMaterials.size() != m_pinnedMaterialCount;
  245. if (materialsChanged)
  246. {
  247. m_pinnedMaterialCount = static_cast<uint32_t>(pinnedMaterials.size());
  248. // Keep the current m_cachedMaterials to avoid release-load the same material
  249. MaterialAssetSet newCache;
  250. // clean up cached material which refcount is 1
  251. for (auto& pinnedMaterial : pinnedMaterials)
  252. {
  253. AZ::Data::AssetId materialAssetid = pinnedMaterial.m_assetId;
  254. // Cache the asset if it's loaded
  255. AZ::Data::Asset<AZ::RPI::MaterialAsset> asset = AZ::Data::AssetManager::Instance().FindAsset<AZ::RPI::MaterialAsset>(materialAssetid, AZ::Data::AssetLoadBehavior::PreLoad);
  256. if (asset.IsReady())
  257. {
  258. newCache.insert(asset);
  259. }
  260. }
  261. m_cachedMaterials = newCache;
  262. }
  263. ImGui::Spacing();
  264. ImGui::Separator();
  265. ImGui::Spacing();
  266. assetBrowserSettings.m_labels.m_root = "Models";
  267. m_modelBrowser.Tick(assetBrowserSettings);
  268. modelsChanged = m_lastPinnedModelCount != m_modelBrowser.GetPinnedAssets().size();
  269. m_imguiSidebar.End();
  270. }
  271. if (materialSwitchRequested || materialsChanged)
  272. {
  273. for (ModelInstanceData& instanceData : m_modelInstanceData)
  274. {
  275. instanceData.m_materialAssetId = GetRandomMaterialId();
  276. }
  277. m_lastMaterialSwitchInSeconds = timeSeconds;
  278. }
  279. if (modelSwitchRequested || modelsChanged)
  280. {
  281. m_lastPinnedModelCount = m_modelBrowser.GetPinnedAssets().size();
  282. for (ModelInstanceData& instanceData : m_modelInstanceData)
  283. {
  284. instanceData.m_modelAssetId = GetRandomModelId();
  285. }
  286. m_lastModelSwitchInSeconds = timeSeconds;
  287. }
  288. if (materialSwitchRequested || materialsChanged || modelSwitchRequested || modelsChanged)
  289. {
  290. DestroyHandles();
  291. FinalizeLatticeInstances();
  292. }
  293. }
  294. } // namespace AtomSampleViewer