turbulence + tuning
This commit is contained in:
parent
caed160def
commit
8a68e44e3d
6 changed files with 160 additions and 90 deletions
|
@ -1,28 +1,43 @@
|
|||
use std::{fs::File, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use clap::{Parser, ValueEnum};
|
||||
use turbulence::generate_turbulence;
|
||||
|
||||
use crate::value_noise::generate_noise;
|
||||
|
||||
mod ppm;
|
||||
mod turbulence;
|
||||
mod value_noise;
|
||||
mod vec2;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Opt {
|
||||
#[clap(long = "algorithm", default_value = "turbulence")]
|
||||
algorithm: Algorithm,
|
||||
|
||||
#[clap(long = "size", default_value = "1024")]
|
||||
size: usize,
|
||||
|
||||
#[clap(short = 'o', long = "out", default_value = "out.ppm")]
|
||||
output_path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Clone)]
|
||||
enum Algorithm {
|
||||
Noise,
|
||||
Turbulence,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let opt = Opt::parse();
|
||||
|
||||
let rng = rand::thread_rng();
|
||||
|
||||
let width = 256;
|
||||
let height = 256;
|
||||
let ppm = generate_noise(width, height, rng);
|
||||
let ppm = match opt.algorithm {
|
||||
Algorithm::Noise => generate_noise(opt.size, opt.size, rng),
|
||||
Algorithm::Turbulence => generate_turbulence(opt.size, opt.size, rng),
|
||||
};
|
||||
|
||||
{
|
||||
let file = File::create(opt.output_path)?;
|
||||
|
|
51
assignment-0/src/turbulence.rs
Normal file
51
assignment-0/src/turbulence.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
// https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/procedural-patterns-noise-part-1/simple-pattern-examples.html
|
||||
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::ppm::{Pixel, Ppm};
|
||||
use crate::value_noise::ValueNoise;
|
||||
use crate::vec2::Vec2;
|
||||
|
||||
pub fn generate_turbulence(
|
||||
width: usize,
|
||||
height: usize,
|
||||
rng: impl RngCore,
|
||||
) -> Ppm {
|
||||
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();
|
||||
Ppm {
|
||||
width,
|
||||
height,
|
||||
data,
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// https://www.scratchapixel.com/lessons/procedural-generation-virtual-worlds/procedural-patterns-noise-part-1/creating-simple-2D-noise.html
|
||||
|
||||
use std::mem::{self};
|
||||
use std::mem;
|
||||
|
||||
use rand::{Rng, RngCore};
|
||||
|
||||
|
@ -42,7 +42,8 @@ pub struct ValueNoise {
|
|||
|
||||
impl ValueNoise {
|
||||
pub fn new(mut rng: impl RngCore) -> Self {
|
||||
let mut r: [f64; MAX_TABLE_SIZE * MAX_TABLE_SIZE] = unsafe { mem::zeroed() };
|
||||
let mut r: [f64; MAX_TABLE_SIZE * MAX_TABLE_SIZE] =
|
||||
unsafe { mem::zeroed() };
|
||||
for k in 0..MAX_TABLE_SIZE * MAX_TABLE_SIZE {
|
||||
r[k] = rng.gen_range(0.0..1.0);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::ops::Mul;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Vec2<T = f64> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
|
|
2
rustfmt.toml
Normal file
2
rustfmt.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
max_width = 80
|
||||
tab_spaces = 2
|
Loading…
Reference in a new issue