rtiow: add dragon scene, tune stltest to compare with cuboid.

Refactor enum Model to use strum.
This commit is contained in:
Bill Thiede 2023-01-30 19:55:28 -08:00
parent fc1bfa419e
commit beeb5e479b
10 changed files with 212 additions and 102 deletions

41
rtiow/Cargo.lock generated
View File

@ -1229,6 +1229,12 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.2.6"
@ -2434,6 +2440,8 @@ dependencies = [
"serde_json",
"stl",
"structopt 0.2.18",
"strum",
"strum_macros",
"vec3",
]
@ -2462,6 +2470,12 @@ dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "ryu"
version = "1.0.12"
@ -2740,7 +2754,7 @@ version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53010261a84b37689f9ed7d395165029f9cc7abb9f56bbfe86bee2597ed25107"
dependencies = [
"heck",
"heck 0.3.3",
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
@ -2752,13 +2766,35 @@ version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"heck 0.3.3",
"proc-macro-error",
"proc-macro2 1.0.50",
"quote 1.0.23",
"syn 1.0.107",
]
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck 0.4.0",
"proc-macro2 1.0.50",
"quote 1.0.23",
"rustversion",
"syn 1.0.107",
]
[[package]]
name = "subtle"
version = "2.4.1"
@ -3163,6 +3199,7 @@ dependencies = [
"renderer",
"stderrlog",
"structopt 0.2.18",
"strum",
]
[[package]]

View File

@ -27,6 +27,8 @@ serde_json = "1.0.91"
structopt = "0.2.18"
vec3 = {path = "../vec3"}
stl = {path = "../../../stl"}
strum = { version = "0.24.1", features = ["derive"] }
strum_macros = "0.24.3"
#stl = {git = "https://git-private.z.xinu.tv/wathiede/stl"}
[dev-dependencies]

View File

