|
1 | | -use crate::math::spline::smoothstep; |
| 1 | +//! Two- and three-dimensional Perlin noise. |
2 | 2 |
|
3 | | -use super::vary::lerp; |
4 | | -use super::vec::{vec2, Vec2}; |
| 3 | +use super::{ |
| 4 | + spline::smoothstep, |
| 5 | + vary::lerp, |
| 6 | + vec::{splat, vec2, vec3, Vec2, Vec3, Vector}, |
| 7 | +}; |
5 | 8 |
|
6 | | -static GRADS: [Vec2; 40] = [ |
7 | | - vec2(0.981, 0.195), |
8 | | - vec2(0.957, 0.290), |
| 9 | +/// Gradient vectors for 2D noise. |
| 10 | +static GRADS_2: [Vec2; 8] = [ |
9 | 11 | vec2(0.924, 0.383), |
10 | | - vec2(0.882, 0.471), |
11 | | - vec2(0.831, 0.556), |
12 | | - vec2(0.556, 0.831), |
13 | | - vec2(0.471, 0.882), |
14 | 12 | vec2(0.383, 0.924), |
15 | | - vec2(0.290, 0.957), |
16 | | - vec2(0.195, 0.981), |
17 | | - vec2(-0.195, 0.981), |
18 | | - vec2(-0.290, 0.957), |
19 | 13 | vec2(-0.383, 0.924), |
20 | | - vec2(-0.471, 0.882), |
21 | | - vec2(-0.556, 0.831), |
22 | | - vec2(-0.634, 0.773), |
23 | | - vec2(-0.882, 0.471), |
24 | 14 | vec2(-0.924, 0.383), |
25 | | - vec2(-0.957, 0.290), |
26 | | - vec2(-0.981, 0.195), |
27 | | - vec2(-0.981, -0.195), |
28 | | - vec2(-0.957, -0.290), |
29 | 15 | vec2(-0.924, -0.383), |
30 | | - vec2(-0.882, -0.471), |
31 | | - vec2(-0.831, -0.556), |
32 | | - vec2(-0.556, -0.831), |
33 | | - vec2(-0.471, -0.882), |
34 | 16 | vec2(-0.383, -0.924), |
35 | | - vec2(-0.290, -0.957), |
36 | | - vec2(-0.195, -0.981), |
37 | | - vec2(0.195, -0.981), |
38 | | - vec2(0.290, -0.957), |
39 | 17 | vec2(0.383, -0.924), |
40 | | - vec2(0.471, -0.882), |
41 | | - vec2(0.556, -0.831), |
42 | | - vec2(0.831, -0.556), |
43 | | - vec2(0.882, -0.471), |
44 | 18 | vec2(0.924, -0.383), |
45 | | - vec2(0.957, -0.290), |
46 | | - vec2(0.981, -0.195), |
47 | 19 | ]; |
48 | 20 |
|
49 | | -fn grad(x: f32, y: f32) -> Vec2 { |
50 | | - GRADS[hash(x as i32, y as i32) % GRADS.len()] |
51 | | -} |
| 21 | +/// Gradient vectors for 3D noise. |
| 22 | +static GRADS_3: [Vec3; 16] = [ |
| 23 | + // |
| 24 | + vec3(0.0, -1.0, -1.0), |
| 25 | + vec3(0.0, -1.0, 1.0), |
| 26 | + vec3(0.0, 1.0, -1.0), |
| 27 | + vec3(0.0, 1.0, 1.0), |
| 28 | + // |
| 29 | + vec3(-1.0, 0.0, -1.0), |
| 30 | + vec3(-1.0, 0.0, 1.0), |
| 31 | + vec3(1.0, 0.0, -1.0), |
| 32 | + vec3(1.0, 0.0, 1.0), |
| 33 | + // |
| 34 | + vec3(-1.0, -1.0, 0.0), |
| 35 | + vec3(-1.0, 1.0, 0.0), |
| 36 | + vec3(1.0, -1.0, 0.0), |
| 37 | + vec3(1.0, 1.0, 0.0), |
| 38 | + // |
| 39 | + vec3(1.0, 1.0, 0.0), |
| 40 | + vec3(-1.0, 1.0, 0.0), |
| 41 | + vec3(0.0, -1.0, 1.0), |
| 42 | + vec3(0.0, -1.0, -1.0), |
| 43 | +]; |
52 | 44 |
|
53 | | -fn fnv(bytes: &[u8]) -> u64 { |
54 | | - const FNV_OFFSET_BASIS: u64 = 14695981039346656037; |
55 | | - const FNV_PRIME: u64 = 1099511628211; |
| 45 | +#[rustfmt::skip] |
| 46 | +static PERM: [u8; 256] = [ |
| 47 | + 156, 2, 157, 90, 75, 199, 55, 167, 62, 92, 101, 253, 66, 134, 113, 83, |
| 48 | + 1, 136, 78, 106, 254, 105, 248, 176, 234, 5, 195, 226, 49, 71, 87, 44, |
| 49 | + 122, 94, 219, 140, 72, 159, 237, 212, 8, 162, 200, 124, 125, 69, 165, 74, |
| 50 | + 245, 42, 89, 216, 158, 108, 238, 184, 217, 73, 126, 210, 14, 111, 19, 188, |
| 51 | + 186, 45, 38, 223, 35, 112, 214, 26, 145, 95, 99, 193, 250, 189, 152, 182, |
| 52 | + 166, 247, 148, 213, 168, 70, 96, 249, 127, 132, 4, 137, 41, 60, 102, 28, |
| 53 | + 27, 240, 227, 155, 211, 230, 9, 80, 178, 3, 68, 153, 143, 84, 179, 181, |
| 54 | + 12, 97, 103, 16, 225, 146, 63, 82, 203, 175, 163, 147, 11, 116, 185, 215, |
| 55 | + 57, 120, 208, 129, 115, 198, 37, 201, 39, 98, 20, 183, 56, 118, 109, 142, |
| 56 | + 138, 65, 117, 114, 160, 25, 43, 191, 204, 161, 22, 251, 139, 79, 131, 231, |
| 57 | + 76, 0, 205, 206, 244, 51, 174, 13, 110, 85, 209, 77, 64, 53, 48, 221, |
| 58 | + 133, 93, 224, 24, 33, 164, 23, 47, 171, 128, 243, 18, 52, 119, 149, 100, |
| 59 | + 246, 233, 31, 192, 252, 190, 15, 172, 91, 229, 144, 54, 61, 58, 220, 36, |
| 60 | + 222, 29, 50, 88, 121, 173, 232, 194, 239, 197, 32, 180, 107, 46, 7, 130, |
| 61 | + 169, 81, 218, 67, 21, 170, 187, 59, 86, 235, 154, 123, 150, 177, 135, 228, |
| 62 | + 104, 242, 6, 151, 255, 34, 30, 141, 202, 196, 236, 207, 241, 40, 17, 10 |
| 63 | +]; |
56 | 64 |
|
57 | | - let mut hash = FNV_OFFSET_BASIS; |
58 | | - for &b in bytes { |
59 | | - hash = hash.wrapping_mul(FNV_PRIME); |
60 | | - hash ^= b as u64; |
61 | | - } |
62 | | - hash |
| 65 | +fn perm(x: i32) -> i32 { |
| 66 | + PERM[(x & 0xFF) as usize] as i32 |
63 | 67 | } |
64 | 68 |
|
65 | | -fn hash(x: i32, y: i32) -> usize { |
66 | | - let val = (x as u32 as u64) << 32 | (y as u32 as u64); |
67 | | - fnv(&val.to_le_bytes()) as usize |
| 69 | +fn grad2(x: f32, y: f32) -> Vec2 { |
| 70 | + let perm = perm(x as i32 + perm(y as i32)); |
| 71 | + GRADS_2[perm as usize & 0x7] |
68 | 72 | } |
69 | 73 |
|
70 | | -pub fn perlin2(pt: Vec2) -> f32 { |
| 74 | +fn grads2(pt: Vec2) -> [Vec2; 4] { |
71 | 75 | use super::float::f32; |
72 | | - |
73 | 76 | let [x0, y0] = pt.map(f32::floor).0; |
74 | 77 |
|
75 | | - let fx = pt.x() - x0; |
76 | | - let fy = pt.y() - y0; |
| 78 | + let g00 = grad2(x0, y0); |
| 79 | + let g01 = grad2(x0, y0 + 1.0); |
| 80 | + let g10 = grad2(x0 + 1.0, y0); |
| 81 | + let g11 = grad2(x0 + 1.0, y0 + 1.0); |
77 | 82 |
|
78 | | - let g00 = grad(x0, y0); |
79 | | - let g01 = grad(x0, y0 + 1.0); |
80 | | - let g10 = grad(x0 + 1.0, y0); |
81 | | - let g11 = grad(x0 + 1.0, y0 + 1.0); |
| 83 | + [g00, g01, g10, g11] |
| 84 | +} |
| 85 | + |
| 86 | +fn grad3(x: f32, y: f32, z: f32) -> Vec3 { |
| 87 | + let perm = perm(x as i32 + perm(y as i32 + perm(z as i32))); |
| 88 | + GRADS_3[perm as usize & 0xF] |
| 89 | +} |
| 90 | + |
| 91 | +fn grads3(pt0: Vec3) -> [Vec3; 8] { |
| 92 | + use super::float::f32; |
| 93 | + let pt1 = pt0 + splat(1.0); |
| 94 | + let [x0, y0, z0] = pt0.0; |
| 95 | + let [x1, y1, z1] = pt1.0; |
| 96 | + |
| 97 | + let g000 = grad3(x0, y0, z0); |
| 98 | + let g001 = grad3(x0, y0, z1); |
| 99 | + let g010 = grad3(x0, y1, z0); |
| 100 | + let g011 = grad3(x0, y1, z1); |
| 101 | + let g100 = grad3(x1, y0, z0); |
| 102 | + let g101 = grad3(x1, y0, z1); |
| 103 | + let g110 = grad3(x1, y1, z0); |
| 104 | + let g111 = grad3(x1, y1, z1); |
| 105 | + |
| 106 | + [g000, g001, g010, g011, g100, g101, g110, g111] |
| 107 | +} |
| 108 | + |
| 109 | +pub fn perlin2(pt: Vec2) -> f32 { |
| 110 | + use super::float::f32; |
| 111 | + let f = pt - pt.map(f32::floor); |
| 112 | + let [fx, fy] = f.0; |
| 113 | + |
| 114 | + let [g00, g01, g10, g11] = grads2(pt); |
82 | 115 |
|
83 | 116 | let d00 = g00.dot(&vec2(fx, fy)); |
84 | 117 | let d01 = g01.dot(&vec2(fx, fy - 1.0)); |
85 | 118 | let d10 = g10.dot(&vec2(fx - 1.0, fy)); |
86 | 119 | let d11 = g11.dot(&vec2(fx - 1.0, fy - 1.0)); |
87 | 120 |
|
88 | | - let a = lerp(smoothstep(fx), d00, d10); |
89 | | - let b = lerp(smoothstep(fx), d01, d11); |
| 121 | + let t = f.map(smoothstep); |
| 122 | + let (a, b) = lerp(t.x(), (d00, d01), (d10, d11)); |
| 123 | + lerp(t.y(), a, b) |
| 124 | +} |
| 125 | + |
| 126 | +pub fn perlin2v(pt: Vec2) -> Vec2 { |
| 127 | + use super::float::f32; |
| 128 | + let fract = pt - pt.map(f32::floor); |
| 129 | + |
| 130 | + let [g00, g01, g10, g11] = grads2(pt); |
| 131 | + |
| 132 | + let t = fract.map(smoothstep); |
| 133 | + let (a, b) = lerp(t.x(), (g00, g01), (g10, g11)); |
| 134 | + lerp(t.y(), a, b) |
| 135 | +} |
| 136 | + |
| 137 | +pub fn perlin3(pt: Vec3) -> f32 { |
| 138 | + use super::float::f32; |
| 139 | + let pt0 = pt.map(f32::floor); |
| 140 | + let f = pt - pt0; |
| 141 | + let i_f: Vec3 = f - splat(1.0); |
| 142 | + |
| 143 | + let [fx, fy, fz] = f.0; |
| 144 | + let [ifx, ify, ifz] = i_f.0; |
| 145 | + |
| 146 | + let [g000, g001, g010, g011, g100, g101, g110, g111] = grads3(pt0); |
| 147 | + |
| 148 | + let d000 = g000.dot(&vec3(fx, fy, fz)); |
| 149 | + let d001 = g001.dot(&vec3(fx, fy, ifz)); |
| 150 | + let d010 = g010.dot(&vec3(fx, ify, fz)); |
| 151 | + let d011 = g011.dot(&vec3(fx, ify, ifz)); |
| 152 | + let d100 = g100.dot(&vec3(ifx, fy, fz)); |
| 153 | + let d101 = g101.dot(&vec3(ifx, fy, ifz)); |
| 154 | + let d110 = g110.dot(&vec3(ifx, ify, fz)); |
| 155 | + let d111 = g111.dot(&vec3(ifx, ify, ifz)); |
| 156 | + |
| 157 | + let t: Vec3 = f.map(smoothstep); |
| 158 | + |
| 159 | + let x0 = Vector::<_>::new([d000, d010, d001, d011]); |
| 160 | + let x1 = Vector::<_>::new([d100, d110, d101, d111]); |
| 161 | + let [y0, y1, y2, y3] = lerp(t.x(), x0, x1).0; |
| 162 | + let (z0, z1) = lerp(t.y(), (y0, y2), (y1, y3)); |
| 163 | + lerp(t.z(), z0, z1) |
| 164 | +} |
| 165 | + |
| 166 | +pub fn perlin3v(pt: Vec3) -> Vec3 { |
| 167 | + use super::float::f32; |
| 168 | + let fract = pt - pt.map(f32::floor); |
| 169 | + |
| 170 | + let [g000, g001, g010, g011, g100, g101, g110, g111] = grads3(pt); |
| 171 | + |
| 172 | + let t: Vec3 = fract.map(smoothstep); |
90 | 173 |
|
91 | | - lerp(smoothstep(fy), a, b) |
| 174 | + let x0 = ((g000, g010), (g001, g011)); |
| 175 | + let x1 = ((g100, g110), (g101, g111)); |
| 176 | + let ((y0, y1), (y2, y3)) = lerp(t.x(), x0, x1); |
| 177 | + let (z0, z1) = lerp(t.y(), (y0, y2), (y1, y3)); |
| 178 | + lerp(t.z(), z0, z1) |
92 | 179 | } |
93 | 180 |
|
94 | 181 | #[cfg(test)] |
95 | 182 | mod tests { |
96 | | - use std::{print, println}; |
97 | | - |
98 | 183 | use super::*; |
99 | | - use crate::math::{polar, turns}; |
| 184 | + use std::dbg; |
100 | 185 |
|
101 | 186 | #[test] |
102 | | - fn test() { |
103 | | - for i in -10..=10 { |
104 | | - for j in -10..=10 { |
105 | | - print!("{:2} ", hash(i, j) % 2); |
| 187 | + fn perlin2_theo() { |
| 188 | + let pt: Vec2 = vec2(9.5, 5.5); |
| 189 | + |
| 190 | + use super::super::float::f32; |
| 191 | + let f = pt - pt.map(f32::floor); |
| 192 | + let [fx, fy] = f.0; |
| 193 | + |
| 194 | + let [g00, g01, g10, g11]: [Vec2; 4] = [ |
| 195 | + vec2(0.924, 0.383), |
| 196 | + vec2(0.383, -0.924), |
| 197 | + vec2(-0.383, 0.924), |
| 198 | + vec2(-0.924, -0.383), |
| 199 | + ]; |
| 200 | + let d00 = g00.dot(&vec2(fx, fy)); |
| 201 | + let d01 = g01.dot(&vec2(fx, fy - 1.0)); |
| 202 | + let d10 = g10.dot(&vec2(fx - 1.0, fy)); |
| 203 | + let d11 = g11.dot(&vec2(fx - 1.0, fy - 1.0)); |
| 204 | + |
| 205 | + let t = f.map(smoothstep); |
| 206 | + let (a, b) = lerp(t.x(), (d00, d01), (d10, d11)); |
| 207 | + |
| 208 | + dbg!(lerp(t.y(), a, b)); |
| 209 | + } |
| 210 | + |
| 211 | + #[test] |
| 212 | + fn perlin2_statistics() { |
| 213 | + let count = 1000u32; |
| 214 | + let div = 10.0; |
| 215 | + let [mut avg, mut min, mut max] = [0.0f32, 1.0, -1.0]; |
| 216 | + for i in 0..count { |
| 217 | + for j in 0..count { |
| 218 | + let v = perlin2(vec2(i as f32, j as f32) / div); |
| 219 | + avg += v; |
| 220 | + min = min.min(v); |
| 221 | + max = max.max(v); |
106 | 222 | } |
107 | | - println!(); |
108 | 223 | } |
| 224 | + avg /= count.pow(2) as f32; |
109 | 225 |
|
110 | | - for i in 0..64 { |
111 | | - let a = turns(i as f32 / 64.0); |
112 | | - |
113 | | - let p = polar(1.0, a); |
114 | | - let v = p.to_cart(); |
115 | | - |
116 | | - println!("vec2({:.3}, {:.3}),", v.x(), v.y()); |
| 226 | + assert_eq!(avg, -0.0004172578); |
| 227 | + assert_eq!(min, -0.6612066); |
| 228 | + assert_eq!(max, 0.6612066); |
| 229 | + } |
| 230 | + #[test] |
| 231 | + fn perlin3_statistics() { |
| 232 | + let count = 100u32; |
| 233 | + let div = 10.0; |
| 234 | + let [mut avg, mut min, mut max] = [0.0f32, 1.0, -1.0]; |
| 235 | + for i in 0..count { |
| 236 | + for j in 0..count { |
| 237 | + for k in 0..count { |
| 238 | + let pt = vec3(i, j, k).map(|c| c as f32) / div; |
| 239 | + let v = perlin3(pt); |
| 240 | + |
| 241 | + avg += v; |
| 242 | + min = min.min(v); |
| 243 | + max = max.max(v); |
| 244 | + } |
| 245 | + } |
117 | 246 | } |
| 247 | + avg /= count.pow(3) as f32; |
118 | 248 |
|
119 | | - panic!() |
| 249 | + assert_eq!(avg, -0.0003959533); |
| 250 | + assert_eq!(min, -0.8853568); |
| 251 | + assert_eq!(max, 0.87813747); |
120 | 252 | } |
121 | 253 | } |
0 commit comments