2022-07-06 11:11:04 +00:00
|
|
|
use rand::distributions::{Distribution, Uniform};
|
|
|
|
use rand::Rng;
|
|
|
|
use crate::Point3;
|
|
|
|
|
|
|
|
pub struct Perlin {
|
|
|
|
ranfloat: Vec<f64>,
|
|
|
|
perm_x: Vec<usize>,
|
|
|
|
perm_y: Vec<usize>,
|
|
|
|
perm_z: Vec<usize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Perlin {
|
|
|
|
const POINT_COUNT: usize = 256;
|
|
|
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let range = Uniform::from(0.0..1.0);
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let mut ranfloat = Vec::with_capacity(Perlin::POINT_COUNT);
|
|
|
|
(0..Perlin::POINT_COUNT).for_each(|_i|ranfloat.push(range.sample(&mut rng)));
|
|
|
|
Perlin {
|
|
|
|
ranfloat,
|
|
|
|
perm_x: Perlin::perlin_generate_perm(),
|
|
|
|
perm_y: Perlin::perlin_generate_perm(),
|
|
|
|
perm_z: Perlin::perlin_generate_perm(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn noise(&self, point: &Point3) -> f64 {
|
2022-07-06 11:28:06 +00:00
|
|
|
let u = point.x() - point.x().floor();
|
|
|
|
let v = point.y() - point.y().floor();
|
|
|
|
let w = point.z() - point.z().floor();
|
2022-07-06 11:30:05 +00:00
|
|
|
let u = u * u * (3.0 - 2.0 * u);
|
|
|
|
let v = v * v * (3.0 - 2.0 * v);
|
|
|
|
let w = w * w * (3.0 - 2.0 * w);
|
2022-07-06 11:28:06 +00:00
|
|
|
let i = point.x().floor() as i32;
|
|
|
|
let j = point.y().floor() as i32;
|
|
|
|
let k = point.z().floor() as i32;
|
|
|
|
let mut c: [[[f64; 2]; 2]; 2] = [[[0.0; 2]; 2]; 2];
|
|
|
|
|
|
|
|
for di in 0..2 {
|
|
|
|
for dj in 0..2 {
|
|
|
|
for dk in 0..2 {
|
|
|
|
let idx = self.perm_x[((i+di) & 255) as usize] ^
|
|
|
|
self.perm_y[((j+dj) & 255) as usize] ^
|
|
|
|
self.perm_z[((k+dk) & 255) as usize];
|
|
|
|
c[di as usize][dj as usize][dk as usize] = self.ranfloat[idx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Perlin::trilinerar_interpolation(c, u, v, w)
|
2022-07-06 11:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn perlin_generate_perm() -> Vec<usize> {
|
|
|
|
let mut p = Vec::with_capacity(Perlin::POINT_COUNT);
|
|
|
|
(0..Perlin::POINT_COUNT).for_each(|i| p.push(i));
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
(1..Perlin::POINT_COUNT).rev().for_each(|idx| {
|
|
|
|
let target = rng.gen_range(0..=idx);
|
|
|
|
p.swap(idx, target);
|
|
|
|
});
|
|
|
|
p
|
|
|
|
}
|
2022-07-06 11:28:06 +00:00
|
|
|
|
|
|
|
fn trilinerar_interpolation(c: [[[f64; 2]; 2]; 2], u: f64, v: f64, w: f64) -> f64 {
|
|
|
|
let mut accum = 0.0;
|
|
|
|
for i in 0..2 {
|
|
|
|
for j in 0..2 {
|
|
|
|
for k in 0..2 {
|
|
|
|
let ifl = i as f64;
|
|
|
|
let jfl = j as f64;
|
|
|
|
let kfl = k as f64;
|
|
|
|
accum += (ifl*u + (1.0-ifl)*(1.0-u)) *
|
|
|
|
(jfl*v + (1.0-jfl)*(1.0-v)) *
|
|
|
|
(kfl*w + (1.0-kfl)*(1.0-w)) *
|
|
|
|
c[i][j][k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
accum
|
|
|
|
}
|
2022-07-06 11:11:04 +00:00
|
|
|
}
|