#![allow(missing_docs)]
#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[inline]
fn fade(t: f64) -> f64 {
t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
}
#[inline]
fn lerp(a: f64, b: f64, t: f64) -> f64 {
a + t * (b - a)
}
#[inline]
fn hash_cell(ix: i32, iy: i32, iz: i32, seed: u32) -> f64 {
let mut h = seed;
h = h.wrapping_add((ix as u32).wrapping_mul(0x6b43_a9b5));
h = h.wrapping_add((iy as u32).wrapping_mul(0x9e37_79b9));
h = h.wrapping_add((iz as u32).wrapping_mul(0x517c_c1b7));
h ^= h >> 16;
h = h.wrapping_mul(0x45d9_f3b7);
h ^= h >> 16;
(h as f64) / (u32::MAX as f64 / 2.0) - 1.0
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValueNoise3D {
pub seed: u32,
}
impl ValueNoise3D {
pub fn new(seed: u32) -> Self {
Self { seed }
}
pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 {
let ix = x.floor() as i32;
let iy = y.floor() as i32;
let iz = z.floor() as i32;
let fx = x - x.floor();
let fy = y - y.floor();
let fz = z - z.floor();
let ux = fade(fx);
let uy = fade(fy);
let uz = fade(fz);
let seed = self.seed;
let v000 = hash_cell(ix, iy, iz, seed);
let v100 = hash_cell(ix + 1, iy, iz, seed);
let v010 = hash_cell(ix, iy + 1, iz, seed);
let v110 = hash_cell(ix + 1, iy + 1, iz, seed);
let v001 = hash_cell(ix, iy, iz + 1, seed);
let v101 = hash_cell(ix + 1, iy, iz + 1, seed);
let v011 = hash_cell(ix, iy + 1, iz + 1, seed);
let v111 = hash_cell(ix + 1, iy + 1, iz + 1, seed);
let x00 = lerp(v000, v100, ux);
let x10 = lerp(v010, v110, ux);
let x01 = lerp(v001, v101, ux);
let x11 = lerp(v011, v111, ux);
let y0 = lerp(x00, x10, uy);
let y1 = lerp(x01, x11, uy);
lerp(y0, y1, uz)
}
#[inline]
pub fn sample_pos(&self, pos: [f64; 3]) -> f64 {
self.sample(pos[0], pos[1], pos[2])
}
#[inline]
pub fn sample_normalized(&self, x: f64, y: f64, z: f64) -> f64 {
self.sample(x, y, z) * 0.5 + 0.5
}
pub fn sample_vec3(&self, x: f64, y: f64, z: f64) -> [f64; 3] {
[
self.sample(x, y, z),
ValueNoise3D::new(self.seed.wrapping_add(0x9e37_79b9)).sample(x, y, z),
ValueNoise3D::new(self.seed.wrapping_add(0x6b43_a9b5)).sample(x, y, z),
]
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FractalNoise {
pub octaves: u32,
pub frequency: f64,
pub persistence: f64,
pub lacunarity: f64,
noise: ValueNoise3D,
}
impl FractalNoise {
pub fn new(seed: u32, octaves: u32) -> Self {
Self {
octaves: octaves.max(1),
frequency: 1.0,
persistence: 0.5,
lacunarity: 2.0,
noise: ValueNoise3D::new(seed),
}
}
pub fn seed(&self) -> u32 {
self.noise.seed
}
pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 {
let mut value = 0.0_f64;
let mut amplitude = 1.0_f64;
let mut frequency = self.frequency;
let mut max_value = 0.0_f64;
let mut oct_seed = self.noise.seed;
for _ in 0..self.octaves {
let n = ValueNoise3D::new(oct_seed);
value += n.sample(x * frequency, y * frequency, z * frequency) * amplitude;
max_value += amplitude;
amplitude *= self.persistence;
frequency *= self.lacunarity;
oct_seed = oct_seed.wrapping_add(0x9e37_79b9);
}
if max_value > 0.0 {
value / max_value
} else {
0.0
}
}
#[inline]
pub fn sample_pos(&self, pos: [f64; 3]) -> f64 {
self.sample(pos[0], pos[1], pos[2])
}
#[inline]
pub fn sample_normalized(&self, x: f64, y: f64, z: f64) -> f64 {
self.sample(x, y, z) * 0.5 + 0.5
}
pub fn turbulence(&self, x: f64, y: f64, z: f64) -> f64 {
let mut value = 0.0_f64;
let mut amplitude = 1.0_f64;
let mut frequency = self.frequency;
let mut max_value = 0.0_f64;
let mut oct_seed = self.noise.seed;
for _ in 0..self.octaves {
let n = ValueNoise3D::new(oct_seed);
value += n.sample(x * frequency, y * frequency, z * frequency).abs() * amplitude;
max_value += amplitude;
amplitude *= self.persistence;
frequency *= self.lacunarity;
oct_seed = oct_seed.wrapping_add(0x9e37_79b9);
}
if max_value > 0.0 {
(value / max_value).clamp(0.0, 1.0)
} else {
0.0
}
}
pub fn ridged(&self, x: f64, y: f64, z: f64) -> f64 {
(1.0 - self.turbulence(x, y, z)).clamp(0.0, 1.0)
}
pub fn turbulence_vec3(&self, x: f64, y: f64, z: f64) -> [f64; 3] {
[
self.sample(x, y, z),
self.sample(x + 1.7, y + 9.2, z + 3.4),
self.sample(x + 8.3, y + 2.8, z + 5.1),
]
}
pub fn turbulence_force(&self, pos: [f64; 3], scale: f64) -> [f64; 3] {
let [tx, ty, tz] = self.turbulence_vec3(pos[0], pos[1], pos[2]);
[tx * scale, ty * scale, tz * scale]
}
}