Basic Perlin texture implementation.
This commit is contained in:
parent
4206ad7289
commit
697d056a9d
1
rtiow/Cargo.lock
generated
1
rtiow/Cargo.lock
generated
@ -490,6 +490,7 @@ dependencies = [
|
|||||||
"cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"image 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ structopt = "0.2.10"
|
|||||||
stderrlog = "0.4.1"
|
stderrlog = "0.4.1"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
cpuprofiler = "0.0.3"
|
cpuprofiler = "0.0.3"
|
||||||
|
lazy_static = "1.1.0"
|
||||||
|
|
||||||
# For better profiling support.
|
# For better profiling support.
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub mod hitable_list;
|
|||||||
pub mod kdtree;
|
pub mod kdtree;
|
||||||
pub mod material;
|
pub mod material;
|
||||||
pub mod moving_sphere;
|
pub mod moving_sphere;
|
||||||
|
pub mod perlin;
|
||||||
pub mod ray;
|
pub mod ray;
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
pub mod scenes;
|
pub mod scenes;
|
||||||
@ -17,6 +18,8 @@ pub mod vec3;
|
|||||||
extern crate crossbeam_channel;
|
extern crate crossbeam_channel;
|
||||||
extern crate image;
|
extern crate image;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate num_cpus;
|
extern crate num_cpus;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|||||||
98
rtiow/src/perlin.rs
Normal file
98
rtiow/src/perlin.rs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
use rand;
|
||||||
|
use rand::Rng;
|
||||||
|
//use rand::SeedableRng;
|
||||||
|
//use rand::XorShiftRng;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
ranfloat: Vec<f32>,
|
||||||
|
perm_x: Vec<usize>,
|
||||||
|
perm_y: Vec<usize>,
|
||||||
|
perm_z: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perlin_generate() -> Vec<f32> {
|
||||||
|
//let mut rng: XorShiftRng = SeedableRng::from_seed(SEED);
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
(0..256).map(|_| rng.gen_range::<f32>(0., 1.)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute(p: &mut Vec<usize>, n: usize) {
|
||||||
|
//let mut rng: XorShiftRng = SeedableRng::from_seed(SEED);
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let mut random = || rng.gen_range::<f32>(0., 1.);
|
||||||
|
for i in (0..n).rev() {
|
||||||
|
let target = (random() * (i + 1) as f32) as usize;
|
||||||
|
let tmp = p[i];
|
||||||
|
p[i] = p[target];
|
||||||
|
p[target] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perlin_generate_perm() -> Vec<usize> {
|
||||||
|
let mut p: Vec<usize> = (0..256).map(|i| i).collect();
|
||||||
|
permute(p.as_mut(), 256);
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trilinear_interp(c: [[[f32; 2]; 2]; 2], u: f32, v: f32, w: f32) -> f32 {
|
||||||
|
let mut accum = 0.;
|
||||||
|
for i in 0..2 {
|
||||||
|
for j in 0..2 {
|
||||||
|
for k in 0..2 {
|
||||||
|
let fi = i as f32;
|
||||||
|
let fj = j as f32;
|
||||||
|
let fk = k as f32;
|
||||||
|
accum += (fi * u + (1. - fi) * (1. - u))
|
||||||
|
* (fj * v + (1. - fj) * (1. - v))
|
||||||
|
* (fk * w + (1. - fk) * (1. - w))
|
||||||
|
* c[i][j][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accum
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Perlin {
|
||||||
|
fn new() -> Perlin {
|
||||||
|
Perlin {
|
||||||
|
ranfloat: perlin_generate(),
|
||||||
|
perm_x: perlin_generate_perm(),
|
||||||
|
perm_y: perlin_generate_perm(),
|
||||||
|
perm_z: perlin_generate_perm(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn noise(&self, p: Vec3) -> f32 {
|
||||||
|
let mut u = p.x - p.x.floor();
|
||||||
|
let mut v = p.y - p.y.floor();
|
||||||
|
let mut w = p.z - p.z.floor();
|
||||||
|
|
||||||
|
// Hermite cubic to round off interpolation and attempt to address 'mach bands'.
|
||||||
|
u = u * u * (3. - 2. * u);
|
||||||
|
v = v * v * (3. - 2. * v);
|
||||||
|
w = w * w * (3. - 2. * w);
|
||||||
|
|
||||||
|
let i = p.x.floor() as usize;
|
||||||
|
let j = p.y.floor() as usize;
|
||||||
|
let k = p.z.floor() as usize;
|
||||||
|
|
||||||
|
let mut c: [[[f32; 2]; 2]; 2] = Default::default();
|
||||||
|
for di in 0..2 {
|
||||||
|
for dj in 0..2 {
|
||||||
|
for dk in 0..2 {
|
||||||
|
c[di][dj][dk] = self.ranfloat[self.perm_x[(i + di) & 255]
|
||||||
|
^ self.perm_y[(j + dj) & 255]
|
||||||
|
^ self.perm_z[(k + dk) & 255]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trilinear_interp(c, u, v, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -76,7 +76,7 @@ pub struct Opt {
|
|||||||
#[structopt(short = "h", long = "height", default_value = "1024")]
|
#[structopt(short = "h", long = "height", default_value = "1024")]
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
/// Sub-samples per pixel
|
/// Sub-samples per pixel
|
||||||
#[structopt(short = "s", long = "subsample", default_value = "1")]
|
#[structopt(short = "s", long = "subsample", default_value = "8")]
|
||||||
pub subsamples: usize,
|
pub subsamples: usize,
|
||||||
/// Select scene to render, one of: "bench", "book", "tutorial" "cube", "bvh", "test"
|
/// Select scene to render, one of: "bench", "book", "tutorial" "cube", "bvh", "test"
|
||||||
#[structopt(long = "model", default_value = "test")]
|
#[structopt(long = "model", default_value = "test")]
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
use std::f32::consts::PI;
|
|
||||||
|
|
||||||
use camera::Camera;
|
use camera::Camera;
|
||||||
use hitable::Hit;
|
use hitable::Hit;
|
||||||
use hitable_list::HitableList;
|
use hitable_list::HitableList;
|
||||||
use kdtree::KDTree;
|
use kdtree::KDTree;
|
||||||
use material::Lambertian;
|
use material::Lambertian;
|
||||||
|
use material::Metal;
|
||||||
|
use moving_sphere::MovingSphere;
|
||||||
use renderer::Opt;
|
use renderer::Opt;
|
||||||
use renderer::Scene;
|
use renderer::Scene;
|
||||||
use sphere::Sphere;
|
use sphere::Sphere;
|
||||||
use texture::CheckerTexture;
|
|
||||||
use texture::ConstantTexture;
|
use texture::ConstantTexture;
|
||||||
|
use texture::NoiseTexture;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
pub fn new(opt: &Opt) -> Scene {
|
pub fn new(opt: &Opt) -> Scene {
|
||||||
let lookfrom = Vec3::new(0.001, 0.001, 20.);
|
let lookfrom = Vec3::new(5., 5., 5.);
|
||||||
let lookat = Vec3::new(0., 0., 0.);
|
let lookat = Vec3::new(0., 0., 0.);
|
||||||
let dist_to_focus = (lookfrom - lookat).length();
|
let dist_to_focus = (lookfrom - lookat).length();
|
||||||
let aperture = 0.1;
|
let aperture = 0.1;
|
||||||
let time_min = 0.;
|
let time_min = 0.;
|
||||||
let time_max = 0.;
|
let time_max = 1.;
|
||||||
let camera = Camera::new(
|
let camera = Camera::new(
|
||||||
lookfrom,
|
lookfrom,
|
||||||
lookat,
|
lookat,
|
||||||
@ -30,48 +30,52 @@ pub fn new(opt: &Opt) -> Scene {
|
|||||||
time_min,
|
time_min,
|
||||||
time_max,
|
time_max,
|
||||||
);
|
);
|
||||||
let mut objects: Vec<Box<Hit>> = vec![Box::new(Sphere::new(
|
let _ground_color = if opt.use_accel {
|
||||||
Vec3::new(0., 0., 0.),
|
Box::new(ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)))
|
||||||
5.,
|
} else {
|
||||||
Box::new(Lambertian::new(Box::new(CheckerTexture::new(
|
Box::new(ConstantTexture::new(Vec3::new(0.4, 1.0, 0.4)))
|
||||||
Box::new(ConstantTexture::new(Vec3::new(0., 0., 0.))),
|
};
|
||||||
Box::new(ConstantTexture::new(Vec3::new(1., 1., 1.))),
|
|
||||||
)))),
|
let objects: Vec<Box<Hit>> = vec![
|
||||||
))];
|
Box::new(Sphere::new(
|
||||||
let num_spheres = 6;
|
Vec3::new(0., 0., 0.),
|
||||||
let radius = 7.;
|
|
||||||
for i in 0..num_spheres {
|
|
||||||
let c1 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).sin();
|
|
||||||
let c2 = radius * ((2. * PI) * (i as f32 / num_spheres as f32)).cos();
|
|
||||||
let center = Vec3::new(0., c1, c2);
|
|
||||||
objects.push(Box::new(Sphere::new(
|
|
||||||
center,
|
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
||||||
1., 0., 0.,
|
0.1, 0.2, 0.5,
|
||||||
))))),
|
))))),
|
||||||
)));
|
)),
|
||||||
let center = Vec3::new(c1, 0., c2);
|
// Big sphere
|
||||||
objects.push(Box::new(Sphere::new(
|
Box::new(Sphere::new(
|
||||||
center,
|
Vec3::new(0., 0., -2.),
|
||||||
|
1.0,
|
||||||
|
Box::new(Lambertian::new(Box::new(NoiseTexture::with_scale(10.)))),
|
||||||
|
)),
|
||||||
|
// Earth sized sphere
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(0., -100.5, 0.),
|
||||||
|
100.,
|
||||||
|
// Box::new(Lambertian::new(ground_color)),
|
||||||
|
Box::new(Lambertian::new(Box::new(NoiseTexture::new()))),
|
||||||
|
)),
|
||||||
|
// Shiny sphere
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vec3::new(1., 0., 0.),
|
||||||
0.5,
|
0.5,
|
||||||
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2)),
|
||||||
0., 1., 0.,
|
)),
|
||||||
))))),
|
Box::new(MovingSphere::new(
|
||||||
)));
|
Vec3::new(-1., 0., -0.25),
|
||||||
let center = Vec3::new(c1, c2, 0.);
|
Vec3::new(-1., 0., 0.25),
|
||||||
objects.push(Box::new(Sphere::new(
|
|
||||||
center,
|
|
||||||
0.5,
|
0.5,
|
||||||
|
0.,
|
||||||
|
1.,
|
||||||
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
Box::new(Lambertian::new(Box::new(ConstantTexture::new(Vec3::new(
|
||||||
0., 0., 1.,
|
0.2, 0.8, 0.2,
|
||||||
))))),
|
))))),
|
||||||
)));
|
)),
|
||||||
}
|
];
|
||||||
let world: Box<Hit> = if opt.use_accel {
|
let world: Box<Hit> = if opt.use_accel {
|
||||||
let kd = KDTree::new(objects, time_min, time_max);
|
Box::new(KDTree::new(objects, time_min, time_max))
|
||||||
//println!("{}", kd);
|
|
||||||
Box::new(kd)
|
|
||||||
} else {
|
} else {
|
||||||
Box::new(HitableList::new(objects))
|
Box::new(HitableList::new(objects))
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use perlin::GENERATOR;
|
||||||
use vec3::Vec3;
|
use vec3::Vec3;
|
||||||
|
|
||||||
pub trait Texture: Send + Sync {
|
pub trait Texture: Send + Sync {
|
||||||
@ -41,3 +42,22 @@ impl Texture for CheckerTexture {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct NoiseTexture {
|
||||||
|
scale: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoiseTexture {
|
||||||
|
pub fn new() -> NoiseTexture {
|
||||||
|
NoiseTexture { scale: 1. }
|
||||||
|
}
|
||||||
|
pub fn with_scale(scale: f32) -> NoiseTexture {
|
||||||
|
NoiseTexture { scale }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Texture for NoiseTexture {
|
||||||
|
fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
|
||||||
|
Vec3::new(1., 1., 1.) * GENERATOR.noise(self.scale * p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user