use std::time::Instant; use anyhow::Result; use structopt::StructOpt; use rtchallenge::{ camera::{Camera, RenderStrategy}, float::consts::PI, lights::PointLightBuilder, materials::MaterialBuilder, matrices::Matrix4x4, shapes::{Geometry, ShapeBuilder}, transformations::view_transform, tuples::Tuple, world::WorldBuilder, Float, WHITE, }; /// Experimenting with balls. #[derive(StructOpt, Debug)] #[structopt(name = "balls")] 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 light1 = PointLightBuilder::default() .position(Tuple::point(-5., 5., -5.)) .intensity(WHITE) .build()?; let light2 = PointLightBuilder::default() .position(Tuple::point(5., 5., -5.)) .intensity([0.2, 0.2, 0.6]) .build()?; let light3 = PointLightBuilder::default() .position(Tuple::point(0., 2., -5.)) .intensity([0.2, 0.2, 0.1]) .build()?; let ball_size = 0.5; let num_per_axis = 3; let center_to_center = 4. * ball_size; let from = Tuple::point( -5. * center_to_center, 5. * center_to_center, -4. * center_to_center, ); let to = Tuple::point( num_per_axis as Float * center_to_center / 2., 0., //num_per_axis as Float * center_to_center / 2., num_per_axis as Float * center_to_center / 2., ); let up = Tuple::point(0., 1., 0.); let mut camera = Camera::new(width, height, PI / 6.); camera.set_transform(view_transform(from, to, up)); camera.render_strategy = opt.render_strategy; camera.samples_per_pixel = opt.samples; let floor = ShapeBuilder::default() .geometry(Geometry::Plane) .transform(Matrix4x4::translation(0., -ball_size, 0.)) .material( MaterialBuilder::default() .color([0.2, 0.2, 0.2]) .specular(0.) .build()?, ) .build()?; let mut objects = vec![floor]; for z in 0..num_per_axis { for y in 0..num_per_axis { for x in 0..num_per_axis { objects.push( ShapeBuilder::default() .transform( Matrix4x4::translation( x as Float * center_to_center, y as Float * center_to_center, z as Float * center_to_center, ) * Matrix4x4::scaling(ball_size, ball_size, ball_size), ) .material( MaterialBuilder::default() .color([0.1, 1., 0.5]) .ambient(y as Float / 4.) .diffuse(x as Float / 4.) .specular(z as Float / 4.) .build()?, ) .build()?, ); } } } let world = WorldBuilder::default() .lights(vec![light1, light2, light3]) .objects(objects) .build()?; let image = camera.render(&world); let path = "/tmp/balls.png"; println!("saving output to {}", path); image.write_to_file(path)?; println!("Render time {:.3} seconds", start.elapsed().as_secs_f32()); Ok(()) }