3
0

View.cpp 30 KB

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