diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index fd4de3d..861e4b5 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -58,7 +58,13 @@ fn main() -> Result<(), std::io::Error> { Box::new(Dielectric::new(1.5)), ), ]; - let cam = Camera::new2x1(); + 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, + ); let world = HitableList::new(objects.iter().map(|o| o).collect()); for j in (0..ny).rev() { for i in 0..nx { diff --git a/rtiow/src/bin/tracer_positionable_camera.rs b/rtiow/src/bin/tracer_positionable_camera.rs new file mode 100644 index 0000000..861e4b5 --- /dev/null +++ b/rtiow/src/bin/tracer_positionable_camera.rs @@ -0,0 +1,89 @@ +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 objects = vec![ + Sphere::new( + Vec3::new(0., 0., -1.), + 0.5, + Box::new(Lambertian::new(Vec3::new(0.1, 0.2, 0.5))), + ), + Sphere::new( + Vec3::new(0., -100.5, -1.), + 100., + Box::new(Lambertian::new(Vec3::new(0.8, 0.8, 0.))), + ), + Sphere::new( + Vec3::new(1., 0., -1.), + 0.5, + Box::new(Metal::new(Vec3::new(0.8, 0.6, 0.2), 0.2)), + ), + Sphere::new(Vec3::new(-1., 0., -1.), 0.5, Box::new(Dielectric::new(1.5))), + 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, + ); + let world = HitableList::new(objects.iter().map(|o| o).collect()); + 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 d9a3d56..4ed5286 100644 --- a/rtiow/src/camera.rs +++ b/rtiow/src/camera.rs @@ -1,4 +1,7 @@ +use std::f32::consts::PI; + use ray::Ray; +use vec3::cross; use vec3::Vec3; pub struct Camera { @@ -18,6 +21,42 @@ impl Camera { } } + // vfov is top to bottom in degrees + pub fn new_lookfrom_vfov( + lookfrom: Vec3, + lookat: Vec3, + vup: Vec3, + vfov: f32, + aspect: f32, + ) -> Camera { + let theta = vfov * PI / 180.; + let half_height = (theta / 2.).tan(); + let half_width = aspect * half_height; + let origin = lookfrom; + let w = (lookfrom - lookat).unit_vector(); + 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, + 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(), + } + } + pub fn get_ray(&self, u: f32, v: f32) -> Ray { Ray::new( self.origin, diff --git a/rtiow/src/vec3.rs b/rtiow/src/vec3.rs index 981df5c..65f938c 100644 --- a/rtiow/src/vec3.rs +++ b/rtiow/src/vec3.rs @@ -18,7 +18,7 @@ pub struct Vec3 { pub fn cross(v1: Vec3, v2: Vec3) -> Vec3 { Vec3 { x: v1.y * v2.z - v1.z * v2.y, - y: v1.x * v2.z - v1.z * v2.x, + y: v1.z * v2.x - v1.x * v2.z, z: v1.x * v2.y - v1.y * v2.x, } }