@ -30,8 +30,10 @@ use crate::{
texture::{ConstantTexture, EnvMap},
vec3::Vec3,
};
use strum::{EnumString, EnumVariantNames};
#[derive(Debug)]
#[derive(Debug, EnumString, EnumVariantNames, strum::Display)]
#[strum(serialize_all = "snake_case")]
pub enum Model {
BVH,
Bench,
@ -46,6 +48,7 @@ pub enum Model {
Test,
Tron,
Tutorial,
Dragon,
}
impl Model {
@ -56,6 +59,7 @@ impl Model {
Model::Book => scenes::book::new(opt),
Model::CornellBox => scenes::cornell_box::new(opt),
Model::CornellSmoke => scenes::cornell_smoke::new(opt),
Model::Dragon => scenes::dragon::new(opt),
Model::Final => scenes::final_scene::new(opt),
Model::Mandelbrot => scenes::mandelbrot::new(opt),
Model::PerlinDebug => scenes::perlin_debug::new(opt),
@ -77,48 +81,6 @@ impl fmt::Display for ModelParseError {
}
}
impl str::FromStr for Model {
type Err = ModelParseError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s {
"bench" => Ok(Model::Bench),
"book" => Ok(Model::Book),
"bvh" => Ok(Model::BVH),
"cornell_box" => Ok(Model::CornellBox),
"cornell_smoke" => Ok(Model::CornellSmoke),
"final" => Ok(Model::Final),
"mandelbrot" => Ok(Model::Mandelbrot),
"perlin_debug" => Ok(Model::PerlinDebug),
"spheramid" => Ok(Model::Spheramid),
"stltest" => Ok(Model::Stltest),
"test" => Ok(Model::Test),
"tron" => Ok(Model::Tron),
"tutorial" => Ok(Model::Tutorial),
_ => Err(ModelParseError(s.to_owned())),
}
}
}
impl std::string::ToString for Model {
fn to_string(&self) -> String {
match self {
Model::BVH => "bvh".to_string(),
Model::Bench => "bench".to_string(),
Model::Book => "book".to_string(),
Model::CornellBox => "cornell_box".to_string(),
Model::CornellSmoke => "cornell_smoke".to_string(),
Model::Final => "final".to_string(),
Model::Mandelbrot => "mandelbrot".to_string(),
Model::PerlinDebug => "perlin_debug".to_string(),
Model::Spheramid => "spheramid".to_string(),
Model::Stltest => "stltest".to_string(),
Model::Test => "test".to_string(),
Model::Tron => "tron".to_string(),
Model::Tutorial => "tutorial".to_string(),
}
}
}
#[derive(Debug, StructOpt)]
#[structopt(name = "tracer", about = "An experimental ray tracer.")]
pub struct Opt {
@ -134,10 +96,9 @@ pub struct Opt {
/// Sub-samples per pixel
#[structopt(short = "s", long = "subsample", default_value = "8")]
pub subsamples: usize,
/// Select scene to render, one of: "bench", "book", "tutorial", "bvh", "test", "cornell_box",
/// "cornell_smoke", "perlin_debug", "final"
#[structopt(long = "model", default_value = "book")]
pub model: Model,
/// Select scene to render.
#[structopt(long = "model")]
pub model: Option<Model>,
/// Path to store pprof profile data, i.e. /tmp/cpuprofile.pprof
#[structopt(long = "pprof", parse(from_os_str))]
pub pprof: Option<PathBuf>,
@ -158,7 +119,7 @@ pub fn opt_hash(opt: &Opt) -> String {
opt.height,
opt.subsamples,
opt.pprof.is_some(),
opt.model.to_string(),
opt.model.as_ref().unwrap().to_string(),
opt.use_accel,
opt.output.display().to_string().replace('/', "_")
)

View File

@ -0,0 +1,119 @@
use std::{
io::{BufReader, Cursor},
sync::Arc,
};
use stl::STL;
use crate::{
bvh_triangles::BVHTriangles,
camera::Camera,
cuboid::Cuboid,
hitable::Hit,
hitable_list::HitableList,
kdtree::KDTree,
material::{Dielectric, DiffuseLight, Lambertian, Metal},
rect::{XYRect, XZRect},
renderer::{Opt, Scene},
scale::Scale,
sphere::Sphere,
texture::{ConstantTexture, EnvMap},
vec3::Vec3,
};
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(0., 40., -100.);
let lookat = Vec3::new(0., 10., 0.);
let dist_to_focus = 10.0;
let aperture = 0.0;
let time_min = 0.;
let time_max = 1.;
let camera = Camera::new(
lookfrom,
lookat,
Vec3::new(0., 1., 0.),
45.,
opt.width as f32 / opt.height as f32,
aperture,
dist_to_focus,
time_min,
time_max,
);
let ground_color = if opt.use_accel {
ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
} else {
ConstantTexture::new(Vec3::new(0.4, 0.4, 0.4))
};
let stl_cube = STL::parse(
BufReader::new(Cursor::new(include_bytes!(
"../../stls/cube.stl"
//"../../stls/stanford_dragon-lowres.stl" //"../../stls/stanford_dragon.stl"
))),
false,
)
.expect("failed to parse cube");
let light_size = 50.;
let light_height = 200.;
let objects: Vec<Box<dyn Hit>> = vec![
// Light from above - white
// Earth sized sphere
Box::new(Sphere::new(
Vec3::new(0., -10000., 0.),
10000.,
Lambertian::new(ground_color),
)),
// Blue sphere
Box::new(Sphere::new(
Vec3::new(0., 20., 40.),
20.,
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))),
)),
Box::new(Sphere::new(
Vec3::new(40., 20., 40.),
20.,
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))),
)),
Box::new(Sphere::new(
Vec3::new(-40., 20., 40.),
20.,
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)),
// STL Mesh
Box::new(Scale::new(
BVHTriangles::new(
&stl_cube,
Dielectric::new(1.5),
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
//Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
),
1.,
//250.,
)),
Box::new(Cuboid::new(
[-20., 0., 0.].into(),
[0., 20., 20.].into(),
Arc::new(Dielectric::new(1.5)),
)),
];
let world: Box<dyn Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max))
} else {
Box::new(HitableList::new(objects))
};
let skybox_bytes = include_bytes!("../../images/envmap.jpg");
let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb();
Scene {
camera,
world,
subsamples: opt.subsamples,
num_threads: opt.num_threads,
width: opt.width,
height: opt.height,
global_illumination: true,
env_map: Some(EnvMap::new(skybox)),
..Default::default()
}
}

View File

@ -3,6 +3,7 @@ pub mod book;
pub mod bvh;
pub mod cornell_box;
pub mod cornell_smoke;
pub mod dragon;
pub mod final_scene;
pub mod mandelbrot;
pub mod perlin_debug;

View File

