3
0

View.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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 <Atom/RPI.Public/View.h>
  9. #include <Atom/RHI/RHISystemInterface.h>
  10. #include <Atom/RPI.Public/RPISystemInterface.h>
  11. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  12. #include <Atom/RPI.Public/Culling.h>
  13. #include <Atom/RPI.Public/RenderPipeline.h>
  14. #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
  15. #include <Atom/RHI/DrawListTagRegistry.h>
  16. #include <Atom/RHI/RHIUtils.h>
  17. #include <AzCore/Casting/lossy_cast.h>
  18. #include <AzCore/Component/ComponentApplicationBus.h>
  19. #include <AzCore/Math/MatrixUtils.h>
  20. #include <AzCore/Serialization/SerializeContext.h>
  21. #include <AzCore/Jobs/JobCompletion.h>
  22. #include <AzCore/Jobs/JobFunction.h>
  23. #include <AzCore/Task/TaskGraph.h>
  24. #include <Atom_RPI_Traits_Platform.h>
  25. #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
  26. #include <MaskedOcclusionCulling/MaskedOcclusionCulling.h>
  27. #endif
  28. namespace AZ
  29. {
  30. namespace RPI
  31. {
  32. // fixed-size software occlusion culling buffer
  33. #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
  34. const uint32_t MaskedSoftwareOcclusionCullingWidth = 1920;
  35. const uint32_t MaskedSoftwareOcclusionCullingHeight = 1080;
  36. #endif
  37. ViewPtr View::CreateView(const AZ::Name& name, UsageFlags usage)
  38. {
  39. View* view = aznew View(name, usage);
  40. return ViewPtr(view);
  41. }
  42. View::View(const AZ::Name& name, UsageFlags usage)
  43. : m_name(name)
  44. , m_usageFlags(usage)
  45. {
  46. AZ_Assert(!name.IsEmpty(), "invalid name");
  47. // Set default matrices
  48. SetWorldToViewMatrix(AZ::Matrix4x4::CreateIdentity());
  49. AZ::Matrix4x4 viewToClipMatrix;
  50. AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, 1, 0.1f, 1000.f, true);
  51. SetViewToClipMatrix(viewToClipMatrix);
  52. if ((usage & UsageFlags::UsageXR))
  53. {
  54. SetViewToClipMatrix(AZ::Matrix4x4::CreateIdentity());
  55. }
  56. TryCreateShaderResourceGroup();
  57. #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
  58. m_maskedOcclusionCulling = MaskedOcclusionCulling::Create();
  59. m_maskedOcclusionCulling->SetResolution(MaskedSoftwareOcclusionCullingWidth, MaskedSoftwareOcclusionCullingHeight);
  60. #endif
  61. }
  62. View::~View()
  63. {
  64. #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
  65. if (m_maskedOcclusionCulling)
  66. {
  67. MaskedOcclusionCulling::Destroy(m_maskedOcclusionCulling);
  68. m_maskedOcclusionCulling = nullptr;
  69. }
  70. #endif
  71. }
  72. void View::SetDrawListMask(const RHI::DrawListMask& drawListMask)
  73. {
  74. if (m_drawListMask != drawListMask)
  75. {
  76. m_drawListMask = drawListMask;
  77. m_drawListContext.Shutdown();
  78. m_drawListContext.Init(m_drawListMask);
  79. }
  80. }
  81. void View::Reset()
  82. {
  83. m_drawListMask.reset();
  84. m_drawListContext.Shutdown();
  85. m_visibleObjectContext.Shutdown();
  86. m_passesByDrawList = nullptr;
  87. }
  88. void View::PrintDrawListMask()
  89. {
  90. AZ_Printf("View", RHI::DrawListMaskToString(m_drawListMask).c_str());
  91. }
  92. RHI::ShaderResourceGroup* View::GetRHIShaderResourceGroup() const
  93. {
  94. return m_shaderResourceGroup->GetRHIShaderResourceGroup();
  95. }
  96. Data::Instance<RPI::ShaderResourceGroup> View::GetShaderResourceGroup()
  97. {
  98. return m_shaderResourceGroup;
  99. }
  100. void View::AddDrawPacket(const RHI::DrawPacket* drawPacket, float depth)
  101. {
  102. // This function is thread safe since DrawListContent has storage per thread for draw item data.
  103. m_drawListContext.AddDrawPacket(drawPacket, depth);
  104. }
  105. void View::AddDrawPacket(const RHI::DrawPacket* drawPacket, const Vector3& worldPosition)
  106. {
  107. Vector3 cameraToObject = worldPosition - m_position;
  108. float depth = cameraToObject.Dot(-m_viewToWorldMatrix.GetBasisZAsVector3());
  109. AddDrawPacket(drawPacket, depth);
  110. }
  111. void View::AddVisibleObject(const void* userData, float depth)
  112. {
  113. // This function is thread safe since VisibleObjectContext has storage per thread for draw item data.
  114. m_visibleObjectContext.AddVisibleObject(userData, depth);
  115. }
  116. void View::AddVisibleObject(const void* userData, const Vector3& worldPosition)
  117. {
  118. Vector3 cameraToObject = worldPosition - m_position;
  119. float depth = cameraToObject.Dot(-m_viewToWorldMatrix.GetBasisZAsVector3());
  120. AddVisibleObject(userData, depth);
  121. }
  122. void View::AddDrawItem(RHI::DrawListTag drawListTag, const RHI::DrawItemProperties& drawItemProperties)
  123. {
  124. m_drawListContext.AddDrawItem(drawListTag, drawItemProperties);
  125. }
  126. void View::ApplyFlags(uint32_t flags)
  127. {
  128. AZStd::atomic_fetch_and(&m_andFlags, flags);
  129. AZStd::atomic_fetch_or(&m_orFlags, flags);
  130. }
  131. void View::ClearFlags(uint32_t flags)
  132. {
  133. AZStd::atomic_fetch_or(&m_andFlags, flags);
  134. AZStd::atomic_fetch_and(&m_orFlags, ~flags);
  135. }
  136. void View::ClearAllFlags()
  137. {
  138. ClearFlags(0xFFFFFFFF);
  139. }
  140. uint32_t View::GetAndFlags() const
  141. {
  142. return m_andFlags;
  143. }
  144. uint32_t View::GetOrFlags() const
  145. {
  146. return m_orFlags;
  147. }
  148. void View::UpdateViewToWorldMatrix(const AZ::Matrix4x4& viewToWorld)
  149. {
  150. m_viewToWorldMatrix = viewToWorld;
  151. //Update view transform
  152. static const Quaternion yUpToZUp = Quaternion::CreateRotationX(-AZ::Constants::HalfPi);
  153. m_viewTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
  154. Quaternion::CreateFromMatrix4x4(m_viewToWorldMatrix) * yUpToZUp, m_viewToWorldMatrix.GetTranslation()).GetOrthogonalized();
  155. }
  156. void View::SetWorldToViewMatrix(const AZ::Matrix4x4& worldToView)
  157. {
  158. UpdateViewToWorldMatrix(worldToView.GetInverseFast());
  159. m_position = m_viewToWorldMatrix.GetTranslation();
  160. m_worldToViewMatrix = worldToView;
  161. m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
  162. if (m_viewToClipExcludeMatrix.has_value())
  163. {
  164. m_worldToClipExcludeMatrix = m_viewToClipExcludeMatrix.value() * m_worldToViewMatrix;
  165. }
  166. m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
  167. m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
  168. m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
  169. }
  170. AZ::Transform View::GetCameraTransform() const
  171. {
  172. return m_viewTransform;
  173. }
  174. void View::SetCameraTransform(const AZ::Matrix3x4& cameraTransform)
  175. {
  176. m_position = cameraTransform.GetTranslation();
  177. // Before inverting the matrix we must first adjust from Z-up to Y-up. The camera world matrix
  178. // is in a Z-up world and an identity matrix means that it faces along the positive-Y axis and Z is up.
  179. // An identity view matrix on the other hand looks along the negative Z-axis.
  180. // So we adjust for this by rotating the camera world matrix by 90 degrees around the X axis.
  181. static AZ::Matrix3x4 zUpToYUp = AZ::Matrix3x4::CreateRotationX(AZ::Constants::HalfPi);
  182. AZ::Matrix3x4 yUpWorld = cameraTransform * zUpToYUp;
  183. float viewToWorldMatrixRaw[16] = {
  184. 1,0,0,0,
  185. 0,1,0,0,
  186. 0,0,1,0,
  187. 0,0,0,1 };
  188. yUpWorld.StoreToRowMajorFloat12(viewToWorldMatrixRaw);
  189. const AZ::Matrix4x4 prevViewToWorldMatrix = m_viewToWorldMatrix;
  190. UpdateViewToWorldMatrix(AZ::Matrix4x4::CreateFromRowMajorFloat16(viewToWorldMatrixRaw));
  191. m_worldToViewMatrix = m_viewToWorldMatrix.GetInverseFast();
  192. m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
  193. if (m_viewToClipExcludeMatrix.has_value())
  194. {
  195. m_worldToClipExcludeMatrix = m_viewToClipExcludeMatrix.value() * m_worldToViewMatrix;
  196. }
  197. m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
  198. // Only signal an update when there is a change, otherwise this might block
  199. // user input from changing the value.
  200. if (!prevViewToWorldMatrix.IsClose(m_viewToWorldMatrix))
  201. {
  202. m_onWorldToViewMatrixChange.Signal(m_worldToViewMatrix);
  203. }
  204. m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
  205. }
  206. void View::SetViewToClipMatrix(const AZ::Matrix4x4& viewToClip)
  207. {
  208. m_viewToClipMatrix = viewToClip;
  209. m_clipToViewMatrix = m_viewToClipMatrix.GetInverseFull();
  210. m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
  211. m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
  212. // Update z depth constant simultaneously
  213. // zNear -> n, zFar -> f
  214. // A = f / (n - f), B = nf / (n - f)
  215. double A = m_viewToClipMatrix.GetElement(2, 2);
  216. double B = m_viewToClipMatrix.GetElement(2, 3);
  217. // Based on linearZ = fn / (depth*(f-n) - f)
  218. m_linearizeDepthConstants.SetX(float(B / A)); //<------------n
  219. m_linearizeDepthConstants.SetY(float(B / (A + 1.0))); //<---------f
  220. m_linearizeDepthConstants.SetZ(float((B * B) / (A * (A + 1.0)))); //<-----nf
  221. m_linearizeDepthConstants.SetW(float(-B / (A * (A + 1.0)))); //<------f-n
  222. // For reverse depth the expression we dont have to do anything different as m_linearizeDepthConstants works out to be the same.
  223. // A = n / (f - n), B = nf / (f - n)
  224. // Based on linearZ = fn / (depth*(n-f) - n)
  225. //m_linearizeDepthConstants.SetX(float(B / A)); //<----f
  226. //m_linearizeDepthConstants.SetY(float(B / (A + 1.0))); //<----n
  227. //m_linearizeDepthConstants.SetZ(float((B * B) / (A * (A + 1.0)))); //<----nf
  228. //m_linearizeDepthConstants.SetW(float(-B / (A * (A + 1.0)))); //<-----n-f
  229. double tanHalfFovX = m_clipToViewMatrix.GetElement(0, 0);
  230. double tanHalfFovY = m_clipToViewMatrix.GetElement(1, 1);
  231. // The constants below try to remapping 0---1 to -1---+1 and multiplying with inverse of projection.
  232. // Assuming that inverse of projection matrix only has value in the first column for first row
  233. // x = (2u-1)*ProjInves[0][0]
  234. // Assuming that inverse of projection matrix only has value in the second column for second row
  235. // y = (1-2v)*ProjInves[1][1]
  236. m_unprojectionConstants.SetX(float(2.0 * tanHalfFovX));
  237. m_unprojectionConstants.SetY(float(-2.0 * tanHalfFovY));
  238. m_unprojectionConstants.SetZ(float(-tanHalfFovX));
  239. m_unprojectionConstants.SetW(float(tanHalfFovY));
  240. m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
  241. }
  242. void View::SetViewToClipExcludeMatrix(const AZ::Matrix4x4* viewToClipExclude)
  243. {
  244. if (viewToClipExclude)
  245. {
  246. m_viewToClipExcludeMatrix = *viewToClipExclude;
  247. m_worldToClipExcludeMatrix = *viewToClipExclude * m_worldToViewMatrix;
  248. }
  249. else
  250. {
  251. m_viewToClipExcludeMatrix.reset();
  252. m_worldToClipExcludeMatrix.reset();
  253. }
  254. }
  255. void View::SetStereoscopicViewToClipMatrix(const AZ::Matrix4x4& viewToClip, bool reverseDepth)
  256. {
  257. m_viewToClipMatrix = viewToClip;
  258. m_clipToViewMatrix = m_viewToClipMatrix.GetInverseFull();
  259. m_worldToClipMatrix = m_viewToClipMatrix * m_worldToViewMatrix;
  260. m_clipToWorldMatrix = m_worldToClipMatrix.GetInverseFull();
  261. // Update z depth constant simultaneously
  262. if(reverseDepth)
  263. {
  264. // zNear -> n, zFar -> f
  265. // A = 2n/(f-n), B = 2fn / (f - n)
  266. // the formula of A and B should be the same as projection matrix's definition
  267. // currently defined in CreateStereoscopicProjection in XRUtils.cpp
  268. double A = m_viewToClipMatrix.GetElement(2, 2);
  269. double B = m_viewToClipMatrix.GetElement(2, 3);
  270. // Based on linearZ = 2fn / (depth*(n-f) - 2n)
  271. m_linearizeDepthConstants.SetX(float(B / A)); //<----f
  272. m_linearizeDepthConstants.SetY(float((2 * B) / (A + 2.0))); //<--- 2n
  273. m_linearizeDepthConstants.SetZ(float((2 * B * B) / (A * (A + 2.0)))); //<-----2fn
  274. m_linearizeDepthConstants.SetW(float((-2 * B) / (A * (A + 2.0)))); //<------n-f
  275. }
  276. else
  277. {
  278. // A = -(f+n)/(f-n), B = -2fn / (f - n)
  279. double A = m_viewToClipMatrix.GetElement(2, 2);
  280. double B = m_viewToClipMatrix.GetElement(2, 3);
  281. //Based on linearZ = 2fn / (depth*(f-n) - (-f-n))
  282. m_linearizeDepthConstants.SetX(float(B / (A + 1.0))); //<----f
  283. m_linearizeDepthConstants.SetY(float((-2 * B * A)/ ((A + 1.0) * (A - 1.0)))); //<--- -f-n
  284. m_linearizeDepthConstants.SetZ(float((2 * B * B) / ((A - 1.0) * (A + 1.0)))); //<-----2fn
  285. m_linearizeDepthConstants.SetW(float((-2 * B) / ((A - 1.0) * (A + 1.0)))); //<------f-n
  286. }
  287. // The constants below try to remap 0---1 to -1---+1 and multiply with inverse of projection.
  288. // Assuming that inverse of projection matrix only has value in the first column for first row
  289. // x = (2u-1)*ProjInves[0][0] + ProjInves[0][3]
  290. // Assuming that inverse of projection matrix only has value in the second column for second row
  291. // y = (1-2v)*ProjInves[1][1] + ProjInves[1][3]
  292. float multiplierConstantX = 2.0f * m_clipToViewMatrix.GetElement(0, 0);
  293. float multiplierConstantY = -2.0f * m_clipToViewMatrix.GetElement(1, 1);
  294. float additionConstantX = m_clipToViewMatrix.GetElement(0, 3) - m_clipToViewMatrix.GetElement(0, 0);
  295. float additionConstantY = m_clipToViewMatrix.GetElement(1, 1) + m_clipToViewMatrix.GetElement(1, 3);
  296. m_unprojectionConstants.SetX(multiplierConstantX);
  297. m_unprojectionConstants.SetY(multiplierConstantY);
  298. m_unprojectionConstants.SetZ(additionConstantX);
  299. m_unprojectionConstants.SetW(additionConstantY);
  300. m_onWorldToClipMatrixChange.Signal(m_worldToClipMatrix);
  301. }
  302. void View::SetClipSpaceOffset(float xOffset, float yOffset)
  303. {
  304. m_clipSpaceOffset.Set(xOffset, yOffset);
  305. }
  306. const AZ::Matrix4x4& View::GetWorldToViewMatrix() const
  307. {
  308. return m_worldToViewMatrix;
  309. }
  310. const AZ::Matrix4x4& View::GetViewToWorldMatrix() const
  311. {
  312. return m_viewToWorldMatrix;
  313. }
  314. AZ::Matrix3x4 View::GetWorldToViewMatrixAsMatrix3x4() const
  315. {
  316. return AZ::Matrix3x4::UnsafeCreateFromMatrix4x4(m_worldToViewMatrix);
  317. }
  318. AZ::Matrix3x4 View::GetViewToWorldMatrixAsMatrix3x4() const
  319. {
  320. return AZ::Matrix3x4::UnsafeCreateFromMatrix4x4(m_viewToWorldMatrix);
  321. }
  322. const AZ::Matrix4x4& View::GetViewToClipMatrix() const
  323. {
  324. return m_viewToClipMatrix;
  325. }
  326. const AZ::Matrix4x4* View::GetWorldToClipExcludeMatrix() const
  327. {
  328. return m_worldToClipExcludeMatrix.has_value() ? &m_worldToClipExcludeMatrix.value() : nullptr;
  329. }
  330. const AZ::Matrix4x4& View::GetWorldToClipMatrix() const
  331. {
  332. return m_worldToClipMatrix;
  333. }
  334. const AZ::Matrix4x4& View::GetClipToWorldMatrix() const
  335. {
  336. return m_clipToWorldMatrix;
  337. }
  338. bool View::HasDrawListTag(RHI::DrawListTag drawListTag)
  339. {
  340. return drawListTag.IsValid() && m_drawListMask[drawListTag.GetIndex()];
  341. }
  342. RHI::DrawListView View::GetDrawList(RHI::DrawListTag drawListTag)
  343. {
  344. return m_drawListContext.GetList(drawListTag);
  345. }
  346. VisibleObjectListView View::GetVisibleObjectList()
  347. {
  348. return m_visibleObjectContext.GetList();
  349. }
  350. void View::FinalizeVisibleObjectList()
  351. {
  352. m_visibleObjectContext.FinalizeLists();
  353. }
  354. void View::FinalizeDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent)
  355. {
  356. AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
  357. m_drawListContext.FinalizeLists();
  358. SortFinalizedDrawListsTG(finalizeDrawListsTGEvent);
  359. }
  360. void View::FinalizeDrawListsJob(AZ::Job* parentJob)
  361. {
  362. AZ_PROFILE_SCOPE(RPI, "View: FinalizeDrawLists");
  363. m_drawListContext.FinalizeLists();
  364. SortFinalizedDrawListsJob(parentJob);
  365. }
  366. void View::SortFinalizedDrawListsTG(AZ::TaskGraphEvent& finalizeDrawListsTGEvent)
  367. {
  368. AZ_PROFILE_SCOPE(RPI, "View: SortFinalizedDrawLists");
  369. RHI::DrawListsByTag& drawListsByTag = m_drawListContext.GetMergedDrawListsByTag();
  370. AZ::TaskGraph drawListSortTG{ "DrawList Sort" };
  371. AZ::TaskDescriptor drawListSortTGDescriptor{"RPI_View_SortFinalizedDrawLists", "Graphics"};
  372. for (size_t idx = 0; idx < drawListsByTag.size(); ++idx)
  373. {
  374. if (drawListsByTag[idx].size() > 1)
  375. {
  376. drawListSortTG.AddTask(drawListSortTGDescriptor, [this, &drawListsByTag, idx]()
  377. {
  378. AZ_PROFILE_SCOPE(RPI, "View: SortDrawList Task");
  379. SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx));
  380. });
  381. }
  382. }
  383. if (!drawListSortTG.IsEmpty())
  384. {
  385. drawListSortTG.Detach();
  386. drawListSortTG.Submit(&finalizeDrawListsTGEvent);
  387. }
  388. }
  389. void View::SortFinalizedDrawListsJob(AZ::Job* parentJob)
  390. {
  391. AZ_PROFILE_SCOPE(RPI, "View: SortFinalizedDrawLists");
  392. RHI::DrawListsByTag& drawListsByTag = m_drawListContext.GetMergedDrawListsByTag();
  393. AZ::JobCompletion jobCompletion;
  394. for (size_t idx = 0; idx < drawListsByTag.size(); ++idx)
  395. {
  396. if (drawListsByTag[idx].size() > 1)
  397. {
  398. auto jobLambda = [this, &drawListsByTag, idx]()
  399. {
  400. AZ_PROFILE_SCOPE(RPI, "View: SortDrawList Job");
  401. SortDrawList(drawListsByTag[idx], RHI::DrawListTag(idx));
  402. };
  403. Job* jobSortDrawList = aznew JobFunction<decltype(jobLambda)>(jobLambda, true, nullptr); // Auto-deletes
  404. if (parentJob)
  405. {
  406. parentJob->StartAsChild(jobSortDrawList);
  407. }
  408. else
  409. {
  410. jobSortDrawList->SetDependent(&jobCompletion);
  411. jobSortDrawList->Start();
  412. }
  413. }
  414. }
  415. if (parentJob)
  416. {
  417. parentJob->WaitForChildren();
  418. }
  419. else
  420. {
  421. jobCompletion.StartAndWaitForCompletion();
  422. }
  423. }
  424. void View::SortDrawList(RHI::DrawList& drawList, RHI::DrawListTag tag)
  425. {
  426. if (!m_passesByDrawList)
  427. {
  428. // Nothing to sort.
  429. return;
  430. }
  431. // Note: it's possible that the m_passesByDrawList doesn't have a pass for the input tag.
  432. // This is because a View can be used for multiple render pipelines.
  433. // So it may contains draw list tag which exists in one render pipeline but not others.
  434. auto itr = m_passesByDrawList->find(tag);
  435. if (itr != m_passesByDrawList->end())
  436. {
  437. itr->second->SortDrawList(drawList);
  438. }
  439. }
  440. void View::ConnectWorldToViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
  441. {
  442. handler.Connect(m_onWorldToViewMatrixChange);
  443. }
  444. void View::ConnectWorldToClipMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
  445. {
  446. handler.Connect(m_onWorldToClipMatrixChange);
  447. }
  448. // [GFX TODO] This function needs unit tests and might need to be reworked
  449. RHI::DrawItemSortKey View::GetSortKeyForPosition(const Vector3& positionInWorld) const
  450. {
  451. // We are using fixed-point depth representation for the u64 sort key
  452. // Compute position in clip space
  453. const Vector4 worldPosition4 = Vector4::CreateFromVector3(positionInWorld);
  454. const Vector4 clipSpacePosition = m_worldToClipMatrix * worldPosition4;
  455. // Get a depth value guaranteed to be in the range 0 to 1
  456. float normalizedDepth = clipSpacePosition.GetZ() / clipSpacePosition.GetW();
  457. normalizedDepth = (normalizedDepth + 1.0f) * 0.5f;
  458. normalizedDepth = AZStd::clamp<float>(normalizedDepth, 0.f, 1.f);
  459. // Convert the depth into a uint64
  460. RHI::DrawItemSortKey sortKey = static_cast<RHI::DrawItemSortKey>(normalizedDepth * azlossy_cast<double>(std::numeric_limits<RHI::DrawItemSortKey>::max()));
  461. return sortKey;
  462. }
  463. float View::CalculateSphereAreaInClipSpace(const AZ::Vector3& sphereWorldPosition, float sphereRadius) const
  464. {
  465. // Projection of a sphere to clip space
  466. // Derived from https://www.iquilezles.org/www/articles/sphereproj/sphereproj.htm
  467. if (sphereRadius <= 0.0f)
  468. {
  469. return 0.0f;
  470. }
  471. const AZ::Matrix4x4& worldToViewMatrix = GetWorldToViewMatrix();
  472. const AZ::Matrix4x4& viewToClipMatrix = GetViewToClipMatrix();
  473. // transform to camera space (eye space)
  474. const Vector4 worldPosition4 = Vector4::CreateFromVector3(sphereWorldPosition);
  475. const Vector4 viewSpacePosition = worldToViewMatrix * worldPosition4;
  476. float zDist = -viewSpacePosition.GetZ(); // in our view space Z is negative in front of the camera
  477. if (zDist < 0.0f)
  478. {
  479. // sphere center is behind camera.
  480. if (zDist < -sphereRadius)
  481. {
  482. return 0.0f; // whole of sphere is behind camera so zero coverage
  483. }
  484. else
  485. {
  486. return 1.0f; // camera is inside sphere so treat as covering whole view
  487. }
  488. }
  489. else
  490. {
  491. if (zDist < sphereRadius)
  492. {
  493. return 1.0f; // camera is inside sphere so treat as covering whole view
  494. }
  495. }
  496. // Element 1,1 of the projection matrix is equal to : 1 / tan(fovY/2) AKA cot(fovY/2)
  497. // See https://stackoverflow.com/questions/46182845/field-of-view-aspect-ratio-view-matrix-from-projection-matrix-hmd-ost-calib
  498. float cotHalfFovY = viewToClipMatrix.GetElement(1, 1);
  499. float radiusSq = sphereRadius * sphereRadius;
  500. float depthSq = zDist * zDist;
  501. float distanceSq = viewSpacePosition.GetAsVector3().GetLengthSq();
  502. float cotHalfFovYSq = cotHalfFovY * cotHalfFovY;
  503. float radiusSqSubDepthSq = radiusSq - depthSq;
  504. const float epsilon = 0.00001f;
  505. if (fabsf(radiusSqSubDepthSq) < epsilon)
  506. {
  507. // treat as covering entire view since we don't want to divide by zero
  508. return 1.0f;
  509. }
  510. // This will return 1.0f when an area equal in size to the viewport height squared is covered.
  511. // So to get actual pixels covered do : coverage * viewport-resolution-y * viewport-resolution-y
  512. // The actual math computes the area of an ellipse as a percentage of the view area, see the paper above for the steps
  513. // to simplify the equations into this calculation.
  514. return -0.25f * cotHalfFovYSq * AZ::Constants::Pi * radiusSq * sqrt(fabsf((distanceSq - radiusSq)/radiusSqSubDepthSq))/radiusSqSubDepthSq;
  515. }
  516. const AZ::Name& View::GetName() const
  517. {
  518. return m_name;
  519. }
  520. View::UsageFlags View::GetUsageFlags() const
  521. {
  522. return m_usageFlags;
  523. }
  524. void View::SetPassesByDrawList(PassesByDrawList* passes)
  525. {
  526. m_passesByDrawList = passes;
  527. }
  528. void View::UpdateSrg()
  529. {
  530. if (m_shaderResourceGroup)
  531. {
  532. if (m_clipSpaceOffset.IsZero())
  533. {
  534. Matrix4x4 worldToClipPrevMatrix = m_viewToClipPrevMatrix * m_worldToViewPrevMatrix;
  535. m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, worldToClipPrevMatrix);
  536. m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, m_worldToClipMatrix);
  537. m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, m_viewToClipMatrix);
  538. m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, m_clipToWorldMatrix);
  539. m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, m_clipToViewMatrix);
  540. }
  541. else
  542. {
  543. // Offset the current and previous frame clip matrices
  544. Matrix4x4 offsetViewToClipMatrix = m_viewToClipMatrix;
  545. offsetViewToClipMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
  546. offsetViewToClipMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
  547. Matrix4x4 offsetViewToClipPrevMatrix = m_viewToClipPrevMatrix;
  548. offsetViewToClipPrevMatrix.SetElement(0, 2, m_clipSpaceOffset.GetX());
  549. offsetViewToClipPrevMatrix.SetElement(1, 2, m_clipSpaceOffset.GetY());
  550. // Build other matrices dependent on the view to clip matrices
  551. Matrix4x4 offsetWorldToClipMatrix = offsetViewToClipMatrix * m_worldToViewMatrix;
  552. Matrix4x4 offsetWorldToClipPrevMatrix = offsetViewToClipPrevMatrix * m_worldToViewPrevMatrix;
  553. m_shaderResourceGroup->SetConstant(m_worldToClipPrevMatrixConstantIndex, offsetWorldToClipPrevMatrix);
  554. m_shaderResourceGroup->SetConstant(m_viewProjectionMatrixConstantIndex, offsetWorldToClipMatrix);
  555. m_shaderResourceGroup->SetConstant(m_projectionMatrixConstantIndex, offsetViewToClipMatrix);
  556. m_shaderResourceGroup->SetConstant(m_clipToWorldMatrixConstantIndex, offsetWorldToClipMatrix.GetInverseFull());
  557. m_shaderResourceGroup->SetConstant(m_projectionMatrixInverseConstantIndex, offsetViewToClipMatrix.GetInverseFull());
  558. }
  559. m_shaderResourceGroup->SetConstant(m_worldPositionConstantIndex, m_position);
  560. m_shaderResourceGroup->SetConstant(m_viewMatrixConstantIndex, m_worldToViewMatrix);
  561. m_shaderResourceGroup->SetConstant(m_viewMatrixInverseConstantIndex, m_viewToWorldMatrix);
  562. m_shaderResourceGroup->SetConstant(m_zConstantsConstantIndex, m_linearizeDepthConstants);
  563. m_shaderResourceGroup->SetConstant(m_unprojectionConstantsIndex, m_unprojectionConstants);
  564. m_shaderResourceGroup->Compile();
  565. }
  566. m_viewToClipPrevMatrix = m_viewToClipMatrix;
  567. m_worldToViewPrevMatrix = m_worldToViewMatrix;
  568. m_clipSpaceOffset.Set(0);
  569. }
  570. void View::BeginCulling()
  571. {
  572. #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
  573. if (m_maskedOcclusionCullingDirty)
  574. {
  575. AZ_PROFILE_SCOPE(RPI, "View: ClearMaskedOcclusionBuffer");
  576. m_maskedOcclusionCulling->ClearBuffer();
  577. m_maskedOcclusionCullingDirty = false;
  578. }
  579. #endif
  580. }
  581. MaskedOcclusionCulling* View::GetMaskedOcclusionCulling()
  582. {
  583. return m_maskedOcclusionCulling;
  584. }
  585. void View::SetMaskedOcclusionCullingDirty(bool dirty)
  586. {
  587. m_maskedOcclusionCullingDirty = dirty;
  588. }
  589. bool View::GetMaskedOcclusionCullingDirty() const
  590. {
  591. return m_maskedOcclusionCullingDirty;
  592. }
  593. void View::TryCreateShaderResourceGroup()
  594. {
  595. if (!m_shaderResourceGroup)
  596. {
  597. if (auto rpiSystemInterface = RPISystemInterface::Get())
  598. {
  599. if (Data::Asset<ShaderAsset> viewSrgShaderAsset = rpiSystemInterface->GetCommonShaderAssetForSrgs();
  600. viewSrgShaderAsset.IsReady())
  601. {
  602. m_shaderResourceGroup =
  603. ShaderResourceGroup::Create(viewSrgShaderAsset, rpiSystemInterface->GetViewSrgLayout()->GetName());
  604. }
  605. }
  606. }
  607. }
  608. void View::OnAddToRenderPipeline()
  609. {
  610. TryCreateShaderResourceGroup();
  611. if (!m_shaderResourceGroup)
  612. {
  613. AZ_Warning("RPI::View", false, "Shader Resource Group failed to initialize");
  614. }
  615. }
  616. void View::SetShadowPassRenderPipelineId(const RenderPipelineId renderPipelineId)
  617. {
  618. m_shadowPassRenderpipelineId = renderPipelineId;
  619. }
  620. RenderPipelineId View::GetShadowPassRenderPipelineId() const
  621. {
  622. return m_shadowPassRenderpipelineId;
  623. }
  624. } // namespace RPI
  625. } // namespace AZ