SsaoExampleComponent.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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.fbx.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. Render::MeshHandleDescriptor descriptor(modelAsset, RPI::Material::FindOrCreate(materialAsset));
  84. descriptor.m_modelChangedEventHandler =
  85. AZ::Render::MeshHandleDescriptor::ModelChangedEvent::Handler{ [this](const AZ::Data::Instance<AZ::RPI::Model>& model)
  86. {
  87. OnModelReady(model);
  88. } };
  89. m_meshHandle = GetMeshFeatureProcessor()->AcquireMesh(descriptor);
  90. GetMeshFeatureProcessor()->SetTransform(m_meshHandle, Transform::CreateIdentity());
  91. }
  92. void SsaoExampleComponent::DeactivateModel()
  93. {
  94. GetMeshFeatureProcessor()->ReleaseMesh(m_meshHandle);
  95. }
  96. // --- SSAO Pipeline ---
  97. void SsaoExampleComponent::CreateSsaoPipeline()
  98. {
  99. AZ::RPI::RenderPipelineDescriptor ssaoPipelineDesc;
  100. ssaoPipelineDesc.m_mainViewTagName = "MainCamera";
  101. ssaoPipelineDesc.m_name = "SsaoPipeline";
  102. ssaoPipelineDesc.m_rootPassTemplate = "SsaoPipeline";
  103. m_ssaoPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(ssaoPipelineDesc, *m_windowContext);
  104. if (m_rayTracingEnabled)
  105. {
  106. RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("RayTracingAmbientOcclusionPass"), m_ssaoPipeline.get());
  107. m_RTAOPass = azrtti_cast<Render::RayTracingAmbientOcclusionPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter));
  108. AZ_Assert(m_RTAOPass, "Couldn't find the RayTracingAmbientOcclusionPass from the SsaoPipeline");
  109. }
  110. else
  111. {
  112. m_aoType = AmbientOcclusionType::SSAO;
  113. }
  114. RPI::PassFilter selectorPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("SelectorPass"), m_ssaoPipeline.get());
  115. m_selector = azrtti_cast<RPI::SelectorPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(selectorPassFilter));
  116. AZ_Assert(m_selector, "Couldn't find the SelectorPass from the SsaoPipeline");
  117. }
  118. void SsaoExampleComponent::DestroySsaoPipeline()
  119. {
  120. m_ssaoPipeline = nullptr;
  121. }
  122. void SsaoExampleComponent::ActivateSsaoPipeline()
  123. {
  124. CreateSsaoPipeline();
  125. m_originalPipeline = m_scene->GetDefaultRenderPipeline();
  126. m_scene->AddRenderPipeline(m_ssaoPipeline);
  127. m_ssaoPipeline->SetDefaultView(m_originalPipeline->GetDefaultView());
  128. m_scene->RemoveRenderPipeline(m_originalPipeline->GetId());
  129. // Create an ImGuiActiveContextScope to ensure the ImGui context on the new pipeline's ImGui pass is activated.
  130. m_imguiScope = AZ::Render::ImGuiActiveContextScope::FromPass({ m_ssaoPipeline->GetId().GetCStr(), "ImGuiPass" });
  131. }
  132. void SsaoExampleComponent::DeactivateSsaoPipeline()
  133. {
  134. m_imguiScope = {}; // restores previous ImGui context.
  135. m_scene->AddRenderPipeline(m_originalPipeline);
  136. m_scene->RemoveRenderPipeline(m_ssaoPipeline->GetId());
  137. DestroySsaoPipeline();
  138. }
  139. // --- SSAO Settings ---
  140. void SsaoExampleComponent::ActivatePostProcessSettings()
  141. {
  142. using namespace AZ;
  143. m_ssaoEntity = CreateEntity("SSAO", GetEntityContextId());
  144. Component* transformComponent = nullptr;
  145. ComponentDescriptorBus::EventResult(
  146. transformComponent,
  147. azrtti_typeid<AzFramework::TransformComponent>(),
  148. &ComponentDescriptorBus::Events::CreateComponent);
  149. m_ssaoEntity->AddComponent(transformComponent);
  150. m_postProcessFeatureProcessor = m_scene->GetFeatureProcessor<Render::PostProcessFeatureProcessorInterface>();
  151. auto* postProcessSettings = m_postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_ssaoEntity->GetId());
  152. m_ssaoSettings = postProcessSettings->GetOrCreateSsaoSettingsInterface();
  153. m_ssaoEntity->Activate();
  154. AZ::EntityBus::MultiHandler::BusConnect(m_ssaoEntity->GetId());
  155. }
  156. void SsaoExampleComponent::DectivatePostProcessSettings()
  157. {
  158. AZ::EntityBus::MultiHandler::BusDisconnect();
  159. if (m_ssaoEntity)
  160. {
  161. DestroyEntity(m_ssaoEntity, GetEntityContextId());
  162. }
  163. }
  164. // --- IMGUI ---
  165. void SsaoExampleComponent::DrawImGUI()
  166. {
  167. if (!m_worldModelAssetLoaded)
  168. {
  169. const ImGuiWindowFlags windowFlags =
  170. ImGuiWindowFlags_NoCollapse |
  171. ImGuiWindowFlags_NoResize |
  172. ImGuiWindowFlags_NoMove;
  173. if (ImGui::Begin("Asset", nullptr, windowFlags))
  174. {
  175. ImGui::Text("World Model: %s", m_worldModelAssetLoaded ? "Loaded" : "Loading...");
  176. ImGui::End();
  177. }
  178. return;
  179. }
  180. if (!m_imguiSidebar.Begin())
  181. {
  182. return;
  183. }
  184. DrawSidebar();
  185. m_imguiSidebar.End();
  186. }
  187. void SsaoExampleComponent::DrawSidebar()
  188. {
  189. ScriptableImGui::ScopedNameContext context{ "SSAO" };
  190. // only enable selecting AO type if ray tracing is enabled
  191. if (m_rayTracingEnabled)
  192. {
  193. ImGui::Text("Ambient Occlusion");
  194. bool aoTypeChanged = false;
  195. aoTypeChanged = ScriptableImGui::RadioButton("Screen space AO", &m_aoType, AmbientOcclusionType::SSAO);
  196. aoTypeChanged = aoTypeChanged | ScriptableImGui::RadioButton("Ray tracing AO", &m_aoType, AmbientOcclusionType::RTAO);
  197. if (aoTypeChanged)
  198. {
  199. SwitchAOType();
  200. }
  201. ImGui::NewLine();
  202. }
  203. if (m_aoType == AmbientOcclusionType::SSAO)
  204. {
  205. ImGui::Text("SSAO Params");
  206. bool enabled = m_ssaoSettings->GetEnabled();
  207. if (ScriptableImGui::Checkbox("Enable", &enabled))
  208. {
  209. m_ssaoSettings->SetEnabled(enabled);
  210. m_ssaoSettings->OnConfigChanged();
  211. }
  212. float strength = m_ssaoSettings->GetStrength();
  213. if (ScriptableImGui::SliderFloat("SSAO Strength", &strength, 0.0f, 2.0f))
  214. {
  215. m_ssaoSettings->SetStrength(strength);
  216. m_ssaoSettings->OnConfigChanged();
  217. }
  218. bool blurEnabled = m_ssaoSettings->GetEnableBlur();
  219. if (ScriptableImGui::Checkbox("Enable Blur", &blurEnabled))
  220. {
  221. m_ssaoSettings->SetEnableBlur(blurEnabled);
  222. m_ssaoSettings->OnConfigChanged();
  223. }
  224. float blurConstFalloff = m_ssaoSettings->GetBlurConstFalloff();
  225. if (ScriptableImGui::SliderFloat("Blur Strength", &blurConstFalloff, 0.0f, 0.95f))
  226. {
  227. m_ssaoSettings->SetBlurConstFalloff(blurConstFalloff);
  228. m_ssaoSettings->OnConfigChanged();
  229. }
  230. float blurDepthFalloffStrength = m_ssaoSettings->GetBlurDepthFalloffStrength();
  231. if (ScriptableImGui::SliderFloat("Blur Sharpness", &blurDepthFalloffStrength, 0.0f, 400.0f))
  232. {
  233. m_ssaoSettings->SetBlurDepthFalloffStrength(blurDepthFalloffStrength);
  234. m_ssaoSettings->OnConfigChanged();
  235. }
  236. float blurDepthFalloffThreshold = m_ssaoSettings->GetBlurDepthFalloffThreshold();
  237. if (ScriptableImGui::SliderFloat("Blur Edge Threshold", &blurDepthFalloffThreshold, 0.0f, 1.0f))
  238. {
  239. m_ssaoSettings->SetBlurDepthFalloffThreshold(blurDepthFalloffThreshold);
  240. m_ssaoSettings->OnConfigChanged();
  241. }
  242. bool downsampleEnabled = m_ssaoSettings->GetEnableDownsample();
  243. if (ScriptableImGui::Checkbox("Enable Downsample", &downsampleEnabled))
  244. {
  245. m_ssaoSettings->SetEnableDownsample(downsampleEnabled);
  246. m_ssaoSettings->OnConfigChanged();
  247. }
  248. }
  249. else if (m_aoType == AmbientOcclusionType::RTAO)
  250. {
  251. ImGui::Text("RTAO Params");
  252. float rayNear = m_RTAOPass->GetRayExtentMin();
  253. if (ScriptableImGui::SliderFloat("Ray near distance", &rayNear, 0.0f, 0.5f))
  254. {
  255. m_RTAOPass->SetRayExtentMin(rayNear);
  256. }
  257. float rayFar = m_RTAOPass->GetRayExtentMax();
  258. if (ScriptableImGui::SliderFloat("Ray far distance", &rayFar, 0.0f, 1.0f))
  259. {
  260. if (rayFar < rayNear)
  261. {
  262. rayFar = rayNear + 0.1f;
  263. }
  264. m_RTAOPass->SetRayExtentMax(rayFar);
  265. }
  266. int32_t maxNumberRays = m_RTAOPass->GetRayNumberPerPixel();
  267. if (ScriptableImGui::SliderInt("Number of rays", &maxNumberRays, 1, 30))
  268. {
  269. m_RTAOPass->SetRayNumberPerPixel(maxNumberRays);
  270. }
  271. }
  272. }
  273. void SsaoExampleComponent::SwitchAOType()
  274. {
  275. if (m_aoType == AmbientOcclusionType::SSAO)
  276. {
  277. m_selector->Connect(1, 0);
  278. }
  279. else if (m_aoType == AmbientOcclusionType::RTAO)
  280. {
  281. m_selector->Connect(0, 0);
  282. }
  283. m_ssaoSettings->SetEnabled(m_aoType == AmbientOcclusionType::SSAO);
  284. m_ssaoSettings->OnConfigChanged();
  285. if (m_RTAOPass)
  286. {
  287. m_RTAOPass->SetEnabled(m_aoType == AmbientOcclusionType::RTAO);
  288. }
  289. }
  290. // --- Camera ---
  291. void SsaoExampleComponent::ActivateCamera()
  292. {
  293. AZ::Debug::CameraControllerRequestBus::Event(
  294. GetCameraEntityId(),
  295. &AZ::Debug::CameraControllerRequestBus::Events::Enable,
  296. azrtti_typeid<AZ::Debug::NoClipControllerComponent>());
  297. Camera::CameraRequestBus::EventResult(
  298. m_originalFarClipDistance,
  299. GetCameraEntityId(),
  300. &Camera::CameraRequestBus::Events::GetFarClipDistance);
  301. const float FarClipDistance = 16384.0f;
  302. Camera::CameraRequestBus::Event(
  303. GetCameraEntityId(),
  304. &Camera::CameraRequestBus::Events::SetFarClipDistance,
  305. FarClipDistance);
  306. MoveCameraToStartPosition();
  307. }
  308. void SsaoExampleComponent::DeactivateCamera()
  309. {
  310. Camera::CameraRequestBus::Event(
  311. GetCameraEntityId(),
  312. &Camera::CameraRequestBus::Events::SetFarClipDistance,
  313. m_originalFarClipDistance);
  314. AZ::Debug::CameraControllerRequestBus::Event(
  315. GetCameraEntityId(),
  316. &AZ::Debug::CameraControllerRequestBus::Events::Disable);
  317. }
  318. void SsaoExampleComponent::MoveCameraToStartPosition()
  319. {
  320. Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, 200.0f);
  321. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetPosition, Vector3(5.0f, 0.0f, 5.0f));
  322. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetHeading, DegToRad(90.0f));
  323. Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &Debug::NoClipControllerRequestBus::Events::SetPitch, DegToRad(-11.936623));
  324. }
  325. // --- Events ---
  326. void SsaoExampleComponent::DefaultWindowCreated()
  327. {
  328. AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &AZ::Render::Bootstrap::DefaultWindowBus::Events::GetDefaultWindowContext);
  329. }
  330. void SsaoExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
  331. {
  332. DrawImGUI();
  333. }
  334. void SsaoExampleComponent::OnEntityDestruction(const AZ::EntityId& entityId)
  335. {
  336. AZ::EntityBus::MultiHandler::BusDisconnect(entityId);
  337. if (m_ssaoEntity && m_ssaoEntity->GetId() == entityId)
  338. {
  339. m_postProcessFeatureProcessor->RemoveSettingsInterface(m_ssaoEntity->GetId());
  340. m_ssaoEntity = nullptr;
  341. }
  342. else
  343. {
  344. AZ_Assert(false, "unexpected entity destruction is signaled.");
  345. }
  346. }
  347. }