Skip to content

Commit d5234c6

Browse files
committed
WIP refactoring noise functions
1 parent 183b80d commit d5234c6

File tree

1 file changed

+54
-53
lines changed

1 file changed

+54
-53
lines changed

core/src/math/noise.rs

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
//! Procedural noise generation.
2+
//!
3+
//! This module implements two- and three-dimensional Perlin Noise.
24
35
use super::{
46
spline::smoothstep,
57
vary::lerp,
6-
vec::{splat, vec2, vec3, Vec2, Vec3, Vector},
8+
vec::{splat, vec2, vec3, Vec2, Vec3},
9+
Vary,
710
};
11+
use crate::math::vary::bilerp;
12+
use std::array;
813

914
/// Returns the Perlin noise value corresponding to the 2D point.
1015
pub fn perlin2(pt: Vec2) -> f32 {
1116
use super::float::f32;
12-
let f = pt - pt.map(f32::floor);
13-
let [fx, fy] = f.0;
14-
17+
let fract = pt - pt.map(f32::floor);
18+
let [fx, fy] = fract.0;
1519
let [g00, g01, g10, g11] = grads2(pt);
1620

1721
let d00 = g00.dot(&vec2(fx, fy));
1822
let d01 = g01.dot(&vec2(fx, fy - 1.0));
1923
let d10 = g10.dot(&vec2(fx - 1.0, fy));
2024
let d11 = g11.dot(&vec2(fx - 1.0, fy - 1.0));
2125

22-
let t = f.map(smoothstep);
23-
let (a, b) = lerp(t.x(), (d00, d01), (d10, d11));
24-
lerp(t.y(), a, b)
26+
let t = fract.map(smoothstep);
27+
bilerp(t.x(), t.y(), d00, d10, d01, d11)
2528
}
2629

