SubpassExampleComponent.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. auto setModelType = [](AZStd::span<const ModelType> types, AZStd::vector<ModelData>& modelDataList)
  162. {
  163. modelDataList.resize(types.size());
  164. for (uint32_t i = 0; i < modelDataList.size(); ++i)
  165. {
  166. modelDataList[i].m_modelType = types[i];
  167. }
  168. };
  169. setModelType(AZStd::span<const ModelType>(&opaqueModels[0], AZ_ARRAY_SIZE(opaqueModels)), m_opaqueModelsData);
  170. }
  171. void SubpassExampleComponent::LoadShaders()
  172. {
  173. const char* shaders[] =
  174. {
  175. "Shaders/RHI/SubpassInputGBuffer.azshader",
  176. "Shaders/RHI/SubpassInputComposition.azshader"
  177. };
  178. m_shaders.resize(AZ_ARRAY_SIZE(shaders));
  179. for (size_t i = 0; i < AZ_ARRAY_SIZE(shaders); ++i)
  180. {
  181. auto shader = LoadShader(shaders[i], SubpassInputExample::SampleName);
  182. if (shader == nullptr)
  183. {
  184. return;
  185. }
  186. m_shaders[i] = shader;
  187. }
  188. }
  189. void SubpassExampleComponent::CreatePipelines()
  190. {
  191. uint32_t subpassIndex = 0;
  192. // Build the render attachment layout with the 2 subpasses.
  193. RHI::RenderAttachmentLayoutBuilder attachmentsBuilder;
  194. // GBuffer Subpass
  195. attachmentsBuilder.AddSubpass()
  196. ->RenderTargetAttachment(RHI::Format::R16G16B16A16_FLOAT, m_positionAttachmentId)
  197. ->RenderTargetAttachment(RHI::Format::R16G16B16A16_FLOAT, m_normalAttachmentId)
  198. ->RenderTargetAttachment(RHI::Format::R8G8B8A8_UNORM, m_albedoAttachmentId)
  199. ->RenderTargetAttachment(m_outputFormat, m_outputAttachmentId)
  200. ->DepthStencilAttachment(AZ::RHI::Format::D32_FLOAT, m_depthStencilAttachmentId);
  201. // Composition Subpass
  202. attachmentsBuilder.AddSubpass()
  203. ->SubpassInputAttachment(m_positionAttachmentId)
  204. ->SubpassInputAttachment(m_normalAttachmentId)
  205. ->SubpassInputAttachment(m_albedoAttachmentId)
  206. ->RenderTargetAttachment(m_outputAttachmentId)
  207. ->DepthStencilAttachment(m_depthStencilAttachmentId);
  208. RHI::RenderAttachmentLayout renderAttachmentLayout;
  209. [[maybe_unused]] RHI::ResultCode result = attachmentsBuilder.End(renderAttachmentLayout);
  210. AZ_Assert(result == RHI::ResultCode::Success, "Failed to create render attachment layout");
  211. {
  212. // GBuffer Scope Pipelines
  213. const auto& shader = m_shaders[GBufferScope];
  214. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  215. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  216. variant.ConfigurePipelineState(pipelineDesc);
  217. pipelineDesc.m_renderStates.m_depthStencilState = RHI::DepthStencilState::CreateReverseDepth();
  218. pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout = renderAttachmentLayout;
  219. pipelineDesc.m_renderAttachmentConfiguration.m_subpassIndex = subpassIndex++;
  220. // Model Pipeline
  221. for (auto& modelData : m_opaqueModelsData)
  222. {
  223. Data::Instance<AZ::RPI::ModelLod> modelLod = m_models[modelData.m_modelType]->GetLods()[0];
  224. modelLod->GetStreamsForMesh(
  225. pipelineDesc.m_inputStreamLayout,
  226. modelData.m_streamBufferList,
  227. nullptr,
  228. shader->GetInputContract(),
  229. 0);
  230. pipelineDesc.m_renderStates.m_rasterState.m_cullMode = modelData.m_modelType == ModelType_Plane ? RHI::CullMode::None : RHI::CullMode::Back;
  231. modelData.m_pipelineState = shader->AcquirePipelineState(pipelineDesc);
  232. if (!modelData.m_pipelineState)
  233. {
  234. AZ_Error(SubpassInputExample::SampleName, false, "Failed to acquire default pipeline state for shader");
  235. return;
  236. }
  237. }
  238. }
  239. {
  240. const auto& shader = m_shaders[CompositionScope];
  241. auto& variant = shader->GetVariant(AZ::RPI::ShaderAsset::RootShaderVariantStableId);
  242. RHI::PipelineStateDescriptorForDraw pipelineDesc;
  243. variant.ConfigurePipelineState(pipelineDesc);
  244. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_enable = 1;
  245. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_writeMask = RHI::DepthWriteMask::Zero;
  246. pipelineDesc.m_renderStates.m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::Less;
  247. pipelineDesc.m_renderAttachmentConfiguration.m_renderAttachmentLayout = renderAttachmentLayout;
  248. pipelineDesc.m_renderAttachmentConfiguration.m_subpassIndex = subpassIndex++;
  249. RHI::InputStreamLayout& inputStreamLayout = pipelineDesc.m_inputStreamLayout;
  250. inputStreamLayout.SetTopology(RHI::PrimitiveTopology::TriangleList);
  251. inputStreamLayout.Finalize();
  252. // Composition Pipeline
  253. m_compositionPipeline = shader->AcquirePipelineState(pipelineDesc);
  254. if (!m_compositionPipeline)
  255. {
  256. AZ_Error(SubpassInputExample::SampleName, false, "Failed to acquire composition pipeline state for shader");
  257. return;
  258. }
  259. }
  260. }
  261. void SubpassExampleComponent::CreateShaderResourceGroups()
  262. {
  263. const Name modelMatrixId{ "m_modelMatrix" };
  264. const Name colorId{ "m_color" };
  265. const Name subpassInputPositionId{ "m_position" };
  266. const Name subpassInputNormalId{ "m_normal" };
  267. const Name subpassInputAlbedoId{ "m_albedo" };
  268. const Name lightsInfoId{ "m_lights" };
  269. for (auto& modelData : m_opaqueModelsData)
  270. {
  271. modelData.m_shaderResourceGroup = CreateShaderResourceGroup(m_shaders[GBufferScope], "SubpassInputModelSrg", SubpassInputExample::SampleName);
  272. AZ::RHI::ShaderInputConstantIndex colorIndex;
  273. FindShaderInputIndex(&m_modelMatrixIndex, modelData.m_shaderResourceGroup, modelMatrixId, SubpassInputExample::SampleName);
  274. FindShaderInputIndex(&colorIndex, modelData.m_shaderResourceGroup, colorId, SubpassInputExample::SampleName);
  275. modelData.m_shaderResourceGroup->SetConstant(colorIndex, AZ::Color(0.2f, 0.3f, 0.1f, 1.0f));
  276. }
  277. m_sceneShaderResourceGroup = CreateShaderResourceGroup(m_shaders[CompositionScope], "SubpassInputSceneSrg", SubpassInputExample::SampleName);
  278. FindShaderInputIndex(&m_lightsInfoIndex, m_sceneShaderResourceGroup, lightsInfoId, SubpassInputExample::SampleName);
  279. m_compositionSubpassInputsSRG = CreateShaderResourceGroup(m_shaders[CompositionScope], "SubpassInputsSrg", SubpassInputExample::SampleName);
  280. FindShaderInputIndex(&m_subpassInputPosition, m_compositionSubpassInputsSRG, subpassInputPositionId, SubpassInputExample::SampleName);
  281. FindShaderInputIndex(&m_subpassInputNormal, m_compositionSubpassInputsSRG, subpassInputNormalId, SubpassInputExample::SampleName);
  282. FindShaderInputIndex(&m_subpassInputAlbedo, m_compositionSubpassInputsSRG, subpassInputAlbedoId, SubpassInputExample::SampleName);
  283. }
  284. void SubpassExampleComponent::CreateGBufferScope()
  285. {
  286. struct ScopeData
  287. {
  288. };
  289. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  290. {
  291. // Bind the position GBuffer
  292. {
  293. RHI::ImageScopeAttachmentDescriptor descriptor;
  294. descriptor.m_attachmentId = m_positionAttachmentId;
  295. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  296. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  297. frameGraph.UseColorAttachment(descriptor);
  298. }
  299. // Bind the normal GBuffer
  300. {
  301. RHI::ImageScopeAttachmentDescriptor descriptor;
  302. descriptor.m_attachmentId = m_normalAttachmentId;
  303. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  304. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  305. frameGraph.UseColorAttachment(descriptor);
  306. }
  307. // Bind the albedo GBuffer
  308. {
  309. RHI::ImageScopeAttachmentDescriptor descriptor;
  310. descriptor.m_attachmentId = m_albedoAttachmentId;
  311. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  312. descriptor.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateVector4Float(0.f, 0.f, 0.f, 0.f);
  313. frameGraph.UseColorAttachment(descriptor);
  314. }
  315. // Bind SwapChain image
  316. {
  317. RHI::ImageScopeAttachmentDescriptor descriptor;
  318. descriptor.m_attachmentId = m_outputAttachmentId;
  319. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  320. frameGraph.UseColorAttachment(descriptor);
  321. }
  322. // Bind DepthStencil image
  323. {
  324. RHI::ImageScopeAttachmentDescriptor dsDesc;
  325. dsDesc.m_attachmentId = m_depthStencilAttachmentId;
  326. dsDesc.m_loadStoreAction.m_clearValue = RHI::ClearValue::CreateDepthStencil(0, 0);
  327. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
  328. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::Write);
  329. }
  330. frameGraph.SetEstimatedItemCount(static_cast<uint32_t>(m_opaqueModelsData.size()));
  331. };
  332. RHI::EmptyCompileFunction<ScopeData> compileFunction;
  333. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  334. {
  335. RHI::CommandList* commandList = context.GetCommandList();
  336. // Bind ViewSrg
  337. commandList->SetShaderResourceGroupForDraw(*m_viewShaderResourceGroup->GetRHIShaderResourceGroup());
  338. // Set persistent viewport and scissor state.
  339. commandList->SetViewports(&m_viewport, 1);
  340. commandList->SetScissors(&m_scissor, 1);
  341. for (size_t i = 0; i < m_opaqueModelsData.size(); ++i)
  342. {
  343. // Model
  344. const auto& modelData = m_opaqueModelsData[i];
  345. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  346. {
  347. modelData.m_shaderResourceGroup->GetRHIShaderResourceGroup()
  348. };
  349. for (const auto& mesh : m_models[modelData.m_modelType]->GetLods()[0]->GetMeshes())
  350. {
  351. RHI::DrawItem drawItem;
  352. drawItem.m_arguments = mesh.m_drawArguments;
  353. drawItem.m_pipelineState = modelData.m_pipelineState.get();
  354. drawItem.m_indexBufferView = &mesh.m_indexBufferView;
  355. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  356. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  357. drawItem.m_streamBufferViewCount = static_cast<uint8_t>(modelData.m_streamBufferList.size());
  358. drawItem.m_streamBufferViews = modelData.m_streamBufferList.data();
  359. commandList->Submit(drawItem);
  360. }
  361. }
  362. };
  363. const RHI::ScopeId forwardScope("GBufferScope");
  364. m_scopeProducers.emplace_back(
  365. aznew RHI::ScopeProducerFunction<
  366. ScopeData,
  367. decltype(prepareFunction),
  368. decltype(compileFunction),
  369. decltype(executeFunction)>(
  370. forwardScope,
  371. ScopeData{},
  372. prepareFunction,
  373. compileFunction,
  374. executeFunction));
  375. }
  376. void SubpassExampleComponent::CreateCompositionScope()
  377. {
  378. struct ScopeData
  379. {
  380. };
  381. const auto prepareFunction = [this](RHI::FrameGraphInterface frameGraph, [[maybe_unused]] ScopeData& scopeData)
  382. {
  383. // Bind the position GBuffer
  384. {
  385. RHI::ImageScopeAttachmentDescriptor descriptor;
  386. descriptor.m_attachmentId = m_positionAttachmentId;
  387. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  388. frameGraph.UseSubpassInputAttachment(descriptor);
  389. }
  390. // Bind the normal GBuffer
  391. {
  392. RHI::ImageScopeAttachmentDescriptor descriptor;
  393. descriptor.m_attachmentId = m_normalAttachmentId;
  394. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  395. frameGraph.UseSubpassInputAttachment(descriptor);
  396. }
  397. // Bind the albedo GBuffer
  398. {
  399. RHI::ImageScopeAttachmentDescriptor descriptor;
  400. descriptor.m_attachmentId = m_albedoAttachmentId;
  401. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  402. frameGraph.UseSubpassInputAttachment(descriptor);
  403. }
  404. // Bind SwapChain image
  405. {
  406. RHI::ImageScopeAttachmentDescriptor descriptor;
  407. descriptor.m_attachmentId = m_outputAttachmentId;
  408. descriptor.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  409. frameGraph.UseColorAttachment(descriptor);
  410. }
  411. // Bind DepthStencil image
  412. {
  413. RHI::ImageScopeAttachmentDescriptor dsDesc;
  414. dsDesc.m_attachmentId = m_depthStencilAttachmentId;
  415. dsDesc.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Load;
  416. frameGraph.UseDepthStencilAttachment(dsDesc, RHI::ScopeAttachmentAccess::Read);
  417. }
  418. frameGraph.SetEstimatedItemCount(1);
  419. };
  420. const auto compileFunction = [this](const RHI::FrameGraphCompileContext& context, [[maybe_unused]] const ScopeData& scopeData)
  421. {
  422. const AZ::RHI::ImageView* positionImageView = context.GetImageView(m_positionAttachmentId);
  423. const AZ::RHI::ImageView* normalImageView = context.GetImageView(m_normalAttachmentId);
  424. const AZ::RHI::ImageView* albedoImageView = context.GetImageView(m_albedoAttachmentId);
  425. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputPosition, positionImageView);
  426. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputNormal, normalImageView);
  427. m_compositionSubpassInputsSRG->SetImageView(m_subpassInputAlbedo, albedoImageView);
  428. m_compositionSubpassInputsSRG->Compile();
  429. };
  430. const auto executeFunction = [this](const RHI::FrameGraphExecuteContext& context, [[maybe_unused]] const ScopeData& scopeData)
  431. {
  432. RHI::CommandList* commandList = context.GetCommandList();
  433. // Bind ViewSrg
  434. commandList->SetShaderResourceGroupForDraw(*m_viewShaderResourceGroup->GetRHIShaderResourceGroup());
  435. // Set persistent viewport and scissor state.
  436. commandList->SetViewports(&m_viewport, 1);
  437. commandList->SetScissors(&m_scissor, 1);
  438. const RHI::ShaderResourceGroup* shaderResourceGroups[] =
  439. {
  440. m_compositionSubpassInputsSRG->GetRHIShaderResourceGroup(),
  441. m_sceneShaderResourceGroup->GetRHIShaderResourceGroup(),
  442. };
  443. RHI::DrawLinear drawArguments;
  444. drawArguments.m_instanceCount = 1;
  445. drawArguments.m_instanceOffset = 0;
  446. drawArguments.m_vertexCount = 4;
  447. drawArguments.m_vertexOffset = 0;
  448. RHI::DrawItem drawItem;
  449. drawItem.m_arguments = RHI::DrawArguments(drawArguments);
  450. drawItem.m_pipelineState = m_compositionPipeline.get();
  451. drawItem.m_indexBufferView = nullptr;
  452. drawItem.m_shaderResourceGroupCount = static_cast<uint8_t>(RHI::ArraySize(shaderResourceGroups));
  453. drawItem.m_shaderResourceGroups = shaderResourceGroups;
  454. drawItem.m_streamBufferViewCount = 0;
  455. drawItem.m_streamBufferViews = nullptr;
  456. commandList->Submit(drawItem);
  457. };
  458. const RHI::ScopeId forwardScope("CompositionScope");
  459. m_scopeProducers.emplace_back(
  460. aznew RHI::ScopeProducerFunction<
  461. ScopeData,
  462. decltype(prepareFunction),
  463. decltype(compileFunction),
  464. decltype(executeFunction)>(
  465. forwardScope,
  466. ScopeData{},
  467. prepareFunction,
  468. compileFunction,
  469. executeFunction));
  470. }
  471. void SubpassExampleComponent::ResetCamera()
  472. {
  473. const float pitch = -AZ::Constants::QuarterPi / 2.0f;
  474. const float distance = 35.0f;
  475. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetCenter, AZ::Vector3(0.f));
  476. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetDistance, distance);
  477. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetMaxDistance, 50.0f);
  478. AZ::Debug::ArcBallControllerRequestBus::Event(m_cameraEntityId, &AZ::Debug::ArcBallControllerRequestBus::Events::SetPitch, pitch);
  479. // Set the camera Transform so we don't have a jump on the first frame.
  480. AZ::Quaternion orientation = AZ::Quaternion::CreateRotationX(pitch);
  481. AZ::Vector3 position = orientation.TransformVector(AZ::Vector3(0, -distance, 0));
  482. AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position));
  483. }
  484. bool SubpassExampleComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  485. {
  486. auto config = azrtti_cast<const SampleComponentConfig*>(baseConfig);
  487. AZ_Assert(config && config->IsValid(), "SubpassExampleComponent required for sample component configuration.");
  488. m_entityContextId = config->m_entityContextId;
  489. m_cameraEntityId = config->m_cameraEntityId;
  490. return BasicRHIComponent::ReadInConfig(baseConfig);
  491. }
  492. void SubpassExampleComponent::SetupScene()
  493. {
  494. // These are the model matrices. They contain the rotation, translation and scale of the objects that we are going to draw.
  495. struct ObjectTransforms
  496. {
  497. AZ::Vector3 m_scale;
  498. AZ::Quaternion m_rotation;
  499. AZ::Vector3 m_translation;
  500. };
  501. AZStd::vector<ObjectTransforms> opaqueObjectTransforms =
  502. { {
  503. { AZ::Vector3(50.0f), AZ::Quaternion::CreateIdentity(), AZ::Vector3::CreateZero() },
  504. { AZ::Vector3(1.0f), AZ::Quaternion::CreateIdentity(), AZ::Vector3(0.f, 0.f, 0.95f) },
  505. { AZ::Vector3(1.5f), AZ::Quaternion::CreateRotationZ(AZ::Constants::Pi), AZ::Vector3(-5.0f, 8.0f, 0.35f)},
  506. { AZ::Vector3(1.5f), AZ::Quaternion::CreateRotationZ(AZ::Constants::QuarterPi * 3.0f), AZ::Vector3(5.0f, 8.0f, 1.5f) }
  507. } };
  508. const float zNear = 1.0f, zFar = 100.0f;
  509. // Camera
  510. float fieldOfView = AZ::Constants::Pi / 4.0f;
  511. float screenAspect = GetViewportWidth() / GetViewportHeight();
  512. MakePerspectiveFovMatrixRH(m_projectionMatrix, fieldOfView, screenAspect, zNear, zFar);
  513. for (uint32_t i = 0; i < m_opaqueModelsData.size(); ++i)
  514. {
  515. const auto& transform = opaqueObjectTransforms[i];
  516. auto& srg = m_opaqueModelsData[i].m_shaderResourceGroup;
  517. auto matrix = AZ::Matrix4x4::CreateFromQuaternionAndTranslation(transform.m_rotation, transform.m_translation) * AZ::Matrix4x4::CreateScale(transform.m_scale);
  518. srg->SetConstant(m_modelMatrixIndex, matrix);
  519. srg->Compile();
  520. }
  521. AZStd::vector<ObjectTransforms> transparentObjectTransforms =
  522. { {
  523. { AZ::Vector3(2.0f), AZ::Quaternion::CreateRotationZ(AZ::Constants::HalfPi), AZ::Vector3(0.0f, 8.0f, 0.0f)},
  524. } };
  525. AZStd::vector<AZ::Vector3> colors =
  526. {
  527. AZ::Vector3(1.0f, 1.0f, 1.0f),
  528. AZ::Vector3(1.0f, 0.0f, 0.0f),
  529. AZ::Vector3(0.0f, 1.0f, 0.0f),
  530. AZ::Vector3(0.0f, 0.0f, 1.0f),
  531. AZ::Vector3(1.0f, 1.0f, 0.0f)
  532. };
  533. struct LightInfo
  534. {
  535. AZ::Vector4 m_position;
  536. // Group color and radius to match packing of the shader.
  537. AZ::Vector4 m_colorAndRadius;
  538. };
  539. constexpr uint32_t numLights = 10;
  540. AZStd::array< LightInfo, numLights> lightsInfo =
  541. { {
  542. {AZ::Vector4(-13, 5, -12, 1.f), AZ::Vector4(1.0f, 1.0f, 1.0f, 50.5f)},
  543. {AZ::Vector4(-5, 14, 3, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 30.4f)},
  544. {AZ::Vector4(5, 5, 4, 1.f), AZ::Vector4(0.0f, 0.0f, 1.0f, 40.2f)},
  545. {AZ::Vector4(2, 13, 2, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 60.8f)},
  546. {AZ::Vector4(0, 1, -2, 1.f), AZ::Vector4(1.0f, 1.0f, 0.0f, 20.0f)},
  547. {AZ::Vector4(1.5f, 12, -4, 1.f), AZ::Vector4(1.0f, 1.0f, 0.0f, 40.9f)},
  548. {AZ::Vector4(5, 5, 2, 1.f), AZ::Vector4(0.0f, 0.0f, 1.0f, 30.1f)},
  549. {AZ::Vector4(-4, 13, -13, 1.f), AZ::Vector4(1.0f, 1.0f, 1.0f, 40.3f)},
  550. {AZ::Vector4(6, 12, -1, 1.f), AZ::Vector4(0.0f, 1.0f, 0.0f, 60.2f)},
  551. {AZ::Vector4(13, 5, 13, 1.f), AZ::Vector4(1.0f, 0.0f, 1.0f, 10.8f)},
  552. } };
  553. m_sceneShaderResourceGroup->SetConstantArray(m_lightsInfoIndex, lightsInfo);
  554. m_sceneShaderResourceGroup->Compile();
  555. }
  556. } // namespace AtomSampleViewer