libnoise/core/sources/functional/
perlin.rs

1use super::constants::*;
2use crate::core::utils::{
3    math::{Vec2, Vec3, Vec4},
4    ptable::PermutationTable,
5};
6
7pub(crate) fn noise1d(perm: &PermutationTable, point: [f64; 1]) -> f64 {
8    let x = point[0];
9    // origin of hypercube in which input lies
10    let x0 = x.floor();
11    // smoothed distance from hypercube origin
12    let dx = x - x0;
13    let dxs = smoothstep_3(dx);
14    // get sign from hashes
15    let x0 = x0.rem_euclid(PERMUTATION_TABLE_SIZE as f64) as usize;
16    let sign0 = ((unsafe { perm.hash1d(x0) } % 2) as f64).mul_add(2.0, -1.0);
17    let sign1 = ((unsafe { perm.hash1d(x0 + 1) } % 2) as f64).mul_add(2.0, -1.0);
18    // compute contributions
19    let n0 = sign0 * dx;
20    let n1 = sign1 * (dx - 1.0);
21    // interpolate values from hypercube corners
22    lerp(n0, n1, dxs) * 2.0
23}
24
25pub(crate) fn noise2d(perm: &PermutationTable, point: [f64; 2]) -> f64 {
26    let x = Vec2::from(point);
27    // origin of hypercube in which input lies
28    let x0 = x.floor();
29    // smoothed distance from hypercube origin
30    let dx = x - x0;
31    let dxs = dx.map(smoothstep_3);
32    // hashed gradient indices
33    let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE);
34    let gi00 = unsafe { perm.hash2d(x0.x, x0.y) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE;
35    let gi01 = unsafe { perm.hash2d(x0.x, x0.y + 1) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE;
36    let gi10 = unsafe { perm.hash2d(x0.x + 1, x0.y) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE;
37    let gi11 = unsafe { perm.hash2d(x0.x + 1, x0.y + 1) } % CORNERPOINT_GRADIENT_LUT_2D_SIZE;
38    // compute contributions
39    let n00 = unsafe { contribution2d(dx.x, dx.y, gi00) };
40    let n01 = unsafe { contribution2d(dx.x, dx.y - 1.0, gi01) };
41    let n10 = unsafe { contribution2d(dx.x - 1.0, dx.y, gi10) };
42    let n11 = unsafe { contribution2d(dx.x - 1.0, dx.y - 1.0, gi11) };
43    // interpolate values from hypercube corners
44    let xn0 = lerp(n00, n10, dxs.x);
45    let xn1 = lerp(n01, n11, dxs.x);
46    lerp(xn0, xn1, dxs.y)
47}
48
49pub(crate) fn noise3d(perm: &PermutationTable, point: [f64; 3]) -> f64 {
50    let x = Vec3::from(point);
51    // origin of hypercube in which input lies
52    let x0 = x.floor();
53    // smoothed distance from hypercube origin
54    let dx = x - x0;
55    let dxs = dx.map(smoothstep_3);
56    // hashed gradient indices
57    let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE);
58    let gi000 = unsafe { perm.hash3d(x0.x, x0.y, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
59    let gi001 = unsafe { perm.hash3d(x0.x, x0.y, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
60    let gi010 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
61    let gi011 = unsafe { perm.hash3d(x0.x, x0.y + 1, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
62    let gi100 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
63    let gi101 = unsafe { perm.hash3d(x0.x + 1, x0.y, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
64    let gi110 = unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
65    let gi111 =
66        unsafe { perm.hash3d(x0.x + 1, x0.y + 1, x0.z + 1) } % CORNERPOINT_GRADIENT_LUT_3D_SIZE;
67    // compute contributions
68    let n000 = unsafe { contribution3d(dx.x, dx.y, dx.z, gi000) };
69    let n001 = unsafe { contribution3d(dx.x, dx.y, dx.z - 1.0, gi001) };
70    let n010 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z, gi010) };
71    let n011 = unsafe { contribution3d(dx.x, dx.y - 1.0, dx.z - 1.0, gi011) };
72    let n100 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z, gi100) };
73    let n101 = unsafe { contribution3d(dx.x - 1.0, dx.y, dx.z - 1.0, gi101) };
74    let n110 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z, gi110) };
75    let n111 = unsafe { contribution3d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, gi111) };
76    // interpolate values from hypercube corners
77    let xn00 = lerp(n000, n100, dxs.x);
78    let xn01 = lerp(n001, n101, dxs.x);
79    let xn10 = lerp(n010, n110, dxs.x);
80    let xn11 = lerp(n011, n111, dxs.x);
81    let yn0 = lerp(xn00, xn10, dxs.y);
82    let yn1 = lerp(xn01, xn11, dxs.y);
83    lerp(yn0, yn1, dxs.z) * 0.6666666666666666
84}
85
86pub(crate) fn noise4d(perm: &PermutationTable, point: [f64; 4]) -> f64 {
87    let x = Vec4::from(point);
88    // origin of hypercube in which input lies
89    let x0 = x.floor();
90    // smoothed distance from hypercube origin
91    let dx = x - x0;
92    let dxs = dx.map(smoothstep_3);
93    // hashed gradient indices
94    let x0 = x0.cast().rem_euclid(PERMUTATION_TABLE_SIZE);
95    let gi0000 = unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
96    let gi0001 =
97        unsafe { perm.hash4d(x0.x, x0.y, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
98    let gi0010 =
99        unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
100    let gi0011 =
101        unsafe { perm.hash4d(x0.x, x0.y, x0.z + 1, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
102    let gi0100 =
103        unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
104    let gi0101 =
105        unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
106    let gi0110 =
107        unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
108    let gi0111 = unsafe { perm.hash4d(x0.x, x0.y + 1, x0.z + 1, x0.w + 1) }
109        % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
110    let gi1000 =
111        unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
112    let gi1001 =
113        unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z, x0.w + 1) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
114    let gi1010 =
115        unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
116    let gi1011 = unsafe { perm.hash4d(x0.x + 1, x0.y, x0.z + 1, x0.w + 1) }
117        % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
118    let gi1100 =
119        unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w) } % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
120    let gi1101 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z, x0.w + 1) }
121        % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
122    let gi1110 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w) }
123        % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
124    let gi1111 = unsafe { perm.hash4d(x0.x + 1, x0.y + 1, x0.z + 1, x0.w + 1) }
125        % CORNERPOINT_GRADIENT_LUT_4D_SIZE;
126    // compute contributions
127    let n0000 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w, gi0000) };
128    let n0001 = unsafe { contribution4d(dx.x, dx.y, dx.z, dx.w - 1.0, gi0001) };
129    let n0010 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w, gi0010) };
130    let n0011 = unsafe { contribution4d(dx.x, dx.y, dx.z - 1.0, dx.w - 1.0, gi0011) };
131    let n0100 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w, gi0100) };
132    let n0101 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z, dx.w - 1.0, gi0101) };
133    let n0110 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w, gi0110) };
134    let n0111 = unsafe { contribution4d(dx.x, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi0111) };
135    let n1000 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w, gi1000) };
136    let n1001 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z, dx.w - 1.0, gi1001) };
137    let n1010 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w, gi1010) };
138    let n1011 = unsafe { contribution4d(dx.x - 1.0, dx.y, dx.z - 1.0, dx.w - 1.0, gi1011) };
139    let n1100 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w, gi1100) };
140    let n1101 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z, dx.w - 1.0, gi1101) };
141    let n1110 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w, gi1110) };
142    let n1111 = unsafe { contribution4d(dx.x - 1.0, dx.y - 1.0, dx.z - 1.0, dx.w - 1.0, gi1111) };
143    // interpolate values from hypercube corners
144    let xn000 = lerp(n0000, n1000, dxs.x);
145    let xn001 = lerp(n0001, n1001, dxs.x);
146    let xn010 = lerp(n0010, n1010, dxs.x);
147    let xn011 = lerp(n0011, n1011, dxs.x);
148    let xn100 = lerp(n0100, n1100, dxs.x);
149    let xn101 = lerp(n0101, n1101, dxs.x);
150    let xn110 = lerp(n0110, n1110, dxs.x);
151    let xn111 = lerp(n0111, n1111, dxs.x);
152    let yn00 = lerp(xn000, xn100, dxs.y);
153    let yn01 = lerp(xn001, xn101, dxs.y);
154    let yn10 = lerp(xn010, xn110, dxs.y);
155    let yn11 = lerp(xn011, xn111, dxs.y);
156    let zn0 = lerp(yn00, yn10, dxs.z);
157    let zn1 = lerp(yn01, yn11, dxs.z);
158    lerp(zn0, zn1, dxs.w) * 0.6664701256514842
159}
160
161#[inline]
162fn smoothstep_3(t: f64) -> f64 {
163    t * t * (t * (-2.0) + 3.0)
164}
165
166#[inline]
167fn lerp(a: f64, b: f64, t: f64) -> f64 {
168    a + t * (b - a)
169}
170
171unsafe fn contribution2d(x: f64, y: f64, gi: usize) -> f64 {
172    unsafe {
173        let gradient = CORNERPOINT_GRADIENT_LUT_2D.get_unchecked(gi);
174        gradient.get_unchecked(0) * x + gradient.get_unchecked(1) * y
175    }
176}
177
178unsafe fn contribution3d(x: f64, y: f64, z: f64, gi: usize) -> f64 {
179    unsafe {
180        let gradient = CORNERPOINT_GRADIENT_LUT_3D.get_unchecked(gi);
181        gradient.get_unchecked(0) * x
182            + gradient.get_unchecked(1) * y
183            + gradient.get_unchecked(2) * z
184    }
185}
186
187unsafe fn contribution4d(x: f64, y: f64, z: f64, w: f64, gi: usize) -> f64 {
188    unsafe {
189        let gradient = CORNERPOINT_GRADIENT_LUT_4D.get_unchecked(gi);
190        gradient.get_unchecked(0) * x
191            + gradient.get_unchecked(1) * y
192            + gradient.get_unchecked(2) * z
193            + gradient.get_unchecked(3) * w
194    }
195}