diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index 7745348..81fd764 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -29,20 +29,93 @@ fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 { Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t } +fn random_scene() -> Vec> { + let mut rng = rand::thread_rng(); + let mut objects: Vec> = vec![Box::new(Sphere::new( + Vec3::new(0., -1000., 0.), + 1000., + Box::new(Lambertian::new(Vec3::new(0.5, 0.5, 0.5))), + ))]; + let mut random = || rng.gen_range::(0., 1.); + + for a in -11..11 { + for b in -11..11 { + let choose_mat = random(); + let center = Vec3::new(a as f32 + 0.9 * random(), 0.2, b as f32 + 0.9 * random()); + if (center - Vec3::new(4., 0.2, 0.)).length() > 0.9 { + let sphere = if choose_mat < 0.8 { + // diffuse + Box::new(Sphere::new( + center, + 0.2, + Box::new(Lambertian::new(Vec3::new( + random() * random(), + random() * random(), + random() * random(), + ))), + )) + } else if choose_mat < 0.95 { + // metal + Box::new(Sphere::new( + center, + 0.2, + Box::new(Metal::new( + Vec3::new( + 0.5 * (1. + random()), + 0.5 * (1. + random()), + 0.5 * (1. + random()), + ), + 0.5 * random(), + )), + )) + } else { + // glass + Box::new(Sphere::new(center, 0.2, Box::new(Dielectric::new(1.5)))) + }; + objects.push(sphere); + }; + } + } + + let more: Vec> = vec![ + Box::new(Sphere::new( + Vec3::new(0., 1., 0.), + 1.0, + Box::new(Dielectric::new(1.5)), + )), + Box::new(Sphere::new( + Vec3::new(-4., 1., 0.), + 1.0, + Box::new(Lambertian::new(Vec3::new(0.4, 0.2, 0.1))), + )), + Box::new(Sphere::new( + Vec3::new(4., 1., 0.), + 1.0, + Box::new(Metal::new(Vec3::new(0.7, 0.6, 0.5), 0.0)), + )), + ]; + objects.extend(more); + objects +} + fn main() -> Result<(), std::io::Error> { let mut rng = rand::thread_rng(); let nx = 200; let ny = 100; let ns = 100; - println!("P3\n{} {}\n255", nx, ny); - let cam = Camera::new_lookfrom_vfov( - Vec3::new(-2., 2., 1.), - Vec3::new(0., 0., -1.), + let lookfrom = Vec3::new(3., 3., 2.); + let lookat = Vec3::new(0., 0., -1.); + let dist_to_focus = (lookfrom - lookat).length(); + let aperture = 2.; + let cam = Camera::new( + lookfrom, + lookat, Vec3::new(0., 1., 0.), - 45., + 20., nx as f32 / ny as f32, + aperture, + dist_to_focus, ); - // TODO(wathiede): Box this instead of using references. let world = HitableList::new(vec![ Box::new(Sphere::new( Vec3::new(0., 0., -1.), @@ -70,6 +143,8 @@ fn main() -> Result<(), std::io::Error> { Box::new(Dielectric::new(1.5)), )), ]); + //let world = HitableList::new(random_scene()); + println!("P3\n{} {}\n255", nx, ny); for j in (0..ny).rev() { for i in 0..nx { let mut col: Vec3 = Default::default(); diff --git a/rtiow/src/bin/tracer_dielectric.rs b/rtiow/src/bin/tracer_dielectric.rs deleted file mode 100644 index a4a4d69..0000000 --- a/rtiow/src/bin/tracer_dielectric.rs +++ /dev/null @@ -1,86 +0,0 @@ -extern crate rand; -extern crate rtiow; - -use rand::Rng; - -use rtiow::camera::Camera; -use rtiow::hitable::Hit; -use rtiow::hitable_list::HitableList; -use rtiow::material::Dielectric; -use rtiow::material::Lambertian; -use rtiow::material::Metal; -use rtiow::ray::Ray; -use rtiow::sphere::Sphere; -use rtiow::vec3::Vec3; - -fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 { - if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) { - let scatter_response = rec.material.scatter(&r, &rec); - if depth < 50 && scatter_response.reflected { - return scatter_response.attenutation - * color(scatter_response.scattered, world, depth + 1); - } - return Default::default(); - } - - // No hit, choose color from background. - let unit_direction = r.direction().unit_vector(); - let t = 0.5 * (unit_direction.y + 1.); - Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t -} - -fn main() -> Result<(), std::io::Error> { - let mut rng = rand::thread_rng(); - let nx = 200; - let ny = 100; - let ns = 100; - println!("P3\n{} {}\n255", nx, ny); - let world = HitableList::new(vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.))), - )), - Box::new(Sphere::new( - Vec3::new(1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - 0.5, - Box::new(Dielectric::new(1.5)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - -0.45, - Box::new(Dielectric::new(1.5)), - )), - ]); - let cam = Camera::new2x1(); - for j in (0..ny).rev() { - for i in 0..nx { - let mut col: Vec3 = Default::default(); - for _ in 0..ns { - let u = (rng.gen_range::(0., 1.) + i as f32) / nx as f32; - let v = (rng.gen_range::(0., 1.) + j as f32) / ny as f32; - let r = cam.get_ray(u, v); - col = col + color(r, &world, 0); - } - col = col / ns as f32; - // Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 - // or sqrt. - col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt()); - let ir = (255.99 * col[0]) as u32; - let ig = (255.99 * col[1]) as u32; - let ib = (255.99 * col[2]) as u32; - println!("{} {} {}", ir, ig, ib); - } - } - Ok(()) -} diff --git a/rtiow/src/bin/tracer_material.rs b/rtiow/src/bin/tracer_material.rs deleted file mode 100644 index b47e461..0000000 --- a/rtiow/src/bin/tracer_material.rs +++ /dev/null @@ -1,80 +0,0 @@ -extern crate rand; -extern crate rtiow; - -use rand::Rng; - -use rtiow::camera::Camera; -use rtiow::hitable::Hit; -use rtiow::hitable_list::HitableList; -use rtiow::material::Lambertian; -use rtiow::material::Metal; -use rtiow::ray::Ray; -use rtiow::sphere::Sphere; -use rtiow::vec3::Vec3; - -fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 { - if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) { - let scatter_response = rec.material.scatter(&r, &rec); - if depth < 50 && scatter_response.reflected { - return scatter_response.attenutation - * color(scatter_response.scattered, world, depth + 1); - } - return Default::default(); - } - - // No hit, choose color from background. - let unit_direction = r.direction().unit_vector(); - let t = 0.5 * (unit_direction.y + 1.); - Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t -} - -fn main() -> Result<(), std::io::Error> { - let mut rng = rand::thread_rng(); - let nx = 200; - let ny = 100; - let ns = 100; - println!("P3\n{} {}\n255", nx, ny); - let world = HitableList::new(vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.8, 0.3, 0.3))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.))), - )), - Box::new(Sphere::new( - Vec3::new(1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.8)), - )), - ]); - let cam = Camera::new2x1(); - for j in (0..ny).rev() { - for i in 0..nx { - let mut col: Vec3 = Default::default(); - for _ in 0..ns { - let u = (rng.gen_range::(0., 1.) + i as f32) / nx as f32; - let v = (rng.gen_range::(0., 1.) + j as f32) / ny as f32; - let r = cam.get_ray(u, v); - col = col + color(r, &world, 0); - } - col = col / ns as f32; - // Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 - // or sqrt. - col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt()); - let ir = (255.99 * col[0]) as u32; - let ig = (255.99 * col[1]) as u32; - let ib = (255.99 * col[2]) as u32; - println!("{} {} {}", ir, ig, ib); - } - } - Ok(()) -} diff --git a/rtiow/src/bin/tracer_positionable_camera.rs b/rtiow/src/bin/tracer_positionable_camera.rs deleted file mode 100644 index fb58629..0000000 --- a/rtiow/src/bin/tracer_positionable_camera.rs +++ /dev/null @@ -1,92 +0,0 @@ -extern crate rand; -extern crate rtiow; - -use rand::Rng; - -use rtiow::camera::Camera; -use rtiow::hitable::Hit; -use rtiow::hitable_list::HitableList; -use rtiow::material::Dielectric; -use rtiow::material::Lambertian; -use rtiow::material::Metal; -use rtiow::ray::Ray; -use rtiow::sphere::Sphere; -use rtiow::vec3::Vec3; - -fn color(r: Ray, world: &Hit, depth: usize) -> Vec3 { - if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) { - let scatter_response = rec.material.scatter(&r, &rec); - if depth < 50 && scatter_response.reflected { - return scatter_response.attenutation - * color(scatter_response.scattered, world, depth + 1); - } - return Default::default(); - } - - // No hit, choose color from background. - let unit_direction = r.direction().unit_vector(); - let t = 0.5 * (unit_direction.y + 1.); - Vec3::new(1., 1., 1.) * (1. - t) + Vec3::new(0.5, 0.7, 1.) * t -} - -fn main() -> Result<(), std::io::Error> { - let mut rng = rand::thread_rng(); - let nx = 200; - let ny = 100; - let ns = 100; - println!("P3\n{} {}\n255", nx, ny); - let world = HitableList::new(vec![ - Box::new(Sphere::new( - Vec3::new(0., 0., -1.), - 0.5, - Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), - )), - Box::new(Sphere::new( - Vec3::new(0., -100.5, -1.), - 100., - Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.))), - )), - Box::new(Sphere::new( - Vec3::new(1., 0., -1.), - 0.5, - Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - 0.5, - Box::new(Dielectric::new(1.5)), - )), - Box::new(Sphere::new( - Vec3::new(-1., 0., -1.), - -0.45, - Box::new(Dielectric::new(1.5)), - )), - ]); - let cam = Camera::new_lookfrom_vfov( - Vec3::new(-2., 2., 1.), - Vec3::new(0., 0., -1.), - Vec3::new(0., 1., 0.), - 90., - nx as f32 / ny as f32, - ); - for j in (0..ny).rev() { - for i in 0..nx { - let mut col: Vec3 = Default::default(); - for _ in 0..ns { - let u = (rng.gen_range::(0., 1.) + i as f32) / nx as f32; - let v = (rng.gen_range::(0., 1.) + j as f32) / ny as f32; - let r = cam.get_ray(u, v); - col = col + color(r, &world, 0); - } - col = col / ns as f32; - // Gamma correct, use gamma 2 correction, which is 1/gamma where gamma=2 which is 1/2 - // or sqrt. - col = Vec3::new(col[0].sqrt(), col[1].sqrt(), col[2].sqrt()); - let ir = (255.99 * col[0]) as u32; - let ig = (255.99 * col[1]) as u32; - let ib = (255.99 * col[2]) as u32; - println!("{} {} {}", ir, ig, ib); - } - } - Ok(()) -} diff --git a/rtiow/src/camera.rs b/rtiow/src/camera.rs index 4ed5286..7a815a6 100644 --- a/rtiow/src/camera.rs +++ b/rtiow/src/camera.rs @@ -1,33 +1,48 @@ +extern crate rand; use std::f32::consts::PI; +use self::rand::Rng; + use ray::Ray; use vec3::cross; use vec3::Vec3; +fn random_in_unit_disk() -> Vec3 { + let mut rng = rand::thread_rng(); + let v = Vec3::new(1., 1., 0.); + loop { + let p = 2. * Vec3::new( + rng.gen_range::(0., 1.), + rng.gen_range::(0., 1.), + 0., + ) - v; + if p.squared_length() < 1. { + return p; + } + } +} + pub struct Camera { origin: Vec3, lower_left_corner: Vec3, horizontal: Vec3, vertical: Vec3, + u: Vec3, + v: Vec3, + w: Vec3, + lens_radius: f32, } impl Camera { - pub fn new2x1() -> Camera { - Camera { - lower_left_corner: Vec3::new(-2., -1., -1.), - horizontal: Vec3::new(4., 0., 0.), - vertical: Vec3::new(0., 2., 0.), - origin: Default::default(), - } - } - // vfov is top to bottom in degrees - pub fn new_lookfrom_vfov( + pub fn new( lookfrom: Vec3, lookat: Vec3, vup: Vec3, vfov: f32, aspect: f32, + aperture: f32, + focus_dist: f32, ) -> Camera { let theta = vfov * PI / 180.; let half_height = (theta / 2.).tan(); @@ -37,30 +52,26 @@ impl Camera { let u = cross(vup, w).unit_vector(); let v = cross(w, u); Camera { - lower_left_corner: origin - half_width * u - half_height * v - w, - horizontal: 2. * half_width * u, - vertical: 2. * half_height * v, + lower_left_corner: origin + - half_width * focus_dist * u + - half_height * focus_dist * v + - focus_dist * w, + horizontal: 2. * half_width * focus_dist * u, + vertical: 2. * half_height * focus_dist * v, origin, - } - } - - // vfov is top to bottom in degrees - pub fn new_vfov(vfov: f32, aspect: f32) -> Camera { - let theta = vfov * PI / 180.; - let half_height = (theta / 2.).tan(); - let half_width = aspect * half_height; - Camera { - lower_left_corner: Vec3::new(-half_width, -half_height, -1.), - horizontal: Vec3::new(2. * half_width, 0., 0.), - vertical: Vec3::new(0., 2. * half_height, 0.), - origin: Default::default(), + w: (lookfrom - lookat).unit_vector(), + u: cross(vup, w).unit_vector(), + v: cross(w, u), + lens_radius: aperture / 2., } } pub fn get_ray(&self, u: f32, v: f32) -> Ray { + let rd = self.lens_radius * random_in_unit_disk(); + 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, ) } }