diff --git a/rtiow/src/bin/tracer.rs b/rtiow/src/bin/tracer.rs index 50c790c..acb5500 100644 --- a/rtiow/src/bin/tracer.rs +++ b/rtiow/src/bin/tracer.rs @@ -10,9 +10,26 @@ use rtiow::ray::Ray; use rtiow::sphere::Sphere; use rtiow::vec3::Vec3; +fn random_in_unit_sphere() -> Vec3 { + let mut rng = rand::thread_rng(); + let v = Vec3::new(1., 1., 1.); + loop { + let p = 2. * Vec3::new( + rng.gen_range::(0., 1.), + rng.gen_range::(0., 1.), + rng.gen_range::(0., 1.), + ) - v; + if p.squared_length() < 1. { + return p; + } + } +} + fn color(r: Ray, world: &Hit) -> Vec3 { - if let Some(rec) = world.hit(r, 0., std::f32::MAX) { - return (rec.normal + 1.) * 0.5; + if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) { + let target = rec.p + rec.normal + random_in_unit_sphere(); + // 50% grey material + return 0.5 * color(Ray::new(rec.p, target - rec.p), world); } // No hit, choose color from background. @@ -43,6 +60,9 @@ fn main() -> Result<(), std::io::Error> { col = col + color(r, &world); } 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; diff --git a/rtiow/src/bin/tracer_diffuse.rs b/rtiow/src/bin/tracer_diffuse.rs new file mode 100644 index 0000000..acb5500 --- /dev/null +++ b/rtiow/src/bin/tracer_diffuse.rs @@ -0,0 +1,73 @@ +extern crate rand; +extern crate rtiow; + +use rand::Rng; + +use rtiow::camera::Camera; +use rtiow::hitable::Hit; +use rtiow::hitable_list::HitableList; +use rtiow::ray::Ray; +use rtiow::sphere::Sphere; +use rtiow::vec3::Vec3; + +fn random_in_unit_sphere() -> Vec3 { + let mut rng = rand::thread_rng(); + let v = Vec3::new(1., 1., 1.); + loop { + let p = 2. * Vec3::new( + rng.gen_range::(0., 1.), + rng.gen_range::(0., 1.), + rng.gen_range::(0., 1.), + ) - v; + if p.squared_length() < 1. { + return p; + } + } +} + +fn color(r: Ray, world: &Hit) -> Vec3 { + if let Some(rec) = world.hit(r, 0.001, std::f32::MAX) { + let target = rec.p + rec.normal + random_in_unit_sphere(); + // 50% grey material + return 0.5 * color(Ray::new(rec.p, target - rec.p), world); + } + + // 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), + Sphere::new(Vec3::new(0., -100.5, -1.), 100.), + ]; + let cam = Camera::new2x1(); + 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); + } + 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/vec3.rs b/rtiow/src/vec3.rs index 6caccfe..fd70a7e 100644 --- a/rtiow/src/vec3.rs +++ b/rtiow/src/vec3.rs @@ -131,6 +131,18 @@ impl Mul for Vec3 { } } +impl Mul for f32 { + type Output = Vec3; + + fn mul(self, v: Vec3) -> Vec3 { + Vec3 { + x: v.x * self, + y: v.y * self, + z: v.z * self, + } + } +} + impl Mul for Vec3 { type Output = Vec3;