💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
6.5 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef ANTKEEPER_MATH_NOISE_SIMPLEX_HPP
  20. #define ANTKEEPER_MATH_NOISE_SIMPLEX_HPP
  21. #include "math/vector.hpp"
  22. #include <algorithm>
  23. #include <utility>
  24. namespace math {
  25. namespace noise {
  26. /// @private
  27. /// @{
  28. /// Number of corners in an *n*-dimensional simplex lattice cell.
  29. template <std::size_t N>
  30. constexpr std::size_t simplex_corner_count = std::size_t(2) << std::max<std::size_t>(0, N - 1);
  31. /// Number of edges in an *n*-dimensional simplex lattice cell.
  32. template <std::size_t N>
  33. constexpr std::size_t simplex_edge_count = (N > 1) ? N * simplex_corner_count<N - 1> : 2;
  34. /// Returns the simplex lattice cell corner vector for a given dimension and index.
  35. template <class T, std::size_t N, std::size_t... I>
  36. constexpr vector<T, N> make_simplex_corner(std::size_t i, std::index_sequence<I...>)
  37. {
  38. return {((i >> I) % 2) * T{2} - T{1}...};
  39. }
  40. /// Builds an array of simplex lattice cell corner vectors for a given dimension.
  41. template <class T, std::size_t N, std::size_t... I>
  42. constexpr std::array<vector<T, N>, simplex_corner_count<N>> make_simplex_corners(std::index_sequence<I...>)
  43. {
  44. return {make_simplex_corner<T, N>(I, std::make_index_sequence<N>{})...};
  45. }
  46. /// Array of simplex lattice cell corner vectors for a given dimension.
  47. template <class T, std::size_t N>
  48. constexpr auto simplex_corners = make_simplex_corners<T, N>(std::make_index_sequence<simplex_corner_count<N>>{});
  49. /// Returns the simplex lattice cell edge vector for a given dimension and index.
  50. template <class T, std::size_t N, std::size_t... I>
  51. constexpr vector<T, N> make_simplex_edge(std::size_t i, std::index_sequence<I...>)
  52. {
  53. std::size_t j = i / (simplex_edge_count<N> / N);
  54. return
  55. {
  56. I < j ?
  57. simplex_corners<T, N - 1>[i % simplex_corner_count<N - 1>][I]
  58. :
  59. I > j ?
  60. simplex_corners<T, N - 1>[i % simplex_corner_count<N - 1>][I - 1]
  61. :
  62. T{0}
  63. ...
  64. };
  65. }
  66. /// Builds an array of simplex lattice cell edge vectors for a given dimension.
  67. template <class T, std::size_t N, std::size_t... I>
  68. constexpr std::array<vector<T, N>, simplex_edge_count<N>> make_simplex_edges(std::index_sequence<I...>)
  69. {
  70. if constexpr (N == 1)
  71. return std::array<vector<T, N>, simplex_edge_count<N>>{vector<T, N>{T{1}}, vector<T, N>{T{-1}}};
  72. else
  73. return {make_simplex_edge<T, N>(I, std::make_index_sequence<N>{})...};
  74. }
  75. /// Array of simplex lattice cell edge vectors for a given dimension.
  76. template <class T, std::size_t N>
  77. constexpr auto simplex_edges = make_simplex_edges<T, N>(std::make_index_sequence<simplex_edge_count<N>>{});
  78. /// @}
  79. /**
  80. * *n*-dimensional simplex noise.
  81. *
  82. * @tparam T Real type.
  83. * @tparam N Number of dimensions.
  84. *
  85. * @param x Input vector.
  86. * @param hash Hash function.
  87. *
  88. * @return Noise value, on `[-1, 1]`.
  89. *
  90. * @see https://en.wikipedia.org/wiki/Simplex_noise
  91. * @see https://catlikecoding.com/unity/tutorials/pseudorandom-noise/simplex-noise/
  92. * @see https://briansharpe.wordpress.com/2012/01/13/simplex-noise/
  93. * @see https://briansharpe.wordpress.com/2011/11/14/two-useful-interpolation-functions-for-noise-development/
  94. * @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116
  95. */
  96. template <class T, std::size_t N>
  97. T simplex(const vector<T, N>& x, std::uint32_t (*hash)(const vector<T, N>&))
  98. {
  99. // Skewing (F) and unskewing (G) factors
  100. static const T f = (std::sqrt(static_cast<T>(N + 1)) - T{1}) / static_cast<T>(N);
  101. static const T g = f / (T{1} + f * static_cast<T>(N));
  102. // Kernel radius set to the height of the equilateral triangle, `sqrt(0.5)`
  103. constexpr T sqr_kernel_radius = T{0.5};
  104. /**
  105. * C2-continuous kernel falloff function.
  106. *
  107. * @param sqr_distance Squared distance from the kernel center.
  108. *
  109. * @return Kernel strength at the given distance.
  110. */
  111. auto falloff = [sqr_kernel_radius](T sqr_distance) constexpr
  112. {
  113. sqr_distance = sqr_kernel_radius - sqr_distance;
  114. return sqr_distance * sqr_distance * sqr_distance;
  115. };
  116. // Normalization factor when using corner gradient vectors
  117. // @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116
  118. static const T corner_normalization = T{1} / ((static_cast<T>(N) / std::sqrt(static_cast<T>(N + 1))) * falloff(static_cast<T>(N) / (T{4} * static_cast<T>(N + 1))));
  119. // Adjust normalization factor for difference in length between corner gradient vectors and edge gradient vectors
  120. static const T edge_normalization = corner_normalization * (std::sqrt(static_cast<T>(N)) / math::length(simplex_edges<T, N>[0]));
  121. // Skew input position to get the origin vertex of the unit hypercube cell to which they belong
  122. const vector<T, N> origin_vertex = math::floor(x + math::sum(x) * f);
  123. // Displacement vector from origin vertex position to input position
  124. const vector<T, N> dx = x - origin_vertex + math::sum(origin_vertex) * g;
  125. // Find axis traversal order
  126. vector<std::size_t, N> axis_order;
  127. for (std::size_t i = 0; i < N; ++i)
  128. axis_order[i] = i;
  129. std::sort
  130. (
  131. axis_order.begin(),
  132. axis_order.end(),
  133. [&dx](std::size_t lhs, std::size_t rhs)
  134. {
  135. return dx[lhs] > dx[rhs];
  136. }
  137. );
  138. T n = T{0};
  139. vector<T, N> current_vertex = origin_vertex;
  140. for (std::size_t i = 0; i <= N; ++i)
  141. {
  142. if (i)
  143. ++current_vertex[axis_order[i - 1]];
  144. // Calculate displacement vector from current vertex to input position
  145. const vector<T, N> d = dx - (current_vertex - origin_vertex) + g * static_cast<T>(i);
  146. // Calculate falloff
  147. T t = falloff(math::length_squared(d));
  148. if (t > T{0})
  149. {
  150. const auto gradient_index = hash(current_vertex) % simplex_edges<T, N>.size();
  151. const vector<T, N>& gradient = simplex_edges<T, N>[gradient_index];
  152. n += math::dot(d, gradient) * t;
  153. }
  154. }
  155. // Normalize value
  156. return n * edge_normalization;
  157. }
  158. } // namespace noise
  159. } // namespace math
  160. #endif // ANTKEEPER_MATH_NOISE_SIMPLEX_HPP