PerlinImprovedNoise.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #include <GradientSignal/PerlinImprovedNoise.h>
  9. #include <numeric>
  10. #include <random> // std::mt19937 std::random_device
  11. namespace GradientSignal
  12. {
  13. //////////////////////////////////////////////////////////////////////////
  14. // http://flafla2.github.io/2014/08/09/perlinnoise.html
  15. // https://gist.github.com/Flafla2/f0260a861be0ebdeef76
  16. // MIT License, http://www.opensource.org/licenses/mit-license.php
  17. // Source: http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html
  18. namespace PerlinImprovedNoiseDetails
  19. {
  20. AZ_INLINE float Gradient(int hash, float x, float y, float z)
  21. {
  22. switch (hash & 0xF)
  23. {
  24. case 0x0: return x + y;
  25. case 0x1: return -x + y;
  26. case 0x2: return x - y;
  27. case 0x3: return -x - y;
  28. case 0x4: return x + z;
  29. case 0x5: return -x + z;
  30. case 0x6: return x - z;
  31. case 0x7: return -x - z;
  32. case 0x8: return y + z;
  33. case 0x9: return -y + z;
  34. case 0xA: return y - z;
  35. case 0xB: return -y - z;
  36. case 0xC: return y + x;
  37. case 0xD: return -y + z;
  38. case 0xE: return y - x;
  39. case 0xF: return -y - z;
  40. default: return 0; // never happens
  41. }
  42. }
  43. AZ_FORCE_INLINE float Fade(float t)
  44. {
  45. // Fade function as defined by Ken Perlin. This eases coordinate values
  46. // so that they will "ease" towards integral values.
  47. // This ends up smoothing the final output.
  48. return t * t * t * (t * (t * 6 - 15) + 10); // 6t^5 - 15t^4 + 10t^3
  49. }
  50. AZ_FORCE_INLINE float Lerp(float a, float b, float x)
  51. {
  52. return a + x * (b - a);
  53. }
  54. }
  55. PerlinImprovedNoise::PerlinImprovedNoise(int seed)
  56. {
  57. PrepareTable(seed);
  58. }
  59. PerlinImprovedNoise::PerlinImprovedNoise(const AZStd::span<int, 512>& permutationTable)
  60. {
  61. AZStd::copy(permutationTable.begin(), permutationTable.end(), m_permutationTable.begin());
  62. }
  63. float PerlinImprovedNoise::GenerateOctaveNoise(float x, float y, float z, int octaves, float persistence, float initialFrequency)
  64. {
  65. float total = 0.0f;
  66. float frequency = initialFrequency;
  67. float amplitude = 1.0f;
  68. float maxValue = 0.0f; // Used for normalizing result to 0.0 - 1.0
  69. for (int i = 0; i < octaves; ++i)
  70. {
  71. total += GenerateNoise(x * frequency, y * frequency, z * frequency) * amplitude;
  72. maxValue += amplitude;
  73. amplitude *= persistence;
  74. frequency *= 2.0f;
  75. }
  76. if (maxValue <= 0.0f)
  77. {
  78. return 0.0f;
  79. }
  80. return total / maxValue;
  81. }
  82. float PerlinImprovedNoise::GenerateNoise(float x, float y, float z)
  83. {
  84. const int fx = (int)std::floor(x);
  85. const int fy = (int)std::floor(y);
  86. const int fz = (int)std::floor(z);
  87. const float xf = x - fx; // We also fade the location to smooth the result.
  88. const float yf = y - fy;
  89. const float zf = z - fz;
  90. const int xi0 = fx & 255; // Calculate the "unit cube" that the point asked will be located in
  91. const int yi0 = fy & 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
  92. const int zi0 = fz & 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube.
  93. const int xi1 = (xi0 + 1) /*% 255*/;
  94. const int yi1 = (yi0 + 1) /*% 255*/;
  95. const int zi1 = (zi0 + 1) /*% 255*/;
  96. const float u = PerlinImprovedNoiseDetails::Fade(xf);
  97. const float v = PerlinImprovedNoiseDetails::Fade(yf);
  98. const float w = PerlinImprovedNoiseDetails::Fade(zf);
  99. const AZStd::array<int, 512>& p = m_permutationTable;
  100. const int aaa = p[p[p[xi0] + yi0] + zi0];
  101. const int aba = p[p[p[xi0] + yi1] + zi0];
  102. const int aab = p[p[p[xi0] + yi0] + zi1];
  103. const int abb = p[p[p[xi0] + yi1] + zi1];
  104. const int baa = p[p[p[xi1] + yi0] + zi0];
  105. const int bba = p[p[p[xi1] + yi1] + zi0];
  106. const int bab = p[p[p[xi1] + yi0] + zi1];
  107. const int bbb = p[p[p[xi1] + yi1] + zi1];
  108. // The gradient function calculates the dot product between a pseudorandom
  109. // gradient vector and the vector from the input coordinate to the 8
  110. // surrounding points in its unit cube. This is all then lerped together as a sort of
  111. // weighted average based on the faded (u,v,w) values we made earlier.
  112. float x1, x2, y1, y2;
  113. x1 = PerlinImprovedNoiseDetails::Lerp(PerlinImprovedNoiseDetails::Gradient(aaa, xf, yf, zf), PerlinImprovedNoiseDetails::Gradient(baa, xf - 1.0f, yf, zf), u);
  114. x2 = PerlinImprovedNoiseDetails::Lerp(PerlinImprovedNoiseDetails::Gradient(aba, xf, yf - 1.0f, zf), PerlinImprovedNoiseDetails::Gradient(bba, xf - 1.0f, yf - 1.0f, zf), u);
  115. y1 = PerlinImprovedNoiseDetails::Lerp(x1, x2, v);
  116. x1 = PerlinImprovedNoiseDetails::Lerp(PerlinImprovedNoiseDetails::Gradient(aab, xf, yf, zf - 1.0f), PerlinImprovedNoiseDetails::Gradient(bab, xf - 1.0f, yf, zf - 1.0f), u);
  117. x2 = PerlinImprovedNoiseDetails::Lerp(PerlinImprovedNoiseDetails::Gradient(abb, xf, yf - 1.0f, zf - 1.0f), PerlinImprovedNoiseDetails::Gradient(bbb, xf - 1.0f, yf - 1.0f, zf - 1.0f), u);
  118. y2 = PerlinImprovedNoiseDetails::Lerp(x1, x2, v);
  119. // For convenience we bound it to 0 - 1 (theoretical min/max before is -1 - 1)
  120. return (PerlinImprovedNoiseDetails::Lerp(y1, y2, w) + 1.0f) / 2.0f;
  121. }
  122. void PerlinImprovedNoise::PrepareTable(int seed)
  123. {
  124. AZStd::array<int, 256> randtable;
  125. std::iota(randtable.begin(), randtable.end(), 0);
  126. std::shuffle(randtable.begin(), randtable.end(), std::mt19937(seed));
  127. for (int x = 0; x < 256; ++x)
  128. {
  129. m_permutationTable[x] = randtable[x];
  130. m_permutationTable[x + 256] = randtable[x];
  131. }
  132. }
  133. }