More noise debugging.
Added another reference implementation in lode.rs. Build CLI to generate noise with various parameters.
This commit is contained in:
265
rtiow/src/bin/noise_explorer.rs
Normal file
265
rtiow/src/bin/noise_explorer.rs
Normal file
@@ -0,0 +1,265 @@
|
||||
#[macro_use]
|
||||
extern crate askama;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate image;
|
||||
extern crate rand;
|
||||
extern crate stderrlog;
|
||||
|
||||
#[macro_use]
|
||||
extern crate structopt;
|
||||
|
||||
extern crate rtiow;
|
||||
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use askama::Template;
|
||||
use rand::SeedableRng;
|
||||
use rand::XorShiftRng;
|
||||
use structopt::StructOpt;
|
||||
|
||||
use rtiow::lode::Noise;
|
||||
use rtiow::vec3::Vec3;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(
|
||||
name = "noise_explorer",
|
||||
about = "CLI for exploring Perlin noise"
|
||||
)]
|
||||
struct Opt {
|
||||
/// Output directory
|
||||
#[structopt(parse(from_os_str), default_value = "/tmp/perlin")]
|
||||
pub output: PathBuf,
|
||||
|
||||
/// Width of noise images
|
||||
#[structopt(short = "w", long = "width", default_value = "128")]
|
||||
pub width: u32,
|
||||
/// Height of noise images
|
||||
#[structopt(short = "h", long = "height", default_value = "128")]
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
enum NoiseType {
|
||||
Scale(f32),
|
||||
Turbulance(usize),
|
||||
Marble {
|
||||
period: Vec3,
|
||||
power: f32,
|
||||
size: usize,
|
||||
},
|
||||
}
|
||||
|
||||
struct NoiseParams {
|
||||
width: u32,
|
||||
height: u32,
|
||||
noise: NoiseType,
|
||||
}
|
||||
|
||||
impl NoiseParams {
|
||||
fn compact_string(&self) -> String {
|
||||
let mut s = format!("w{}-h{}", self.width, self.height);
|
||||
|
||||
match self.noise {
|
||||
NoiseType::Scale(scale) => s.push_str(&format!("-s{:.2}", scale)),
|
||||
|
||||
NoiseType::Turbulance(turbulence) => s.push_str(&format!("-t{}", turbulence)),
|
||||
NoiseType::Marble {
|
||||
period,
|
||||
power,
|
||||
size,
|
||||
} => s.push_str(&format!(
|
||||
"-m{}-{}-{}",
|
||||
period.to_string().replace(" ", "-"),
|
||||
power,
|
||||
size
|
||||
)),
|
||||
}
|
||||
s
|
||||
}
|
||||
fn image_name(&self) -> String {
|
||||
format!("noise-{}.png", self.compact_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn render_noise_to_disk<P>(output_dir: P, noise_params: &NoiseParams) -> Result<(), std::io::Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
let ref mut rng: XorShiftRng = SeedableRng::from_seed(SEED);
|
||||
let ref output_dir: &Path = output_dir.as_ref();
|
||||
fs::create_dir_all(output_dir)?;
|
||||
let mut img = image::GrayImage::new(noise_params.width, noise_params.height);
|
||||
let tex = Noise::new(rng);
|
||||
|
||||
for x in 0..img.width() {
|
||||
for y in 0..img.height() {
|
||||
let u = x as f32 / 2.;
|
||||
let v = y as f32 / 2.;
|
||||
let p = Vec3::new(u, v, 1.);
|
||||
let luma = match noise_params.noise {
|
||||
NoiseType::Scale(scale) => tex.value(p, scale),
|
||||
|
||||
NoiseType::Turbulance(turbulence) => tex.turbulence(p, turbulence),
|
||||
NoiseType::Marble {
|
||||
period,
|
||||
power,
|
||||
size,
|
||||
} => tex.marble(p, period, power, size),
|
||||
};
|
||||
|
||||
if luma > 1. {
|
||||
info!("Hot pixel @ {}x{}: {}", x, y, luma);
|
||||
}
|
||||
if luma < 0. {
|
||||
info!("Cold pixel @ {}x{}: {}", x, y, luma);
|
||||
}
|
||||
let luma = (luma * 255.) as u8;
|
||||
img.put_pixel(x, y, image::Luma([luma]));
|
||||
}
|
||||
}
|
||||
|
||||
let path = output_dir.join(noise_params.image_name());
|
||||
info!("Saving {}", path.display());
|
||||
img.save(path)
|
||||
}
|
||||
|
||||
struct Specimen {
|
||||
title: String,
|
||||
params: Vec<NoiseParams>,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "index.html")]
|
||||
struct IndexTemplate {
|
||||
render_time: u64,
|
||||
specimens: Vec<Specimen>,
|
||||
}
|
||||
|
||||
fn render_html<P>(output_dir: P, specimens: Vec<Specimen>) -> Result<(), std::io::Error>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let index = IndexTemplate {
|
||||
render_time: SystemTime::now()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs(),
|
||||
specimens,
|
||||
};
|
||||
fs::write(
|
||||
output_dir.as_ref().join("index.html"),
|
||||
index.render().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
stderrlog::new()
|
||||
.verbosity(3)
|
||||
.timestamp(stderrlog::Timestamp::Millisecond)
|
||||
.init()
|
||||
.unwrap();
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let mut specimens = Vec::new();
|
||||
let mut specimen = Specimen {
|
||||
title: "Unperturbed".into(),
|
||||
params: Vec::new(),
|
||||
};
|
||||
{
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Scale(1.),
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
specimens.push(specimen);
|
||||
|
||||
let mut specimen = Specimen {
|
||||
title: "Varying Scale Factor <1".into(),
|
||||
params: Vec::new(),
|
||||
};
|
||||
let debug = false;
|
||||
if !debug {
|
||||
for scale in 1..10 {
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Scale(scale as f32 / 10.),
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
specimens.push(specimen);
|
||||
|
||||
let mut specimen = Specimen {
|
||||
title: "Varying Scale Factor >1".into(),
|
||||
params: Vec::new(),
|
||||
};
|
||||
for scale in 1..10 {
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Scale(scale as f32),
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
specimens.push(specimen);
|
||||
|
||||
let mut specimen = Specimen {
|
||||
title: "Varying Turbulence Factor".into(),
|
||||
params: Vec::new(),
|
||||
};
|
||||
for turbulence in 0..9 {
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Turbulance(1 << turbulence),
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
specimens.push(specimen);
|
||||
|
||||
let mut specimen = Specimen {
|
||||
title: "Varying Marble".into(),
|
||||
params: Vec::new(),
|
||||
};
|
||||
for power in 1..10 {
|
||||
for size in 1..6 {
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Marble {
|
||||
period: Vec3::new(5., 10., 0.),
|
||||
power: power as f32,
|
||||
size: 1 << size,
|
||||
},
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
}
|
||||
for power in 1..10 {
|
||||
let params = NoiseParams {
|
||||
width: opt.width,
|
||||
height: opt.height,
|
||||
noise: NoiseType::Marble {
|
||||
period: Vec3::new(0., 1., 0.),
|
||||
power: power as f32,
|
||||
size: 32,
|
||||
},
|
||||
};
|
||||
render_noise_to_disk(&opt.output, ¶ms)?;
|
||||
specimen.params.push(params);
|
||||
}
|
||||
specimens.push(specimen);
|
||||
}
|
||||
render_html(&opt.output, specimens)
|
||||
}
|
||||
5
rtiow/src/build.rs
Normal file
5
rtiow/src/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
extern crate askama;
|
||||
|
||||
fn main() {
|
||||
askama::rerun_if_templates_changed();
|
||||
}
|
||||
@@ -7,6 +7,7 @@ pub mod flip_normals;
|
||||
pub mod hitable;
|
||||
pub mod hitable_list;
|
||||
pub mod kdtree;
|
||||
pub mod lode;
|
||||
pub mod material;
|
||||
pub mod moving_sphere;
|
||||
pub mod perlin;
|
||||
@@ -23,8 +24,6 @@ pub mod vec3;
|
||||
extern crate crossbeam_channel;
|
||||
extern crate image;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate num_cpus;
|
||||
extern crate rand;
|
||||
|
||||
85
rtiow/src/lode.rs
Normal file
85
rtiow/src/lode.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
/// Implements the concepts from https://lodev.org/cgtutor/randomnoise.html
|
||||
use std::f32::consts::PI;
|
||||
|
||||
use rand;
|
||||
|
||||
use vec3::Vec3;
|
||||
|
||||
const NOISE_SIZE: usize = 64;
|
||||
pub struct Noise {
|
||||
noise: [[[f32; NOISE_SIZE]; NOISE_SIZE]; NOISE_SIZE],
|
||||
}
|
||||
|
||||
impl Noise {
|
||||
pub fn new<R>(rng: &mut R) -> Noise
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
let mut noise = [[[0.; NOISE_SIZE]; NOISE_SIZE]; NOISE_SIZE];
|
||||
for x in 0..NOISE_SIZE {
|
||||
for y in 0..NOISE_SIZE {
|
||||
for z in 0..NOISE_SIZE {
|
||||
noise[x][y][z] = rng.gen_range::<f32>(0., 1.);
|
||||
}
|
||||
}
|
||||
}
|
||||
Noise { noise }
|
||||
}
|
||||
|
||||
pub fn marble(&self, p: Vec3, period: Vec3, power: f32, size: usize) -> f32 {
|
||||
let xyz_value = p.x * period.x / NOISE_SIZE as f32
|
||||
+ p.y * period.y / NOISE_SIZE as f32
|
||||
+ p.z * period.z / NOISE_SIZE as f32
|
||||
+ power * self.turbulence(p, size);
|
||||
//info!("p {} xyz_value {}", p, xyz_value);
|
||||
(xyz_value * PI).sin().abs()
|
||||
}
|
||||
|
||||
pub fn turbulence(&self, p: Vec3, factor: usize) -> f32 {
|
||||
let mut value = 0.;
|
||||
let initial_factor = factor;
|
||||
let mut factor = factor;
|
||||
|
||||
while factor >= 1 {
|
||||
value += self.value(p / factor as f32, 1.) * factor as f32;
|
||||
factor /= 2;
|
||||
}
|
||||
0.5 * value / initial_factor as f32
|
||||
}
|
||||
|
||||
pub fn value(&self, p: Vec3, scale: f32) -> f32 {
|
||||
let p = p / scale;
|
||||
// Fractional part of vector components
|
||||
let x = p.x - p.x.floor();
|
||||
let y = p.y - p.y.floor();
|
||||
let z = p.z - p.z.floor();
|
||||
|
||||
// Wrap around the arrays
|
||||
let x1 = (p.x.floor() as usize + NOISE_SIZE) % NOISE_SIZE;
|
||||
let y1 = (p.y.floor() as usize + NOISE_SIZE) % NOISE_SIZE;
|
||||
let z1 = (p.z.floor() as usize + NOISE_SIZE) % NOISE_SIZE;
|
||||
|
||||
// Neighbor values
|
||||
let x2 = (x1 as usize + NOISE_SIZE - 1) % NOISE_SIZE;
|
||||
let y2 = (y1 as usize + NOISE_SIZE - 1) % NOISE_SIZE;
|
||||
let z2 = (z1 as usize + NOISE_SIZE - 1) % NOISE_SIZE;
|
||||
|
||||
trace!(target: "noise", "p {}", p);
|
||||
trace!(target: "noise", "x {:.2} y {:.2} z {:.2}", x, y, z);
|
||||
trace!(target: "noise", "x1 {:.2} y1 {:.2} z1 {:.2}", x1, y1, z1);
|
||||
trace!(target: "noise", "x2 {:.2} y2 {:.2} z2 {:.2}", x2, y2, z2);
|
||||
let mut value = 0.;
|
||||
// Smooth the noise with bilinear interpolation. Completely untested
|
||||
value += x * y * z * self.noise[x1][y1][z1];
|
||||
value += (1. - x) * y * z * self.noise[x2][y1][z1];
|
||||
value += x * (1. - y) * z * self.noise[x1][y2][z1];
|
||||
value += x * y * (1. - z) * self.noise[x1][y1][z2];
|
||||
value += (1. - x) * (1. - y) * z * self.noise[x2][y2][z1];
|
||||
value += x * (1. - y) * (1. - z) * self.noise[x1][y2][z2];
|
||||
value += (1. - x) * y * (1. - z) * self.noise[x2][y1][z2];
|
||||
value += (1. - x) * (1. - y) * (1. - z) * self.noise[x2][y2][z2];
|
||||
|
||||
trace!(target: "noise", "luma {}", value);
|
||||
value
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,8 @@
|
||||
use rand;
|
||||
use rand::Rng;
|
||||
//use rand::SeedableRng;
|
||||
//use rand::XorShiftRng;
|
||||
|
||||
use vec3::dot;
|
||||
use vec3::Vec3;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref GENERATOR: Perlin = Perlin::new();
|
||||
}
|
||||
//const SEED: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
|
||||
pub struct Perlin {
|
||||
ran_vec: Vec<Vec3>,
|
||||
perm_x: Vec<usize>,
|
||||
@@ -18,9 +10,10 @@ pub struct Perlin {
|
||||
perm_z: Vec<usize>,
|
||||
}
|
||||
|
||||
fn perlin_generate() -> Vec<Vec3> {
|
||||
//let mut rng: XorShiftRng = SeedableRng::from_seed(SEED);
|
||||
let mut rng = rand::thread_rng();
|
||||
fn perlin_generate<R>(rng: &mut R) -> Vec<Vec3>
|
||||
where
|
||||
R: Rng,
|
||||
{
|
||||
(0..256)
|
||||
.map(|_| {
|
||||
Vec3::new(
|
||||
@@ -31,9 +24,10 @@ fn perlin_generate() -> Vec<Vec3> {
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn perlin_generate_perm() -> Vec<usize> {
|
||||
//let mut rng: XorShiftRng = SeedableRng::from_seed(SEED);
|
||||
let mut rng = rand::thread_rng();
|
||||
fn perlin_generate_perm<R>(rng: &mut R) -> Vec<usize>
|
||||
where
|
||||
R: Rng,
|
||||
{
|
||||
let mut p: Vec<usize> = (0..256).map(|i| i).collect();
|
||||
rng.shuffle(&mut p);
|
||||
p
|
||||
@@ -61,32 +55,73 @@ fn perlin_interp(c: [[[Vec3; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 {
|
||||
}
|
||||
}
|
||||
}
|
||||
//info!("u {} v {} accum {}", u, v, accum);
|
||||
accum
|
||||
}
|
||||
|
||||
pub fn turb(p: Vec3, depth: usize) -> f32 {
|
||||
let mut accum = 0.;
|
||||
let mut temp_p = p;
|
||||
let mut weight = 1.;
|
||||
for _ in 0..depth {
|
||||
accum += weight * GENERATOR.noise(temp_p);
|
||||
weight *= 0.5;
|
||||
temp_p = temp_p * 0.2;
|
||||
}
|
||||
accum.abs()
|
||||
}
|
||||
|
||||
impl Perlin {
|
||||
fn new() -> Perlin {
|
||||
Perlin {
|
||||
ran_vec: perlin_generate(),
|
||||
perm_x: perlin_generate_perm(),
|
||||
perm_y: perlin_generate_perm(),
|
||||
perm_z: perlin_generate_perm(),
|
||||
}
|
||||
pub fn new<R>(rng: &mut R) -> Perlin
|
||||
where
|
||||
R: Rng,
|
||||
{
|
||||
let p = Perlin {
|
||||
ran_vec: perlin_generate(rng),
|
||||
perm_x: perlin_generate_perm(rng),
|
||||
perm_y: perlin_generate_perm(rng),
|
||||
perm_z: perlin_generate_perm(rng),
|
||||
};
|
||||
info!(
|
||||
"ran_vec: {}",
|
||||
p.ran_vec
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
info!(
|
||||
"perm_x: {}",
|
||||
p.perm_x
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
info!(
|
||||
"perm_y: {}",
|
||||
p.perm_y
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
info!(
|
||||
"perm_z: {}",
|
||||
p.perm_z
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
p
|
||||
}
|
||||
|
||||
pub fn noise(&self, p: Vec3) -> f32 {
|
||||
pub fn turb(&self, p: Vec3, depth: usize) -> f32 {
|
||||
let mut accum = 0.;
|
||||
let mut temp_p = p;
|
||||
let mut weight = 1.;
|
||||
for _ in 0..depth {
|
||||
accum += weight * self.noise(temp_p);
|
||||
weight *= 0.5;
|
||||
temp_p = temp_p * 0.2;
|
||||
}
|
||||
accum.abs()
|
||||
}
|
||||
|
||||
pub fn noise<V>(&self, p: V) -> f32
|
||||
where
|
||||
V: Into<Vec3>,
|
||||
{
|
||||
let p = p.into();
|
||||
let u = p.x - p.x.floor();
|
||||
let v = p.y - p.y.floor();
|
||||
let w = p.z - p.z.floor();
|
||||
|
||||
@@ -234,15 +234,15 @@ pub fn render(
|
||||
io::stdout().flush().unwrap();
|
||||
if store_intermediate {
|
||||
let path = output_dir.join(format!("iteration{:05}.png", acc_count));
|
||||
trace!(target: "renderer", "Saving {}", path.to_string_lossy());
|
||||
trace!(target: "renderer", "Saving {}", path.display());
|
||||
img.save(&path)
|
||||
.unwrap_or_else(|_| panic!("Failed save {}", path.to_string_lossy()));
|
||||
.unwrap_or_else(|_| panic!("Failed save {}", path.display()));
|
||||
}
|
||||
}
|
||||
println!();
|
||||
io::stdout().flush().unwrap();
|
||||
let path = output_dir.join("final.png");
|
||||
// Write the contents of this image to the Writer in PNG format.
|
||||
trace!(target: "renderer", "Saving {}", path.to_string_lossy());
|
||||
trace!(target: "renderer", "Saving {}", path.display());
|
||||
img.save(path)
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
|
||||
let nb = 20;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let ref mut rng = rand::thread_rng();
|
||||
let mut boxlist: Vec<Box<Hit>> = Vec::with_capacity(10000);
|
||||
let mut list: Vec<Box<Hit>> = Vec::new();
|
||||
let white: Arc<Material> = Arc::new(Lambertian::new(ConstantTexture::new([0.73, 0.73, 0.73])));
|
||||
@@ -127,7 +127,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
)));
|
||||
|
||||
// Perlin noise sphere
|
||||
let pertext = NoiseTexture::with_scale(0.1);
|
||||
let pertext = NoiseTexture::with_scale(rng, 0.1);
|
||||
list.push(Box::new(Sphere::new(
|
||||
[220., 280., 300.],
|
||||
80.,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rand;
|
||||
|
||||
use camera::Camera;
|
||||
use hitable::Hit;
|
||||
use hitable_list::HitableList;
|
||||
@@ -30,7 +32,9 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
time_min,
|
||||
time_max,
|
||||
);
|
||||
let pertext: Arc<Texture> = Arc::new(NoiseTexture::with_scale(10.));
|
||||
// TODO(wathiede): Use XOR rng for predictability?
|
||||
let ref mut rng = rand::thread_rng();
|
||||
let pertext: Arc<Texture> = Arc::new(NoiseTexture::with_scale(rng, 10.));
|
||||
|
||||
let objects: Vec<Box<Hit>> = vec![
|
||||
Box::new(Sphere::new(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use image;
|
||||
use rand;
|
||||
|
||||
use camera::Camera;
|
||||
use hitable::Hit;
|
||||
@@ -35,6 +36,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
time_min,
|
||||
time_max,
|
||||
);
|
||||
let ref mut rng = rand::thread_rng();
|
||||
let _ground_color = if opt.use_accel {
|
||||
Box::new(ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)))
|
||||
} else {
|
||||
@@ -51,7 +53,7 @@ pub fn new(opt: &Opt) -> Scene {
|
||||
Vec3::new(0., -1000., 0.),
|
||||
1000.,
|
||||
// Box::new(Lambertian::new(ground_color)),
|
||||
Lambertian::new(NoiseTexture::with_scale(10.)),
|
||||
Lambertian::new(NoiseTexture::with_scale(rng, 10.)),
|
||||
)),
|
||||
Box::new(XZRect::new(
|
||||
-100.,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use image::RgbImage;
|
||||
use rand;
|
||||
|
||||
use perlin::turb;
|
||||
use perlin::GENERATOR;
|
||||
use perlin::Perlin;
|
||||
use vec3::Vec3;
|
||||
|
||||
pub trait Texture: Send + Sync {
|
||||
@@ -71,24 +71,34 @@ where
|
||||
|
||||
pub struct NoiseTexture {
|
||||
scale: f32,
|
||||
perlin: Perlin,
|
||||
}
|
||||
|
||||
impl NoiseTexture {
|
||||
pub fn new() -> NoiseTexture {
|
||||
NoiseTexture { scale: 1. }
|
||||
pub fn new<R>(rng: &mut R) -> NoiseTexture
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
NoiseTexture::with_scale(rng, 1.)
|
||||
}
|
||||
pub fn with_scale(scale: f32) -> NoiseTexture {
|
||||
NoiseTexture { scale }
|
||||
pub fn with_scale<R>(rng: &mut R, scale: f32) -> NoiseTexture
|
||||
where
|
||||
R: rand::Rng,
|
||||
{
|
||||
NoiseTexture {
|
||||
scale,
|
||||
perlin: Perlin::new(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Texture for NoiseTexture {
|
||||
fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
|
||||
let _ = GENERATOR;
|
||||
let _ = turb;
|
||||
Vec3::new(1., 1., 1.) * 0.5 * (1. + self.perlin.noise(self.scale * p))
|
||||
|
||||
//Vec3::new(1., 1., 1.) * turb(self.scale * p, 7)
|
||||
//Vec3::new(1., 1., 1.) * 0.5 * (1. + turb(self.scale * p, 7))
|
||||
Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * turb(p, 7)).sin())
|
||||
//Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * self.perlin.turb(p, 7)).sin())
|
||||
//Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user