MSAA_RPI_ExampleComponent.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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 <MSAA_RPI_ExampleComponent.h>
  9. #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
  10. #include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
  11. #include <Atom/RPI.Public/View.h>
  12. #include <Atom/RPI.Public/Image/StreamingImage.h>
  13. #include <Atom/RPI.Public/Shader/ShaderSystemInterface.h>
  14. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  15. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  16. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  17. #include <Atom/RPI.Reflect/Shader/ShaderCommonTypes.h>
  18. #include <Utils/Utils.h>
  19. #include <SampleComponentManager.h>
  20. #include <SampleComponentConfig.h>
  21. #include <Atom/Bootstrap/DefaultWindowBus.h>
  22. #include <Automation/ScriptableImGui.h>
  23. #include <Automation/ScriptRunnerBus.h>
  24. #include <RHI/BasicRHIComponent.h>
  25. namespace AtomSampleViewer
  26. {
  27. void MSAA_RPI_ExampleComponent::Reflect(AZ::ReflectContext* context)
  28. {
  29. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  30. {
  31. serializeContext->Class < MSAA_RPI_ExampleComponent, AZ::Component>()
  32. ->Version(0)
  33. ;
  34. }
  35. }
  36. void MSAA_RPI_ExampleComponent::Activate()
  37. {
  38. m_imguiSidebar.Activate();
  39. AZ::TickBus::Handler::BusConnect();
  40. ExampleComponentRequestBus::Handler::BusConnect(GetEntityId());
  41. AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler::BusConnect();
  42. // save the current render pipeline
  43. m_originalPipeline = m_scene->GetDefaultRenderPipeline();
  44. m_scene->RemoveRenderPipeline(m_originalPipeline->GetId());
  45. // switch to the sample render pipeline
  46. ChangeRenderPipeline();
  47. // set ArcBall camera controller
  48. AZ::Debug::CameraControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable,
  49. azrtti_typeid<AZ::Debug::ArcBallControllerComponent>());
  50. ActivateModel();
  51. ActivateIbl();
  52. }
  53. void MSAA_RPI_ExampleComponent::Deactivate()
  54. {
  55. GetMeshFeatureProcessor()->ReleaseMesh(m_meshHandle);
  56. AZ::Debug::CameraControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::CameraControllerRequestBus::Events::Disable);
  57. m_defaultIbl.Reset();
  58. // reset the number of MSAA samples and the RPI scene
  59. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::ResetNumMSAASamples);
  60. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::ClearRPIScene);
  61. AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler::BusDisconnect();
  62. ExampleComponentRequestBus::Handler::BusDisconnect();
  63. AZ::TickBus::Handler::BusDisconnect();
  64. m_imguiSidebar.Deactivate();
  65. }
  66. void MSAA_RPI_ExampleComponent::ChangeRenderPipeline()
  67. {
  68. m_imguiScope = {}; // restores previous ImGui context.
  69. // remove currently running sample pipeline, if any
  70. if (m_samplePipeline)
  71. {
  72. m_scene->RemoveRenderPipeline(m_samplePipeline->GetId());
  73. m_samplePipeline = nullptr;
  74. }
  75. bool isNonMsaaPipeline = (m_numSamples == 1);
  76. // if we are changing between the MSAA and non-MSAA pipelines we need to force a reset on the RPI scene. This is
  77. // necessary to re-initialize all of the feature processor shaders and Srgs
  78. if (isNonMsaaPipeline != m_isNonMsaaPipeline)
  79. {
  80. // set the number of MSAA samples and reset the RPI scene
  81. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::SetNumMSAASamples, static_cast<uint16_t>(m_numSamples));
  82. SampleComponentManagerRequestBus::Broadcast(&SampleComponentManagerRequests::ResetRPIScene);
  83. // reset internal sample scene related data
  84. ResetScene();
  85. // remove the default render pipeline
  86. AZ::RPI::RenderPipelinePtr defaultPipeline = m_scene->GetDefaultRenderPipeline();
  87. m_scene->RemoveRenderPipeline(defaultPipeline->GetId());
  88. // scene IBL is cleared after the reset, re-activate it
  89. ActivateIbl();
  90. m_isNonMsaaPipeline = isNonMsaaPipeline;
  91. }
  92. // create the new sample pipeline
  93. AZ::RPI::RenderPipelineDescriptor pipelineDesc;
  94. pipelineDesc.m_mainViewTagName = "MainCamera";
  95. pipelineDesc.m_name = "MSAA";
  96. pipelineDesc.m_rootPassTemplate = "MainPipeline";
  97. pipelineDesc.m_renderSettings.m_multisampleState.m_samples = static_cast<uint16_t>(m_numSamples);
  98. m_samplePipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineDesc, *m_windowContext);
  99. // add the sample pipeline to the scene
  100. m_scene->AddRenderPipeline(m_samplePipeline);
  101. m_samplePipeline->SetDefaultView(m_originalPipeline->GetDefaultView());
  102. m_scene->SetDefaultRenderPipeline(m_samplePipeline->GetId());
  103. // create an ImGuiActiveContextScope to ensure the ImGui context on the new pipeline's ImGui pass is activated.
  104. m_imguiScope = AZ::Render::ImGuiActiveContextScope::FromPass({ m_samplePipeline->GetId().GetCStr(), "ImGuiPass" });
  105. }
  106. void MSAA_RPI_ExampleComponent::ResetCamera()
  107. {
  108. const float pitch = -AZ::Constants::QuarterPi - 0.025f;
  109. const float heading = AZ::Constants::QuarterPi - 0.05f;
  110. const float distance = 3.0f;
  111. AZ::Debug::ArcBallControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::ArcBallControllerRequestBus::Events::SetCenter, AZ::Vector3(0.f));
  112. AZ::Debug::ArcBallControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::ArcBallControllerRequestBus::Events::SetDistance, distance);
  113. AZ::Debug::ArcBallControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::ArcBallControllerRequestBus::Events::SetMaxDistance, 50.0f);
  114. AZ::Debug::ArcBallControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::ArcBallControllerRequestBus::Events::SetPitch, pitch);
  115. AZ::Debug::ArcBallControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::ArcBallControllerRequestBus::Events::SetHeading, heading);
  116. }
  117. void MSAA_RPI_ExampleComponent::DefaultWindowCreated()
  118. {
  119. AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &AZ::Render::Bootstrap::DefaultWindowBus::Events::GetDefaultWindowContext);
  120. }
  121. AZ::Data::Asset<AZ::RPI::MaterialAsset> MSAA_RPI_ExampleComponent::GetMaterialAsset()
  122. {
  123. AZ::RPI::AssetUtils::TraceLevel traceLevel = AZ::RPI::AssetUtils::TraceLevel::Assert;
  124. return AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::MaterialAsset>(DefaultPbrMaterialPath, traceLevel);
  125. }
  126. AZ::Data::Asset<AZ::RPI::ModelAsset> MSAA_RPI_ExampleComponent::GetModelAsset()
  127. {
  128. AZ::RPI::AssetUtils::TraceLevel traceLevel = AZ::RPI::AssetUtils::TraceLevel::Assert;
  129. switch (m_modelType)
  130. {
  131. case 0:
  132. return AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>("objects/cylinder.fbx.azmodel", traceLevel);
  133. case 1:
  134. return AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>("objects/cube.fbx.azmodel", traceLevel);
  135. case 2:
  136. return AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>("objects/shaderball_simple.fbx.azmodel", traceLevel);
  137. }
  138. AZ_Warning("MSAA_RPI_ExampleComponent", false, "Unsupported model type");
  139. return AZ::RPI::AssetUtils::GetAssetByProductPath<AZ::RPI::ModelAsset>("objects/cylinder.fbx.azmodel", traceLevel);
  140. }
  141. void MSAA_RPI_ExampleComponent::ActivateModel()
  142. {
  143. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScript);
  144. AZ::Render::MeshHandleDescriptor descriptor(GetModelAsset(), AZ::RPI::Material::FindOrCreate(GetMaterialAsset()));
  145. descriptor.m_modelChangedEventHandler =
  146. AZ::Render::MeshHandleDescriptor::ModelChangedEvent::Handler{ [this](const AZ::Data::Instance<AZ::RPI::Model>& model)
  147. {
  148. OnModelReady(model);
  149. } };
  150. m_meshHandle = GetMeshFeatureProcessor()->AcquireMesh(descriptor);
  151. GetMeshFeatureProcessor()->SetTransform(m_meshHandle, AZ::Transform::CreateIdentity());
  152. }
  153. void MSAA_RPI_ExampleComponent::OnModelReady(AZ::Data::Instance<AZ::RPI::Model> model)
  154. {
  155. AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset = model->GetModelAsset();
  156. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  157. }
  158. void MSAA_RPI_ExampleComponent::ActivateIbl()
  159. {
  160. m_defaultIbl.Init(m_scene);
  161. // reduce the exposure so the model isn't overly bright
  162. m_defaultIbl.SetExposure(-0.5f);
  163. }
  164. void MSAA_RPI_ExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
  165. {
  166. DrawSidebar();
  167. }
  168. void MSAA_RPI_ExampleComponent::DrawSidebar()
  169. {
  170. if (!m_imguiSidebar.Begin())
  171. {
  172. return;
  173. }
  174. bool refresh = false;
  175. refresh = DrawSidebarModeChooser(refresh);
  176. refresh = DrawSideBarModelChooser(refresh);
  177. m_imguiSidebar.End();
  178. if (refresh)
  179. {
  180. // Note that the model's have some multisample information embedded into their pipeline state, so delete and recreate the model
  181. GetMeshFeatureProcessor()->ReleaseMesh(m_meshHandle);
  182. ChangeRenderPipeline();
  183. ActivateModel();
  184. }
  185. }
  186. bool MSAA_RPI_ExampleComponent::DrawSidebarModeChooser(bool refresh)
  187. {
  188. ScriptableImGui::ScopedNameContext context{ "Mode" };
  189. ImGui::Text("Num Samples");
  190. refresh |= ScriptableImGui::RadioButton("MSAA None", &m_numSamples, 1);
  191. refresh |= ScriptableImGui::RadioButton("MSAA 2x", &m_numSamples, 2);
  192. refresh |= ScriptableImGui::RadioButton("MSAA 4x", &m_numSamples, 4);
  193. refresh |= ScriptableImGui::RadioButton("MSAA 8x", &m_numSamples, 8);
  194. return refresh;
  195. }
  196. bool MSAA_RPI_ExampleComponent::DrawSideBarModelChooser(bool refresh)
  197. {
  198. ScriptableImGui::ScopedNameContext context{ "Model" };
  199. ImGui::NewLine();
  200. ImGui::Text("Model");
  201. refresh |= ScriptableImGui::RadioButton("Cylinder", &m_modelType, 0);
  202. refresh |= ScriptableImGui::RadioButton("Cube", &m_modelType, 1);
  203. refresh |= ScriptableImGui::RadioButton("ShaderBall", &m_modelType, 2);
  204. return refresh;
  205. }
  206. }