noise_functions/base/
perlin.rs

1use crate::{
2    base::impl_noise,
3    math::{floor, lerp},
4};
5
6#[cfg(feature = "nightly-simd")]
7use core::simd::{f32x2, f32x4};
8
9/// 2/3/4 dimensional Perlin noise.
10#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
11pub struct Perlin;
12
13impl_noise!(234 Perlin);
14
15impl Perlin {
16    #[inline]
17    fn gen2(self, [x, y]: [f32; 2], seed: i32) -> f32 {
18        // implementation from FastNoiseLite
19        use crate::from_fast_noise_lite::{floor_to_int, grad2, interp_quintic, PRIME_X, PRIME_Y};
20
21        let mut x0 = floor_to_int(x);
22        let mut y0 = floor_to_int(y);
23
24        let xd0 = x - x0 as f32;
25        let yd0 = y - y0 as f32;
26
27        let xd1 = xd0 - 1.0;
28        let yd1 = yd0 - 1.0;
29
30        let xs = interp_quintic(xd0);
31        let ys = interp_quintic(yd0);
32
33        x0 = x0.wrapping_mul(PRIME_X);
34        y0 = y0.wrapping_mul(PRIME_Y);
35
36        let x1 = x0.wrapping_add(PRIME_X);
37        let y1 = y0.wrapping_add(PRIME_Y);
38
39        let xf0 = lerp(grad2(seed, x0, y0, xd0, yd0), grad2(seed, x1, y0, xd1, yd0), xs);
40        let xf1 = lerp(grad2(seed, x0, y1, xd0, yd1), grad2(seed, x1, y1, xd1, yd1), xs);
41
42        lerp(xf0, xf1, ys) * 1.4247691104677813
43    }
44
45    #[inline]
46    fn gen3(self, [x, y, z]: [f32; 3], seed: i32) -> f32 {
47        // implementation from FastNoiseLite
48        use crate::from_fast_noise_lite::{floor_to_int, grad3, interp_quintic, PRIME_X, PRIME_Y, PRIME_Z};
49
50        let mut x0 = floor_to_int(x);
51        let mut y0 = floor_to_int(y);
52        let mut z0 = floor_to_int(z);
53
54        let xd0 = x - x0 as f32;
55        let yd0 = y - y0 as f32;
56        let zd0 = z - z0 as f32;
57
58        let xd1 = xd0 - 1.0;
59        let yd1 = yd0 - 1.0;
60        let zd1 = zd0 - 1.0;
61
62        let xs = interp_quintic(xd0);
63        let ys = interp_quintic(yd0);
64        let zs = interp_quintic(zd0);
65
66        x0 = x0.wrapping_mul(PRIME_X);
67        y0 = y0.wrapping_mul(PRIME_Y);
68        z0 = z0.wrapping_mul(PRIME_Z);
69
70        let x1 = x0.wrapping_add(PRIME_X);
71        let y1 = y0.wrapping_add(PRIME_Y);
72        let z1 = z0.wrapping_add(PRIME_Z);
73
74        let xf00 = lerp(grad3(seed, x0, y0, z0, xd0, yd0, zd0), grad3(seed, x1, y0, z0, xd1, yd0, zd0), xs);
75        let xf10 = lerp(grad3(seed, x0, y1, z0, xd0, yd1, zd0), grad3(seed, x1, y1, z0, xd1, yd1, zd0), xs);
76        let xf01 = lerp(grad3(seed, x0, y0, z1, xd0, yd0, zd1), grad3(seed, x1, y0, z1, xd1, yd0, zd1), xs);
77        let xf11 = lerp(grad3(seed, x0, y1, z1, xd0, yd1, zd1), grad3(seed, x1, y1, z1, xd1, yd1, zd1), xs);
78
79        let yf0 = lerp(xf00, xf10, ys);
80        let yf1 = lerp(xf01, xf11, ys);
81
82        lerp(yf0, yf1, zs) * 0.964921414852142333984375
83    }
84
85    #[inline]
86    fn gen4(self, [x, y, z, w]: [f32; 4], seed: i32) -> f32 {
87        // implementation from FastNoise2
88        use crate::from_fast_noise_2::{gradient_dot4, hash_primes4, interp_quintic, primes};
89
90        let xs = floor(x);
91        let ys = floor(y);
92        let zs = floor(z);
93        let ws = floor(w);
94
95        let x0 = (xs as i32).wrapping_mul(primes::X);
96        let y0 = (ys as i32).wrapping_mul(primes::Y);
97        let z0 = (zs as i32).wrapping_mul(primes::Z);
98        let w0 = (ws as i32).wrapping_mul(primes::W);
99        let x1 = x0.wrapping_add(primes::X);
100        let y1 = y0.wrapping_add(primes::Y);
101        let z1 = z0.wrapping_add(primes::Z);
102        let w1 = w0.wrapping_add(primes::W);
103
104        let xf0 = x - xs;
105        let yf0 = y - ys;
106        let zf0 = z - zs;
107        let wf0 = w - ws;
108        let xf1 = xf0 - 1.0;
109        let yf1 = yf0 - 1.0;
110        let zf1 = zf0 - 1.0;
111        let wf1 = wf0 - 1.0;
112
113        let xs = interp_quintic(xf0);
114        let ys = interp_quintic(yf0);
115        let zs = interp_quintic(zf0);
116        let ws = interp_quintic(wf0);
117
118        0.964921414852142333984375f32
119            * lerp(
120                lerp(
121                    lerp(
122                        lerp(
123                            gradient_dot4(hash_primes4(seed, x0, y0, z0, w0), xf0, yf0, zf0, wf0),
124                            gradient_dot4(hash_primes4(seed, x1, y0, z0, w0), xf1, yf0, zf0, wf0),
125                            xs,
126                        ),
127                        lerp(
128                            gradient_dot4(hash_primes4(seed, x0, y1, z0, w0), xf0, yf1, zf0, wf0),
129                            gradient_dot4(hash_primes4(seed, x1, y1, z0, w0), xf1, yf1, zf0, wf0),
130                            xs,
131                        ),
132                        ys,
133                    ),
134                    lerp(
135                        lerp(
136                            gradient_dot4(hash_primes4(seed, x0, y0, z1, w0), xf0, yf0, zf1, wf0),
137                            gradient_dot4(hash_primes4(seed, x1, y0, z1, w0), xf1, yf0, zf1, wf0),
138                            xs,
139                        ),
140                        lerp(
141                            gradient_dot4(hash_primes4(seed, x0, y1, z1, w0), xf0, yf1, zf1, wf0),
142                            gradient_dot4(hash_primes4(seed, x1, y1, z1, w0), xf1, yf1, zf1, wf0),
143                            xs,
144                        ),
145                        ys,
146                    ),
147                    zs,
148                ),
149                lerp(
150                    lerp(
151                        lerp(
152                            gradient_dot4(hash_primes4(seed, x0, y0, z0, w1), xf0, yf0, zf0, wf1),
153                            gradient_dot4(hash_primes4(seed, x1, y0, z0, w1), xf1, yf0, zf0, wf1),
154                            xs,
155                        ),
156                        lerp(
157                            gradient_dot4(hash_primes4(seed, x0, y1, z0, w1), xf0, yf1, zf0, wf1),
158                            gradient_dot4(hash_primes4(seed, x1, y1, z0, w1), xf1, yf1, zf0, wf1),
159                            xs,
160                        ),
161                        ys,
162                    ),
163                    lerp(
164                        lerp(
165                            gradient_dot4(hash_primes4(seed, x0, y0, z1, w1), xf0, yf0, zf1, wf1),
166                            gradient_dot4(hash_primes4(seed, x1, y0, z1, w1), xf1, yf0, zf1, wf1),
167                            xs,
168                        ),
169                        lerp(
170                            gradient_dot4(hash_primes4(seed, x0, y1, z1, w1), xf0, yf1, zf1, wf1),
171                            gradient_dot4(hash_primes4(seed, x1, y1, z1, w1), xf1, yf1, zf1, wf1),
172                            xs,
173                        ),
174                        ys,
175                    ),
176                    zs,
177                ),
178                ws,
179            )
180    }
181
182    #[inline]
183    #[cfg(feature = "nightly-simd")]
184    fn gen2a(self, point: f32x2, seed: i32) -> f32 {
185        // based on the implementation from FastNoiseLite
186        use crate::from_fast_noise_lite::{floor_to_int, grad2, interp_quintic, splat, PRIME_XY};
187
188        use core::simd::num::SimdInt;
189
190        let v0 = floor_to_int(point);
191        let d0 = point - v0.cast::<f32>();
192        let d1 = d0 - splat(1.0);
193        let vs = interp_quintic(d0);
194        let v0 = v0 * PRIME_XY;
195        let v1 = v0 + PRIME_XY;
196
197        let xf0 = lerp(grad2(seed, v0[0], v0[1], d0[0], d0[1]), grad2(seed, v1[0], v0[1], d1[0], d0[1]), vs[0]);
198        let xf1 = lerp(grad2(seed, v0[0], v1[1], d0[0], d1[1]), grad2(seed, v1[0], v1[1], d1[0], d1[1]), vs[0]);
199
200        lerp(xf0, xf1, vs[1]) * 1.4247691104677813
201    }
202
203    #[inline]
204    #[cfg(feature = "nightly-simd")]
205    fn gen3a(self, point: f32x4, seed: i32) -> f32 {
206        // based on the implementation from FastNoiseLite
207        use core::simd::{i32x4, num::SimdInt};
208
209        use crate::from_fast_noise_lite::{floor_to_int, grad3_with_hash, interp_quintic, Index4x4, PRIME_XYZ};
210
211        #[inline(always)]
212        fn create_hash(mut hash: i32x4) -> Index4x4<64> {
213            hash *= i32x4::splat(0x27d4eb2d);
214            hash ^= hash >> i32x4::splat(15);
215            Index4x4::new(hash)
216        }
217
218        let mut v0 = floor_to_int(point);
219        let d0 = point - v0.cast::<f32>();
220        let d1 = d0 - f32x4::splat(1.0);
221        let vs = interp_quintic(d0);
222        v0 *= PRIME_XYZ;
223        let v1 = v0 + PRIME_XYZ;
224
225        let hs = i32x4::from_array([v0[1] ^ v0[2], v1[1] ^ v0[2], v0[1] ^ v1[2], v1[1] ^ v1[2]]);
226
227        let h = create_hash(hs ^ i32x4::splat(v0[0] ^ seed));
228
229        let t0 = f32x4::from_array([
230            grad3_with_hash(h[0], d0[0], d0[1], d0[2]),
231            grad3_with_hash(h[1], d0[0], d1[1], d0[2]),
232            grad3_with_hash(h[2], d0[0], d0[1], d1[2]),
233            grad3_with_hash(h[3], d0[0], d1[1], d1[2]),
234        ]);
235
236        let h = create_hash(hs ^ i32x4::splat(v1[0] ^ seed));
237
238        let t1 = f32x4::from_array([
239            grad3_with_hash(h[0], d1[0], d0[1], d0[2]),
240            grad3_with_hash(h[1], d1[0], d1[1], d0[2]),
241            grad3_with_hash(h[2], d1[0], d0[1], d1[2]),
242            grad3_with_hash(h[3], d1[0], d1[1], d1[2]),
243        ]);
244
245        let vfx = lerp(t0, t1, f32x4::splat(vs[0]));
246
247        let yf0: f32 = lerp(vfx[0], vfx[1], vs[1]);
248        let yf1: f32 = lerp(vfx[2], vfx[3], vs[1]);
249
250        lerp(yf0, yf1, vs[2]) * 0.964921414852142333984375
251    }
252
253    #[inline]
254    #[cfg(feature = "nightly-simd")]
255    fn gen4a(self, point: f32x4, seed: i32) -> f32 {
256        self.gen4(point.into(), seed)
257    }
258}