ClipmapBounds.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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/Math/Vector2.h>
  12. #include <AzCore/std/containers/vector.h>
  13. #include <TerrainRenderer/Vector2i.h>
  14. #include <TerrainRenderer/Aabb2i.h>
  15. namespace Terrain
  16. {
  17. struct ClipmapBoundsDescriptor
  18. {
  19. //! Width and height of the clipmap in texels.
  20. uint32_t m_size = 1024;
  21. //! Current center location of the clipmap in world space
  22. AZ::Vector2 m_worldSpaceCenter = AZ::Vector2::CreateZero();
  23. // Updates to the clipmap will be produced in multiples of this value. This
  24. // allows for larger but less frequent updates, and gives some wiggle room
  25. // for each movement before an update is triggered.
  26. // Note: This also means that whatever uses this clipmap should only ever
  27. // display m_size - (2 * m_clipmapUpdateMultiple) pixels from the clipmap.
  28. // Use GetWorldSpaceSafeDistance() to get the safe distance from center.
  29. uint32_t m_clipmapUpdateMultiple = 4;
  30. //! Scale of the clip map compared to the world. A scale of 0.5 means that
  31. //! a clipmap of size 1024 would cover 512 meters.
  32. float m_clipmapToWorldScale = 1.0f;
  33. };
  34. struct ClipmapBoundsRegion
  35. {
  36. //! The world bounds of the updated region. Z is ignored.
  37. AZ::Aabb m_worldAabb;
  38. //! The clipmaps bounds of the updated region. Will always be between 0 and size.
  39. //! Min inclusive, max exclusive.
  40. Aabb2i m_localAabb;
  41. bool operator==(const ClipmapBoundsRegion& other) const;
  42. bool operator!=(const ClipmapBoundsRegion& other) const;
  43. };
  44. using ClipmapBoundsRegionList = AZStd::vector<ClipmapBoundsRegion>;
  45. // This class manages a single clipmap region. A clipmap is a virtual view into a much larger
  46. // region, where the clipmap view is centered around a point like the current camera position.
  47. // The clipmap texture wraps to form a repeating grid and never moves, but only data within
  48. // the clipmap bounds is actually valid. This makes looking up data in the clipmap trivial
  49. // since it's just the world coordinate scaled by some amount. This technique also allows for
  50. // only the edge areas of the clipmap to be updated as the center point moves around the world.
  51. //
  52. // The edges of the clipmap bounds will typically run through the texture, dividing it into 4
  53. // regions, except in cases where the clipmap bounds happen to be aligned with the underlying
  54. // grid. This means whenever some bounding box needs to be updated in the clipmap, it may actually
  55. // translate to 4 different areas of the underlying texture - one for each quadrant.
  56. //
  57. // This class aids in figuring out which areas of a clipmap need to be updated as its center point
  58. // moves around in the world, and can map a single region that needs to be updated into several
  59. // separate regions for each quadrant.
  60. /*
  61. ___________________________
  62. | | | | | Clipmap Clipmap
  63. | | | | | Bounds Texture (Tiled)
  64. |______|______|______|______| ______ ______
  65. | | _|____ | | | | | |____|_|
  66. | | | | | | | |_|_*__| | | |
  67. |______|____|_|_*__|_|______| |_|____| |_*__|_|
  68. | | |_|____| | |
  69. | | | | |
  70. |______|______|______|______|
  71. | | | | |
  72. | | | | |
  73. |______|______|______|______|
  74. */
  75. class ClipmapBounds
  76. {
  77. public:
  78. ClipmapBounds() = default;
  79. explicit ClipmapBounds(const ClipmapBoundsDescriptor& desc);
  80. ~ClipmapBounds() = default;
  81. //! Updates the clipmap bounds using a world coordinate center position and returns
  82. //! 0-6 regions that need to be updated due to moving beyond the margins. These update
  83. //! regions will always be at least the size of the margin, and will represent horizontal
  84. //! and/or vertical strips along the edges of the clipmap. An optional untouched region
  85. //! aabb can be passed to this function to get an aabb of areas inside the bounds of the
  86. //! clipmap but not updated by the center moving. This can be useful in cases where part
  87. //! of the bounds of the clipmap is dirty, but areas that will already be updated due
  88. //! to the center moving shouldn't be updated twice.
  89. ClipmapBoundsRegionList UpdateCenter(const AZ::Vector2& newCenter, AZ::Aabb* untouchedRegion = nullptr);
  90. //! Updates the clipmap bounds using a position in clipmap space (no scaling) and returns
  91. //! 0-6 regions that need to be updated due to moving beyond the margins. These update
  92. //! regions will always be at least the size of the margin, and will represent horizontal
  93. //! and/or vertical strips along the edges of the clipmap. An optional untouched region
  94. //! aabb can be passed to this function to get an aabb of areas inside the bounds of the
  95. //! clipmap but not updated by the center moving. This can be useful in cases where part
  96. //! of the bounds of the clipmap is dirty, but areas that will already be updated due
  97. //! to the center moving shouldn't be updated twice.
  98. ClipmapBoundsRegionList UpdateCenter(const Vector2i& newCenter, AZ::Aabb* untouchedRegion = nullptr);
  99. //! The biggest possible number of regions can return when calling UpdateCenter();
  100. static constexpr uint32_t MaxUpdateRegions = 6;
  101. //! Takes in a single world space aabb and transforms it into 0-4 regions in the clipmap clamped
  102. //! to the bounds of the clipmap.
  103. ClipmapBoundsRegionList TransformRegion(AZ::Aabb worldSpaceRegion);
  104. //! Takes in a single world space min and max 2d bounds and transforms it into 0-4 regions in the clipmap clamped
  105. //! to the bounds of the clipmap.
  106. ClipmapBoundsRegionList TransformRegion(const AZ::Vector2& worldSpaceMin, const AZ::Vector2& worldSpaceMax);
  107. //! Takes in a single unscaled clipmap space region and transforms it into 0-4 regions in the clipmap clamped
  108. //! to the bounds of the clipmap.
  109. ClipmapBoundsRegionList TransformRegion(Aabb2i clipSpaceRegion);
  110. //! Returns the bounds covered by this clipmap in world space. Z component is always 0.
  111. AZ::Aabb GetWorldBounds() const;
  112. //! Returns the safe x and y distance from the center in world space. This is based on the scale,
  113. //! clipmap size, and m_clipmapUpdateMultiple. For example, a clipmap size 1024 with scale
  114. //! 0.25 and margin of 4 would have a safe distance of (1024 * 0.5 - 4) * 0.25 = 127.0f.
  115. float GetWorldSpaceSafeDistance() const;
  116. //! Returns the center of the clipmap in clipmap space.
  117. Vector2i GetCenterInClipmapSpace() const;
  118. //! Returns the center of the clipmap in world space.
  119. AZ::Vector2 GetCenterInWorldSpace() const;
  120. //! Returns the modulated center of the clipmap in [0, size).
  121. Vector2i GetModCenter() const;
  122. private:
  123. enum class RoundMode
  124. {
  125. Average,
  126. Floor,
  127. Ceil,
  128. };
  129. //! Returns the center point snapped to a multiple of m_clipmapUpdateMultiple. This isn't
  130. //! a simple rounding operation. The value returned will only be different from the current
  131. //! center if the value passed in is greater than m_clipmapUpdateMultiple away from the center.
  132. Vector2i GetSnappedCenter(const Vector2i& center);
  133. //! Returns the bounds covered by the clipmap in local space
  134. Aabb2i GetLocalBounds() const;
  135. //! Applies scale and averages a world space vector to get a clip space vector.
  136. Vector2i GetClipSpaceVector(const AZ::Vector2& worldSpaceVector, RoundMode roundMode = RoundMode::Average) const;
  137. //! Applies inverse scale to get a world aabb from clip space aabb.
  138. AZ::Aabb GetWorldSpaceAabb(const Aabb2i& clipSpaceAabb) const;
  139. Vector2i m_center;
  140. Vector2i m_modCenter;
  141. int32_t m_size;
  142. int32_t m_halfSize;
  143. int32_t m_clipmapUpdateMultiple;
  144. float m_clipmapToWorldScale;
  145. float m_worldToClipmapScale;
  146. };
  147. }