2730
/// Returns the Perlin gradient vector corresponding to the 2D point.
@@ -31,58 +34,63 @@ pub fn perlin2(pt: Vec2) -> f32 {
3134
pub fn perlin2v(pt: Vec2) -> Vec2 {
3235
use super::float::f32;
3336
let fract = pt - pt.map(f32::floor);
34-
3537
let [g00, g01, g10, g11] = grads2(pt);
36-
3738
let t = fract.map(smoothstep);
38-
let (a, b) = lerp(t.x(), (g00, g01), (g10, g11));
39-
lerp(t.y(), a, b)
39+
bilerp(t.x(), t.y(), g00, g10, g01, g11)
40+
}
41+
42+
trait ArrayExt<T> {
43+
/// Splits `self` to arrays of length `I` and `J`.
44+
fn split_to<const I: usize, const J: usize>(&self) -> (&[T; I], &[T; J]);
45+
}
46+
47+
impl<T, const N: usize> ArrayExt<T> for [T; N] {
48+
fn split_to<const I: usize, const J: usize>(&self) -> (&[T; I], &[T; J]) {
49+
const {
50+
assert!(I + J <= N);
51+
}
52+
let (a, b) = self[..I + J].split_at(I);
53+
(a.try_into().unwrap(), b.try_into().unwrap())
54+
}
4055
}
4156

4257
/// Returns the Perlin noise value corresponding to the 3D point.
4358
pub fn perlin3(pt: Vec3) -> f32 {
4459
use super::float::f32;
4560
let pt0 = pt.map(f32::floor);
46-
let f = pt - pt0;
47-
let i_f: Vec3 = f - splat(1.0);
61+
let fract = pt - pt0;
62+
let grads = grads3(pt0);
4863

49-
let [fx, fy, fz] = f.0;
50-
let [ifx, ify, ifz] = i_f.0;
64+
let [fx, fy, fz] = array::from_fn(|i| [fract[i], fract[i] - 1.0]);
5165

52-
let [g000, g001, g010, g011, g100, g101, g110, g111] = grads3(pt0);
66+
let yzs: [_; 4] = array::from_fn(|i| [fy[(i >> 1) & 1], fz[i & 1]]);
5367

54-
let d000 = g000.dot(&vec3(fx, fy, fz));
55-
let d001 = g001.dot(&vec3(fx, fy, ifz));
56-
let d010 = g010.dot(&vec3(fx, ify, fz));
57-
let d011 = g011.dot(&vec3(fx, ify, ifz));
58-
let d100 = g100.dot(&vec3(ifx, fy, fz));
59-
let d101 = g101.dot(&vec3(ifx, fy, ifz));
60-
let d110 = g110.dot(&vec3(ifx, ify, fz));
61-
let d111 = g111.dot(&vec3(ifx, ify, ifz));
68+
let (left, right) = grads.split_to::<4, 4>();
6269

63-
let t: Vec3 = f.map(smoothstep);
70+
let left: [f32; 4] = array::from_fn(|i| {
71+
let [y, z] = yzs[i];
72+
left[i].dot(&vec3(fx[0], y, z))
73+
});
74+
let right: [f32; 4] = array::from_fn(|i| {
75+
let [y, z] = yzs[i];
76+
right[i].dot(&vec3(fx[1], y, z))
77+
});
6478

65-
let x0 = Vector::<_>::new([d000, d010, d001, d011]);
66-
let x1 = Vector::<_>::new([d100, d110, d101, d111]);
67-
let [y0, y1, y2, y3] = lerp(t.x(), x0, x1).0;
68-
let (z0, z1) = lerp(t.y(), (y0, y2), (y1, y3));
69-
lerp(t.z(), z0, z1)
79+
trilerp(fract, left, right)
7080
}
7181

7282
/// Returns the Perlin gradient vector corresponding to the 3D point.
7383
pub fn perlin3v(pt: Vec3) -> Vec3 {
7484
use super::float::f32;
7585
let fract = pt - pt.map(f32::floor);
86+
let [lbn, lbf, ltn, ltf, rbn, rbf, rtn, rtf] = grads3(pt);
87+
trilerp(fract, [lbn, lbf, ltn, ltf], [rbn, rbf, rtn, rtf])
88+
}
7689

77-
let [g000, g001, g010, g011, g100, g101, g110, g111] = grads3(pt);
78-
79-
let t: Vec3 = fract.map(smoothstep);
80-
81-
let x0 = ((g000, g010), (g001, g011));
82-
let x1 = ((g100, g110), (g101, g111));
83-
let ((y0, y1), (y2, y3)) = lerp(t.x(), x0, x1);
84-
let (z0, z1) = lerp(t.y(), (y0, y2), (y1, y3));
85-
lerp(t.z(), z0, z1)
90+
fn trilerp<V: Vary>(pt: Vec3, left: [V; 4], right: [V; 4]) -> V {
91+
let [x, y, z] = pt.0.map(smoothstep);
92+
let [bot_near, bot_far, top_near, top_far] = lerp(x, left, right);
93+
bilerp(y, z, bot_near, top_near, bot_far, top_far)
8694
}
8795

8896
fn perm(x: i32) -> i32 {
@@ -112,10 +120,6 @@ fn grad3(x: f32, y: f32, z: f32) -> Vec3 {
112120
}
113121

114122
fn grads3(pt0: Vec3) -> [Vec3; 8] {
115-
let pt1 = pt0 + splat(1.0);
116-
let [x0, y0, z0] = pt0.0;
117-
let [x1, y1, z1] = pt1.0;
118-
119123
//
120124
// 011 +--------------+ 111
121125
// / | / |
@@ -128,16 +132,13 @@ fn grads3(pt0: Vec3) -> [Vec3; 8] {
128132
// 000 +--------------+ 100
129133
//
130134

131-
let g000 = grad3(x0, y0, z0);
132-
let g001 = grad3(x0, y0, z1);
133-
let g010 = grad3(x0, y1, z0);
134-
let g011 = grad3(x0, y1, z1);
135-
let g100 = grad3(x1, y0, z0);
136-
let g101 = grad3(x1, y0, z1);
137-
let g110 = grad3(x1, y1, z0);
138-
let g111 = grad3(x1, y1, z1);
139-
140-
[g000, g001, g010, g011, g100, g101, g110, g111]
135+
let pts = [pt0, pt0 + splat(1.0)];
136+
array::from_fn(|i| {
137+
let x = pts[(i >> 2) & 1].x();
138+
let y = pts[(i >> 1) & 1].y();
139+
let z = pts[i & 1].z();
140+
grad3(x, y, z)
141+
})
141142
}
142143

143144
const A: f32 = 1.237;

0 commit comments

Comments
 (0)