2023-01-21 08:55:19 +00:00
|
|
|
// Follows this algorithm:
|
2023-01-21 08:22:22 +00:00
|
|
|
// https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/procedural-patterns-noise-part-1/simple-pattern-examples.html
|
|
|
|
|
|
|
|
use rand::RngCore;
|
|
|
|
|
2023-01-21 08:55:19 +00:00
|
|
|
use crate::image::{Image, Pixel};
|
2023-01-21 08:22:22 +00:00
|
|
|
use crate::value_noise::ValueNoise;
|
|
|
|
use crate::vec2::Vec2;
|
|
|
|
|
|
|
|
pub fn generate_turbulence(
|
|
|
|
width: usize,
|
|
|
|
height: usize,
|
|
|
|
rng: impl RngCore,
|
2023-01-21 08:55:19 +00:00
|
|
|
) -> Image {
|
2023-01-21 08:22:22 +00:00
|
|
|
let mut noise_map = vec![0.0; width * height];
|
|
|
|
let noise = ValueNoise::new(rng);
|
|
|
|
|
|
|
|
let frequency = 0.02;
|
|
|
|
let frequency_mult = 1.8;
|
|
|
|
let amplitude_mult = 0.35;
|
|
|
|
let num_layers = 5;
|
|
|
|
let mut max_noise_val = 0.0f64;
|
|
|
|
|
|
|
|
for j in 0..height {
|
|
|
|
for i in 0..width {
|
|
|
|
let mut noise_point = Vec2::new(i as f64, j as f64) * frequency;
|
|
|
|
let mut amplitude = 1.0;
|
|
|
|
|
|
|
|
for _ in 0..num_layers {
|
|
|
|
noise_map[j * width + i] =
|
|
|
|
(2.0 * noise.eval(noise_point) - 1.0).abs() * amplitude;
|
|
|
|
noise_point = noise_point * frequency_mult;
|
|
|
|
amplitude *= amplitude_mult;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_noise_val = max_noise_val.max(noise_map[j * width + i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let data = noise_map
|
|
|
|
.into_iter()
|
|
|
|
.map(|f| {
|
|
|
|
let v = (f / max_noise_val * 192.0 + 32.0).floor() as u8;
|
|
|
|
Pixel(v, v, v)
|
|
|
|
})
|
|
|
|
.collect();
|
2023-01-21 08:55:19 +00:00
|
|
|
Image {
|
2023-01-21 08:22:22 +00:00
|
|
|
width,
|
|
|
|
height,
|
|
|
|
data,
|
|
|
|
}
|
|
|
|
}
|