simplex_23d/
lib.rs

1#[cfg(test)]
2mod tests;
3
4// Rust implementation of:
5//
6// Simplex noise demystified
7// Stefan Gustavson, Linköping University, Sweden (stegu@itn.liu.se), 2005-03-22
8//
9// https://github.com/stegu/perlin-noise/blob/master/simplexnoise.pdf
10// 
11// https://web.archive.org/web/20210506195658/http://weber.itn.liu.se/~stegu/simplexnoise/SimplexNoise.java
12//
13
14const SQRT3: f32 = 1.732_050_8; //  f32::sqrt(3.0);
15const F2: f32 = 0.5 * (SQRT3 - 1.0);
16const G2: f32 = (3.0 - SQRT3) / 6.0;
17const F3: f32 = 1.0 / 3.0;
18const G3: f32 = 1.0 / 6.0; // Very nice and simple unskew factor, too
19
20const GRAD3: [[f32; 3]; 12] = [
21    [1.0, 1.0, 0.0],
22    [-1.0, 1.0, 0.0],
23    [1.0, -1.0, 0.0],
24    [-1.0, -1.0, 0.0],
25    [1.0, 0.0, 1.0],
26    [-1.0, 0.0, 1.0],
27    [1.0, 0.0, -1.0],
28    [-1.0, 0.0, -1.0],
29    [0.0, 1.0, 1.0],
30    [0.0, -1.0, 1.0],
31    [0.0, 1.0, -1.0],
32    [0.0, -1.0, -1.0],
33];
34
35// uses a seed value to generate a permutation table and the same table with values mod 12
36fn generate_perm_mod12(seed: u64) -> ([usize; 512], [usize; 512]) {
37    use rand::{seq::SliceRandom, SeedableRng};
38    // random number generator with seed:
39    let mut rng: rand::rngs::StdRng = SeedableRng::seed_from_u64(seed);
40    let mut seq: Vec<_> = (0usize..256).collect();
41    seq.shuffle(&mut rng);
42    let mut perm = [0; 512];
43    let mut perm_mod12 = [0; 512];
44    // To remove the need for index wrapping, double the permutation table length
45    // mod 12 to lookup the gradients of the simplex corners
46    for i in 0..512 {
47        let value = seq[i & 255];
48        perm[i] = value;
49        perm_mod12[i] = value % 12;
50    }
51    (perm, perm_mod12)
52}
53
54#[inline(always)]
55fn fastfloor(x: f32) -> i32 {
56    if x > 0.0 {
57        x as i32
58    } else {
59        (x as i32) - 1
60    }
61}
62
63#[inline(always)]
64fn dot2(x0: f32, y0: f32, x1: f32, y1: f32) -> f32 {
65    x0 * x1 + y0 * y1
66}
67
68#[inline(always)]
69fn dot3(x0: f32, y0: f32, z0: f32, x1: f32, y1: f32, z1: f32) -> f32 {
70    x0 * x1 + y0 * y1 + z0 * z1
71}
72
73/// Simplex noise generator instance that keeps a permutation table internally.
74pub struct Simplex {
75    seed: u64,
76    perm: [usize; 512],
77    perm_mod12: [usize; 512],
78}
79
80impl Simplex {
81    /// Create a new simplex noise generator for the given seed value.
82    /// 
83    /// Creates a pre-computed permutation table using the seed value.
84    pub fn new(seed: u64) -> Self {
85        let (perm, perm_mod12) = generate_perm_mod12(seed);
86        Self {
87            seed,
88            perm,
89            perm_mod12
90        }
91    }
92
93    /// Sample the noise function in 2D at the given coordinates.
94    /// 
95    /// For frequency, multiply the coordinates by the desired frequency.
96    pub fn sample2d(&self, x: f32, y: f32) -> f32 {
97        // Skew the input space to determine which simplex cell we're in
98
99        let s = (x + y) * F2; // Hairy factor for 2D
100        let i = fastfloor(x + s);
101        let j = fastfloor(y + s);
102        let t = ((i + j) as f32) * G2;
103        let x0 = (i as f32) - t; // Unskew the cell origin back to (x,y) space
104        let y0 = (j as f32) - t;
105        let x0 = x - x0; // The x,y distances from the cell origin
106        let y0 = y - y0;
107
108        // For the 2D case, the simplex shape is an equilateral triangle.
109        // Determine which simplex we are in.
110        // Offsets for second (middle) corner of simplex in (i,j) coords
111        let (i1, j1) = if x0 > y0 {
112            (1, 0) // lower triangle, XY order: (0,0)->(1,0)->(1,1)
113        } else {
114            (0, 1) // upper triangle, YX order: (0,0)->(0,1)->(1,1)
115        };
116
117        // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
118        // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
119        // c = (3-sqrt(3))/6
120        let x1 = x0 - (i1 as f32) + G2; // Offsets for middle corner in (x,y) unskewed coords
121        let y1 = y0 - (j1 as f32) + G2;
122        let x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
123        let y2 = y0 - 1.0 + 2.0 * G2;
124
125        // Work out the hashed gradient indices of the three simplex corners
126        let ii: usize = (i & 255) as usize;
127        let jj: usize = (j & 255) as usize;
128        let gi0 = self.perm_mod12[ii + self.perm[jj]];
129        let gi1 = self.perm_mod12[ii + i1 + self.perm[jj + j1]];
130        let gi2 = self.perm_mod12[ii + 1 + self.perm[jj + 1]];
131
132        // Calculate the contribution from the three corners
133        // double n0, n1, n2; // Noise contributions from the three corners
134        let mut t0 = 0.5 - x0 * x0 - y0 * y0;
135        let n0 = if t0 < 0.0 {
136            0.0
137        } else {
138            t0 *= t0;
139            t0 * t0 * dot2(GRAD3[gi0][0], GRAD3[gi0][1], x0, y0) // (x,y) of grad3 used for 2D gradient
140        };
141
142        let mut t1 = 0.5 - x1 * x1 - y1 * y1;
143        let n1 = if t1 < 0.0 {
144            0.0
145        } else {
146            t1 *= t1;
147            t1 * t1 * dot2(GRAD3[gi1][0], GRAD3[gi1][1], x1, y1)
148        };
149
150        let mut t2 = 0.5 - x2 * x2 - y2 * y2;
151        let n2 = if t2 < 0.0 {
152            0.0
153        } else {
154            t2 *= t2;
155            t2 * t2 * dot2(GRAD3[gi2][0], GRAD3[gi2][1], x2, y2)
156        };
157
158        // Add contributions from each corner to get the final noise value.
159        // The result is scaled to return values in the interval [-1,1].
160        n0 + n1 + n2
161    }
162
163    /// Sample the noise function in 3D at the given coordinates.
164    /// 
165    /// For frequency, multiply the coordinates by the desired frequency.
166    pub fn sample3d(&self, x: f32, y: f32, z: f32) -> f32 {
167        // Skew the input space to determine which simplex cell we're in
168        let s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
169        let i = fastfloor(x + s);
170        let j = fastfloor(y + s);
171        let k = fastfloor(z + s);
172        let t = (i + j + k) as f32 * G3;
173        let x0 = i as f32 - t; // Unskew the cell origin back to (x,y,z) space
174        let y0 = j as f32 - t;
175        let z0 = k as f32 - t;
176        let x0 = x - x0; // The x,y,z distances from the cell origin
177        let y0 = y - y0;
178        let z0 = z - z0;
179        // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
180        // Determine which simplex we are in.
181
182        // Offsets for second corner of simplex in (i,j,k) coords
183        let i1;
184        let j1;
185        let k1;
186
187        // Offsets for third corner of simplex in (i,j,k) coords
188        let i2;
189        let j2;
190        let k2;
191
192        if x0 >= y0 {
193            if y0 >= z0 {
194                i1 = 1;
195                j1 = 0;
196                k1 = 0;
197                i2 = 1;
198                j2 = 1;
199                k2 = 0;
200            }
201            // X Y Z order
202            else if x0 >= z0 {
203                i1 = 1;
204                j1 = 0;
205                k1 = 0;
206                i2 = 1;
207                j2 = 0;
208                k2 = 1;
209            }
210            // X Z Y order
211            else {
212                i1 = 0;
213                j1 = 0;
214                k1 = 1;
215                i2 = 1;
216                j2 = 0;
217                k2 = 1;
218            } // Z X Y order
219        } else {
220            // x0<y0
221            if y0 < z0 {
222                i1 = 0;
223                j1 = 0;
224                k1 = 1;
225                i2 = 0;
226                j2 = 1;
227                k2 = 1;
228            }
229            // Z Y X order
230            else if x0 < z0 {
231                i1 = 0;
232                j1 = 1;
233                k1 = 0;
234                i2 = 0;
235                j2 = 1;
236                k2 = 1;
237            }
238            // Y Z X order
239            else {
240                i1 = 0;
241                j1 = 1;
242                k1 = 0;
243                i2 = 1;
244                j2 = 1;
245                k2 = 0;
246            } // Y X Z order
247        }
248        // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
249        // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
250        // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
251        // c = 1/6.
252        let x1 = x0 - i1 as f32 + G3; // Offsets for second corner in (x,y,z) coords
253        let y1 = y0 - j1 as f32 + G3;
254        let z1 = z0 - k1 as f32 + G3;
255        let x2 = x0 - i2 as f32 + 2.0 * G3; // Offsets for third corner in (x,y,z) coords
256        let y2 = y0 - j2 as f32 + 2.0 * G3;
257        let z2 = z0 - k2 as f32 + 2.0 * G3;
258        let x3 = x0 - 1.0 + 3.0 * G3; // Offsets for last corner in (x,y,z) coords
259        let y3 = y0 - 1.0 + 3.0 * G3;
260        let z3 = z0 - 1.0 + 3.0 * G3;
261        // Work out the hashed gradient indices of the four simplex corners
262        let ii = (i & 255) as usize;
263        let jj = (j & 255) as usize;
264        let kk = (k & 255) as usize;
265        let gi0 = self.perm_mod12[ii + self.perm[jj + self.perm[kk]]];
266        let gi1 = self.perm_mod12[ii + i1 + self.perm[jj + j1 + self.perm[kk + k1]]];
267        let gi2 = self.perm_mod12[ii + i2 + self.perm[jj + j2 + self.perm[kk + k2]]];
268        let gi3 = self.perm_mod12[ii + 1 + self.perm[jj + 1 + self.perm[kk + 1]]];
269        // Calculate the contribution from the four corners
270        // let n0, n1, n2, n3;
271        // Noise contributions from the four corners
272        let mut t0 = 0.5 - x0 * x0 - y0 * y0 - z0 * z0;
273        let n0 = if t0 < 0.0 {
274            0.0
275        } else {
276            t0 *= t0;
277            t0 * t0 * dot3(GRAD3[gi0][0], GRAD3[gi0][1], GRAD3[gi0][2], x0, y0, z0)
278        };
279
280        let mut t1 = 0.5 - x1 * x1 - y1 * y1 - z1 * z1;
281        let n1 = if t1 < 0.0 {
282            0.0
283        } else {
284            t1 *= t1;
285            t1 * t1 * dot3(GRAD3[gi1][0], GRAD3[gi1][1], GRAD3[gi1][2], x1, y1, z1)
286        };
287
288        let mut t2 = 0.5 - x2 * x2 - y2 * y2 - z2 * z2;
289        let n2 = if t2 < 0.0 {
290            0.0
291        } else {
292            t2 *= t2;
293            t2 * t2 * dot3(GRAD3[gi2][0], GRAD3[gi2][1], GRAD3[gi2][2], x2, y2, z2)
294        };
295
296        let mut t3 = 0.5 - x3 * x3 - y3 * y3 - z3 * z3;
297        let n3 = if t3 < 0.0 {
298            0.0
299        } else {
300            t3 *= t3;
301            t3 * t3 * dot3(GRAD3[gi3][0], GRAD3[gi3][1], GRAD3[gi3][2], x3, y3, z3)
302        };
303
304        // Add contributions from each corner to get the final noise value.
305        // The result is scaled to stay just inside [-1,1]
306        n0 + n1 + n2 + n3
307    }
308
309    /// Returns the seed value that was used to generate the permutation table.
310    pub fn seed(&self) -> u64 {
311        self.seed
312    }
313}