From 270a7ec34953a385f24394a97d6dd9971b7b7099 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Thu, 5 Aug 2021 20:41:47 -0700 Subject: [PATCH] eoc12: show use of cube. --- rtchallenge/examples/eoc12.rs | 232 ++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 rtchallenge/examples/eoc12.rs diff --git a/rtchallenge/examples/eoc12.rs b/rtchallenge/examples/eoc12.rs new file mode 100644 index 0000000..99b12dc --- /dev/null +++ b/rtchallenge/examples/eoc12.rs @@ -0,0 +1,232 @@ +use std::time::Instant; + +use anyhow::Result; +use structopt::StructOpt; + +use rtchallenge::prelude::*; + +use rtchallenge::{ + camera::RenderStrategy, + float::consts::PI, + patterns::{test_pattern, BLACK_PAT, WHITE_PAT}, + WHITE, +}; + +/// End of chapter 12 challenge. +#[derive(StructOpt, Debug)] +#[structopt(name = "eoc12")] +struct Opt { + /// Strategy for casting rays into image. + #[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, + /// Rendered image width in pixels. + #[structopt(short, long, default_value = "2560")] + width: usize, + /// Rendered image height in pixels. + #[structopt(short, long, default_value = "1440")] + height: usize, +} + +fn main() -> Result<()> { + let start = Instant::now(); + let opt = Opt::from_args(); + + let light1 = PointLightBuilder::default() + .position(point(-5., 5., -5.)) + .intensity(WHITE) + .build()?; + let light2 = PointLightBuilder::default() + .position(point(5., 5., -5.)) + .intensity([0.2, 0.2, 0.6]) + .build()?; + let light3 = PointLightBuilder::default() + .position(point(0., 2., -5.)) + .intensity([0.2, 0.2, 0.1]) + .build()?; + + let from = point(2., 8., -10.); + let to = point(2., 1., -1.); + let up = point(0., 1., 0.); + let camera = CameraBuilder::default() + .hsize(opt.width) + .vsize(opt.height) + .field_of_view(PI / 6.) + .transform(view_transform(from, to, up)) + .render_strategy(opt.render_strategy) + .samples_per_pixel(opt.samples) + .build()?; + + let floor = plane() + .material( + MaterialBuilder::default() + .color( + checkers_pattern( + ring_pattern([0.8, 0.8, 0.2].into(), [0.8, 0.2, 0.8].into()) + .transform(scaling(1. / 8., 1. / 8., 1. / 8.)) + .build()?, + ring_pattern([0.2, 0.8, 0.2].into(), [0.8, 0.2, 0.2].into()) + .transform(scaling(1. / 4., 1. / 4., 1. / 4.)) + .build()?, + ) + .transform(translation(0., 1., 0.) * scaling(2., 2., 2.)) + .build()?, + ) + .specular(0.) + .reflective(0.5) + .build()?, + ) + .build()?; + let sphere_size = scaling(0.5, 0.5, 0.5); + + let x1y1 = sphere() + .transform(translation(1., 1., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color( + gradient_pattern([0., 0., 1.].into(), [1., 1., 0.].into()) + .transform(scaling(2., 1., 1.) * translation(-0.5, 0., 0.)) + .build()?, + ) + .diffuse(0.7) + .specular(0.3) + .reflective(0.5) + .build()?, + ) + .build()?; + + let x2y1 = sphere() + .transform(translation(2., 1., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color(stripe_pattern(WHITE_PAT, BLACK_PAT).build()?) + .diffuse(0.7) + .specular(0.3) + .build()?, + ) + .build()?; + + let x3y1 = sphere() + .transform(translation(3., 1., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color( + stripe_pattern(WHITE_PAT, BLACK_PAT) + .transform(scaling(0.2, 1., 1.)) + .build()?, + ) + .diffuse(0.7) + .specular(0.0) + .build()?, + ) + .build()?; + + let x1y2 = sphere() + .transform(translation(1., 2., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color(test_pattern().build()?) + .diffuse(0.7) + .specular(0.3) + .build()?, + ) + .build()?; + + let x2y2 = sphere() + .transform(translation(2., 2., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color( + ring_pattern(WHITE_PAT, BLACK_PAT) + .transform(scaling(0.2, 0.2, 0.2)) + .build()?, + ) + .diffuse(0.7) + .specular(0.3) + .build()?, + ) + .build()?; + + let x3y2 = sphere() + .transform(translation(3., 2., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color( + checkers_pattern(WHITE_PAT, BLACK_PAT) + .transform(scaling(0.5, 0.5, 0.5)) + .build()?, + ) + .diffuse(0.7) + .specular(0.3) + .build()?, + ) + .build()?; + + let x1y2z1 = sphere() + .transform(translation(1., 2., -1.) * sphere_size) + .material( + MaterialBuilder::default() + .color([0.8, 0.2, 0.2]) + .diffuse(0.7) + .specular(0.3) + .transparency(0.5) + .build()?, + ) + .build()?; + + let x2y2z1 = sphere() + .transform(translation(2., 2., -1.) * sphere_size) + .material( + MaterialBuilder::default() + .color([0.8, 0.2, 0.2]) + .diffuse(0.7) + .specular(0.3) + .transparency(0.9) + .refractive_index(1.5) + .build()?, + ) + .build()?; + + let x3y2z1 = cube() + .transform( + translation(3., 2., -1.) * (sphere_size * scaling(0.5, 0.5, 0.5)) * rotation_y(PI / 4.), + ) + .material( + MaterialBuilder::default() + .color([0.8, 0.8, 0.2]) + .diffuse(0.7) + .specular(0.3) + .reflective(0.5) + .build()?, + ) + .build()?; + + let x2y4z1 = sphere() + .transform(translation(2., 4., 0.) * sphere_size) + .material( + MaterialBuilder::default() + .color([0.2, 0.2, 0.8]) + .diffuse(0.7) + .specular(0.3) + .build()?, + ) + .build()?; + + let world = WorldBuilder::default() + .lights(vec![light1, light2, light3]) + .objects(vec![ + floor, x1y1, x2y1, x3y1, x1y2, x2y2, x3y2, x1y2z1, x2y2z1, x2y4z1, x3y2z1, + ]) + .build()?; + + let image = camera.render(&world); + + let path = "/tmp/eoc12.png"; + println!("saving output to {}", path); + image.write_to_file(path)?; + println!("Render time {:.3} seconds", start.elapsed().as_secs_f32()); + Ok(()) +}