SceneReloadSoakTestComponent.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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 <SceneReloadSoakTestComponent.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/Component/DebugCamera/NoClipControllerBus.h>
  14. #include <AzCore/Component/Entity.h>
  15. #include <RHI/BasicRHIComponent.h>
  16. #include <SceneReloadSoakTestComponent_Traits_Platform.h>
  17. namespace AtomSampleViewer
  18. {
  19. using namespace AZ;
  20. using namespace RPI;
  21. void SceneReloadSoakTestComponent::Reflect(ReflectContext* context)
  22. {
  23. if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
  24. {
  25. serializeContext->Class<SceneReloadSoakTestComponent, EntityLatticeTestComponent>()
  26. ->Version(0)
  27. ;
  28. }
  29. }
  30. void SceneReloadSoakTestComponent::Activate()
  31. {
  32. m_timeSettings.clear();
  33. m_timeSettings.push_back(TimeSetting{2.0f, 1});
  34. m_timeSettings.push_back(TimeSetting{0.2f, 50});
  35. m_timeSettings.push_back(TimeSetting{0.5f, 10});
  36. m_timeSettings.push_back(TimeSetting{1.0f, 5});
  37. m_countdown = 0;
  38. m_totalTime = 0;
  39. m_currentSettingIndex = 0;
  40. m_currentCount = 0;
  41. m_totalResetCount = 0;
  42. SetLatticeDimensions(ATOMSAMPLEVIEWER_TRAIT_SCENE_RELOAD_SOAK_TEST_COMPONENT_LATTICE_SIZE, ATOMSAMPLEVIEWER_TRAIT_SCENE_RELOAD_SOAK_TEST_COMPONENT_LATTICE_SIZE, ATOMSAMPLEVIEWER_TRAIT_SCENE_RELOAD_SOAK_TEST_COMPONENT_LATTICE_SIZE);
  43. Base::Activate();
  44. TickBus::Handler::BusConnect();
  45. ExampleComponentRequestBus::Handler::BusConnect(GetEntityId());
  46. }
  47. void SceneReloadSoakTestComponent::Deactivate()
  48. {
  49. ExampleComponentRequestBus::Handler::BusDisconnect();
  50. TickBus::Handler::BusDisconnect();
  51. Base::Deactivate();
  52. }
  53. void SceneReloadSoakTestComponent::ResetCamera()
  54. {
  55. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetHeading, DegToRad(-25));
  56. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetPitch, DegToRad(25));
  57. }
  58. void SceneReloadSoakTestComponent::PrepareCreateLatticeInstances(uint32_t instanceCount)
  59. {
  60. m_materialIsUnique.reserve(instanceCount);
  61. m_meshHandles.reserve(instanceCount);
  62. const char* materialPath = DefaultPbrMaterialPath;
  63. const char* modelPath = "objects/shaderball_simple.fbx.azmodel";
  64. Data::AssetCatalogRequestBus::BroadcastResult(
  65. m_materialAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  66. materialPath, azrtti_typeid<MaterialAsset>(), false);
  67. Data::AssetCatalogRequestBus::BroadcastResult(
  68. m_modelAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  69. modelPath, azrtti_typeid<ModelAsset>(), false);
  70. AZ_Assert(m_materialAssetId.IsValid(), "Failed to get material asset id: %s", materialPath);
  71. AZ_Assert(m_modelAssetId.IsValid(), "Failed to get model asset id: %s", modelPath);
  72. }
  73. void SceneReloadSoakTestComponent::CreateLatticeInstance(const Transform& transform)
  74. {
  75. Data::Asset<MaterialAsset> materialAsset;
  76. materialAsset.Create(m_materialAssetId);
  77. // We have a mixture of both unique and shared instance to give more variety and therefore more opportunity for things to break.
  78. bool materialIsUnique = (m_materialIsUnique.size() % 2) == 0;
  79. auto materialInstance = materialIsUnique ? Material::Create(materialAsset) : Material::FindOrCreate(materialAsset);
  80. m_materialIsUnique.push_back(materialIsUnique);
  81. Data::Asset<ModelAsset> modelAsset;
  82. modelAsset.Create(m_modelAssetId);
  83. auto meshHandle = GetMeshFeatureProcessor()->AcquireMesh(Render::MeshHandleDescriptor(modelAsset, materialInstance));
  84. GetMeshFeatureProcessor()->SetTransform(meshHandle, transform);
  85. m_meshHandles.emplace_back(AZStd::move(meshHandle));
  86. }
  87. void SceneReloadSoakTestComponent::DestroyLatticeInstances()
  88. {
  89. m_materialIsUnique.clear();
  90. for (auto& meshHandle : m_meshHandles)
  91. {
  92. GetMeshFeatureProcessor()->ReleaseMesh(meshHandle);
  93. }
  94. m_meshHandles.clear();
  95. }
  96. void SceneReloadSoakTestComponent::OnTick(float deltaTime, [[maybe_unused]] ScriptTimePoint scriptTime)
  97. {
  98. // There are some crashes that specifically occurred when unloading a scene while compiling material changes
  99. {
  100. // Create a new SimpleLcgRandom every time TickMaterialUpdate is called to keep a consistent seed and consistent color selection.
  101. SimpleLcgRandom random;
  102. bool updatedSharedMaterialInstance = false;
  103. size_t entityIndex = 0;
  104. for (auto& meshHandle : m_meshHandles)
  105. {
  106. static const float speed = 4.0f;
  107. const float t = static_cast<float>(sin(m_totalTime * speed) * 0.5f + 0.5f);
  108. static const Color colorOptions[] =
  109. {
  110. Color(1.0f, 0.0f, 0.0f, 1.0f),
  111. Color(0.0f, 1.0f, 0.0f, 1.0f),
  112. Color(0.0f, 0.0f, 1.0f, 1.0f),
  113. Color(1.0f, 1.0f, 0.0f, 1.0f),
  114. Color(0.0f, 1.0f, 1.0f, 1.0f),
  115. Color(1.0f, 0.0f, 1.0f, 1.0f),
  116. };
  117. const int colorIndexA = random.GetRandom() % AZ_ARRAY_SIZE(colorOptions);
  118. int colorIndexB = colorIndexA;
  119. while (colorIndexA == colorIndexB)
  120. {
  121. colorIndexB = random.GetRandom() % AZ_ARRAY_SIZE(colorOptions);
  122. }
  123. const Color color = colorOptions[colorIndexA] * t + colorOptions[colorIndexB] * (1.0f - t);
  124. if (m_materialIsUnique[entityIndex] || !updatedSharedMaterialInstance)
  125. {
  126. for (auto& customMaterialPair : GetMeshFeatureProcessor()->GetCustomMaterials(meshHandle))
  127. {
  128. if (Data::Instance<Material> material = customMaterialPair.second.m_material)
  129. {
  130. MaterialPropertyIndex colorPropertyIndex = material->FindPropertyIndex(Name("baseColor.color"));
  131. if (colorPropertyIndex.IsValid())
  132. {
  133. material->SetPropertyValue(colorPropertyIndex, color);
  134. material->Compile();
  135. if (!m_materialIsUnique[entityIndex])
  136. {
  137. updatedSharedMaterialInstance = true;
  138. }
  139. }
  140. else
  141. {
  142. AZ_Error("", false, "Could not find the color property index");
  143. }
  144. }
  145. }
  146. }
  147. entityIndex++;
  148. }
  149. }
  150. m_countdown -= deltaTime;
  151. m_totalTime += deltaTime;
  152. // Rebuild the scene every time the countdown expires.
  153. // We might also need to move to the next TimeSetting with a new countdown time.
  154. if (m_countdown < 0)
  155. {
  156. TimeSetting currentSetting = m_timeSettings[m_currentSettingIndex % m_timeSettings.size()];
  157. m_countdown = currentSetting.resetDelay;
  158. // The TimeSetting struct tells us how many times we should use it, before moving to the next TimeSetting struct
  159. m_currentCount++;
  160. if (m_currentCount >= currentSetting.count)
  161. {
  162. m_currentCount = 0;
  163. m_currentSettingIndex++;
  164. }
  165. m_totalResetCount++;
  166. AZ_TracePrintf("", "SceneReloadSoakTest RESET # %d @ time %f. Next reset in %f s\n", m_totalResetCount, m_totalTime, m_countdown);
  167. RebuildLattice();
  168. }
  169. }
  170. } // namespace AtomSampleViewer