AssetLoadTestComponent.cpp 13 KB

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