MSAA_RPI_ExampleComponent.cpp 11 KB

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