💿🐜 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.

222 lines
6.8 KiB

  1. /*
  2. * Copyright (C) 2023 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 "math/hash/make-uint.hpp"
  23. #include "math/hash/pcg.hpp"
  24. #include <algorithm>
  25. #include <utility>
  26. namespace math {
  27. namespace noise {
  28. /**
  29. * Number of corners in an *n*-dimensional simplex lattice cell.
  30. *
  31. * @private
  32. */
  33. template <std::size_t N>
  34. constexpr std::size_t simplex_corner_count = std::size_t(2) << std::max<std::size_t>(0, N - 1);
  35. /**
  36. * Number of edges in an *n*-dimensional simplex lattice cell.
  37. *
  38. * @private
  39. */
  40. template <std::size_t N>
  41. constexpr std::size_t simplex_edge_count = (N > 1) ? N * simplex_corner_count<N - 1> : 2;
  42. /**
  43. * Returns the simplex lattice cell corner vector for a given dimension and index.
  44. *
  45. * @private
  46. */
  47. template <class T, std::size_t N, std::size_t... I>
  48. [[nodiscard]] constexpr vector<T, N> make_simplex_corner(std::size_t i, std::index_sequence<I...>)
  49. {
  50. return {((i >> I) % 2) * T{2} - T{1}...};
  51. }
  52. /**
  53. * Builds an array of simplex lattice cell corner vectors for a given dimension.
  54. *
  55. * @private
  56. */
  57. template <class T, std::size_t N, std::size_t... I>
  58. [[nodiscard]] constexpr std::array<vector<T, N>, simplex_corner_count<N>> make_simplex_corners(std::index_sequence<I...>)
  59. {
  60. return {make_simplex_corner<T, N>(I, std::make_index_sequence<N>{})...};
  61. }
  62. /**
  63. * Array of simplex lattice cell corner vectors for a given dimension.
  64. *
  65. * @private
  66. */
  67. template <class T, std::size_t N>
  68. constexpr auto simplex_corners = make_simplex_corners<T, N>(std::make_index_sequence<simplex_corner_count<N>>{});
  69. /**
  70. * Returns the simplex lattice cell edge vector for a given dimension and index.
  71. *
  72. * @private
  73. */
  74. template <class T, std::size_t N, std::size_t... I>
  75. [[nodiscard]] constexpr vector<T, N> make_simplex_edge(std::size_t i, std::index_sequence<I...>)
  76. {
  77. std::size_t j = i / (simplex_edge_count<N> / N);
  78. return
  79. {
  80. I < j ?
  81. simplex_corners<T, N - 1>[i % simplex_corner_count<N - 1>][I]
  82. :
  83. I > j ?
  84. simplex_corners<T, N - 1>[i % simplex_corner_count<N - 1>][I - 1]
  85. :
  86. T{0}
  87. ...
  88. };
  89. }
  90. /**
  91. * Builds an array of simplex lattice cell edge vectors for a given dimension.
  92. *
  93. * @private
  94. */
  95. template <class T, std::size_t N, std::size_t... I>
  96. [[nodiscard]] constexpr std::array<vector<T, N>, simplex_edge_count<N>> make_simplex_edges(std::index_sequence<I...>)
  97. {
  98. if constexpr (N == 1)
  99. return std::array<vector<T, N>, simplex_edge_count<N>>{vector<T, N>{T{1}}, vector<T, N>{T{-1}}};
  100. else
  101. return {make_simplex_edge<T, N>(I, std::make_index_sequence<N>{})...};
  102. }
  103. /**
  104. * Array of simplex lattice cell edge vectors for a given dimension.
  105. *
  106. * @private
  107. */
  108. template <class T, std::size_t N>
  109. constexpr auto simplex_edges = make_simplex_edges<T, N>(std::make_index_sequence<simplex_edge_count<N>>{});
  110. /**
  111. * *n*-dimensional simplex noise.
  112. *
  113. * @tparam T Real type.
  114. * @tparam N Number of dimensions.
  115. *
  116. * @param position Input position.
  117. * @param hash Hash function.
  118. *
  119. * @return Noise value, on `[-1, 1]`.
  120. *
  121. * @see https://en.wikipedia.org/wiki/Simplex_noise
  122. * @see https://catlikecoding.com/unity/tutorials/pseudorandom-noise/simplex-noise/
  123. * @see https://briansharpe.wordpress.com/2012/01/13/simplex-noise/
  124. * @see https://briansharpe.wordpress.com/2011/11/14/two-useful-interpolation-functions-for-noise-development/
  125. * @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116
  126. */
  127. template <class T, std::size_t N>
  128. [[nodiscard]] T simplex
  129. (
  130. const vector<T, N>& position,
  131. vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
  132. )
  133. {
  134. // Skewing (F) and unskewing (G) factors
  135. static const T f = (std::sqrt(static_cast<T>(N + 1)) - T{1}) / static_cast<T>(N);
  136. static const T g = f / (T{1} + f * static_cast<T>(N));
  137. // Kernel radius set to the height of the equilateral triangle, `sqrt(0.5)`
  138. constexpr T sqr_kernel_radius = T{0.5};
  139. /**
  140. * C2-continuous kernel falloff function.
  141. *
  142. * @param sqr_distance Squared distance from the kernel center.
  143. *
  144. * @return Kernel strength at the given distance.
  145. */
  146. auto falloff = [sqr_kernel_radius](T sqr_distance) constexpr
  147. {
  148. sqr_distance = sqr_kernel_radius - sqr_distance;
  149. return sqr_distance * sqr_distance * sqr_distance;
  150. };
  151. // Normalization factor when using corner gradient vectors
  152. // @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116
  153. 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))));
  154. // Adjust normalization factor for difference in length between corner gradient vectors and edge gradient vectors
  155. static const T edge_normalization = corner_normalization * (std::sqrt(static_cast<T>(N)) / length(simplex_edges<T, N>[0]));
  156. // Skew input position to get the origin vertex of the unit hypercube cell to which they belong
  157. const vector<T, N> origin_vertex = floor(position + sum(position) * f);
  158. // Displacement vector from origin vertex position to input position
  159. const vector<T, N> dx = position - origin_vertex + sum(origin_vertex) * g;
  160. // Find axis traversal order
  161. vector<std::size_t, N> axis_order;
  162. for (std::size_t i = 0; i < N; ++i)
  163. axis_order[i] = i;
  164. std::sort
  165. (
  166. axis_order.begin(),
  167. axis_order.end(),
  168. [&dx](std::size_t lhs, std::size_t rhs)
  169. {
  170. return dx[lhs] > dx[rhs];
  171. }
  172. );
  173. T n = T{0};
  174. vector<T, N> current_vertex = origin_vertex;
  175. for (std::size_t i = 0; i <= N; ++i)
  176. {
  177. if (i)
  178. ++current_vertex[axis_order[i - 1]];
  179. // Calculate displacement vector from current vertex to input position
  180. const vector<T, N> d = dx - (current_vertex - origin_vertex) + g * static_cast<T>(i);
  181. // Calculate falloff
  182. T t = falloff(sqr_length(d));
  183. if (t > T{0})
  184. {
  185. const hash::make_uint_t<T> gradient_index = hash(current_vertex)[0] % simplex_edges<T, N>.size();
  186. const vector<T, N>& gradient = simplex_edges<T, N>[gradient_index];
  187. n += dot(d, gradient) * t;
  188. }
  189. }
  190. // Normalize value
  191. return n * edge_normalization;
  192. }
  193. } // namespace noise
  194. } // namespace math
  195. #endif // ANTKEEPER_MATH_NOISE_SIMPLEX_HPP