172 lines
5.0 KiB
Rust
172 lines
5.0 KiB
Rust
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 10 challenge.
|
|
#[derive(StructOpt, Debug)]
|
|
#[structopt(name = "eoc10")]
|
|
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., 2., -10.);
|
|
let to = point(2., 1., 0.);
|
|
let up = point(0., 1., 0.);
|
|
let camera = CameraBuilder::default()
|
|
.hsize(opt.width)
|
|
.vsize(opt.height)
|
|
.field_of_view(PI / 4.)
|
|
.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(WHITE_PAT, BLACK_PAT)
|
|
.transform(translation(1., 0., 0.) * scaling(2., 2., 2.))
|
|
.build()?,
|
|
)
|
|
.specular(0.)
|
|
.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)
|
|
.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 world = WorldBuilder::default()
|
|
.lights(vec![light1, light2, light3])
|
|
.objects(vec![floor, x1y1, x2y1, x3y1, x1y2, x2y2, x3y2])
|
|
.build()?;
|
|
|
|
let image = camera.render(&world);
|
|
|
|
let path = "/tmp/eoc10.png";
|
|
println!("saving output to {}", path);
|
|
image.write_to_file(path)?;
|
|
println!("Render time {:.3} seconds", start.elapsed().as_secs_f32());
|
|
Ok(())
|
|
}
|