@ -1,23 +1,28 @@
use std::io::{BufReader, Cursor};
use std::{
io::{BufReader, Cursor},
sync::Arc,
};
use stl::STL;
use crate::{
bvh_triangles::BVHTriangles,
camera::Camera,
cuboid::Cuboid,
hitable::Hit,
hitable_list::HitableList,
kdtree::KDTree,
material::{DiffuseLight, Lambertian, Metal},
material::{Dielectric, DiffuseLight, Lambertian, Metal},
rect::{XYRect, XZRect},
renderer::{Opt, Scene},
scale::Scale,
sphere::Sphere,
texture::ConstantTexture,
texture::{ConstantTexture, EnvMap},
vec3::Vec3,
};
pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(-20., 100., -100.);
let lookfrom = Vec3::new(0., 40., -100.);
let lookat = Vec3::new(0., 10., 0.);
let dist_to_focus = 10.0;
let aperture = 0.0;
@ -41,9 +46,7 @@ pub fn new(opt: &Opt) -> Scene {
};
let stl_cube = STL::parse(
BufReader::new(Cursor::new(include_bytes!(
"../../stls/stanford_dragon-lowres.stl"
))),
BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))),
false,
)
.expect("failed to parse cube");
@ -51,65 +54,41 @@ pub fn new(opt: &Opt) -> Scene {
let light_height = 200.;
let objects: Vec<Box<dyn Hit>> = vec![
// Light from above - white
Box::new(XZRect::new(
-light_size,
light_size,
-light_size,
light_size,
light_height,
DiffuseLight::new(ConstantTexture::new(Vec3::new(15., 15., 15.))),
)),
// Light from back - green
Box::new(XYRect::new(
-light_size,
light_size,
-light_size,
light_size,
-light_height,
DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 15., 1.))),
)),
// Light from front - blue
Box::new(XYRect::new(
-light_size,
light_size,
-light_size,
light_size,
light_height,
DiffuseLight::new(ConstantTexture::new(Vec3::new(1., 1., 15.))),
)),
// Earth sized sphere
Box::new(Sphere::new(
Vec3::new(0., -1200., 0.),
1000.,
Vec3::new(0., -10000., 0.),
10000.,
Lambertian::new(ground_color),
)),
/*
// Blue sphere
Box::new(Sphere::new(
Vec3::new(-40., 20., 0.),
Vec3::new(0., 20., 40.),
20.,
Lambertian::new(ConstantTexture::new(Vec3::new(0.1, 0.2, 0.5))),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 0.2, 1.))),
)),
*/
// Shiny sphere
Box::new(Sphere::new(
Vec3::new(40., 20., -40.),
Vec3::new(40., 20., 40.),
20.,
Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(0.2, 1.0, 0.2))),
)),
Box::new(Sphere::new(
Vec3::new(-40., 20., 40.),
20.,
Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)),
// STL Mesh
Box::new(Scale::new(
BVHTriangles::new(
Box::new(BVHTriangles::new(
&stl_cube,
Lambertian::new(ConstantTexture::new(Vec3::new(0.6, 0.6, 0.6))),
),
//1.,
250.,
Dielectric::new(1.5),
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
//Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)),
Box::new(Cuboid::new(
[-20., 0., 0.].into(),
[0., 20., 20.].into(),
Arc::new(Dielectric::new(1.5)),
)),
];
let world: Box<dyn Hit> = if opt.use_accel {
@ -117,6 +96,8 @@ pub fn new(opt: &Opt) -> Scene {
} else {
Box::new(HitableList::new(objects))
};
let skybox_bytes = include_bytes!("../../images/envmap.jpg");
let skybox = image::load_from_memory(skybox_bytes).unwrap().to_rgb();
Scene {
camera,
world,
@ -124,6 +105,8 @@ pub fn new(opt: &Opt) -> Scene {
num_threads: opt.num_threads,
width: opt.width,
height: opt.height,
global_illumination: true,
env_map: Some(EnvMap::new(skybox)),
..Default::default()
}
}

View File

@ -0,0 +1 @@
/home/wathiede/3dprint/stl/stanford_dragon-lowres.stl

View File

@ -11,3 +11,4 @@ log = "0.4.17"
renderer = { path = "../renderer" }
stderrlog = "0.4.3"
structopt = "0.2.18"
strum = "0.24.1"

View File

@ -6,7 +6,8 @@ use cpuprofiler::PROFILER;
use log::info;
use structopt::StructOpt;
use renderer::renderer::{render, Opt};
use renderer::renderer::{render, Model, Opt};
use strum::VariantNames;
#[cfg(not(feature = "profile"))]
struct MockTimer;
@ -41,8 +42,12 @@ fn main() -> Result<(), std::io::Error> {
.init()
.unwrap();
let opt = Opt::from_args();
if opt.model.is_none() {
eprintln!("--model should be one of {:?}", Model::VARIANTS);
return Ok(());
}
info!("{:?}", opt);
let scene = opt.model.scene(&opt);
let scene = opt.model.as_ref().unwrap().scene(&opt);
fs::create_dir_all(&opt.output)?;
if opt.pprof.is_some() && !cfg!(feature = "profile") {
panic!("profiling disabled at compile time, but -pprof specified");