use std::time::Instant; use anyhow::Result; use structopt::StructOpt; use rtchallenge::{ camera::{Camera, RenderStrategy}, float::consts::PI, lights::PointLight, materials::Material, matrices::Matrix4x4, spheres::Sphere, transformations::view_transform, tuples::{Color, Tuple}, world::World, WHITE, }; /// End of chapter 8 challenge. #[derive(StructOpt, Debug)] #[structopt(name = "eoc8")] 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 = Sphere::default(); floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.)); floor.material = Material { color: Color::new(1., 0.9, 0.9), specular: 0., ..Material::default() }; let mut left_wall = Sphere::default(); left_wall.set_transform( Matrix4x4::translation(0., 0., 5.) * Matrix4x4::rotation_y(-PI / 4.) * Matrix4x4::rotation_x(PI / 2.) * Matrix4x4::scaling(10., 0.01, 10.), ); left_wall.material = floor.material.clone(); let mut right_wall = Sphere::default(); right_wall.set_transform( Matrix4x4::translation(0., 0., 5.) * Matrix4x4::rotation_y(PI / 4.) * Matrix4x4::rotation_x(PI / 2.) * Matrix4x4::scaling(10., 0.00001, 10.), ); right_wall.material = floor.material.clone(); let mut middle = Sphere::default(); 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 = Sphere::default(); 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 = Sphere::default(); 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, light3]; world.objects = vec![floor, left_wall, right_wall, middle, right, left]; let image = camera.render(&world); let path = "/tmp/eoc8.png"; println!("saving output to {}", path); image.write_to_file(path)?; println!("Render time {:.3} seconds", start.elapsed().as_secs_f32()); Ok(()) }