TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
77 / 77
100.0%
Branches:
21 / 21
100.0%
Functions:
13 / 13
100.0%

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
8/8
✓ Branch 0 taken 290072452 times.
✓ Branch 1 taken 399350129 times.
✓ Branch 2 taken 310885255 times.
✓ Branch 3 taken 320967226 times.
✓ Branch 4 taken 334617161 times.
✓ Branch 5 taken 322333058 times.
✓ Branch 6 taken 343462213 times.
✓ Branch 7 taken 329404078 times.
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
2/2
✓ Branch 0 taken 217746309 times.
✓ Branch 1 taken 222396640 times.
440142949 const float u = h < 8u ? x : y;
61
6/6
✓ Branch 0 taken 331933274 times.
✓ Branch 1 taken 108209675 times.
✓ Branch 2 taken 303252699 times.
✓ Branch 3 taken 28680575 times.
✓ Branch 4 taken 28234067 times.
✓ Branch 5 taken 275018632 times.
440142949 const float v = h < 4u ? y : (h == 12u || h == 14u ? x : z);
62
4/4
✓ Branch 0 taken 218759423 times.
✓ Branch 1 taken 221383526 times.
✓ Branch 2 taken 219693049 times.
✓ Branch 3 taken 220449900 times.
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
1/1
✓ Branch 2 taken 54912796 times.
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