Refactored to improve some performance.
1. Removed duplication to increase performance a little bit 2. Fixed some minor rendering related issues 3. Added a Defocus Blur Demo
This commit is contained in:
parent
52c6c76c0d
commit
f75d0d2b7d
|
@ -1,10 +1,19 @@
|
|||
use crate::types::{Ray, Vec3};
|
||||
use {
|
||||
crate::types::{Ray, Vec3},
|
||||
rand::Rng,
|
||||
};
|
||||
|
||||
pub struct Camera {
|
||||
pub origin: Vec3,
|
||||
pub horizontal: Vec3,
|
||||
pub vertical: Vec3,
|
||||
pub lower_left_corner: Vec3,
|
||||
origin: Vec3,
|
||||
horizontal: Vec3,
|
||||
vertical: Vec3,
|
||||
lower_left_corner: Vec3,
|
||||
lens_radius: f64,
|
||||
|
||||
// position vectors
|
||||
u: Vec3,
|
||||
v: Vec3,
|
||||
w: Vec3,
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
|
@ -13,7 +22,15 @@ impl Camera {
|
|||
// look_at is the point where camera is looking
|
||||
// v_up is camera's up vector. i.e. it points upwards from the camera
|
||||
// orthogonal to look_from - look_at vector
|
||||
pub fn new(look_from: Vec3, look_at: Vec3, v_up: Vec3, vertical_fov: f64, aspect: f64) -> Self {
|
||||
pub fn new(
|
||||
look_from: Vec3,
|
||||
look_at: Vec3,
|
||||
v_up: Vec3,
|
||||
vertical_fov: f64,
|
||||
aspect: f64,
|
||||
aperture: f64,
|
||||
focus_distance: f64,
|
||||
) -> Self {
|
||||
// convert degree to radian
|
||||
let angle = vertical_fov * std::f64::consts::PI / 180.0;
|
||||
let half_height = (angle / 2.0).tan();
|
||||
|
@ -24,35 +41,42 @@ impl Camera {
|
|||
let u = v_up.cross(&w).unit_vector();
|
||||
let v = w.cross(&u);
|
||||
|
||||
let lower_left_corner = origin - u * half_width - v * half_height - w;
|
||||
let lower_left_corner = origin
|
||||
- u * focus_distance * half_width
|
||||
- v * focus_distance * half_height
|
||||
- w * focus_distance;
|
||||
let horizontal = u * half_width * 2.0;
|
||||
let vertical = v * half_height * 2.0;
|
||||
let lens_radius = aperture / 2.0;
|
||||
|
||||
Self {
|
||||
lens_radius,
|
||||
lower_left_corner,
|
||||
horizontal,
|
||||
vertical,
|
||||
origin,
|
||||
u,
|
||||
v,
|
||||
w,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ray(&self, u: f64, v: f64) -> Ray {
|
||||
let mut rng = rand::thread_rng();
|
||||
let rd = random_in_unit_disk(&mut rng) * self.lens_radius;
|
||||
let offset = self.u * rd.x() + self.v * rd.y();
|
||||
Ray::new(
|
||||
self.origin,
|
||||
self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin,
|
||||
self.origin + offset,
|
||||
self.lower_left_corner + self.horizontal * u + self.vertical * v - self.origin - offset,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for Camera {
|
||||
fn default() -> Self {
|
||||
Camera::new(
|
||||
Vec3::new(0.0, 0.0, 0.0),
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
90.0,
|
||||
// 2:1 aspect ratio width:height
|
||||
2.0,
|
||||
)
|
||||
fn random_in_unit_disk(rng: &mut rand::rngs::ThreadRng) -> Vec3 {
|
||||
let mut p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
|
||||
while p.dot(&p) >= 1.0 {
|
||||
p = Vec3::new(rng.gen::<f64>(), rng.gen::<f64>(), 0.0) * 2.0 - Vec3::new(1.0, 0.0, 0.0);
|
||||
}
|
||||
p
|
||||
}
|
||||
|
|
125
src/demos/defocus_blur.rs
Normal file
125
src/demos/defocus_blur.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use {
|
||||
crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{
|
||||
material::{Dielectric, Lambertian, Metal},
|
||||
Hitable, HitableList, Ray, Sphere, Vec3,
|
||||
},
|
||||
Camera,
|
||||
},
|
||||
rand::Rng,
|
||||
};
|
||||
|
||||
pub struct DefocusBlur;
|
||||
|
||||
impl Demo for DefocusBlur {
|
||||
fn name(&self) -> &'static str {
|
||||
"defocus-blur"
|
||||
}
|
||||
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
let radius = (std::f64::consts::PI / 4.0).cos();
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(-radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Lambertian::new(Vec3::new(0.0, 0.0, 1.0))),
|
||||
)),
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Metal::with_fuzz(Vec3::new(0.5, 0.5, 0.0), 0.2)),
|
||||
)),
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(-3.0 * radius, 0.0, -1.0),
|
||||
radius,
|
||||
Box::new(Dielectric::new(1.5)),
|
||||
)),
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, -100.5, -1.0),
|
||||
100.0,
|
||||
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
||||
)),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(3.0, 3.0, 2.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
let aperture = 2.0;
|
||||
let distance_to_focus = (lookfrom - lookat).length();
|
||||
let camera = Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
20.0,
|
||||
aspect_ratio,
|
||||
aperture,
|
||||
distance_to_focus,
|
||||
);
|
||||
Some(camera)
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
let mut color = Vec3::new(0.0, 0.0, 0.0);
|
||||
for _s in 0..samples {
|
||||
let u = (i as f64 + rng.gen::<f64>()) / x as f64;
|
||||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
buffer[offset + 2] = (255.99 * color.b().sqrt()) as u8;
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_color(ray: Ray, world: &HitableList, depth: u32) -> Vec3 {
|
||||
if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) {
|
||||
if depth >= 50 {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
} else {
|
||||
let material = hit_rec.material.as_ref();
|
||||
if let (attenuation, Some(scattered_ray)) = material.unwrap().scatter(&ray, &hit_rec) {
|
||||
calc_color(scattered_ray, &world, depth + 1) * attenuation
|
||||
} else {
|
||||
Vec3::new(0.0, 0.0, 0.0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let unit_direction = ray.direction().unit_vector();
|
||||
let t = 0.5 * (unit_direction.y() + 1.0);
|
||||
Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t
|
||||
}
|
||||
}
|
|
@ -17,16 +17,8 @@ impl Demo for DielectricMaterial {
|
|||
"dielectric-material"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
|
||||
let world = HitableList {
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
|
@ -54,9 +46,26 @@ impl Demo for DielectricMaterial {
|
|||
Box::new(Dielectric::new(1.5)),
|
||||
)),
|
||||
],
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
let camera: Camera = Default::default();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
|
|
|
@ -14,7 +14,22 @@ impl Demo for DiffuseMaterials {
|
|||
"diffuse-materials"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
@ -22,15 +37,9 @@ impl Demo for DiffuseMaterials {
|
|||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
|
||||
let world = HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
};
|
||||
|
||||
let camera: Camera = Default::default();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Hitable, HitableList, Ray, Sphere, Vec3},
|
||||
Camera,
|
||||
};
|
||||
pub struct HitableSphere;
|
||||
|
||||
|
@ -9,7 +10,22 @@ impl Demo for HitableSphere {
|
|||
"sphere-using-hit-table"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
_camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
@ -17,18 +33,13 @@ impl Demo for HitableSphere {
|
|||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let world = world.unwrap();
|
||||
|
||||
let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
|
||||
let horizontal = Vec3::new(4.0, 0.0, 0.0);
|
||||
let vertical = Vec3::new(0.0, 2.0, 0.0);
|
||||
let origin = Vec3::new(0.0, 0.0, 0.0);
|
||||
|
||||
let world = HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
};
|
||||
let mut offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
for i in start_x..start_x + nx {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
pub struct LinearGradientRectangle;
|
||||
|
||||
use crate::{
|
||||
types::{Ray, Vec3},
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
{demos::Chunk, Demo},
|
||||
};
|
||||
|
||||
|
@ -10,7 +11,13 @@ impl Demo for LinearGradientRectangle {
|
|||
"linear-gradient-rectangle"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
_camera: Option<&Camera>,
|
||||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
|
|
@ -17,16 +17,8 @@ impl Demo for Materials {
|
|||
"metal-material"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
|
||||
let world = HitableList {
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
|
@ -49,9 +41,25 @@ impl Demo for Materials {
|
|||
Box::new(Metal::with_fuzz(Vec3::new(0.8, 0.8, 0.8), 0.5)),
|
||||
)),
|
||||
],
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
|
||||
let camera: Camera = Default::default();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
|
@ -63,7 +71,7 @@ impl Demo for Materials {
|
|||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
color += calc_color(ray, world.unwrap(), 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod defocus_blur;
|
||||
mod dielectric_material;
|
||||
mod diffuse_materials;
|
||||
mod hitable_sphere;
|
||||
|
@ -9,6 +10,7 @@ mod simple_rectangle;
|
|||
mod simple_sphere;
|
||||
mod surface_normal_sphere;
|
||||
|
||||
pub use defocus_blur::DefocusBlur;
|
||||
pub use dielectric_material::DielectricMaterial;
|
||||
pub use diffuse_materials::DiffuseMaterials;
|
||||
pub use hitable_sphere::HitableSphere;
|
||||
|
@ -21,7 +23,10 @@ pub use simple_sphere::SimpleSphere;
|
|||
pub use surface_normal_sphere::SurfaceNormalSphere;
|
||||
|
||||
use {
|
||||
crate::{HORIZONTAL_PARTITION, VERTICAL_PARTITION},
|
||||
crate::{
|
||||
types::{HitableList, Vec3},
|
||||
Camera, HORIZONTAL_PARTITION, VERTICAL_PARTITION,
|
||||
},
|
||||
rayon::prelude::*,
|
||||
std::{
|
||||
fs::File,
|
||||
|
@ -45,45 +50,69 @@ pub trait Demo: std::marker::Sync {
|
|||
fn render(&self, buf: &mut Vec<u8>, width: usize, height: usize, samples: u8) {
|
||||
let nx = width / VERTICAL_PARTITION;
|
||||
let ny = height / HORIZONTAL_PARTITION;
|
||||
let world = self.world();
|
||||
let camera = self.camera(nx as f64 / ny as f64);
|
||||
|
||||
let buf = Arc::new(Mutex::new(buf));
|
||||
|
||||
(0..VERTICAL_PARTITION).into_par_iter().for_each(move |j| {
|
||||
(0..VERTICAL_PARTITION).into_par_iter().for_each(|j| {
|
||||
let buf = buf.clone();
|
||||
(0..HORIZONTAL_PARTITION)
|
||||
.into_par_iter()
|
||||
.for_each(move |i| {
|
||||
let start_y = j * ny;
|
||||
let start_x = i * nx;
|
||||
let x = width;
|
||||
let y = height;
|
||||
let mut chunk = Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
buffer: vec![0; nx * ny * 4],
|
||||
};
|
||||
self.render_chunk(&mut chunk, samples);
|
||||
(0..HORIZONTAL_PARTITION).into_par_iter().for_each(|i| {
|
||||
let start_y = j * ny;
|
||||
let start_x = i * nx;
|
||||
let x = width;
|
||||
let y = height;
|
||||
let mut chunk = Chunk {
|
||||
x,
|
||||
y,
|
||||
nx,
|
||||
ny,
|
||||
start_x,
|
||||
start_y,
|
||||
buffer: vec![0; nx * ny * 4],
|
||||
};
|
||||
self.render_chunk(&mut chunk, camera.as_ref(), world.as_ref(), samples);
|
||||
|
||||
let mut buf = buf.lock().unwrap();
|
||||
let mut buf = buf.lock().unwrap();
|
||||
|
||||
let mut temp_offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
let real_offset = ((y - j - 1) * x + start_x) * 4;
|
||||
let mut temp_offset = 0;
|
||||
for j in start_y..start_y + ny {
|
||||
let real_offset = ((y - j - 1) * x + start_x) * 4;
|
||||
|
||||
buf[real_offset..real_offset + nx * 4]
|
||||
.copy_from_slice(&chunk.buffer[temp_offset..temp_offset + nx * 4]);
|
||||
buf[real_offset..real_offset + nx * 4]
|
||||
.copy_from_slice(&chunk.buffer[temp_offset..temp_offset + nx * 4]);
|
||||
|
||||
temp_offset += nx * 4;
|
||||
}
|
||||
})
|
||||
temp_offset += nx * 4;
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8);
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
None
|
||||
}
|
||||
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(0.0, 0.0, 0.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
Some(Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
90.0,
|
||||
aspect_ratio,
|
||||
0.0,
|
||||
1.0,
|
||||
))
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
);
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
|
|
|
@ -17,17 +17,9 @@ impl Demo for PositionableCamera {
|
|||
"positionable-camera"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
let radius = (std::f64::consts::PI / 4.0).cos();
|
||||
|
||||
let world = HitableList {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::with_material(
|
||||
Vec3::new(-radius, 0.0, -1.0),
|
||||
|
@ -50,15 +42,39 @@ impl Demo for PositionableCamera {
|
|||
Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.0))),
|
||||
)),
|
||||
],
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
let camera = Camera::new(
|
||||
Vec3::new(-2.0, 2.0, 1.0),
|
||||
Vec3::new(0.0, 0.0, -1.0),
|
||||
fn camera(&self, aspect_ratio: f64) -> Option<Camera> {
|
||||
let lookfrom = Vec3::new(-2.0, 2.0, 1.0);
|
||||
let lookat = Vec3::new(0.0, 0.0, -1.0);
|
||||
Some(Camera::new(
|
||||
lookfrom,
|
||||
lookat,
|
||||
Vec3::new(0.0, 1.0, 0.0),
|
||||
68.0,
|
||||
nx as f64 / ny as f64,
|
||||
);
|
||||
aspect_ratio,
|
||||
0.0,
|
||||
1.0,
|
||||
))
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
let ny = chunk.ny;
|
||||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
let world = world.unwrap();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
|
@ -72,9 +88,7 @@ impl Demo for PositionableCamera {
|
|||
let ray = camera.get_ray(u, v);
|
||||
color += calc_color(ray, &world, 0);
|
||||
}
|
||||
|
||||
color /= samples as f64;
|
||||
|
||||
// gamma 2 corrected
|
||||
buffer[offset] = (255.99 * color.r().sqrt()) as u8;
|
||||
buffer[offset + 1] = (255.99 * color.g().sqrt()) as u8;
|
||||
|
|
|
@ -12,7 +12,23 @@ impl Demo for SimpleAntialiasing {
|
|||
fn name(&self) -> &'static str {
|
||||
"simple-antialiasing"
|
||||
}
|
||||
fn render_chunk(&self, chunk: &mut Chunk, samples: u8) {
|
||||
|
||||
fn world(&self) -> Option<HitableList> {
|
||||
Some(HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
camera: Option<&Camera>,
|
||||
world: Option<&HitableList>,
|
||||
samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
@ -20,15 +36,8 @@ impl Demo for SimpleAntialiasing {
|
|||
let start_x = chunk.start_x;
|
||||
let start_y = chunk.start_y;
|
||||
let buffer = &mut chunk.buffer;
|
||||
let camera = camera.unwrap();
|
||||
|
||||
let world = HitableList {
|
||||
list: vec![
|
||||
Box::new(Sphere::new(Vec3::new(0.0, 0.0, -1.0), 0.5)),
|
||||
Box::new(Sphere::new(Vec3::new(0.0, -100.5, -1.0), 100.0)),
|
||||
],
|
||||
};
|
||||
|
||||
let camera: Camera = Default::default();
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut offset = 0;
|
||||
|
||||
|
@ -40,7 +49,7 @@ impl Demo for SimpleAntialiasing {
|
|||
let v = (j as f64 + rng.gen::<f64>()) / y as f64;
|
||||
|
||||
let r = camera.get_ray(u, v);
|
||||
color += calc_color(r, &world);
|
||||
color += calc_color(r, world.unwrap());
|
||||
}
|
||||
color /= samples as f64;
|
||||
buffer[offset] = (255.99 * color.r()) as u8;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::demos::{Chunk, Demo};
|
||||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::HitableList,
|
||||
Camera,
|
||||
};
|
||||
|
||||
pub struct SimpleRectangle;
|
||||
|
||||
|
@ -7,7 +11,13 @@ impl Demo for SimpleRectangle {
|
|||
"simple_rectangle"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
_camera: Option<&Camera>,
|
||||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Ray, Vec3},
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
};
|
||||
|
||||
const RADIUS: f64 = 0.5;
|
||||
|
@ -12,7 +13,13 @@ impl Demo for SimpleSphere {
|
|||
"simple_sphere"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
_camera: Option<&Camera>,
|
||||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{
|
||||
demos::{Chunk, Demo},
|
||||
types::{Ray, Vec3},
|
||||
types::{HitableList, Ray, Vec3},
|
||||
Camera,
|
||||
};
|
||||
|
||||
const RADIUS: f64 = 0.5;
|
||||
|
@ -11,7 +12,13 @@ impl Demo for SurfaceNormalSphere {
|
|||
"surface_normal_sphere"
|
||||
}
|
||||
|
||||
fn render_chunk(&self, chunk: &mut Chunk, _samples: u8) {
|
||||
fn render_chunk(
|
||||
&self,
|
||||
chunk: &mut Chunk,
|
||||
_camera: Option<&Camera>,
|
||||
_world: Option<&HitableList>,
|
||||
_samples: u8,
|
||||
) {
|
||||
let x = chunk.x;
|
||||
let y = chunk.y;
|
||||
let nx = chunk.nx;
|
||||
|
|
|
@ -80,6 +80,7 @@ fn main() -> Result<(), String> {
|
|||
Some(Keycode::Num8) => active_demo = Box::new(demos::Materials),
|
||||
Some(Keycode::Num9) => active_demo = Box::new(demos::DielectricMaterial),
|
||||
Some(Keycode::Num0) => active_demo = Box::new(demos::PositionableCamera),
|
||||
Some(Keycode::Minus) => active_demo = Box::new(demos::DefocusBlur),
|
||||
None => unreachable!(),
|
||||
_ => (),
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ pub struct HitRecord<'a> {
|
|||
pub material: Option<&'a Box<dyn Material>>,
|
||||
}
|
||||
|
||||
pub trait Hitable {
|
||||
pub trait Hitable: Send + Sync {
|
||||
fn hit(&self, _ray: &Ray, _t_min: f64, _t_max: f64) -> Option<HitRecord> {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use {
|
|||
rand::Rng,
|
||||
};
|
||||
|
||||
pub trait Material {
|
||||
pub trait Material: Send + Sync {
|
||||
fn scatter(&self, ray: &Ray, hit_rec: &HitRecord) -> (Vec3, Option<Ray>);
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,8 @@ impl Material for Dielectric {
|
|||
}
|
||||
}
|
||||
|
||||
// Polynomial approximation to figure out reflectivity as the angle changes
|
||||
// Christophe Schlick's Polynomial approximation to figure out reflectivity as the angle changes
|
||||
// See Fresnel Equations, https://en.wikipedia.org/wiki/Fresnel_equations
|
||||
fn schlick(cosine: f64, reflection_index: f64) -> f64 {
|
||||
let mut r0 = (1.0 - reflection_index) / (1.0 + reflection_index);
|
||||
r0 = r0 * r0;
|
||||
|
|
Loading…
Reference in New Issue
Block a user