SubpassExampleComponent.cpp 30 KB

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