eoc11: example illustrating concepts from chapter 11 and extended pattern concepts from chapter 10.

This commit is contained in:
Bill Thiede 2021-08-01 19:18:07 -07:00
parent 926fffa29f
commit 7a80179f41

View File

@ -0,0 +1,218 @@
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 11 challenge.
#[derive(StructOpt, Debug)]
#[structopt(name = "eoc11")]
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 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,
])
.build()?;
let image = camera.render(&world);
let path = "/tmp/eoc11.png";
println!("saving output to {}", path);
image.write_to_file(path)?;
println!("Render time {:.3} seconds", start.elapsed().as_secs_f32());
Ok(())
}