sandbox
Loading...
Searching...
No Matches
noise.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_MATH_NOISE_HPP_
3#define LIBSBX_MATH_NOISE_HPP_
4
5#include <array>
6#include <cinttypes>
7
8#include <libsbx/math/vector2.hpp>
9#include <libsbx/math/random.hpp>
11
12namespace sbx::math {
13
14class noise {
15
16 inline static auto permutation = std::array<std::uint8_t, 256>{
17 151, 160, 137, 91, 90, 15,
18 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23,
19 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
20 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,
21 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244,
22 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
23 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123,
24 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,
25 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
26 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228,
27 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107,
28 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,
29 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
30 };
31
32 inline static constexpr auto F2 = 0.366025403f;
33 inline static constexpr auto G2 = 0.211324865f;
34
35public:
36
37 static constexpr auto fractal(const std::float_t x, const std::float_t y, std::uint32_t octaves) -> std::float_t {
38 auto output = 0.f;
39 auto denom = 0.f;
40 auto frequency = 1.0f;
41 auto amplitude = 1.0f;
42
43 for (auto i = 0u; i < octaves; i++) {
44 output += (amplitude * simplex(x * frequency, y * frequency));
45 denom += amplitude;
46
47 frequency *= 2.0f;
48 amplitude *= 0.5f;
49 }
50
51 return (output / denom);
52 }
53
54 static constexpr auto fractal(const sbx::math::vector3& vector, std::uint32_t octaves) -> std::float_t {
55 return fractal(vector.x(), vector.y(), vector.z(), octaves);
56 }
57
58 static constexpr auto fractal(const std::float_t x, const std::float_t y, const std::float_t z, std::uint32_t octaves) -> std::float_t {
59 auto output = 0.f;
60 auto denom = 0.f;
61 auto frequency = 1.0f;
62 auto amplitude = 1.0f;
63
64 for (auto i = 0u; i < octaves; i++) {
65 output += (amplitude * simplex(x * frequency, y * frequency, z * frequency));
66 denom += amplitude;
67
68 frequency *= 2.0f;
69 amplitude *= 0.5f;
70 }
71
72 return (output / denom);
73 }
74
75 static constexpr auto simplex(const std::float_t x, const std::float_t y) -> std::float_t {
76 auto n0 = 0.0f;
77 auto n1 = 0.0f;
78 auto n2 = 0.0f;
79
80 const auto s = (x + y) * F2;
81 const auto xs = x + s;
82 const auto ys = y + s;
83 const auto i = fast_floor(xs);
84 const auto j = fast_floor(ys);
85
86 const auto t = static_cast<std::float_t>(i + j) * G2;
87 const auto X0 = static_cast<std::float_t>(i) - t;
88 const auto Y0 = static_cast<std::float_t>(j) - t;
89 const auto x0 = x - X0;
90 const auto y0 = y - Y0;
91
92 auto i1 = 0.0f;
93 auto j1 = 0.0f;
94
95 if (x0 > y0) {
96 i1 = 1.0f;
97 j1 = 0.0f;
98 } else {
99 i1 = 0.0f;
100 j1 = 1.0f;
101 }
102
103 const auto x1 = x0 - i1 + G2;
104 const auto y1 = y0 - j1 + G2;
105 const auto x2 = x0 - 1.0f + 2.0f * G2;
106 const auto y2 = y0 - 1.0f + 2.0f * G2;
107
108 const auto gi0 = hash(i + hash(j));
109 const auto gi1 = hash(i + i1 + hash(j + j1));
110 const auto gi2 = hash(i + 1 + hash(j + 1));
111
112 auto t0 = 0.5f - x0 * x0 - y0 * y0;
113
114 if (t0 < 0.0f) {
115 n0 = 0.0f;
116 } else {
117 t0 *= t0;
118 n0 = t0 * t0 * grad(gi0, x0, y0);
119 }
120
121 auto t1 = 0.5f - x1 * x1 - y1 * y1;
122
123 if (t1 < 0.0f) {
124 n1 = 0.0f;
125 } else {
126 t1 *= t1;
127 n1 = t1 * t1 * grad(gi1, x1, y1);
128 }
129
130 auto t2 = 0.5f - x2 * x2 - y2 * y2;
131
132 if (t2 < 0.0f) {
133 n2 = 0.0f;
134 } else {
135 t2 *= t2;
136 n2 = t2 * t2 * grad(gi2, x2, y2);
137 }
138
139 return 45.23065f * (n0 + n1 + n2);
140 }
141
142 static constexpr auto simplex(const std::float_t x, const std::float_t y, const std::float_t z) -> std::float_t {
143 auto n0 = 0.0f;
144 auto n1 = 0.0f;
145 auto n2 = 0.0f;
146 auto n3 = 0.0f; // Noise contributions from the four corners
147
148 // Skewing/Unskewing factors for 3D
149 constexpr auto F3 = 1.0f / 3.0f;
150 constexpr auto G3 = 1.0f / 6.0f;
151
152 // Skew the input space to determine which simplex cell we're in
153 auto s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
154 auto i = fast_floor(x + s);
155 auto j = fast_floor(y + s);
156 auto k = fast_floor(z + s);
157 auto t = (i + j + k) * G3;
158 auto X0 = i - t; // Unskew the cell origin back to (x,y,z) space
159 auto Y0 = j - t;
160 auto Z0 = k - t;
161 auto x0 = x - X0; // The x,y,z distances from the cell origin
162 auto y0 = y - Y0;
163 auto z0 = z - Z0;
164
165 // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
166 // Determine which simplex we are in.
167 auto i1 = 0.0f;
168 auto j1 = 0.0f;
169 auto k1 = 0.0f; // Offsets for second corner of simplex in (i,j,k) coords
170 auto i2 = 0.0f;
171 auto j2 = 0.0f;
172 auto k2 = 0.0f; // Offsets for third corner of simplex in (i,j,k) coords
173
174 if (x0 >= y0) {
175 if (y0 >= z0) {
176 i1 = 1;
177 j1 = 0;
178 k1 = 0;
179 i2 = 1;
180 j2 = 1;
181 k2 = 0; // X Y Z order
182 } else if (x0 >= z0) {
183 i1 = 1;
184 j1 = 0;
185 k1 = 0;
186 i2 = 1;
187 j2 = 0;
188 k2 = 1; // X Z Y order
189 } else {
190 i1 = 0;
191 j1 = 0;
192 k1 = 1;
193 i2 = 1;
194 j2 = 0;
195 k2 = 1; // Z X Y order
196 }
197 } else { // x0<y0
198 if (y0 < z0) {
199 i1 = 0;
200 j1 = 0;
201 k1 = 1;
202 i2 = 0;
203 j2 = 1;
204 k2 = 1; // Z Y X order
205 } else if (x0 < z0) {
206 i1 = 0;
207 j1 = 1;
208 k1 = 0;
209 i2 = 0;
210 j2 = 1;
211 k2 = 1; // Y Z X order
212 } else {
213 i1 = 0;
214 j1 = 1;
215 k1 = 0;
216 i2 = 1;
217 j2 = 1;
218 k2 = 0; // Y X Z order
219 }
220 }
221
222 // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
223 // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
224 // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
225 // c = 1/6.
226 auto x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
227 auto y1 = y0 - j1 + G3;
228 auto z1 = z0 - k1 + G3;
229 auto x2 = x0 - i2 + 2.0f * G3; // Offsets for third corner in (x,y,z) coords
230 auto y2 = y0 - j2 + 2.0f * G3;
231 auto z2 = z0 - k2 + 2.0f * G3;
232 auto x3 = x0 - 1.0f + 3.0f * G3; // Offsets for last corner in (x,y,z) coords
233 auto y3 = y0 - 1.0f + 3.0f * G3;
234 auto z3 = z0 - 1.0f + 3.0f * G3;
235
236 // Work out the hashed gradient indices of the four simplex corners
237 auto gi0 = hash(i + hash(j + hash(k)));
238 auto gi1 = hash(i + i1 + hash(j + j1 + hash(k + k1)));
239 auto gi2 = hash(i + i2 + hash(j + j2 + hash(k + k2)));
240 auto gi3 = hash(i + 1 + hash(j + 1 + hash(k + 1)));
241
242 // Calculate the contribution from the four corners
243 auto t0 = 0.6f - x0*x0 - y0*y0 - z0*z0;
244
245 if (t0 < 0) {
246 n0 = 0.0;
247 } else {
248 t0 *= t0;
249 n0 = t0 * t0 * grad(gi0, x0, y0, z0);
250 }
251
252 auto t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1;
253
254 if (t1 < 0) {
255 n1 = 0.0;
256 } else {
257 t1 *= t1;
258 n1 = t1 * t1 * grad(gi1, x1, y1, z1);
259 }
260
261 auto t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2;
262
263 if (t2 < 0) {
264 n2 = 0.0;
265 } else {
266 t2 *= t2;
267 n2 = t2 * t2 * grad(gi2, x2, y2, z2);
268 }
269
270 auto t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3;
271
272 if (t3 < 0) {
273 n3 = 0.0;
274 } else {
275 t3 *= t3;
276 n3 = t3 * t3 * grad(gi3, x3, y3, z3);
277 }
278
279 // Add contributions from each corner to get the final noise value.
280 // The result is scaled to stay just inside [-1,1]
281 return 32.0f * (n0 + n1 + n2 + n3);
282 }
283
284private:
285
286 static constexpr auto fast_floor(std::float_t fp) -> std::int32_t {
287 auto i = static_cast<std::int32_t>(fp);
288 return (fp < i) ? (i - 1) : (i);
289 }
290
291 template<typename Type>
292 static constexpr auto hash(Type i) -> std::uint8_t {
293 return permutation[static_cast<std::uint8_t>(i)];
294 }
295
296 static constexpr auto grad(std::int32_t hash, std::float_t x, std::float_t y) -> std::float_t {
297 const auto h = hash & 0x3F;
298 const auto u = h < 4 ? x : y;
299 const auto v = h < 4 ? y : x;
300
301 return ((h & 1) ? -u : u) + ((h & 2) ? -2.0f * v : 2.0f * v);
302 }
303
304 static constexpr float grad(std::int32_t hash, std::float_t x, std::float_t y, std::float_t z) {
305 const auto h = hash & 15;
306 const auto u = h < 8 ? x : y;
307 const auto v = h < 4 ? y : h == 12 || h == 14 ? x : z;
308
309 return ((h & 1) ? -u : u) + ((h & 2) ? -v : v);
310 }
311
312}; // class noise
313
314} // namespace sbx::math
315
316#endif // LIBSBX_MATH_NOISE_HPP_
Definition: vector3.hpp:23
Definition: noise.hpp:14
Core numeric concepts and type traits.