SubpassExampleComponent.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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 <RHI/SubpassExampleComponent.h>
  9. #include <Utils/Utils.h>
  10. #include <SampleComponentManager.h>
  11. #include <SampleComponentConfig.h>
  12. #include <Atom/Component/DebugCamera/ArcBallControllerComponent.h>
  13. #include <Atom/RHI/CommandList.h>
  14. #include <Atom/RHI/IndirectBufferWriter.h>
  15. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  16. #include <Atom/RHI.Reflect/RenderAttachmentLayoutBuilder.h>
  17. #include <Atom/RPI.Public/Shader/Shader.h>
  18. #include <Atom/RPI.Public/View.h>
  19. #include <Atom/RPI.Public/ViewProviderBus.h>
  20. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  21. #include <AzCore/Serialization/SerializeContext.h>
  22. #include <AzCore/Math/MatrixUtils.h>
  23. namespace AtomSampleViewer
  24. {
  25. using namespace AZ;
  26. namespace SubpassInputExample
  27. {
  28. const char* SampleName = "SubpassInputExample";
  29. }
  30. SubpassExampleComponent::SubpassExampleComponent()
  31. : m_albedoAttachmentId("albedoAttachmentId")
  32. , m_normalAttachmentId("normalAttachmentId")
  33. , m_positionAttachmentId("positionAttachmentId")
  34. , m_depthStencilAttachmentId("depthAttachmentId")
  35. {
  36. m_supportRHISamplePipeline = true;
  37. }
  38. void SubpassExampleComponent::Reflect(AZ::ReflectContext* context)
  39. {
  40. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  41. {
  42. serializeContext->Class<SubpassExampleComponent, AZ::Component>()
  43. ->Version(0)
  44. ;
  45. }
  46. }
  47. void SubpassExampleComponent::OnFramePrepare(AZ::RHI::FrameGraphBuilder& frameGraphBuilder)
  48. {
  49. using namespace AZ;
  50. RHI::FrameGraphAttachmentInterface builder = frameGraphBuilder.GetAttachmentDatabase();
  51. uint32_t width = static_cast<uint32_t>(GetViewportWidth());
  52. uint32_t height = static_cast<uint32_t>(GetViewportHeight());
  53. {
  54. // Create the depth buffer for rendering.
  55. const AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D(
  56. AZ::RHI::ImageBindFlags::DepthStencil,
  57. width,
  58. height,
  59. AZ::RHI::Format::D32_FLOAT);
  60. const AZ::RHI::TransientImageDescriptor transientImageDescriptor(m_depthStencilAttachmentId, imageDescriptor);
  61. builder.CreateTransientImage(transientImageDescriptor);
  62. }
  63. {
  64. // Create the GBuffer position render target.
  65. const AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D(
  66. AZ::RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderRead,
  67. width,
  68. height,
  69. AZ::RHI::Format::R16G16B16A16_FLOAT);
  70. const AZ::RHI::TransientImageDescriptor transientImageDescriptor(m_positionAttachmentId, imageDescriptor);
  71. builder.CreateTransientImage(transientImageDescriptor);
  72. }
  73. {
  74. // Create the GBuffer normal render target.
  75. const AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D(
  76. AZ::RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderRead,
  77. width,
  78. height,
  79. AZ::RHI::Format::R16G16B16A16_FLOAT);
  80. const AZ::RHI::TransientImageDescriptor transientImageDescriptor(m_normalAttachmentId, imageDescriptor);
  81. builder.CreateTransientImage(transientImageDescriptor);
  82. }
  83. {
  84. // Create the GBuffer albedo render target.
  85. const AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D(
  86. AZ::RHI::ImageBindFlags::Color | RHI::ImageBindFlags::ShaderRead,
  87. width,
  88. height,
  89. AZ::RHI::Format::R8G8B8A8_UNORM);
  90. const AZ::RHI::TransientImageDescriptor transientImageDescriptor(m_albedoAttachmentId, imageDescriptor);
  91. builder.CreateTransientImage(transientImageDescriptor);
  92. }
  93. BasicRHIComponent::OnFramePrepare(frameGraphBuilder);
  94. }
  95. void SubpassExampleComponent::Activate()
  96. {
  97. LoadModels();
  98. LoadShaders();
  99. CreateShaderResourceGroups();
  100. CreatePipelines();
  101. CreateGBufferScope();
  102. CreateCompositionScope();
  103. SetupScene();
  104. AZ::Debug::CameraControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::CameraControllerRequestBus::Events::Enable,
  105. azrtti_typeid<AZ::Debug::ArcBallControllerComponent>());
  106. AZ::RPI::ViewPtr cameraView;
  107. // The RPI::View associated to this component can be obtained through the ViewProvider, by using Entity Id.
  108. AZ::RPI::ViewProviderBus::EventResult(cameraView, m_cameraEntityId, &AZ::RPI::ViewProvider::GetView);
  109. if (cameraView)
  110. {
  111. m_viewShaderResourceGroup = cameraView->GetShaderResourceGroup();
  112. }
  113. AZ::RHI::RHISystemNotificationBus::Handler::BusConnect();
  114. ExampleComponentRequestBus::Handler::BusConnect(GetEntityId());
  115. }
  116. void SubpassExampleComponent::Deactivate()
  117. {
  118. AZ::Debug::CameraControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::CameraControllerRequestBus::Events::Disable);
  119. ExampleComponentRequestBus::Handler::BusDisconnect();
  120. AZ::RHI::RHISystemNotificationBus::Handler::BusDisconnect();
  121. m_viewShaderResourceGroup = nullptr;
  122. m_windowContext = nullptr;
  123. m_scopeProducers.clear();
  124. }
  125. void SubpassExampleComponent::LoadModels()
  126. {
  127. const char* modelsPath[ModelType_Count] =
  128. {
  129. "objects/plane.azmodel",
  130. "objects/shaderball_simple.azmodel",
  131. "objects/bunny.azmodel",
  132. "objects/suzanne.azmodel",
  133. };
  134. for (uint32_t i = 0; i < AZ_ARRAY_SIZE(modelsPath); ++i)
  135. {
  136. Data::AssetId modelAssetId;
  137. Data::AssetCatalogRequestBus::BroadcastResult(
  138. modelAssetId, &Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
  139. modelsPath[i], azrtti_typeid<AZ::RPI::ModelAsset>(), false);
  140. if (!modelAssetId.IsValid())
  141. {
  142. continue;
  143. }
  144. // Load the asset
  145. auto modelAsset = Data::AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(
  146. modelAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
  147. modelAsset.BlockUntilLoadComplete();
  148. if (!modelAsset.IsReady())
  149. {
  150. continue;
  151. }
  152. m_models[i] = AZ::RPI::Model::FindOrCreate(modelAsset);
  153. }
  154. const ModelType opaqueModels[] =
  155. {
  156. ModelType_Plane,
  157. ModelType_ShaderBall,
  158. ModelType_Bunny,
  159. ModelType_Suzanne,
  160. };
  161. AZStd::span<const ModelType> types(&opaqueModels[0], AZ_ARRAY_SIZE(opaqueModels));
  162. m_opaqueModelsData.resize(types.size());
  163. for (uint32_t i = 0; i < m_opaqueModelsData.size(); ++i)
  164. {
  165. m_opaqueModelsData[i].m_modelType = types[i];
  166. m_meshCount += aznumeric_cast<uint32_t>(m_models[m_opaqueModelsData[i].m_modelType]->GetLods()[0]->GetMeshes().size());
  167. }
  168. }
  169. void SubpassExampleComponent::LoadShaders()
  170. {
  171. const char* shaders[] =
  172. {
  173. "Shaders/RHI/SubpassInputGBuffer.azshader",
  174. "Shaders/RHI/SubpassInputComposition.azshader"
  175. };
  176. m_shaders.resize(AZ_ARRAY_SIZE(shaders));
  177. for (size_t i = 0; i < AZ_ARRAY_SIZE(shaders); ++i)
  178. {
  179. auto shader = LoadShader(shaders[i], SubpassInputExample::SampleName);
  180. if (shader == nullptr)
  181. {
  182. return;
  183. }
  184. m_shaders[i] = shader;
  185. }
  186. }
  187. void SubpassExampleComponent::CreatePipelines()
  188. {
  189. uint32_t subpassIndex = 0;
  190. // Build the render attachment layout with the 2 subpasses.
  191. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  192. // GBuffer Subpass
  193. attachmentsBuilder.AddSubpass()
  194. ->RenderTargetAttachment(RHI::Format::R16G16B16A16_FLOAT, m_positionAttachmentId)
  195. ->RenderTargetAttachment(RHI::Format::R16G16B16A16_FLOAT, m_normalAttachmentId)
  196. ->RenderTargetAttachment(RHI::Format::R8G8B8A8_UNORM, m_albedoAttachmentId)
  197. ->RenderTargetAttachment(m_outputFormat, m_outputAttachmentId)
  198. ->DepthStencilAttachment(AZ::RHI::Format::D32_FLOAT, m_depthStencilAttachmentId);
  199. // Composition Subpass
  200. attachmentsBuilder.AddSubpass()
  201. ->SubpassInputAttachment(m_positionAttachmentId, RHI::ImageAspectFlags::Color)
  202. ->SubpassInputAttachment(m_normalAttachmentId, RHI::ImageAspectFlags::Color)
  203. ->SubpassInputAttachment(m_albedoAttachmentId, RHI::ImageAspectFlags::Color)
  204. ->RenderTargetAttachment(m_outputAttachmentId)
  205. ->DepthStencilAttachment(m_depthStencilAttachmentId);
  206. RHI::RenderAttachmentLayout renderAttachmentLayout;
  207. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(renderAttachmentLayout);
  208. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  209. {
  210. // GBuffer Scope Pipelines
  211. const auto& shader = m_shaders[GBufferScope];
  212. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  213. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  214. variant.ConfigurePipelineState(pipelineDesc);
  215. pipelineDesc.m_renderStates.m_depthStencilState = RHI::DepthStencilState::CreateReverseDepth();
  216. pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout = renderAttachmentLayout;
  217. pipelineDesc.m_renderAttachmentConfiguration.m_subpassIndex = subpassIndex++;
  218. // Model Pipeline
  219. for (auto& modelData : m_opaqueModelsData)
  220. {
  221. Data::Instance<AZ::RPI::ModelLod> modelLod = m_models[modelData.m_modelType]->GetLods()[0];
  222. modelLod->GetStreamsForMesh(
  223. pipelineDesc.m_inputStreamLayout,
  224. modelData.m_streamBufferList,
  225. nullptr,
  226. shader->GetInputContract(),
  227. 0);
  228. pipelineDesc.m_renderStates.m_rasterState.m_cullMode = modelData.m_modelType == ModelType_Plane ? RHI::CullMode::None : RHI::CullMode::Back;
  229. modelData.m_pipelineState = shader->AcquirePipelineState(pipelineDesc);
  230. if (!modelData.m_pipelineState)
  231. {
  232. AZ_Error(SubpassInputExample::SampleName, false, "Failed to acquire default pipeline state for shader");
  233. return;
  234. }
  235. }
  236. }
  237. {
  238. const auto& shader = m_shaders[CompositionScope];
  239. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  240. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  241. variant.ConfigurePipelineState(pipelineDesc);
  242. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_enable = 1;
  243. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_writeMask = RHI::DepthWriteMask::Zero;
  244. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::Less;
  245. pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout = renderAttachmentLayout;
  246. pipelineDesc.m_renderAttachmentConfiguration.m_subpassIndex = subpassIndex++;
  247. RHI::InputStreamLayout& inputStreamLayout = pipelineDesc.m_inputStreamLayout;
  248. inputStreamLayout.SetTopology(RHI::PrimitiveTopology::TriangleList);
  249. inputStreamLayout.Finalize();
  250. // Composition Pipeline
  251. m_compositionPipeline = shader->AcquirePipelineState(pipelineDesc);
  252. if (!m_compositionPipeline)
  253. {
  254. AZ_Error(SubpassInputExample::SampleName, false, "Failed to acquire composition pipeline state for shader");
  255. return;
  256. }
  257. }
  258. }
  259. void SubpassExampleComponent::CreateShaderResourceGroups()
  260. {
  261. const Name modelMatrixId{ "m_modelMatrix" };
  262. const Name colorId{ "m_color" };
  263. const Name subpassInputPositionId{ "m_position" };
  264. const Name subpassInputNormalId{ "m_normal" };
  265. const Name subpassInputAlbedoId{ "m_albedo" };
  266. const Name lightsInfoId{ "m_lights" };
  267. for (auto& modelData : m_opaqueModelsData)
  268. {
  269. modelData.m_shaderResourceGroup = CreateShaderResourceGroup(m_shaders[GBufferScope], "SubpassInputModelSrg", SubpassInputExample::SampleName);
  270. AZ::RHI::ShaderInputConstantIndex colorIndex;
  271. FindShaderInputIndex(&m_modelMatrixIndex, modelData.m_shaderResourceGroup, modelMatrixId, SubpassInputExample::SampleName);
  272. FindShaderInputIndex(&colorIndex, modelData.m_shaderResourceGroup, colorId, SubpassInputExample::SampleName);
  273. modelData.m_shaderResourceGroup->SetConstant(colorIndex, AZ::Color(0.2f, 0.3f, 0.1f, 1.0f));
  274. }
  275. m_sceneShaderResourceGroup = CreateShaderResourceGroup(m_shaders[CompositionScope], "SubpassInputSceneSrg", SubpassInputExample::SampleName);
  276. FindShaderInputIndex(&m_lightsInfoIndex, m_sceneShaderResourceGroup, lightsInfoId, SubpassInputExample::SampleName);
  277. m_compositionSubpassInputsSRG = CreateShaderResourceGroup(m_shaders[CompositionScope], "SubpassInputsSrg", SubpassInputExample::SampleName);
  278. FindShaderInputIndex(&m_subpassInputPosition, m_compositionSubpassInputsSRG, subpassInputPositionId, SubpassInputExample::SampleName);
  279. FindShaderInputIndex(&m_subpassInputNormal, m_compositionSubpassInputsSRG, subpassInputNormalId, SubpassInputExample::SampleName);
  280. FindShaderInputIndex(&m_subpassInputAlbedo, m_compositionSubpassInputsSRG, subpassInputAlbedoId, SubpassInputExample::SampleName);
  281. }
  282. void SubpassExampleComponent::CreateGBufferScope()
  283. {
  284. struct ScopeData
  285. {
  286. };
  287. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  288. {
  289. // Bind the position GBuffer
  290. {
  291. RHI::ImageScopeAttachmentDescriptor descriptor;
  292. descriptor.m_attachmentId = m_positionAttachmentId;
  293. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  294. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  295. frameGraph.UseColorAttachment(descriptor);
  296. }
  297. // Bind the normal GBuffer
  298. {
  299. RHI::ImageScopeAttachmentDescriptor descriptor;
  300. descriptor.m_attachmentId = m_normalAttachmentId;
  301. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  302. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  303. frameGraph.UseColorAttachment(descriptor);
  304. }
  305. // Bind the albedo GBuffer
  306. {
  307. RHI::ImageScopeAttachmentDescriptor descriptor;
  308. descriptor.m_attachmentId = m_albedoAttachmentId;
  309. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  310. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  311. frameGraph.UseColorAttachment(descriptor);
  312. }
  313. // Bind SwapChain image
  314. {
  315. RHI::ImageScopeAttachmentDescriptor descriptor;
  316. descriptor.m_attachmentId = m_outputAttachmentId;
  317. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  318. frameGraph.UseColorAttachment(descriptor);
  319. }
  320. // Bind DepthStencil image
  321. {
  322. RHI::ImageScopeAttachmentDescriptor dsDesc;
  323. dsDesc.m_attachmentId = m_depthStencilAttachmentId;
  324. dsDesc.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateDepthStencil(0, 0);
  325. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  326. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::Write);
  327. }
  328. frameGraph.SetEstimatedItemCount(m_meshCount);
  329. };
  330. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  331. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  332. {
  333. RHI::CommandList* commandList = context.GetCommandList();
  334. // Bind ViewSrg
  335. commandList->SetShaderResourceGroupForDraw(*m_viewShaderResourceGroup->GetRHIShaderResourceGroup());
  336. // Set persistent viewport and scissor state.
  337. commandList->SetViewports(&m_viewport, 1);
  338. commandList->SetScissors(&m_scissor, 1);
  339. for (size_t i = 0; i < m_opaqueModelsData.size(); ++i)
  340. {
  341. // Model
  342. const auto& modelData = m_opaqueModelsData[i];
  343. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  344. {
  345. modelData.m_shaderResourceGroup->GetRHIShaderResourceGroup()
  346. };
  347. for (const auto& mesh : m_models[modelData.m_modelType]->GetLods()[0]->GetMeshes())
  348. {
  349. RHI::DrawItem drawItem;
  350. drawItem.m_arguments = mesh.m_drawArguments;
  351. drawItem.m_pipelineState = modelData.m_pipelineState.get();
  352. drawItem.m_indexBufferView = &mesh.m_indexBufferView;
  353. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  354. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  355. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(modelData.m_streamBufferList.size());
  356. drawItem.m_streamBufferViews = modelData.m_streamBufferList.data();
  357. commandList->Submit(drawItem);
  358. }
  359. }
  360. };
  361. const RHI::ScopeId forwardScope("GBufferScope");
  362. m_scopeProducers.emplace_back(
  363. aznew RHI::ScopeProducerFunction<
  364. ScopeData,
  365. decltype(prepareFunction),
  366. decltype(compileFunction),
  367. decltype(executeFunction)>(
  368. forwardScope,
  369. ScopeData{},
  370. prepareFunction,
  371. compileFunction,
  372. executeFunction));
  373. }
  374. void SubpassExampleComponent::CreateCompositionScope()
  375. {
  376. struct ScopeData
  377. {
  378. };
  379. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  380. {
  381. // Bind the position GBuffer
  382. {
  383. RHI::ImageScopeAttachmentDescriptor descriptor;
  384. descriptor.m_attachmentId = m_positionAttachmentId;
  385. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  386. frameGraph.UseSubpassInputAttachment(descriptor);
  387. }
  388. // Bind the normal GBuffer
  389. {
  390. RHI::ImageScopeAttachmentDescriptor descriptor;
  391. descriptor.m_attachmentId = m_normalAttachmentId;
  392. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  393. frameGraph.UseSubpassInputAttachment(descriptor);
  394. }
  395. // Bind the albedo GBuffer
  396. {
  397. RHI::ImageScopeAttachmentDescriptor descriptor;
  398. descriptor.m_attachmentId = m_albedoAttachmentId;
  399. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  400. frameGraph.UseSubpassInputAttachment(descriptor);
  401. }
  402. // Bind SwapChain image
  403. {
  404. RHI::ImageScopeAttachmentDescriptor descriptor;
  405. descriptor.m_attachmentId = m_outputAttachmentId;
  406. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  407. frameGraph.UseColorAttachment(descriptor);
  408. }
  409. // Bind DepthStencil image
  410. {
  411. RHI::ImageScopeAttachmentDescriptor dsDesc;
  412. dsDesc.m_attachmentId = m_depthStencilAttachmentId;
  413. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  414. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::Read);
  415. }
  416. frameGraph.SetEstimatedItemCount(1);
  417. };
  418. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  419. {
  420. const AZ::RHI::ImageView* positionImageView = context.GetImageView(m_positionAttachmentId);
  421. const AZ::RHI::ImageView* normalImageView = context.GetImageView(m_normalAttachmentId);
  422. const AZ::RHI::ImageView* albedoImageView = context.GetImageView(m_albedoAttachmentId);
  423. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputPosition, positionImageView);
  424. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputNormal, normalImageView);
  425. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputAlbedo, albedoImageView);
  426. m_compositionSubpassInputsSRG->Compile();
  427. };
  428. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  429. {
  430. RHI::CommandList* commandList = context.GetCommandList();
  431. // Bind ViewSrg
  432. commandList->SetShaderResourceGroupForDraw(*m_viewShaderResourceGroup->GetRHIShaderResourceGroup());
  433. // Set persistent viewport and scissor state.
  434. commandList->SetViewports(&m_viewport, 1);
  435. commandList->SetScissors(&m_scissor, 1);
  436. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  437. {
  438. m_compositionSubpassInputsSRG->GetRHIShaderResourceGroup(),
  439. m_sceneShaderResourceGroup->GetRHIShaderResourceGroup(),
  440. };
  441. RHI::DrawLinear drawArguments;
  442. drawArguments.m_instanceCount = 1;
  443. drawArguments.m_instanceOffset = 0;
  444. drawArguments.m_vertexCount = 4;
  445. drawArguments.m_vertexOffset = 0;
  446. RHI::DrawItem drawItem;
  447. drawItem.m_arguments = RHI::DrawArguments(drawArguments);
  448. drawItem.m_pipelineState = m_compositionPipeline.get();
  449. drawItem.m_indexBufferView = nullptr;
  450. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  451. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  452. drawItem.m_streamBufferViewCount = 0;
  453. drawItem.m_streamBufferViews = nullptr;
  454. commandList->Submit(drawItem);
  455. };
  456. const RHI::ScopeId forwardScope("CompositionScope");
  457. m_scopeProducers.emplace_back(
  458. aznew RHI::ScopeProducerFunction<
  459. ScopeData,
  460. decltype(prepareFunction),
  461. decltype(compileFunction),
  462. decltype(executeFunction)>(
  463. forwardScope,
  464. ScopeData{},
  465. prepareFunction,
  466. compileFunction,
  467. executeFunction));
  468. }
  469. void SubpassExampleComponent::ResetCamera()
  470. {
  471. const float pitch = -AZ::Constants::QuarterPi / 2.0f;
  472. const float distance = 35.0f;
  473. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetCenter, AZ::Vector3(0.f));
  474. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetDistance, distance);
  475. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetMaxDistance, 50.0f);
  476. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetPitch, pitch);
  477. // Set the camera Transform so we don't have a jump on the first frame.
  478. AZ::Quaternion orientation = AZ::Quaternion::CreateRotationX(pitch);
  479. AZ::Vector3 position = orientation.TransformVector(AZ::Vector3(0, -distance, 0));
  480. AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position));
  481. }
  482. bool SubpassExampleComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  483. {
  484. auto config = azrtti_cast<const SampleComponentConfig*>(baseConfig);
  485. AZ_Assert(config && config->IsValid(), "SubpassExampleComponent required for sample component configuration.");
  486. m_entityContextId = config->m_entityContextId;
  487. m_cameraEntityId = config->m_cameraEntityId;
  488. return BasicRHIComponent::ReadInConfig(baseConfig);
  489. }
  490. void SubpassExampleComponent::SetupScene()
  491. {
  492. // These are the model matrices. They contain the rotation, translation and scale of the objects that we are going to draw.
  493. struct ObjectTransforms
  494. {
  495. AZ::Vector3 m_scale;
  496. AZ::Quaternion m_rotation;
  497. AZ::Vector3 m_translation;
  498. };
  499. AZStd::vector<ObjectTransforms> opaqueObjectTransforms =
  500. { {
  501. { AZ::Vector3(50.0f), AZ::Quaternion::CreateIdentity(), AZ::Vector3::CreateZero() },
  502. { AZ::Vector3(1.0f), AZ::Quaternion::CreateIdentity(), AZ::Vector3(0.f, 0.f, 0.95f) },
  503. { AZ::Vector3(1.5f), AZ::Quaternion::CreateRotationZ(AZ::Constants::Pi), AZ::Vector3(-5.0f, 8.0f, 0.35f)},
  504. { AZ::Vector3(1.5f), AZ::Quaternion::CreateRotationZ(AZ::Constants::QuarterPi * 3.0f), AZ::Vector3(5.0f, 8.0f, 1.5f) }
  505. } };
  506. const float zNear = 1.0f, zFar = 100.0f;
  507. // Camera
  508. float fieldOfView = AZ::Constants::Pi / 4.0f;
  509. float screenAspect = GetViewportWidth() / GetViewportHeight();
  510. MakePerspectiveFovMatrixRH(m_projectionMatrix, fieldOfView, screenAspect, zNear, zFar);
  511. for (uint32_t i = 0; i < m_opaqueModelsData.size(); ++i)
  512. {
  513. const auto& transform = opaqueObjectTransforms[i];
  514. auto& srg = m_opaqueModelsData[i].m_shaderResourceGroup;
  515. auto matrix = AZ::Matrix4x4::CreateFromQuaternionAndTranslation(transform.m_rotation, transform.m_translation) * AZ::Matrix4x4::CreateScale(transform.m_scale);
  516. srg->SetConstant(m_modelMatrixIndex, matrix);
  517. srg->Compile();
  518. }
  519. AZStd::vector<ObjectTransforms> transparentObjectTransforms =
  520. { {
  521. { AZ::Vector3(2.0f), AZ::Quaternion::CreateRotationZ(AZ::Constants::HalfPi), AZ::Vector3(0.0f, 8.0f, 0.0f)},
  522. } };
  523. AZStd::vector<AZ::Vector3> colors =
  524. {
  525. AZ::Vector3(1.0f, 1.0f, 1.0f),
  526. AZ::Vector3(1.0f, 0.0f, 0.0f),
  527. AZ::Vector3(0.0f, 1.0f, 0.0f),
  528. AZ::Vector3(0.0f, 0.0f, 1.0f),
  529. AZ::Vector3(1.0f, 1.0f, 0.0f)
  530. };
  531. struct LightInfo
  532. {
  533. AZ::Vector4 m_position;
  534. // Group color and radius to match packing of the shader.
  535. AZ::Vector4 m_colorAndRadius;
  536. };
  537. constexpr uint32_t numLights = 10;
  538. AZStd::array< LightInfo, numLights> lightsInfo =
  539. { {
  540. {AZ::Vector4(-13, 5, -12, 1.f), AZ::Vector4(1.0f, 1.0f, 1.0f, 50.5f)},
  541. {AZ::Vector4(-5, 14, 3, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 30.4f)},
  542. {AZ::Vector4(5, 5, 4, 1.f), AZ::Vector4(0.0f, 0.0f, 1.0f, 40.2f)},
  543. {AZ::Vector4(2, 13, 2, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 60.8f)},
  544. {AZ::Vector4(0, 1, -2, 1.f), AZ::Vector4(1.0f, 1.0f, 0.0f, 20.0f)},
  545. {AZ::Vector4(1.5f, 12, -4, 1.f), AZ::Vector4(1.0f, 1.0f, 0.0f, 40.9f)},
  546. {AZ::Vector4(5, 5, 2, 1.f), AZ::Vector4(0.0f, 0.0f, 1.0f, 30.1f)},
  547. {AZ::Vector4(-4, 13, -13, 1.f), AZ::Vector4(1.0f, 1.0f, 1.0f, 40.3f)},
  548. {AZ::Vector4(6, 12, -1, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 60.2f)},
  549. {AZ::Vector4(13, 5, 13, 1.f), AZ::Vector4(1.0f, 0.0f, 1.0f, 10.8f)},
  550. } };
  551. m_sceneShaderResourceGroup->SetConstantArray(m_lightsInfoIndex, lightsInfo);
  552. m_sceneShaderResourceGroup->Compile();
  553. }
  554. } // namespace AtomSampleViewer