diff --git a/rtchallenge/examples/eoc9.rs b/rtchallenge/examples/eoc9.rs new file mode 100644 index 0000000..217c5a8 --- /dev/null +++ b/rtchallenge/examples/eoc9.rs @@ -0,0 +1,101 @@ +use std::time::Instant; + +use anyhow::Result; +use structopt::StructOpt; + +use rtchallenge::{ + camera::{Camera, RenderStrategy}, + float::consts::PI, + lights::PointLight, + materials::Material, + matrices::Matrix4x4, + shapes::Shape, + transformations::view_transform, + tuples::{Color, Tuple}, + world::World, + WHITE, +}; + +/// End of chapter 9 challenge. +#[derive(StructOpt, Debug)] +#[structopt(name = "eoc9")] +struct Opt { + #[structopt(long, default_value = "rayon")] + render_strategy: RenderStrategy, + /// Number of samples per pixel. 0 renders from the center of the pixel, 1 or more samples N + /// times randomly across the pixel. + #[structopt(short, long, default_value = "0")] + samples: usize, +} + +fn main() -> Result<()> { + let start = Instant::now(); + let opt = Opt::from_args(); + let width = 2560; + let height = 1440; + + let light_position = Tuple::point(-10., 10., -10.); + let light_color = WHITE; + let light1 = PointLight::new(light_position, light_color); + let light_position = Tuple::point(10., 10., -10.); + let light_color = Color::new(0.2, 0.2, 0.2); + let light2 = PointLight::new(light_position, light_color); + let light_position = Tuple::point(0., 10., -10.); + let light3 = PointLight::new(light_position, light_color); + + let mut camera = Camera::new(width, height, PI / 4.); + let from = Tuple::point(0., 1.5, -5.); + let to = Tuple::point(0., 1., 0.); + let up = Tuple::point(0., 1., 0.); + camera.set_transform(view_transform(from, to, up)); + camera.render_strategy = opt.render_strategy; + camera.samples_per_pixel = opt.samples; + + let mut floor = Shape::plane(); + floor.material = Material { + color: Color::new(1., 0.9, 0.9), + specular: 0., + ..Material::default() + }; + + let mut middle = Shape::sphere(); + middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5)); + middle.material = Material { + color: Color::new(0.1, 1., 0.5), + diffuse: 0.7, + specular: 0.3, + ..Material::default() + }; + + let mut right = Shape::sphere(); + right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5)); + right.material = Material { + color: Color::new(1., 1., 1.), + diffuse: 0.7, + specular: 0.0, + ..Material::default() + }; + + let mut left = Shape::sphere(); + left.set_transform( + Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33), + ); + left.material = Material { + color: Color::new(1., 0.8, 0.1), + diffuse: 0.7, + specular: 0.3, + ..Material::default() + }; + + let mut world = World::default(); + world.lights = vec![light1, light2]; + world.objects = vec![floor, middle, right, left]; + + let image = camera.render(&world); + + let path = "/tmp/eoc9.png"; + println!("saving output to {}", path); + image.write_to_file(path)?; + println!("Render time {:.3} seconds", start.elapsed().as_secs_f32()); + Ok(()) +}