noise/perlin.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Improved Perlin gradient noise in 2D and 3D. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/noise/hash.h" | ||
| 6 | #include "terraingen/noise/lattice.h" | ||
| 7 | |||
| 8 | namespace terraingen { | ||
| 9 | |||
| 10 | namespace detail { | ||
| 11 | |||
| 12 | /// Perlin's quintic fade 6t^5 - 15t^4 + 10t^3 of a fraction `t` in [0, 1], C^2 across cell | ||
| 13 | /// edges. | ||
| 14 | 1555615449 | constexpr float PerlinFade(float t) { | |
| 15 | 1555615449 | return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); | |
| 16 | } | ||
| 17 | |||
| 18 | /// Linear interpolation, a + t (b - a). | ||
| 19 | 2470730466 | constexpr float Lerp(float t, float a, float b) { | |
| 20 | 2470730466 | return a + t * (b - a); | |
| 21 | } | ||
| 22 | |||
| 23 | /// Dot product of an offset with one of eight unit gradients: the axis directions and the | ||
| 24 | /// diagonals. | ||
| 25 | /// @param hash Corner hash; its low three bits pick the gradient. | ||
| 26 | 2651091572 | inline float PerlinGradient2(uint32_t hash, float x, float y) { | |
| 27 | 2651091572 | constexpr float kInvSqrt2 = 0.707106781186547524f; | |
| 28 | 2651091572 | switch (hash & 7u) { | |
| 29 | 290072452 | case 0u: | |
| 30 | 290072452 | return x; | |
| 31 | 399350129 | case 1u: | |
| 32 | 399350129 | return -x; | |
| 33 | 310885255 | case 2u: | |
| 34 | 310885255 | return y; | |
| 35 | 320967226 | case 3u: | |
| 36 | 320967226 | return -y; | |
| 37 | 334617161 | case 4u: | |
| 38 | 334617161 | return (x + y) * kInvSqrt2; | |
| 39 | 322333058 | case 5u: | |
| 40 | 322333058 | return (y - x) * kInvSqrt2; | |
| 41 | 343462213 | case 6u: | |
| 42 | 343462213 | return (x - y) * kInvSqrt2; | |
| 43 | 329404078 | default: | |
| 44 | 329404078 | return -(x + y) * kInvSqrt2; | |
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | /// The hash of a 2D lattice corner, shared by Perlin and simplex noise. | ||
| 49 | /// @param ix Corner x, wrapped to 32 bits. | ||
| 50 | /// @param iy Corner y, wrapped to 32 bits. | ||
| 51 | 2651093110 | inline uint32_t PerlinCornerHash(uint32_t ix, uint32_t iy, uint32_t seed) { | |
| 52 | 2651093110 | return Pcg3dHash(SeededLatticeKey2(ix, iy, seed)).x; | |
| 53 | } | ||
| 54 | |||
| 55 | /// Dot product of an offset with one of Perlin's twelve cube-edge gradients (sixteen with | ||
| 56 | /// repeats). | ||
| 57 | /// @param hash Corner hash; its low four bits pick the gradient. | ||
| 58 | 440142949 | inline float PerlinGradient3(uint32_t hash, float x, float y, float z) { | |
| 59 | 440142949 | const uint32_t h = hash & 15u; | |
| 60 | 440142949 | const float u = h < 8u ? x : y; | |
| 61 | 440142949 | const float v = h < 4u ? y : (h == 12u || h == 14u ? x : z); | |
| 62 | 440142949 | return ((h & 1u) == 0u ? u : -u) + ((h & 2u) == 0u ? v : -v); | |
| 63 | } | ||
| 64 | |||
| 65 | /// The hash of a 3D Perlin lattice corner. | ||
| 66 | /// @param ix Corner x, wrapped to 32 bits. | ||
| 67 | /// @param iy Corner y, wrapped to 32 bits. | ||
| 68 | /// @param iz Corner z, wrapped to 32 bits. | ||
| 69 | 440142941 | inline uint32_t PerlinCornerHash3(uint32_t ix, uint32_t iy, uint32_t iz, uint32_t seed) { | |
| 70 | 440142941 | return Pcg3dHash(PerlinLatticeKey3(ix, iy, iz, seed)).x; | |
| 71 | } | ||
| 72 | |||
| 73 | /// The gradient term of one corner of `point`'s cell: its gradient dotted with the offset from | ||
| 74 | /// it. | ||
| 75 | /// @param corner The corner as bits: 1 for +x, 2 for +y and 4 for +z. | ||
| 76 | 439302371 | inline float PerlinCorner3(LatticePoint3 point, uint32_t corner, uint32_t seed) { | |
| 77 | 439302371 | const uint32_t dx = corner & 1u; | |
| 78 | 439302371 | const uint32_t dy = (corner >> 1u) & 1u; | |
| 79 | 439302371 | const uint32_t dz = corner >> 2u; | |
| 80 | 439302371 | const uint32_t hash = PerlinCornerHash3(uint32_t(point.ix) + dx, uint32_t(point.iy) + dy, | |
| 81 | 439302371 | uint32_t(point.iz) + dz, seed); | |
| 82 | 439302371 | return PerlinGradient3(hash, point.fx - float(dx), point.fy - float(dy), point.fz - float(dz)); | |
| 83 | } | ||
| 84 | |||
| 85 | } // namespace detail | ||
| 86 | |||
| 87 | /// 2D improved Perlin gradient noise at a lattice cell plus fraction; zero at lattice | ||
| 88 | /// points. Passing the cell separately keeps precision far from the origin. | ||
| 89 | /// @param fx Fraction in x, in [0, 1). | ||
| 90 | /// @param fy Fraction in y, in [0, 1). | ||
| 91 | /// @return Noise in [-1, 1]. | ||
| 92 | 662160714 | inline float PerlinNoise2(int32_t ix, int32_t iy, float fx, float fy, uint32_t seed) { | |
| 93 | 662160714 | const uint32_t x0 = uint32_t(ix); | |
| 94 | 662160714 | const uint32_t y0 = uint32_t(iy); | |
| 95 | 662160714 | const uint32_t x1 = x0 + 1u; | |
| 96 | 662160714 | const uint32_t y1 = y0 + 1u; | |
| 97 | |||
| 98 | 662160714 | const float n00 = detail::PerlinGradient2(detail::PerlinCornerHash(x0, y0, seed), fx, fy); | |
| 99 | const float n10 = | ||
| 100 | 662160714 | detail::PerlinGradient2(detail::PerlinCornerHash(x1, y0, seed), fx - 1.0f, fy); | |
| 101 | const float n01 = | ||
| 102 | 662160714 | detail::PerlinGradient2(detail::PerlinCornerHash(x0, y1, seed), fx, fy - 1.0f); | |
| 103 | const float n11 = | ||
| 104 | 662160714 | detail::PerlinGradient2(detail::PerlinCornerHash(x1, y1, seed), fx - 1.0f, fy - 1.0f); | |
| 105 | |||
| 106 | 662160714 | const float u = detail::PerlinFade(fx); | |
| 107 | 662160714 | const float v = detail::PerlinFade(fy); | |
| 108 | |||
| 109 | 662160714 | constexpr float kSqrt2 = 1.41421356237309505f; | |
| 110 | 662160714 | return kSqrt2 * detail::Lerp(v, detail::Lerp(u, n00, n10), detail::Lerp(u, n01, n11)); | |
| 111 | } | ||
| 112 | |||
| 113 | /// 2D improved Perlin gradient noise at a point in lattice units. | ||
| 114 | /// @return Noise in [-1, 1]. | ||
| 115 | 563858397 | inline float PerlinNoise2(float x, float y, uint32_t seed) { | |
| 116 | 563858397 | const LatticePoint2 point = SplitLattice2(x, y); | |
| 117 | 563858397 | return PerlinNoise2(point.ix, point.iy, point.fx, point.fy, seed); | |
| 118 | } | ||
| 119 | |||
| 120 | /// 2D improved Perlin gradient noise at a double-precision point in lattice units, split | ||
| 121 | /// into cell and fraction before narrowing so it stays exact far from the origin. | ||
| 122 | /// @return Noise in [-1, 1]. | ||
| 123 | #ifndef __SLANG__ | ||
| 124 | 97974633 | inline float PerlinNoise2Precise(double x, double y, uint32_t seed) { | |
| 125 | 97974633 | const LatticePoint2 point = SplitLatticePrecise2(x, y); | |
| 126 | 97974633 | return PerlinNoise2(point.ix, point.iy, point.fx, point.fy, seed); | |
| 127 | } | ||
| 128 | #endif | ||
| 129 | |||
| 130 | /// 3D improved Perlin gradient noise at a lattice cell and fraction; zero at lattice | ||
| 131 | /// points and clamped to [-1, 1]. | ||
| 132 | /// @return Noise in [-1, 1]. | ||
| 133 | 54912796 | inline float PerlinNoise3(LatticePoint3 point, uint32_t seed) { | |
| 134 | 54912796 | const float c000 = detail::PerlinCorner3(point, 0u, seed); | |
| 135 | 54912796 | const float c100 = detail::PerlinCorner3(point, 1u, seed); | |
| 136 | 54912796 | const float c010 = detail::PerlinCorner3(point, 2u, seed); | |
| 137 | 54912796 | const float c110 = detail::PerlinCorner3(point, 3u, seed); | |
| 138 | 54912796 | const float c001 = detail::PerlinCorner3(point, 4u, seed); | |
| 139 | 54912796 | const float c101 = detail::PerlinCorner3(point, 5u, seed); | |
| 140 | 54912796 | const float c011 = detail::PerlinCorner3(point, 6u, seed); | |
| 141 | 54912796 | const float c111 = detail::PerlinCorner3(point, 7u, seed); | |
| 142 | 54912796 | const float u = detail::PerlinFade(point.fx); | |
| 143 | 54912796 | const float v = detail::PerlinFade(point.fy); | |
| 144 | 54912796 | const float w = detail::PerlinFade(point.fz); | |
| 145 | 54912796 | const float near = detail::Lerp(v, detail::Lerp(u, c000, c100), detail::Lerp(u, c010, c110)); | |
| 146 | 54912796 | const float far = detail::Lerp(v, detail::Lerp(u, c001, c101), detail::Lerp(u, c011, c111)); | |
| 147 | 54912796 | return clamp(detail::Lerp(w, near, far), -1.0f, 1.0f); | |
| 148 | } | ||
| 149 | |||
| 150 | /// 3D improved Perlin gradient noise at a double-precision point in lattice units, split | ||
| 151 | /// into cell and fraction before narrowing so it stays exact on a planet's surface. | ||
| 152 | /// @return Noise in [-1, 1]. | ||
| 153 | #ifndef __SLANG__ | ||
| 154 | 99878 | inline float PerlinNoise3Precise(double x, double y, double z, uint32_t seed) { | |
| 155 | 99878 | return PerlinNoise3(SplitLatticePrecise3(x, y, z), seed); | |
| 156 | } | ||
| 157 | #endif | ||
| 158 | |||
| 159 | /// 3D improved Perlin gradient noise at a point in lattice units. | ||
| 160 | /// @return Noise in [-1, 1]. | ||
| 161 | 7851027 | inline float PerlinNoise3(float x, float y, float z, uint32_t seed) { | |
| 162 | 7851027 | return PerlinNoise3(SplitLattice3(x, y, z), seed); | |
| 163 | } | ||
| 164 | |||
| 165 | } // namespace terraingen | ||
| 166 |