SsaoExampleComponent.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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 <SsaoExampleComponent.h>
  9. #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
  10. #include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
  11. #include <Atom/Component/DebugCamera/NoClipControllerBus.h>
  12. #include <Atom/RPI.Public/View.h>
  13. #include <Atom/RPI.Public/Image/StreamingImage.h>
  14. #include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
  15. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  16. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  17. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  18. #include <Utils/Utils.h>
  19. #include <EntityUtilityFunctions.h>
  20. #include <SampleComponentManager.h>
  21. #include <SampleComponentConfig.h>
  22. #include <Atom/Bootstrap/DefaultWindowBus.h>
  23. #include <Automation/ScriptableImGui.h>
  24. #include <Automation/ScriptRunnerBus.h>
  25. #include <AzFramework/Components/TransformComponent.h>
  26. #include <RHI/BasicRHIComponent.h>
  27. namespace AtomSampleViewer
  28. {
  29. using namespace AZ;
  30. using namespace AZ::Render;
  31. using namespace AZ::RPI;
  32. void SsaoExampleComponent::Reflect(AZ::ReflectContext* context)
  33. {
  34. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  35. {
  36. serializeContext->Class<SsaoExampleComponent, AZ::Component>()
  37. ->Version(0)
  38. ;
  39. }
  40. }
  41. // --- Activate/Deactivate ---
  42. void SsaoExampleComponent::Activate()
  43. {
  44. // We have a non-msaa pipeline, adjust the shader system supervariant settings accordingly
  45. AZ::Name noMsaaSupervariant = AZ::Name(AZ::RPI::NoMsaaSupervariantName);
  46. AZ::RPI::ShaderSystemInterface::Get()->SetSupervariantName(noMsaaSupervariant);
  47. RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
  48. m_rayTracingEnabled = device->GetFeatures().m_rayTracing;
  49. AZ::TickBus::Handler::BusConnect();
  50. AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler::BusConnect();
  51. ActivateSsaoPipeline();
  52. ActivateCamera();
  53. ActivateModel();
  54. ActivatePostProcessSettings();
  55. m_imguiSidebar.Activate();
  56. SwitchAOType();
  57. }
  58. void SsaoExampleComponent::Deactivate()
  59. {
  60. m_imguiSidebar.Deactivate();
  61. DectivatePostProcessSettings();
  62. DeactivateModel();
  63. DeactivateCamera();
  64. DeactivateSsaoPipeline();
  65. AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler::BusDisconnect();
  66. AZ::TickBus::Handler::BusDisconnect();
  67. // Reset the number of MSAA samples and the RPI scene
  68. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::ResetNumMSAASamples);
  69. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::ClearRPIScene);
  70. }
  71. // --- World Model ---
  72. void SsaoExampleComponent::OnModelReady(AZ::Data::Instance<AZ::RPI::Model> model)
  73. {
  74. m_worldModelAssetLoaded = true;
  75. }
  76. void SsaoExampleComponent::ActivateModel()
  77. {
  78. const char* modelPath = "objects/sponza.azmodel";
  79. // Get Model and Material asset
  80. Data::Asset<RPI::ModelAsset> modelAsset = RPI::AssetUtils::GetAssetByProductPath<RPI::ModelAsset>(modelPath, RPI::AssetUtils::TraceLevel::Assert);
  81. Data::Asset<RPI::MaterialAsset> materialAsset = RPI::AssetUtils::GetAssetByProductPath<RPI::MaterialAsset>(DefaultPbrMaterialPath, RPI::AssetUtils::TraceLevel::Assert);
  82. // Create Mesh and Model
  83. MeshFeatureProcessorInterface* meshFeatureProcessor = GetMeshFeatureProcessor();
  84. m_meshHandle = meshFeatureProcessor->AcquireMesh(MeshHandleDescriptor{ modelAsset }, RPI::Material::FindOrCreate(materialAsset));
  85. meshFeatureProcessor->SetTransform(m_meshHandle, Transform::CreateIdentity());
  86. Data::Instance<RPI::Model> model = meshFeatureProcessor->GetModel(m_meshHandle);
  87. // Async Model loading
  88. if (model)
  89. {
  90. OnModelReady(model);
  91. }
  92. else
  93. {
  94. meshFeatureProcessor->ConnectModelChangeEventHandler(m_meshHandle, m_meshChangedHandler);
  95. }
  96. }
  97. void SsaoExampleComponent::DeactivateModel()
  98. {
  99. GetMeshFeatureProcessor()->ReleaseMesh(m_meshHandle);
  100. }
  101. // --- SSAO Pipeline ---
  102. void SsaoExampleComponent::CreateSsaoPipeline()
  103. {
  104. AZ::RPI::RenderPipelineDescriptor ssaoPipelineDesc;
  105. ssaoPipelineDesc.m_mainViewTagName = "MainCamera";
  106. ssaoPipelineDesc.m_name = "SsaoPipeline";
  107. ssaoPipelineDesc.m_rootPassTemplate = "SsaoPipeline";
  108. m_ssaoPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(ssaoPipelineDesc, *m_windowContext);
  109. if (m_rayTracingEnabled)
  110. {
  111. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("RayTracingAmbientOcclusionPass"), m_ssaoPipeline.get());
  112. m_RTAOPass = azrtti_cast<Render::RayTracingAmbientOcclusionPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter));
  113. AZ_Assert(m_RTAOPass, "Couldn't find the RayTracingAmbientOcclusionPass from the SsaoPipeline");
  114. }
  115. else
  116. {
  117. m_aoType = AmbientOcclusionType::SSAO;
  118. }
  119. RPI::PassFilter selectorPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("SelectorPass"), m_ssaoPipeline.get());
  120. m_selector = azrtti_cast<RPI::SelectorPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(selectorPassFilter));
  121. AZ_Assert(m_selector, "Couldn't find the SelectorPass from the SsaoPipeline");
  122. }
  123. void SsaoExampleComponent::DestroySsaoPipeline()
  124. {
  125. m_ssaoPipeline = nullptr;
  126. }
  127. void SsaoExampleComponent::ActivateSsaoPipeline()
  128. {
  129. CreateSsaoPipeline();
  130. m_originalPipeline = m_scene->GetDefaultRenderPipeline();
  131. m_scene->AddRenderPipeline(m_ssaoPipeline);
  132. m_ssaoPipeline->SetDefaultView(m_originalPipeline->GetDefaultView());
  133. m_scene->RemoveRenderPipeline(m_originalPipeline->GetId());
  134. // Create an ImGuiActiveContextScope to ensure the ImGui context on the new pipeline's ImGui pass is activated.
  135. m_imguiScope = AZ::Render::ImGuiActiveContextScope::FromPass({ m_ssaoPipeline->GetId().GetCStr(), "ImGuiPass" });
  136. }
  137. void SsaoExampleComponent::DeactivateSsaoPipeline()
  138. {
  139. m_imguiScope = {}; // restores previous ImGui context.
  140. m_scene->AddRenderPipeline(m_originalPipeline);
  141. m_scene->RemoveRenderPipeline(m_ssaoPipeline->GetId());
  142. DestroySsaoPipeline();
  143. }
  144. // --- SSAO Settings ---
  145. void SsaoExampleComponent::ActivatePostProcessSettings()
  146. {
  147. using namespace AZ;
  148. m_ssaoEntity = CreateEntity("SSAO", GetEntityContextId());
  149. Component* transformComponent = nullptr;
  150. ComponentDescriptorBus::EventResult(
  151. transformComponent,
  152. azrtti_typeid<AzFramework::TransformComponent>(),
  153. &ComponentDescriptorBus::Events::CreateComponent);
  154. m_ssaoEntity->AddComponent(transformComponent);
  155. m_postProcessFeatureProcessor = m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
  156. auto* postProcessSettings = m_postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_ssaoEntity->GetId());
  157. m_ssaoSettings = postProcessSettings->GetOrCreateSsaoSettingsInterface();
  158. m_ssaoEntity->Activate();
  159. AZ::EntityBus::MultiHandler::BusConnect(m_ssaoEntity->GetId());
  160. }
  161. void SsaoExampleComponent::DectivatePostProcessSettings()
  162. {
  163. AZ::EntityBus::MultiHandler::BusDisconnect();
  164. if (m_ssaoEntity)
  165. {
  166. DestroyEntity(m_ssaoEntity, GetEntityContextId());
  167. }
  168. }
  169. // --- IMGUI ---
  170. void SsaoExampleComponent::DrawImGUI()
  171. {
  172. if (!m_worldModelAssetLoaded)
  173. {
  174. const ImGuiWindowFlags windowFlags =
  175. ImGuiWindowFlags_NoCollapse |
  176. ImGuiWindowFlags_NoResize |
  177. ImGuiWindowFlags_NoMove;
  178. if (ImGui::Begin("Asset", nullptr, windowFlags))
  179. {
  180. ImGui::Text("World Model: %s", m_worldModelAssetLoaded ? "Loaded" : "Loading...");
  181. ImGui::End();
  182. }
  183. return;
  184. }
  185. if (!m_imguiSidebar.Begin())
  186. {
  187. return;
  188. }
  189. DrawSidebar();
  190. m_imguiSidebar.End();
  191. }
  192. void SsaoExampleComponent::DrawSidebar()
  193. {
  194. ScriptableImGui::ScopedNameContext context{ "SSAO" };
  195. // only enable selecting AO type if ray tracing is enabled
  196. if (m_rayTracingEnabled)
  197. {
  198. ImGui::Text("Ambient Occlusion");
  199. bool aoTypeChanged = false;
  200. aoTypeChanged = ScriptableImGui::RadioButton("Screen space AO", &m_aoType, AmbientOcclusionType::SSAO);
  201. aoTypeChanged = aoTypeChanged | ScriptableImGui::RadioButton("Ray tracing AO", &m_aoType, AmbientOcclusionType::RTAO);
  202. if (aoTypeChanged)
  203. {
  204. SwitchAOType();
  205. }
  206. ImGui::NewLine();
  207. }
  208. if (m_aoType == AmbientOcclusionType::SSAO)
  209. {
  210. ImGui::Text("SSAO Params");
  211. bool enabled = m_ssaoSettings->GetEnabled();
  212. if (ScriptableImGui::Checkbox("Enable", &enabled))
  213. {
  214. m_ssaoSettings->SetEnabled(enabled);
  215. m_ssaoSettings->OnConfigChanged();
  216. }
  217. float strength = m_ssaoSettings->GetStrength();
  218. if (ScriptableImGui::SliderFloat("SSAO Strength", &strength, 0.0f, 2.0f))
  219. {
  220. m_ssaoSettings->SetStrength(strength);
  221. m_ssaoSettings->OnConfigChanged();
  222. }
  223. bool blurEnabled = m_ssaoSettings->GetEnableBlur();
  224. if (ScriptableImGui::Checkbox("Enable Blur", &blurEnabled))
  225. {
  226. m_ssaoSettings->SetEnableBlur(blurEnabled);
  227. m_ssaoSettings->OnConfigChanged();
  228. }
  229. float blurConstFalloff = m_ssaoSettings->GetBlurConstFalloff();
  230. if (ScriptableImGui::SliderFloat("Blur Strength", &blurConstFalloff, 0.0f, 0.95f))
  231. {
  232. m_ssaoSettings->SetBlurConstFalloff(blurConstFalloff);
  233. m_ssaoSettings->OnConfigChanged();
  234. }
  235. float blurDepthFalloffStrength = m_ssaoSettings->GetBlurDepthFalloffStrength();
  236. if (ScriptableImGui::SliderFloat("Blur Sharpness", &blurDepthFalloffStrength, 0.0f, 400.0f))
  237. {
  238. m_ssaoSettings->SetBlurDepthFalloffStrength(blurDepthFalloffStrength);
  239. m_ssaoSettings->OnConfigChanged();
  240. }
  241. float blurDepthFalloffThreshold = m_ssaoSettings->GetBlurDepthFalloffThreshold();
  242. if (ScriptableImGui::SliderFloat("Blur Edge Threshold", &blurDepthFalloffThreshold, 0.0f, 1.0f))
  243. {
  244. m_ssaoSettings->SetBlurDepthFalloffThreshold(blurDepthFalloffThreshold);
  245. m_ssaoSettings->OnConfigChanged();
  246. }
  247. bool downsampleEnabled = m_ssaoSettings->GetEnableDownsample();
  248. if (ScriptableImGui::Checkbox("Enable Downsample", &downsampleEnabled))
  249. {
  250. m_ssaoSettings->SetEnableDownsample(downsampleEnabled);
  251. m_ssaoSettings->OnConfigChanged();
  252. }
  253. }
  254. else if (m_aoType == AmbientOcclusionType::RTAO)
  255. {
  256. ImGui::Text("RTAO Params");
  257. float rayNear = m_RTAOPass->GetRayExtentMin();
  258. if (ScriptableImGui::SliderFloat("Ray near distance", &rayNear, 0.0f, 0.5f))
  259. {
  260. m_RTAOPass->SetRayExtentMin(rayNear);
  261. }
  262. float rayFar = m_RTAOPass->GetRayExtentMax();
  263. if (ScriptableImGui::SliderFloat("Ray far distance", &rayFar, 0.0f, 1.0f))
  264. {
  265. if (rayFar < rayNear)
  266. {
  267. rayFar = rayNear + 0.1f;
  268. }
  269. m_RTAOPass->SetRayExtentMax(rayFar);
  270. }
  271. int32_t maxNumberRays = m_RTAOPass->GetRayNumberPerPixel();
  272. if (ScriptableImGui::SliderInt("Number of rays", &maxNumberRays, 1, 30))
  273. {
  274. m_RTAOPass->SetRayNumberPerPixel(maxNumberRays);
  275. }
  276. }
  277. }
  278. void SsaoExampleComponent::SwitchAOType()
  279. {
  280. if (m_aoType == AmbientOcclusionType::SSAO)
  281. {
  282. m_selector->Connect(1, 0);
  283. }
  284. else if (m_aoType == AmbientOcclusionType::RTAO)
  285. {
  286. m_selector->Connect(0, 0);
  287. }
  288. m_ssaoSettings->SetEnabled(m_aoType == AmbientOcclusionType::SSAO);
  289. m_ssaoSettings->OnConfigChanged();
  290. if (m_RTAOPass)
  291. {
  292. m_RTAOPass->SetEnabled(m_aoType == AmbientOcclusionType::RTAO);
  293. }
  294. }
  295. // --- Camera ---
  296. void SsaoExampleComponent::ActivateCamera()
  297. {
  298. AZ::Debug::CameraControllerRequestBus::Event(
  299. GetCameraEntityId(),
  300. &AZ::Debug::CameraControllerRequestBus::Events::Enable,
  301. azrtti_typeid<AZ::Debug::NoClipControllerComponent>());
  302. Camera::CameraRequestBus::EventResult(
  303. m_originalFarClipDistance,
  304. GetCameraEntityId(),
  305. &Camera::CameraRequestBus::Events::GetFarClipDistance);
  306. const float FarClipDistance = 16384.0f;
  307. Camera::CameraRequestBus::Event(
  308. GetCameraEntityId(),
  309. &Camera::CameraRequestBus::Events::SetFarClipDistance,
  310. FarClipDistance);
  311. MoveCameraToStartPosition();
  312. }
  313. void SsaoExampleComponent::DeactivateCamera()
  314. {
  315. Camera::CameraRequestBus::Event(
  316. GetCameraEntityId(),
  317. &Camera::CameraRequestBus::Events::SetFarClipDistance,
  318. m_originalFarClipDistance);
  319. AZ::Debug::CameraControllerRequestBus::Event(
  320. GetCameraEntityId(),
  321. &AZ::Debug::CameraControllerRequestBus::Events::Disable);
  322. }
  323. void SsaoExampleComponent::MoveCameraToStartPosition()
  324. {
  325. Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, 200.0f);
  326. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetPosition, Vector3(5.0f, 0.0f, 5.0f));
  327. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetHeading, DegToRad(90.0f));
  328. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetPitch, DegToRad(-11.936623));
  329. }
  330. // --- Events ---
  331. void SsaoExampleComponent::DefaultWindowCreated()
  332. {
  333. AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &AZ::Render::Bootstrap::DefaultWindowBus::Events::GetDefaultWindowContext);
  334. }
  335. void SsaoExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
  336. {
  337. DrawImGUI();
  338. }
  339. void SsaoExampleComponent::OnEntityDestruction(const AZ::EntityId& entityId)
  340. {
  341. AZ::EntityBus::MultiHandler::BusDisconnect(entityId);
  342. if (m_ssaoEntity && m_ssaoEntity->GetId() == entityId)
  343. {
  344. m_postProcessFeatureProcessor->RemoveSettingsInterface(m_ssaoEntity->GetId());
  345. m_ssaoEntity = nullptr;
  346. }
  347. else
  348. {
  349. AZ_Assert(false, "unexpected entity destruction is signaled.");
  350. }
  351. }
  352. }