您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

413 行
14 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net>
  5. // © 2013—2014 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. // © 2013—2014 Guillaume Bittoun <guillaume.bittoun@gmail.com>
  7. //
  8. // Lol Engine is free software. It comes without any warranty, to
  9. // the extent permitted by applicable law. You can redistribute it
  10. // and/or modify it under the terms of the Do What the Fuck You Want
  11. // to Public License, Version 2, as published by the WTFPL Task Force.
  12. // See http://www.wtfpl.net/ for more details.
  13. //
  14. #pragma once
  15. #include "gradient.h"
  16. #include <lol/vector> // lol::vec_t
  17. #include <lol/transform> // lol::mat_t
  18. #include <vector> // std::vector
  19. #include <cmath> // std::fabs
  20. #include <algorithm> // std::min, std::max
  21. namespace lol
  22. {
  23. /*
  24. * Simplex noise in dimension N
  25. * ----------------------------
  26. *
  27. * The N-dimensional regular hypercube can be split into N! simplices that
  28. * all have the main diagonal as a shared edge.
  29. * - number of simplices: N!
  30. * - number of vertices per simplex: N+1
  31. * - number of edges: N(N+1)/2
  32. * - minimum edge length: 1 (hypercube edges, e.g. [1,0,0,…,0])
  33. * - maximum edge length: sqrt(N) (hypercube diagonal, i.e. [1,1,1,…,1])
  34. *
  35. * We skew the simplicial grid along the main diagonal by a factor f =
  36. * sqrt(N+1), which means the diagonal of the initial parallelotope has
  37. * length sqrt(N/(N+1)). The edges of that parallelotope have length
  38. * sqrt(N/(N+1)), too. A formula for the maximum edge length was found
  39. * empirically:
  40. * - minimum edge length: sqrt(N/(N+1)) (parallelotope edges and diagonal)
  41. * - maximum edge length: sqrt(floor((N+1)²/4)/(N+1))
  42. */
  43. template<int N>
  44. class simplex_noise : public gradient_provider<N>
  45. {
  46. public:
  47. simplex_noise()
  48. : gradient_provider<N>()
  49. {
  50. #if 0
  51. debugprint();
  52. #endif
  53. }
  54. simplex_noise(int seed)
  55. : gradient_provider<N>(seed)
  56. {
  57. }
  58. /* Evaluate noise at a given point */
  59. inline float eval(vec_t<float, N> position) const
  60. {
  61. // Retrieve the containing hypercube origin and associated decimals
  62. vec_t<int, N> origin;
  63. vec_t<float, N> pos;
  64. get_origin(skew(position), origin, pos);
  65. return get_noise(origin, pos);
  66. }
  67. /* Only for debug purposes: return the gradient vector of the given
  68. * point’s simplex origin. */
  69. inline vec_t<float, N> gradient(vec_t<float, N> position) const
  70. {
  71. vec_t<int, N> origin;
  72. vec_t<float, N> pos;
  73. get_origin(skew(position), origin, pos);
  74. return get_gradient(origin);
  75. }
  76. protected:
  77. inline float get_noise(vec_t<int, N> origin,
  78. vec_t<float, N> const & pos) const
  79. {
  80. using std::min;
  81. /* For a given position [0…1]^N inside a regular N-hypercube, find
  82. * the N-simplex which contains that position, and return a path
  83. * along the hypercube edges from (0,0,…,0) to (1,1,…,1) which
  84. * uniquely describes that simplex. */
  85. vec_t<int, N> traversal_order;
  86. for (int i = 0; i < N; ++i)
  87. traversal_order[i] = i;
  88. /* Naïve bubble sort — enough for now since the general complexity
  89. * of our algorithm is O(N²). Sorting in O(N²) will not hurt more! */
  90. for (int i = 0; i < N; ++i)
  91. for (int j = i + 1; j < N; ++j)
  92. if (pos[traversal_order[i]] < pos[traversal_order[j]])
  93. std::swap(traversal_order[i], traversal_order[j]);
  94. /* Get the position in world coordinates, too */
  95. vec_t<float, N> world_pos = unskew(pos);
  96. /* “corner” will traverse the simplex along its edges in world
  97. * coordinates. */
  98. vec_t<float, N> world_corner(0.f);
  99. float result = 0.f, sum = 0.f, special = 0.f;
  100. for (int i = 0; i < N + 1; ++i)
  101. {
  102. #if 1
  103. /* In “Noise Hardware” (2-17) Perlin uses 0.6 - d².
  104. *
  105. * In an errata to “Simplex noise demystified”, Gustavson uses
  106. * 0.5 - d² instead, saying “else the noise is not continuous at
  107. * simplex boundaries”.
  108. * And indeed, the distance between any given simplex vertex and
  109. * the opposite hyperplane is 1/sqrt(2), so the contribution of
  110. * that vertex should never be > 0 for points further than
  111. * 1/sqrt(2). Hence 0.5 - d².
  112. *
  113. * I prefer to use 1 - 2d² and compensate for the d⁴ below by
  114. * dividing the final result by 2⁴, because manipulating values
  115. * between 0 and 1 is more convenient. */
  116. float d = 1.0f - 2.f * sqlength(world_pos - world_corner);
  117. #else
  118. // DEBUG: this is the linear contribution of each vertex
  119. // in the skewed simplex. Unfortunately it creates artifacts.
  120. float d = ((i == 0) ? 1.f : pos[traversal_order[i - 1]])
  121. - ((i == N) ? 0.f : pos[traversal_order[i]]);
  122. #endif
  123. #if 0
  124. // DEBUG: identify simplex features:
  125. // -4.f: centre (-2.f),
  126. // -3.f: r=0.38 sphere of influence (contribution = 1/4)
  127. // -2.f: r=0.52 sphere of influence (contribution = 1/24)
  128. if (d > 0.99f) special = min(special, -4.f);
  129. if (d > 0.7f && d < 0.72f) special = min(special, -3.f);
  130. if (d > 0.44f && d < 0.46f) special = min(special, -2.f);
  131. #endif
  132. if (d > 0)
  133. {
  134. // Perlin uses 8d⁴ whereas Gustavson uses d⁴ and a final
  135. // multiplication factor at the end. Let’s go with
  136. // Gustavson, it’s a few multiplications less.
  137. d = d * d * d * d;
  138. //d = (3.f - 2.f * d) * d * d;
  139. //d = ((6 * d - 15) * d + 10) * d * d * d;
  140. result += d * dot(this->get_gradient(origin),
  141. world_pos - world_corner);
  142. sum += d;
  143. }
  144. if (i < N)
  145. {
  146. auto axis = vec_t<float, N>::axis(traversal_order[i]);
  147. world_corner += unskew(axis);
  148. origin[traversal_order[i]] += 1;
  149. }
  150. }
  151. #if 0
  152. if (special < 0.f)
  153. return special;
  154. #else
  155. (void)special;
  156. #endif
  157. return get_scale() * result;
  158. }
  159. static inline float get_scale()
  160. {
  161. /* FIXME: Gustavson uses the value 70 for dimension 2, 32 for
  162. * dimension 3, and 27 for dimension 4, and uses non-unit gradients
  163. * of length sqrt(2), sqrt(2) and sqrt(3), saying “The result is
  164. * scaled to stay just inside [-1,1]” which honestly is just not
  165. * true.
  166. * Experiments show that the scaling factor is remarkably close
  167. * to 6.7958 for all high dimensions (measured up to 12). */
  168. return N == 2 ? 6.2003f
  169. : N == 3 ? 6.7297f
  170. : N == 4 ? 6.7861f
  171. : N == 5 ? 6.7950f
  172. : N == 6 ? 6.7958f
  173. : N == 7 ? 6.7958f
  174. : /* 7+ */ 6.7958f;
  175. }
  176. static inline vec_t<float, N> skew(vec_t<float, N> const &v)
  177. {
  178. /* Quoting Perlin in “Hardware Noise” (2-18):
  179. * The “skew factor” f should be set to f = sqrt(N+1), so that
  180. * the point (1,1,...1) is transformed to the point (f,f,...f). */
  181. float const sum = dot(v, vec_t<float, N>(1));
  182. float const f = sqrt(1.f + N);
  183. return v + vec_t<float, N>(sum * (f - 1) / N);
  184. }
  185. static inline vec_t<float, N> unskew(vec_t<float, N> const &v)
  186. {
  187. float const sum = dot(v, vec_t<float, N>(1));
  188. float const f = sqrt(1.f + N);
  189. return v + vec_t<float, N>(sum * (1 / f - 1) / N);
  190. }
  191. /* For a given world position, extract grid coordinates (origin) and
  192. * the corresponding delta position (pos). */
  193. inline void get_origin(vec_t<float, N> const & world_position,
  194. vec_t<int, N> & origin, vec_t<float, N> & pos) const
  195. {
  196. // Finding floor point index
  197. for (int i = 0; i < N; ++i)
  198. origin[i] = (int)world_position[i] - (world_position[i] < 0);
  199. // Extracting decimal part from simplex sample
  200. pos = world_position - (vec_t<float, N>)origin;
  201. }
  202. private:
  203. void debugprint()
  204. {
  205. using std::min, std::max, std::fabs;
  206. // Print some debug information
  207. printf("Simplex Noise of Dimension %d\n", N);
  208. long long int n = 1; for (int i = 1; i <= N; ++i) n *= i;
  209. printf(" - each hypercube cell has %lld simplices "
  210. "with %d vertices and %d edges\n", n, N + 1, N * (N + 1) / 2);
  211. vec_t<float, N> diagonal(1.f);
  212. printf(" - regular hypercube:\n");
  213. printf(" · edge length 1\n");
  214. printf(" · diagonal length %f\n", length(diagonal));
  215. printf(" - unskewed parallelotope:\n");
  216. printf(" · edge length %f\n", length(unskew(diagonal)));
  217. printf(" · diagonal length %f\n", length(unskew(diagonal)));
  218. printf(" · simplex edge lengths between %f and %f\n",
  219. sqrt((float)N/(N+1)), sqrt((N+1)*(N+1)/4/(float)(N+1)));
  220. /* Generate simplex vertices */
  221. vec_t<float, N> vertices[N + 1];
  222. vertices[0] = vec_t<float, N>(0.f);
  223. for (int i = 0; i < N; ++i)
  224. {
  225. vertices[i + 1] = vertices[i];
  226. vertices[i + 1][i] += 1.f;
  227. }
  228. for (int i = 0; i < N + 1; ++i)
  229. vertices[i] = unskew(vertices[i]);
  230. /* Output information for each vertex */
  231. for (int i = 0; i < N + 1; ++i)
  232. {
  233. printf(" - vertex %d\n", i);
  234. /* Coordinates for debugging purposes */
  235. #if 0
  236. printf(" · [");
  237. for (int k = 0; k < N; ++k)
  238. printf(" %f", vertices[i][k]);
  239. printf(" ]\n");
  240. #endif
  241. /* Analyze edge lengths from that vertex */
  242. #if 0
  243. float minlength = 1.0f;
  244. float maxlength = 0.0f;
  245. for (int j = 0; j < N + 1; ++j)
  246. {
  247. if (i == j)
  248. continue;
  249. float l = length(vertices[i] - vertices[j]);
  250. minlength = min(minlength, l);
  251. maxlength = max(maxlength, l);
  252. }
  253. printf(" · edge lengths between %f and %f\n",
  254. minlength, maxlength);
  255. #endif
  256. /* Experimental calculation of the distance to the opposite
  257. * hyperplane, by picking random points. Works reasonably
  258. * well up to dimension 6. After that, we’d need something
  259. * better such as gradient walk. */
  260. #if 0
  261. float mindist = 1.0f;
  262. for (int run = 0; run < 10000000; ++run)
  263. {
  264. vec_t<float, N> p(0.f);
  265. float sum = 0.f;
  266. for (int j = 0; j < N + 1; ++j)
  267. {
  268. if (i == j)
  269. continue;
  270. float k = rand(1.f);
  271. p += k * vertices[j];
  272. sum += k;
  273. }
  274. mindist = min(mindist, distance(vertices[i], p / sum));
  275. }
  276. printf(" · approx. dist. to opposite hyperplane: %f\n", mindist);
  277. #endif
  278. /* Find a normal vector to the opposite hyperplane. First, pick
  279. * any point p(i0) on the hyperplane. We just need i0 != i. Then,
  280. * build a matrix where each row is p(i0)p(j) for all j != i0.
  281. * Multiplying this matrix by the normal vectors gives a vector
  282. * full of zeroes except at position i. So we build a vector
  283. * full of zeroes except at position i, and multiply it by the
  284. * matrix inverse. */
  285. #if 1
  286. int i0 = (i == 0) ? 1 : 0;
  287. mat_t<float, N, N> m;
  288. for (int j = 0; j < N; ++j)
  289. {
  290. auto v = vertices[j < i0 ? j : j + 1] - vertices[i0];
  291. for (int k = 0; k < N; ++k)
  292. m[k][j] = v[k];
  293. }
  294. auto axis = vec_t<float, N>::axis(i < i0 ? i : i - 1);
  295. auto normal = normalize(inverse(m) * axis);
  296. /* Find distance from current vertex to the opposite hyperplane.
  297. * Just use the projection theorem in N dimensions. */
  298. auto w = vertices[i] - vertices[i0];
  299. float dist = fabs(dot(normal, w));
  300. printf(" · distance to opposite hyperplane: %f\n", dist);
  301. #endif
  302. }
  303. /* Compute some statistics about the noise. TODO: histogram */
  304. #if 0
  305. vec_t<float, N> input(0.f);
  306. for (int run = 0; run < 1000000; ++run)
  307. {
  308. float t = eval(input);
  309. input[run % N] = rand(1000.f);
  310. }
  311. #endif
  312. /* Try to find max noise value by climbing gradient */
  313. float minval = 0.f, maxval = 0.f;
  314. std::vector<vec_t<float, N>> deltas;
  315. for (int i = 0; i < N; ++i)
  316. {
  317. auto v = vec_t<float, N>::axis(i);
  318. deltas.push_back(v);
  319. deltas.push_back(-v);
  320. }
  321. for (int run = 0; run < 1000; ++run)
  322. {
  323. /* Pick a random vector */
  324. vec_t<float, N> v;
  325. for (int i = 0; i < N; ++i)
  326. v[i] = rand(-100.f, 100.f);
  327. float t = eval(v);
  328. float e = 0.1f;
  329. /* Climb up gradient in all dimensions */
  330. while (e > 1e-6f)
  331. {
  332. int best_delta = -1;
  333. float best_t2 = t;
  334. for (int i = 0; i < (int)deltas.size(); ++i)
  335. {
  336. float t2 = eval(v + e * deltas[i]);
  337. if (fabs(t2) > fabs(best_t2))
  338. {
  339. best_delta = i;
  340. best_t2 = t2;
  341. }
  342. }
  343. if (best_delta == -1)
  344. e *= 0.5f;
  345. else
  346. {
  347. v += e * deltas[best_delta];
  348. t = best_t2;
  349. }
  350. }
  351. minval = min(t, minval);
  352. maxval = max(t, maxval);
  353. }
  354. printf(" - noise value min/max: %f %f\n", minval, maxval);
  355. float newscale = 1.f / max(-minval, maxval);
  356. if (newscale < 1.f)
  357. printf(" - could replace scale %f with %f\n",
  358. get_scale(), newscale * get_scale());
  359. else
  360. printf(" - scale looks OK\n");
  361. printf("\n");
  362. }
  363. };
  364. } // namespace lol