noise/simplex.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Simplex noise in 2D and 3D. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/noise/perlin.h" | ||
| 6 | |||
| 7 | namespace terraingen { | ||
| 8 | |||
| 9 | namespace detail { | ||
| 10 | |||
| 11 | /// The contribution (0.5 - r^2)^4 dot(g, d) of one simplex corner; 0 for r^2 >= 0.5. | ||
| 12 | /// @param ci Corner x on the skewed lattice, wrapped to 32 bits. | ||
| 13 | /// @param cj Corner y on the skewed lattice, wrapped to 32 bits. | ||
| 14 | /// @param dx Offset x from the corner, unskewed. | ||
| 15 | /// @param dy Offset y from the corner, unskewed. | ||
| 16 | 2706174 | inline float SimplexCorner(uint32_t ci, uint32_t cj, float dx, float dy, uint32_t seed) { | |
| 17 | 2706174 | const float t = 0.5f - dx * dx - dy * dy; | |
| 18 | 2706174 | if (t <= 0.0f) { | |
| 19 | 257458 | return 0.0f; | |
| 20 | } | ||
| 21 | 2448716 | const float t2 = t * t; | |
| 22 | 2448716 | return t2 * t2 * PerlinGradient2(PerlinCornerHash(ci, cj, seed), dx, dy); | |
| 23 | } | ||
| 24 | |||
| 25 | /// The contribution (0.5 - r^2)^4 dot(g, d) of one corner of a 3D simplex, with `PerlinNoise3`'s | ||
| 26 | /// gradients and corner hash; 0 for r^2 >= 0.5. | ||
| 27 | 1142812 | inline float SimplexCorner3(uint32_t ci, uint32_t cj, uint32_t ck, float dx, float dy, float dz, | |
| 28 | uint32_t seed) { | ||
| 29 | 1142812 | const float t = 0.5f - dx * dx - dy * dy - dz * dz; | |
| 30 | 1142812 | if (t <= 0.0f) { | |
| 31 | 302245 | return 0.0f; | |
| 32 | } | ||
| 33 | 840567 | const float t2 = t * t; | |
| 34 | 840567 | return t2 * t2 * PerlinGradient3(PerlinCornerHash3(ci, cj, ck, seed), dx, dy, dz); | |
| 35 | } | ||
| 36 | |||
| 37 | } // namespace detail | ||
| 38 | |||
| 39 | /// 2D simplex noise at a point in lattice units, with the gradients and corner hash of | ||
| 40 | /// `PerlinNoise2`. | ||
| 41 | /// @return Noise in [-1, 1]. | ||
| 42 | 902058 | inline float SimplexNoise2(float x, float y, uint32_t seed) { | |
| 43 | 902058 | constexpr float kSkew = 0.366025403784438647f; // (sqrt(3) - 1) / 2 | |
| 44 | 902058 | constexpr float kUnskew = 0.211324865405187118f; // (3 - sqrt(3)) / 6 | |
| 45 | 902058 | constexpr float kScale = 99.0f; | |
| 46 | |||
| 47 | 902058 | const float skew = (x + y) * kSkew; | |
| 48 | 902058 | const float cellX = floor(x + skew); | |
| 49 | 902058 | const float cellY = floor(y + skew); | |
| 50 | 902058 | const float unskew = (cellX + cellY) * kUnskew; | |
| 51 | 902058 | const float x0 = x - (cellX - unskew); | |
| 52 | 902058 | const float y0 = y - (cellY - unskew); | |
| 53 | |||
| 54 | 902058 | const uint32_t stepX = x0 > y0 ? 1u : 0u; | |
| 55 | 902058 | const uint32_t stepY = 1u - stepX; | |
| 56 | 902058 | const float x1 = x0 - float(stepX) + kUnskew; | |
| 57 | 902058 | const float y1 = y0 - float(stepY) + kUnskew; | |
| 58 | 902058 | const float x2 = x0 - 1.0f + 2.0f * kUnskew; | |
| 59 | 902058 | const float y2 = y0 - 1.0f + 2.0f * kUnskew; | |
| 60 | |||
| 61 | 902058 | const uint32_t i = uint32_t(int32_t(cellX)); | |
| 62 | 902058 | const uint32_t j = uint32_t(int32_t(cellY)); | |
| 63 | 902058 | return kScale * (detail::SimplexCorner(i, j, x0, y0, seed) + | |
| 64 | 902058 | detail::SimplexCorner(i + stepX, j + stepY, x1, y1, seed) + | |
| 65 | 902058 | detail::SimplexCorner(i + 1u, j + 1u, x2, y2, seed)); | |
| 66 | } | ||
| 67 | |||
| 68 | /// 3D simplex noise (Perlin 2001, Gustavson 2005) at a lattice cell and fraction, on the | ||
| 69 | /// tetrahedral lattice skewed by (x + y + z) / 3. The skew is split into integer and fractional | ||
| 70 | /// parts, so points far from the origin keep the precision of their fraction. | ||
| 71 | /// @return Noise in [-1, 1]. | ||
| 72 | 285703 | inline float SimplexNoise3(LatticePoint3 point, uint32_t seed) { | |
| 73 | 285703 | constexpr float kScale = 76.0f; | |
| 74 | 285703 | const int32_t cellSum = int32_t(uint32_t(point.ix) + uint32_t(point.iy) + uint32_t(point.iz)); | |
| 75 | 285703 | int32_t third = cellSum / 3; | |
| 76 | 285703 | if (cellSum - 3 * third < 0) { | |
| 77 | 97557 | third -= 1; | |
| 78 | } | ||
| 79 | 285703 | const float remainder = float(cellSum - 3 * third); | |
| 80 | 285703 | const float skew = (remainder + point.fx + point.fy + point.fz) / 3.0f; | |
| 81 | 285703 | const float stepX = floor(point.fx + skew); | |
| 82 | 285703 | const float stepY = floor(point.fy + skew); | |
| 83 | 285703 | const float stepZ = floor(point.fz + skew); | |
| 84 | 285703 | const float unskew = (remainder + stepX + stepY + stepZ) / 6.0f; | |
| 85 | 285703 | const float x0 = point.fx - stepX + unskew; | |
| 86 | 285703 | const float y0 = point.fy - stepY + unskew; | |
| 87 | 285703 | const float z0 = point.fz - stepZ + unskew; | |
| 88 | |||
| 89 | 285703 | uint32_t i1 = 0u; | |
| 90 | 285703 | uint32_t j1 = 0u; | |
| 91 | 285703 | uint32_t k1 = 0u; | |
| 92 | 285703 | uint32_t i2 = 0u; | |
| 93 | 285703 | uint32_t j2 = 0u; | |
| 94 | 285703 | uint32_t k2 = 0u; | |
| 95 | 285703 | if (x0 >= y0) { | |
| 96 | 143114 | if (y0 >= z0) { | |
| 97 | 47859 | i1 = 1u; | |
| 98 | 47859 | i2 = 1u; | |
| 99 | 47859 | j2 = 1u; | |
| 100 | 95255 | } else if (x0 >= z0) { | |
| 101 | 47811 | i1 = 1u; | |
| 102 | 47811 | i2 = 1u; | |
| 103 | 47811 | k2 = 1u; | |
| 104 | } else { | ||
| 105 | 47444 | k1 = 1u; | |
| 106 | 47444 | i2 = 1u; | |
| 107 | 47444 | k2 = 1u; | |
| 108 | } | ||
| 109 | 142589 | } else if (y0 < z0) { | |
| 110 | 49119 | k1 = 1u; | |
| 111 | 49119 | j2 = 1u; | |
| 112 | 49119 | k2 = 1u; | |
| 113 | 93470 | } else if (x0 < z0) { | |
| 114 | 48491 | j1 = 1u; | |
| 115 | 48491 | j2 = 1u; | |
| 116 | 48491 | k2 = 1u; | |
| 117 | } else { | ||
| 118 | 44979 | j1 = 1u; | |
| 119 | 44979 | i2 = 1u; | |
| 120 | 44979 | j2 = 1u; | |
| 121 | } | ||
| 122 | 285703 | constexpr float kUnskew = 1.0f / 6.0f; | |
| 123 | 285703 | const float x1 = x0 - float(i1) + kUnskew; | |
| 124 | 285703 | const float y1 = y0 - float(j1) + kUnskew; | |
| 125 | 285703 | const float z1 = z0 - float(k1) + kUnskew; | |
| 126 | 285703 | const float x2 = x0 - float(i2) + 2.0f * kUnskew; | |
| 127 | 285703 | const float y2 = y0 - float(j2) + 2.0f * kUnskew; | |
| 128 | 285703 | const float z2 = z0 - float(k2) + 2.0f * kUnskew; | |
| 129 | 285703 | const float x3 = x0 - 1.0f + 3.0f * kUnskew; | |
| 130 | 285703 | const float y3 = y0 - 1.0f + 3.0f * kUnskew; | |
| 131 | 285703 | const float z3 = z0 - 1.0f + 3.0f * kUnskew; | |
| 132 | |||
| 133 | 285703 | const uint32_t i = uint32_t(point.ix) + uint32_t(third) + uint32_t(int32_t(stepX)); | |
| 134 | 285703 | const uint32_t j = uint32_t(point.iy) + uint32_t(third) + uint32_t(int32_t(stepY)); | |
| 135 | 285703 | const uint32_t k = uint32_t(point.iz) + uint32_t(third) + uint32_t(int32_t(stepZ)); | |
| 136 | 285703 | const float sum = detail::SimplexCorner3(i, j, k, x0, y0, z0, seed) + | |
| 137 | 285703 | detail::SimplexCorner3(i + i1, j + j1, k + k1, x1, y1, z1, seed) + | |
| 138 | 285703 | detail::SimplexCorner3(i + i2, j + j2, k + k2, x2, y2, z2, seed) + | |
| 139 | 285703 | detail::SimplexCorner3(i + 1u, j + 1u, k + 1u, x3, y3, z3, seed); | |
| 140 | 285703 | return clamp(kScale * sum, -1.0f, 1.0f); | |
| 141 | } | ||
| 142 | |||
| 143 | /// 3D simplex noise at a point in lattice units. | ||
| 144 | /// @return Noise in [-1, 1]. | ||
| 145 | 28101 | inline float SimplexNoise3(float x, float y, float z, uint32_t seed) { | |
| 146 | 28101 | return SimplexNoise3(SplitLattice3(x, y, z), seed); | |
| 147 | } | ||
| 148 | |||
| 149 | } // namespace terraingen | ||
| 150 |