TerrainClipmapManager.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. #pragma once
  9. #include <AzCore/base.h>
  10. #include <AzCore/std/containers/array.h>
  11. #include <AzFramework/Terrain/TerrainDataRequestBus.h>
  12. #include <Atom/Feature/Utils/GpuBufferHandler.h>
  13. #include <Atom/RHI/FrameGraphAttachmentInterface.h>
  14. #include <Atom/RHI/FrameGraphInterface.h>
  15. #include <Atom/RPI.Public/Image/AttachmentImage.h>
  16. #include <Atom/RPI.Public/Scene.h>
  17. #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
  18. #include <TerrainRenderer/ClipmapBounds.h>
  19. #include <TerrainRenderer/TerrainAreaMaterialRequestBus.h>
  20. #include <TerrainRenderer/TerrainMacroMaterialBus.h>
  21. namespace Terrain
  22. {
  23. //! Clipmap configuration to set basic properties of the clipmaps.
  24. //! Derived properties will be automatically calculated based on the given data, including:
  25. //! Precision of each clipmap level, depth of the clipmap stack.
  26. struct ClipmapConfiguration
  27. {
  28. AZ_CLASS_ALLOCATOR(ClipmapConfiguration, AZ::SystemAllocator);
  29. AZ_RTTI(ClipmapConfiguration, "{5CC8A81E-B850-46BA-A577-E21530D9ED04}");
  30. ClipmapConfiguration() = default;
  31. virtual ~ClipmapConfiguration() = default;
  32. //! Max clipmap number that can have. Used to initialize fixed arrays.
  33. static constexpr uint32_t MacroClipmapStackSizeMax = 16;
  34. static constexpr uint32_t DetailClipmapStackSizeMax = 16;
  35. static constexpr uint32_t SharedClipmapStackSizeMax = AZStd::max(ClipmapConfiguration::MacroClipmapStackSizeMax, ClipmapConfiguration::DetailClipmapStackSizeMax);
  36. enum ClipmapSize : uint32_t
  37. {
  38. ClipmapSize512 = 512u,
  39. ClipmapSize1024 = 1024u,
  40. ClipmapSize2048 = 2048u
  41. };
  42. //! Enable clipmap feature for rendering
  43. bool m_clipmapEnabled = false;
  44. //! The size of the clipmap image in each layer.
  45. ClipmapSize m_clipmapSize = ClipmapSize1024;
  46. //! Max render radius that the lowest resolution clipmap can cover.
  47. //! Radius in: meters.
  48. //! For example, 1000 means the clipmaps render 1000 meters at most from the view position.
  49. float m_macroClipmapMaxRenderRadius = 2048.0f;
  50. float m_detailClipmapMaxRenderRadius = 256.0f;
  51. //! The resolution of the highest resolution clipmap in the stack.
  52. //! The actual max resolution may be higher due to matching max render radius.
  53. //! Resolution in: texels per meter.
  54. float m_macroClipmapMaxResolution = 2.0f;
  55. float m_detailClipmapMaxResolution = 2048.0f;
  56. //! The scale base between two adjacent clipmap layers.
  57. //! For example, 3 means the (n+1)th clipmap covers 3^2 = 9 times
  58. //! to what is covered by the nth clipmap.
  59. float m_macroClipmapScaleBase = 2.0f;
  60. float m_detailClipmapScaleBase = 2.0f;
  61. //! The margin of the clipmap where the data won't be used, so that bigger margin results in less frequent update.
  62. //! But bigger margin also means it tends to use lower resolution clipmap.
  63. //! Size in: texels.
  64. uint32_t m_macroClipmapMarginSize = 4;
  65. uint32_t m_detailClipmapMarginSize = 4;
  66. //! In addition to the above margin size used for updating,
  67. //! this margin is a safety margin to avoid edge cases when blending or sampling.
  68. //! For example, due to toroidal addressing, 2 physical adjacent texels can locate
  69. //! on the opposite edges in the clipmap in logical space. They may be accidentally blended
  70. //! by float rounding errors. Size in texels.
  71. uint32_t m_extendedClipmapMarginSize = 2;
  72. //! The size of the blending area between each clipmap level.
  73. //! Size in texels.
  74. uint32_t m_clipmapBlendSize = 256;
  75. //! Calculate how many layers of clipmap is needed.
  76. //! Final result must be less or equal than the MacroClipmapStackSizeMax/DetailClipmapStackSizeMax.
  77. uint32_t CalculateMacroClipmapStackSize() const;
  78. uint32_t CalculateDetailClipmapStackSize() const;
  79. };
  80. //! This class manages all terrain clipmaps' creation and update.
  81. //! It should be owned by the TerrianFeature Processor and provide data and images
  82. //! for the ClipmapGenerationPass and terrain forward rendering pass.
  83. class TerrainClipmapManager
  84. : private TerrainMacroMaterialNotificationBus::Handler
  85. , private TerrainAreaMaterialNotificationBus::Handler
  86. , private AzFramework::Terrain::TerrainDataNotificationBus::Handler
  87. {
  88. friend class TerrainClipmapGenerationPass;
  89. public:
  90. AZ_RTTI(TerrainClipmapManager, "{5892AEE6-F3FA-4DFC-BBEC-77E1B91506A2}");
  91. AZ_DISABLE_COPY_MOVE(TerrainClipmapManager);
  92. TerrainClipmapManager();
  93. virtual ~TerrainClipmapManager() = default;
  94. //! Name for each clipmap image.
  95. enum ClipmapName : uint32_t
  96. {
  97. MacroColor = 0,
  98. MacroNormal,
  99. DetailColor,
  100. DetailNormal,
  101. DetailHeight,
  102. DetailRoughness,
  103. DetailSpecularF0,
  104. DetailMetalness,
  105. DetailOcclusion,
  106. Count
  107. };
  108. //! Shader input names
  109. static constexpr const char* ClipmapDataShaderInput = "m_clipmapData";
  110. static constexpr const char* ClipmapImageShaderInput[ClipmapName::Count] = {
  111. "m_macroColorClipmaps",
  112. "m_macroNormalClipmaps",
  113. "m_detailColorClipmaps",
  114. "m_detailNormalClipmaps",
  115. "m_detailHeightClipmaps",
  116. "m_detailRoughnessClipmaps",
  117. "m_detailSpecularF0Clipmaps",
  118. "m_detailMetalnessClipmaps",
  119. "m_detailOcclusionClipmaps",
  120. };
  121. void SetConfiguration(const ClipmapConfiguration& config);
  122. bool IsClipmapEnabled() const;
  123. void Initialize(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg);
  124. bool IsInitialized() const;
  125. void Reset();
  126. //! Reset full refresh flag so that all the clipmap image will be repainted.
  127. void TriggerFullRefresh();
  128. void UpdateSrgIndices(AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& srg);
  129. void Update(const AZ::Vector3& cameraPosition, const AZ::RPI::Scene* scene, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg);
  130. //! Import the clipmap to the frame graph and set scope attachment access,
  131. //! so that the compute pass can build dependencies accordingly.
  132. void ImportClipmap(ClipmapName clipmapName, AZ::RHI::FrameGraphAttachmentInterface attachmentDatabase) const;
  133. void UseClipmap(ClipmapName clipmapName, AZ::RHI::ScopeAttachmentAccess access, AZ::RHI::FrameGraphInterface frameGraph) const;
  134. //! Get the clipmap images for passes using them.
  135. AZ::Data::Instance<AZ::RPI::AttachmentImage> GetClipmapImage(ClipmapName clipmapName) const;
  136. //! Get the dispatch thread num for the clipmap compute shader based on the current frame.
  137. void GetMacroDispatchThreadNum(uint32_t& outThreadX, uint32_t& outThreadY, uint32_t& outThreadZ) const;
  138. void GetDetailDispatchThreadNum(uint32_t& outThreadX, uint32_t& outThreadY, uint32_t& outThreadZ) const;
  139. //! Get the size of the clipmap from config.
  140. uint32_t GetClipmapSize() const;
  141. //! Returns if there are clipmap regions requiring update.
  142. bool HasMacroClipmapUpdate() const;
  143. bool HasDetailClipmapUpdate() const;
  144. private:
  145. //! Update the C++ copy of the clipmap data. And will later be bound to the terrain SRG.
  146. void UpdateClipmapData(
  147. const AZ::Vector3& cameraPosition,
  148. const AZ::RPI::Scene* scene,
  149. AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg);
  150. //! Initialzation functions.
  151. void QueryMacroClipmapStackSize();
  152. void QueryDetailClipmapStackSize();
  153. void InitializeMacroClipmapBounds(const AZ::Vector2& center);
  154. void InitializeMacroClipmapData();
  155. void InitializeMacroClipmapImages();
  156. void InitializeMacroClipmapGpuBuffer();
  157. void InitializeDetailClipmapBounds(const AZ::Vector2& center);
  158. void InitializeDetailClipmapData();
  159. void InitializeDetailClipmapImages();
  160. void InitializeDetailClipmapGpuBuffer();
  161. //! Clear functions.
  162. void ClearMacroClipmapImages();
  163. void ClearMacroClipmapGpuBuffer();
  164. void ClearDetailClipmapImages();
  165. void ClearDetailClipmapGpuBuffer();
  166. //! Cached terrain SRG for configuration update.
  167. AZ::Data::Instance<AZ::RPI::ShaderResourceGroup> m_terrainSrg;
  168. using RawVector2f = AZStd::array<float, 2>;
  169. using RawVector4f = AZStd::array<float, 4>;
  170. using RawVector2u = AZStd::array<uint32_t, 2>;
  171. using RawVector4u = AZStd::array<uint32_t, 4>;
  172. //! Data to be passed to shaders
  173. struct alignas(16) ClipmapData
  174. {
  175. //! Current viewport size.
  176. RawVector2f m_viewportSize;
  177. //! The max range that the clipmap is covering.
  178. float m_macroClipmapMaxRenderRadius;
  179. float m_detailClipmapMaxRenderRadius;
  180. //! The scale base between two adjacent clipmap layers.
  181. //! For example, 3 means the (n+1)th clipmap covers 3^2 = 9 times
  182. //! to what is covered by the nth clipmap.
  183. float m_macroClipmapScaleBase;
  184. float m_detailClipmapScaleBase;
  185. //! Size of the clipmap stack.
  186. uint32_t m_macroClipmapStackSize;
  187. uint32_t m_detailClipmapStackSize;
  188. //! The margin size of the edge of the clipmap where the data won't be used.
  189. //! Use float to reduce frequent casting in shaders.
  190. float m_macroClipmapMarginSize;
  191. float m_detailClipmapMarginSize;
  192. //! In addition to the above margin size used for updating,
  193. //! this margin is a safety margin to avoid edge cases when blending or sampling.
  194. float m_extendedClipmapMarginSize;
  195. //! The size of the clipmap image in each layer.
  196. //! Given 2 copies in different types to save casting.
  197. float m_clipmapSizeFloat;
  198. uint32_t m_clipmapSizeUint;
  199. //! The texel position where blending to the next level should start. Equivalent to:
  200. //! m_clipmapSizeFloat / 2.0 - m_macroClipmapMarginSize - m_extendedClipmapMarginSize
  201. //! Cached for frequent access.
  202. float m_validMacroClipmapRadius;
  203. //! Same as above, equivalent to:
  204. //! m_clipmapSizeFloat / 2.0 - m_detailClipmapMarginSize - m_extendedClipmapMarginSize
  205. float m_validDetailClipmapRadius;
  206. //! The size of the blending area between each clipmap level.
  207. float m_clipmapBlendSize;
  208. //! The number of regions to be updated during the current frame.
  209. uint32_t m_macroClipmapUpdateRegionCount = 0;
  210. uint32_t m_detailClipmapUpdateRegionCount = 0;
  211. //! Numbers match the compute shader invoking call dispatch(X, Y, 1).
  212. uint32_t m_macroDispatchGroupCountX = 1;
  213. uint32_t m_macroDispatchGroupCountY = 1;
  214. uint32_t m_detailDispatchGroupCountX = 1;
  215. uint32_t m_detailDispatchGroupCountY = 1;
  216. //! Debug data
  217. //! Enables debug overlay to indicate clipmap levels.
  218. float m_macroClipmapOverlayFactor = 0.0f;
  219. float m_detailClipmapOverlayFactor = 0.0f;
  220. // 0: macro color clipmap
  221. // 1: macro normal clipmap
  222. // 2: detail color clipmap
  223. // 3: detail normal clipmap
  224. // 4: detail height clipmap
  225. // 5: detail roughness clipmap
  226. // 6: detail specularF0 clipmap
  227. // 7: detail metalness clipmap
  228. // 8: detail occlusion clipmap
  229. uint32_t m_debugClipmapId = 0;
  230. // Which clipmap level to sample from, or texture array index.
  231. float m_debugClipmapLevel = 0; // cast to float in CPU
  232. // How big the clipmap should appear on the screen.
  233. float m_debugScale = 0.5f;
  234. // Multiplier adjustment for final color output.
  235. float m_debugBrightness = 1.0f;
  236. //! Clipmap centers in texel coordinates ranging [0, size).
  237. //! Clipmap centers are the logical center of the texture, based on toroidal addressing.
  238. struct ClipmapCenter
  239. {
  240. RawVector2u m_macro;
  241. RawVector2u m_detail;
  242. };
  243. AZStd::array<ClipmapCenter, ClipmapConfiguration::SharedClipmapStackSizeMax> m_clipmapCenters;
  244. //! Clipmap centers in world coordinates.
  245. struct ClipmapWorldCenter
  246. {
  247. RawVector2f m_macro;
  248. RawVector2f m_detail;
  249. };
  250. AZStd::array<ClipmapWorldCenter, ClipmapConfiguration::SharedClipmapStackSizeMax> m_clipmapWorldCenters;
  251. //! A scale converting the length from the texture space to the world space.
  252. //! For example: given texel (u0, v0) and (u1, v1), dtexel = sqrt((u0 - u1)^2, (v0 - v1)^2)
  253. //! dworld = dtexel * clipmapToWorldScale.
  254. struct ClipmapToWorldScale
  255. {
  256. float m_macro;
  257. float m_detail;
  258. RawVector2f m_padding;
  259. };
  260. AZStd::array<ClipmapToWorldScale, ClipmapConfiguration::SharedClipmapStackSizeMax> m_clipmapToWorldScale;
  261. };
  262. ClipmapData m_clipmapData;
  263. //! They describe how clipmaps are initilized and updated.
  264. //! Data will be gathered from them when camera moves.
  265. AZStd::vector<ClipmapBounds> m_macroClipmapBounds;
  266. AZStd::vector<ClipmapBounds> m_detailClipmapBounds;
  267. //! GPU buffer containing the region aabbs to be updated during this frame.
  268. AZ::Render::GpuBufferHandler m_macroClipmapUpdateRegionsBuffer;
  269. AZ::Render::GpuBufferHandler m_detailClipmapUpdateRegionsBuffer;
  270. struct ClipmapUpdateRegion
  271. {
  272. RawVector4u m_updateRegion;
  273. uint32_t m_clipmapLevel;
  274. // 16 bytes alignment padding
  275. AZStd::array<uint32_t, 3> m_padding;
  276. ClipmapUpdateRegion(uint32_t clipmapLevel, RawVector4u updateRegion)
  277. : m_clipmapLevel(clipmapLevel)
  278. , m_updateRegion(updateRegion)
  279. {
  280. }
  281. };
  282. AZStd::vector<ClipmapUpdateRegion> m_macroClipmapUpdateRegions;
  283. AZStd::vector<ClipmapUpdateRegion> m_detailClipmapUpdateRegions;
  284. //! Terrain SRG input.
  285. AZ::RHI::ShaderInputNameIndex m_terrainSrgClipmapDataIndex = ClipmapDataShaderInput;
  286. AZ::RHI::ShaderInputNameIndex m_terrainSrgClipmapImageIndex[ClipmapName::Count];
  287. //! Clipmap images.
  288. AZ::Data::Instance<AZ::RPI::AttachmentImage> m_clipmaps[ClipmapName::Count];
  289. //! The actual stack size calculated from the configuration.
  290. uint32_t m_macroClipmapStackSize;
  291. uint32_t m_detailClipmapStackSize;
  292. //! Clipmap config that sets basic properties of the clipmaps.
  293. ClipmapConfiguration m_config;
  294. //! Flag used to refresh the class and prevent doule initialization.
  295. bool m_isInitialized = false;
  296. //! Flag to generate the full clipmap in situation such as first frame and material update.
  297. bool m_fullRefreshClipmaps = true;
  298. //! Dispatch threads for the compute pass.
  299. uint32_t m_macroTotalDispatchThreadX = 0;
  300. uint32_t m_macroTotalDispatchThreadY = 0;
  301. uint32_t m_detailTotalDispatchThreadX = 0;
  302. uint32_t m_detailTotalDispatchThreadY = 0;
  303. //! Group threads defined in the compute shader.
  304. static constexpr uint32_t MacroGroupThreadX = 8;
  305. static constexpr uint32_t MacroGroupThreadY = 8;
  306. static constexpr uint32_t DetailGroupThreadX = 8;
  307. static constexpr uint32_t DetailGroupThreadY = 8;
  308. // AzFramework::Terrain::TerrainDataNotificationBus overrides...
  309. void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
  310. // TerrainMacroMaterialNotificationBus overrides...
  311. void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& material) override;
  312. void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& material) override;
  313. void OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override;
  314. void OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) override;
  315. // TerrainAreaMaterialNotificationBus overrides...
  316. void OnTerrainDefaultSurfaceMaterialCreated(AZ::EntityId entityId, AZ::Data::Instance<AZ::RPI::Material> material) override;
  317. void OnTerrainDefaultSurfaceMaterialDestroyed(AZ::EntityId entityId) override;
  318. void OnTerrainDefaultSurfaceMaterialChanged(AZ::EntityId entityId, AZ::Data::Instance<AZ::RPI::Material> newMaterial) override;
  319. void OnTerrainSurfaceMaterialMappingCreated(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, AZ::Data::Instance<AZ::RPI::Material> material) override;
  320. void OnTerrainSurfaceMaterialMappingDestroyed(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag) override;
  321. void OnTerrainSurfaceMaterialMappingMaterialChanged(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, AZ::Data::Instance<AZ::RPI::Material> material) override;
  322. void OnTerrainSurfaceMaterialMappingTagChanged(AZ::EntityId entityId, SurfaceData::SurfaceTag oldSurfaceTag, SurfaceData::SurfaceTag newSurfaceTag) override;
  323. void OnTerrainSurfaceMaterialMappingRegionCreated(AZ::EntityId entityId, const AZ::Aabb& region) override;
  324. void OnTerrainSurfaceMaterialMappingRegionDestroyed(AZ::EntityId entityId, const AZ::Aabb& oldRegion) override;
  325. void OnTerrainSurfaceMaterialMappingRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override;
  326. };
  327. }