SceneReloadSoakTestComponent.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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.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. Render::MaterialAssignmentMap materials;
  76. Render::MaterialAssignment& defaultMaterial = materials[Render::DefaultMaterialAssignmentId];
  77. defaultMaterial.m_materialAsset = Data::AssetManager::Instance().GetAsset<MaterialAsset>(m_materialAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
  78. defaultMaterial.m_materialAsset.BlockUntilLoadComplete();
  79. // We have a mixture of both unique and shared instance to give more variety and therefore more opportunity for things to break.
  80. bool materialIsUnique = (m_materialIsUnique.size() % 2) == 0;
  81. defaultMaterial.m_materialInstance = materialIsUnique ?
  82. Material::Create(defaultMaterial.m_materialAsset) :
  83. Material::FindOrCreate(defaultMaterial.m_materialAsset);
  84. m_materialIsUnique.push_back(materialIsUnique);
  85. Data::Asset<ModelAsset> modelAsset;
  86. modelAsset.Create(m_modelAssetId);
  87. auto meshHandle = GetMeshFeatureProcessor()->AcquireMesh(Render::MeshHandleDescriptor{ modelAsset }, materials);
  88. GetMeshFeatureProcessor()->SetTransform(meshHandle, transform);
  89. m_meshHandles.push_back(AZStd::move(meshHandle));
  90. }
  91. void SceneReloadSoakTestComponent::DestroyLatticeInstances()
  92. {
  93. m_materialIsUnique.clear();
  94. for (auto& meshHandle : m_meshHandles)
  95. {
  96. GetMeshFeatureProcessor()->ReleaseMesh(meshHandle);
  97. }
  98. m_meshHandles.clear();
  99. }
  100. void SceneReloadSoakTestComponent::OnTick(float deltaTime, [[maybe_unused]] ScriptTimePoint scriptTime)
  101. {
  102. // There are some crashes that specifically occurred when unloading a scene while compiling material changes
  103. {
  104. // Create a new SimpleLcgRandom every time TickMaterialUpdate is called to keep a consistent seed and consistent color selection.
  105. SimpleLcgRandom random;
  106. bool updatedSharedMaterialInstance = false;
  107. size_t entityIndex = 0;
  108. MaterialPropertyIndex colorPropertyIndex;
  109. for (auto& meshHandle : m_meshHandles)
  110. {
  111. const Render::MaterialAssignmentMap& materials = GetMeshFeatureProcessor()->GetMaterialAssignmentMap(meshHandle);
  112. const auto defaultMaterialItr = materials.find(Render::DefaultMaterialAssignmentId);
  113. const auto& defaultMaterial = defaultMaterialItr != materials.end() ? defaultMaterialItr->second : Render::MaterialAssignment();
  114. Data::Instance<Material> material = defaultMaterial.m_materialInstance;
  115. if (material == nullptr)
  116. {
  117. continue;
  118. }
  119. static const float speed = 4.0f;
  120. const float t = static_cast<float>(sin(m_totalTime * speed) * 0.5f + 0.5f);
  121. static const Color colorOptions[] =
  122. {
  123. Color(1.0f, 0.0f, 0.0f, 1.0f),
  124. Color(0.0f, 1.0f, 0.0f, 1.0f),
  125. Color(0.0f, 0.0f, 1.0f, 1.0f),
  126. Color(1.0f, 1.0f, 0.0f, 1.0f),
  127. Color(0.0f, 1.0f, 1.0f, 1.0f),
  128. Color(1.0f, 0.0f, 1.0f, 1.0f),
  129. };
  130. const int colorIndexA = random.GetRandom() % AZ_ARRAY_SIZE(colorOptions);
  131. int colorIndexB = colorIndexA;
  132. while (colorIndexA == colorIndexB)
  133. {
  134. colorIndexB = random.GetRandom() % AZ_ARRAY_SIZE(colorOptions);
  135. }
  136. const Color color = colorOptions[colorIndexA] * t + colorOptions[colorIndexB] * (1.0f - t);
  137. if (m_materialIsUnique[entityIndex] || !updatedSharedMaterialInstance)
  138. {
  139. if (colorPropertyIndex.IsNull())
  140. {
  141. colorPropertyIndex = material->FindPropertyIndex(Name("baseColor.color"));
  142. }
  143. if (colorPropertyIndex.IsValid())
  144. {
  145. material->SetPropertyValue(colorPropertyIndex, color);
  146. if (!m_materialIsUnique[entityIndex])
  147. {
  148. updatedSharedMaterialInstance = true;
  149. }
  150. }
  151. else
  152. {
  153. AZ_Error("", false, "Could not find the color property index");
  154. }
  155. material->Compile();
  156. }
  157. entityIndex++;
  158. }
  159. }
  160. m_countdown -= deltaTime;
  161. m_totalTime += deltaTime;
  162. // Rebuild the scene every time the countdown expires.
  163. // We might also need to move to the next TimeSetting with a new countdown time.
  164. if (m_countdown < 0)
  165. {
  166. TimeSetting currentSetting = m_timeSettings[m_currentSettingIndex % m_timeSettings.size()];
  167. m_countdown = currentSetting.resetDelay;
  168. // The TimeSetting struct tells us how many times we should use it, before moving to the next TimeSetting struct
  169. m_currentCount++;
  170. if (m_currentCount >= currentSetting.count)
  171. {
  172. m_currentCount = 0;
  173. m_currentSettingIndex++;
  174. }
  175. m_totalResetCount++;
  176. AZ_TracePrintf("", "SceneReloadSoakTest RESET # %d @ time %f. Next reset in %f s\n", m_totalResetCount, m_totalTime, m_countdown);
  177. RebuildLattice();
  178. }
  179. }
  180. } // namespace AtomSampleViewer