TerrainDetailMaterialManager.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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/Math/Aabb.h>
  11. #include <AzCore/std/containers/array.h>
  12. #include <AzCore/std/function/function_template.h>
  13. #include <AzFramework/Terrain/TerrainDataRequestBus.h>
  14. #include <TerrainRenderer/Aabb2i.h>
  15. #include <TerrainRenderer/ClipmapBounds.h>
  16. #include <TerrainRenderer/TerrainAreaMaterialRequestBus.h>
  17. #include <TerrainRenderer/Vector2i.h>
  18. #include <Atom/RPI.Public/Material/Material.h>
  19. #include <Atom/RPI.Public/Image/AttachmentImage.h>
  20. #include <Atom/RPI.Reflect/Image/Image.h>
  21. #include <Atom/Feature/Utils/IndexedDataVector.h>
  22. #include <Atom/Feature/Utils/SparseVector.h>
  23. #include <Atom/Feature/Utils/GpuBufferHandler.h>
  24. namespace Terrain
  25. {
  26. struct DetailMaterialConfiguration
  27. {
  28. AZ_CLASS_ALLOCATOR(DetailMaterialConfiguration, AZ::SystemAllocator);
  29. AZ_RTTI(DetailMaterialConfiguration, "{D2A2EFBB-B0C2-4363-9B32-15B9ACD52902}");
  30. DetailMaterialConfiguration() = default;
  31. virtual ~DetailMaterialConfiguration() = default;
  32. bool m_useHeightBasedBlending = false;
  33. float m_renderDistance = 512.0f;
  34. float m_fadeDistance = 64.0f;
  35. float m_scale = 1.0f;
  36. };
  37. class TerrainDetailMaterialManager
  38. : private AzFramework::Terrain::TerrainDataNotificationBus::Handler
  39. , private TerrainAreaMaterialNotificationBus::Handler
  40. {
  41. public:
  42. AZ_RTTI(TerrainDetailMaterialManager, "{3CBAF88F-E3B1-43B8-97A5-999133188BCC}");
  43. AZ_DISABLE_COPY_MOVE(TerrainDetailMaterialManager);
  44. TerrainDetailMaterialManager() = default;
  45. ~TerrainDetailMaterialManager() = default;
  46. void Initialize(
  47. const AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg,
  48. const AZ::Data::Instance<AZ::RPI::Material>& materialInstance);
  49. bool IsInitialized() const;
  50. void Reset();
  51. bool UpdateSrgIndices(const AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& srg);
  52. void Update(const AZ::Vector3& cameraPosition, AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>& terrainSrg);
  53. void SetDetailMaterialConfiguration(const DetailMaterialConfiguration& params);
  54. private:
  55. using MaterialInstance = AZ::Data::Instance<AZ::RPI::Material>;
  56. static constexpr auto InvalidImageIndex = AZStd::numeric_limits<uint32_t>::max();
  57. enum DetailTextureFlags : uint32_t
  58. {
  59. None = 0b0000'0000'0000'0000'0000'0000'0000'0000,
  60. UseTextureBaseColor = 0b0000'0000'0000'0000'0000'0000'0000'0001,
  61. UseTextureNormal = 0b0000'0000'0000'0000'0000'0000'0000'0010,
  62. UseTextureMetallic = 0b0000'0000'0000'0000'0000'0000'0000'0100,
  63. UseTextureRoughness = 0b0000'0000'0000'0000'0000'0000'0000'1000,
  64. UseTextureOcclusion = 0b0000'0000'0000'0000'0000'0000'0001'0000,
  65. UseTextureHeight = 0b0000'0000'0000'0000'0000'0000'0010'0000,
  66. UseTextureSpecularF0 = 0b0000'0000'0000'0000'0000'0000'0100'0000,
  67. FlipNormalX = 0b0000'0000'0000'0001'0000'0000'0000'0000,
  68. FlipNormalY = 0b0000'0000'0000'0010'0000'0000'0000'0000,
  69. BlendModeMask = 0b0000'0000'0001'1100'0000'0000'0000'0000,
  70. BlendModeLerp = 0b0000'0000'0000'0100'0000'0000'0000'0000,
  71. BlendModeLinearLight = 0b0000'0000'0000'1000'0000'0000'0000'0000,
  72. BlendModeMultiply = 0b0000'0000'0000'1100'0000'0000'0000'0000,
  73. BlendModeOverlay = 0b0000'0000'0001'0000'0000'0000'0000'0000,
  74. };
  75. struct DetailMaterialShaderData
  76. {
  77. // Uv (data is 3x3, padding each row for explicit alignment)
  78. AZStd::array<float, 12> m_uvTransform
  79. {
  80. 1.0, 0.0, 0.0, 0.0,
  81. 0.0, 1.0, 0.0, 0.0,
  82. 0.0, 0.0, 1.0, 0.0,
  83. };
  84. float m_baseColorRed{ 1.0f };
  85. float m_baseColorGreen{ 1.0f };
  86. float m_baseColorBlue{ 1.0f };
  87. // Factor / Scale / Bias for input textures
  88. float m_baseColorFactor{ 1.0f };
  89. float m_normalFactor{ 1.0f };
  90. float m_metalFactor{ 0.0f };
  91. float m_roughnessScale{ 1.0f };
  92. float m_roughnessBias{ 0.0f };
  93. float m_specularF0Factor{ 0.5f };
  94. float m_occlusionFactor{ 1.0f };
  95. float m_heightFactor{ 1.0f };
  96. float m_heightOffset{ 0.0f };
  97. float m_heightBlendFactor{ 0.5f };
  98. float m_heightWeightClampFactor{ 0.1f };
  99. // Flags
  100. DetailTextureFlags m_flags{ 0 };
  101. // Image indices
  102. uint32_t m_colorImageIndex{ InvalidImageIndex };
  103. uint32_t m_normalImageIndex{ InvalidImageIndex };
  104. uint32_t m_roughnessImageIndex{ InvalidImageIndex };
  105. uint32_t m_metalnessImageIndex{ InvalidImageIndex };
  106. uint32_t m_specularF0ImageIndex{ InvalidImageIndex };
  107. uint32_t m_occlusionImageIndex{ InvalidImageIndex };
  108. uint32_t m_heightImageIndex{ InvalidImageIndex };
  109. // 16 byte aligned
  110. uint32_t m_padding[2]{ 0 };
  111. };
  112. static constexpr size_t SizeOfDetailMaterialShaderData = sizeof(DetailMaterialShaderData);
  113. static_assert(SizeOfDetailMaterialShaderData % 16 == 0, "DetailMaterialShaderData must be 16 byte aligned.");
  114. struct DetailMaterialData
  115. {
  116. AZ::Data::AssetId m_assetId;
  117. uint32_t m_refCount = 0;
  118. uint16_t m_detailMaterialBufferIndex{ 0xFFFF };
  119. AZ::Data::Instance<AZ::RPI::Image> m_colorImage;
  120. AZ::Data::Instance<AZ::RPI::Image> m_normalImage;
  121. AZ::Data::Instance<AZ::RPI::Image> m_roughnessImage;
  122. AZ::Data::Instance<AZ::RPI::Image> m_metalnessImage;
  123. AZ::Data::Instance<AZ::RPI::Image> m_specularF0Image;
  124. AZ::Data::Instance<AZ::RPI::Image> m_occlusionImage;
  125. AZ::Data::Instance<AZ::RPI::Image> m_heightImage;
  126. };
  127. struct DetailMaterialSurface
  128. {
  129. AZ::Crc32 m_surfaceTag;
  130. uint16_t m_detailMaterialId;
  131. };
  132. struct DetailMaterialListRegion
  133. {
  134. AZ::EntityId m_entityId;
  135. AZ::Aabb m_region{AZ::Aabb::CreateNull()};
  136. AZStd::vector<DetailMaterialSurface> m_materialsForSurfaces;
  137. uint16_t m_defaultDetailMaterialId{ 0xFFFF };
  138. bool HasMaterials()
  139. {
  140. return m_defaultDetailMaterialId != InvalidDetailMaterialId || !m_materialsForSurfaces.empty();
  141. }
  142. };
  143. using DetailMaterialContainer = AZ::Render::IndexedDataVector<DetailMaterialData>;
  144. static constexpr auto InvalidDetailMaterialId = DetailMaterialContainer::NoFreeSlot;
  145. // System-level parameters
  146. int32_t m_detailTextureSize{ 1024 };
  147. float m_detailTextureScale{ 0.5f };
  148. // AzFramework::Terrain::TerrainDataNotificationBus overrides...
  149. void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
  150. // TerrainAreaMaterialNotificationBus overrides...
  151. void OnTerrainDefaultSurfaceMaterialCreated(AZ::EntityId entityId, AZ::Data::Instance<AZ::RPI::Material> material) override;
  152. void OnTerrainDefaultSurfaceMaterialDestroyed(AZ::EntityId entityId) override;
  153. void OnTerrainDefaultSurfaceMaterialChanged(AZ::EntityId entityId, AZ::Data::Instance<AZ::RPI::Material> newMaterial) override;
  154. void OnTerrainSurfaceMaterialMappingCreated(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) override;
  155. void OnTerrainSurfaceMaterialMappingDestroyed(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag) override;
  156. void OnTerrainSurfaceMaterialMappingMaterialChanged(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) override;
  157. void OnTerrainSurfaceMaterialMappingTagChanged(
  158. AZ::EntityId entityId, SurfaceData::SurfaceTag oldSurfaceTag, SurfaceData::SurfaceTag newSurfaceTag) override;
  159. void OnTerrainSurfaceMaterialMappingRegionCreated(AZ::EntityId entityId, const AZ::Aabb& region) override;
  160. void OnTerrainSurfaceMaterialMappingRegionDestroyed(AZ::EntityId entityId, const AZ::Aabb& oldRegion) override;
  161. void OnTerrainSurfaceMaterialMappingRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override;
  162. //! Creates or updates an existing detail material with settings from a material instance
  163. uint16_t CreateOrUpdateDetailMaterial(MaterialInstance material);
  164. //! Decrements the ref count on a detail material and removes it if it reaches 0
  165. void CheckDetailMaterialForDeletion(uint16_t detailMaterialId);
  166. //! Updates a specific detail material with settings from a material instance
  167. void UpdateDetailMaterialData(uint16_t detailMaterialIndex, MaterialInstance material);
  168. //! Checks to see if the detail material id texture needs to update based on the camera position. Any
  169. //! required updates are then executed.
  170. void CheckUpdateDetailTexture(const AZ::Vector3& cameraPosition);
  171. //! Updates the detail texture in a given area
  172. void UpdateDetailTexture(const AZ::Aabb& worldUpdateAabb, const Aabb2i& textureUpdateAabb);
  173. //! Finds the detail material Id for a region and surface type
  174. uint16_t GetDetailMaterialForSurfaceType(const DetailMaterialListRegion& materialRegion, AZ::Crc32 surfaceType) const;
  175. //! Finds a region for a position. Returns nullptr if none found.
  176. const DetailMaterialListRegion* FindRegionForPosition(const AZ::Vector2& position) const;
  177. //! Initializes shader data for the default passthrough material which is used when no other detail material is found.
  178. void InitializePassthroughDetailMaterial();
  179. //! Updates data regarding the material ID texture and resets it so it will get rebuilt.
  180. void InitializeTextureParams();
  181. //! Updates paramters related to detail materials on the terrain material itself.
  182. void UpdateTerrainMaterial();
  183. using DefaultMaterialSurfaceCallback = AZStd::function<void(DetailMaterialSurface&)>;
  184. bool ForSurfaceTag(DetailMaterialListRegion& materialRegion,
  185. SurfaceData::SurfaceTag surfaceTag, DefaultMaterialSurfaceCallback callback);
  186. DetailMaterialListRegion* FindByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector<DetailMaterialListRegion>& container);
  187. DetailMaterialListRegion& FindOrCreateByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector<DetailMaterialListRegion>& container);
  188. void RemoveByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector<DetailMaterialListRegion>& container);
  189. DetailMaterialConfiguration m_config;
  190. AZ::Data::Instance<AZ::RPI::AttachmentImage> m_detailTextureImage;
  191. AZ::Data::Instance<AZ::RPI::Material> m_terrainMaterial;
  192. DetailMaterialContainer m_detailMaterials;
  193. AZ::Render::IndexedDataVector<DetailMaterialListRegion> m_detailMaterialRegions;
  194. AZ::Render::SparseVector<size_t> m_detailMaterialShaderIndex;
  195. AZStd::unordered_map<int, AZStd::vector<DetailMaterialShaderData>> m_detailMaterialShaderData;
  196. AZ::Render::GpuBufferHandler m_detailMaterialDataBuffer;
  197. uint8_t m_passthroughMaterialId = 0;
  198. AZ::Aabb m_dirtyDetailRegion{ AZ::Aabb::CreateNull() };
  199. ClipmapBounds m_detailMaterialIdBounds;
  200. AZ::RHI::ShaderInputImageIndex m_detailMaterialIdPropertyIndex;
  201. AZ::RHI::ShaderInputBufferIndex m_detailMaterialDataIndex;
  202. AZ::RHI::ShaderInputConstantIndex m_detailScalePropertyIndex;
  203. bool m_isInitialized{ false };
  204. bool m_detailMaterialBufferNeedsUpdate{ false };
  205. bool m_detailImageNeedsUpdate{ false };
  206. };
  207. }