rtiow: Many changes

Add debugging hit DebugHit.
Move some color helpers from mandelbrot to colors mod.
Implement Texture trait for [f32;3]
This commit is contained in:
Bill Thiede 2023-02-13 20:57:10 -08:00
parent deb46acb5a
commit e19ec20c7b
9 changed files with 294 additions and 77 deletions

129
rtiow/Cargo.lock generated
View File

@ -450,6 +450,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytecount"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@ -467,6 +473,37 @@ dependencies = [
"iovec", "iovec",
] ]
[[package]]
name = "camino"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055"
dependencies = [
"serde",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
dependencies = [
"camino",
"cargo-platform",
"semver 1.0.16",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "cast" name = "cast"
version = "0.3.0" version = "0.3.0"
@ -1028,6 +1065,15 @@ dependencies = [
"backtrace 0.3.67", "backtrace 0.3.67",
] ]
[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"version_check 0.9.4",
]
[[package]] [[package]]
name = "failure" name = "failure"
version = "0.1.8" version = "0.1.8"
@ -1195,6 +1241,12 @@ version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.1.26" version = "0.1.26"
@ -2015,6 +2067,33 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "peg"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367"
dependencies = [
"peg-macros",
"peg-runtime",
]
[[package]]
name = "peg-macros"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d"
dependencies = [
"peg-runtime",
"proc-macro2 1.0.50",
"quote 1.0.23",
]
[[package]]
name = "peg-runtime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5"
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "1.0.1" version = "1.0.1"
@ -2094,6 +2173,18 @@ dependencies = [
"plotters-backend", "plotters-backend",
] ]
[[package]]
name = "ply-rs"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbadf9cb4a79d516de4c64806fe64ffbd8161d1ac685d000be789fb628b88963"
dependencies = [
"byteorder",
"linked-hash-map",
"peg",
"skeptic",
]
[[package]] [[package]]
name = "png" name = "png"
version = "0.15.3" version = "0.15.3"
@ -2198,6 +2289,17 @@ dependencies = [
"unarray", "unarray",
] ]
[[package]]
name = "pulldown-cmark"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63"
dependencies = [
"bitflags",
"memchr",
"unicase 2.6.0",
]
[[package]] [[package]]
name = "quick-error" name = "quick-error"
version = "1.2.3" version = "1.2.3"
@ -2555,7 +2657,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [ dependencies = [
"semver", "semver 0.9.0",
] ]
[[package]] [[package]]
@ -2636,6 +2738,15 @@ dependencies = [
"semver-parser", "semver-parser",
] ]
[[package]]
name = "semver"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "semver-parser" name = "semver-parser"
version = "0.7.0" version = "0.7.0"
@ -2752,6 +2863,21 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
name = "skeptic"
version = "0.13.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
dependencies = [
"bytecount",
"cargo_metadata",
"error-chain 0.12.4",
"glob",
"pulldown-cmark",
"tempfile",
"walkdir",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.7" version = "0.4.7"
@ -2807,6 +2933,7 @@ dependencies = [
"ansi_term", "ansi_term",
"anyhow", "anyhow",
"byteorder", "byteorder",
"ply-rs",
"structopt 0.3.26", "structopt 0.3.26",
"thiserror", "thiserror",
"vec3", "vec3",

View File

@ -0,0 +1,46 @@
use rand::{self, Rng};
use crate::vec3::Vec3;
// HSV values in [0..1]
// returns [r, g, b] values from 0 to 255
//From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
pub fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 {
let h_i = (h * 6.) as i32;
let f = h * 6. - h_i as f32;
let p = v * (1. - s);
let q = v * (1. - f * s);
let t = v * (1. - (1. - f) * s);
match h_i {
0 => Vec3::new(v, t, p),
1 => Vec3::new(q, v, p),
2 => Vec3::new(p, v, t),
3 => Vec3::new(p, q, v),
4 => Vec3::new(t, p, v),
5 => Vec3::new(v, p, q),
_ => panic!("Unknown H value {}", h_i),
}
}
pub fn generate_rainbow(num: usize) -> Vec<Vec3> {
(0..num)
.map(|n| {
let h = n as f32 / num as f32;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}
pub fn generate_palette(num: usize) -> Vec<Vec3> {
let mut rng = rand::thread_rng();
let mut random = || rng.gen();
// use golden ratio
let golden_ratio_conjugate = 0.618_034;
let mut h = random();
(0..num)
.map(|_| {
h += golden_ratio_conjugate;
h %= 1.0;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}

View File

@ -0,0 +1,46 @@
use crate::{
aabb::AABB,
hitable::{Hit, HitRecord},
material::Lambertian,
ray::Ray,
texture::{self, ConstantTexture},
vec3::Vec3,
};
#[derive(Debug)]
pub struct DebugHit<H>
where
H: Hit,
{
hitable: H,
material: Lambertian<[f32; 3]>,
}
impl<H> DebugHit<H>
where
H: Hit,
{
pub fn new(hitable: H) -> DebugHit<H>
where {
DebugHit {
hitable,
material: Lambertian::new([0.2, 0.2, 0.2]),
}
}
}
impl<H> Hit for DebugHit<H>
where
H: Hit,
{
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
if let Some(hit) = self.hitable.hit(r, t_min, t_max) {
return Some(HitRecord { t: hit.t, ..hit });
}
None
}
fn bounding_box(&self, t_min: f32, t_max: f32) -> Option<AABB> {
self.hitable.bounding_box(t_min, t_max)
}
}

View File

@ -2,8 +2,10 @@ pub mod aabb;
pub mod bvh; pub mod bvh;
pub mod bvh_triangles; pub mod bvh_triangles;
pub mod camera; pub mod camera;
pub mod colors;
pub mod constant_medium; pub mod constant_medium;
pub mod cuboid; pub mod cuboid;
pub mod debug_hit;
pub mod flip_normals; pub mod flip_normals;
pub mod glowybox; pub mod glowybox;
pub mod hitable; pub mod hitable;

View File

@ -1,15 +1,21 @@
use std::io::{BufReader, Cursor}; use std::{
f32::consts::PI,
io::{BufReader, Cursor},
iter::Inspect,
};
use stl::STL; use stl::STL;
use crate::{ use crate::{
bvh_triangles::BVHTriangles, bvh_triangles::BVHTriangles,
camera::Camera, camera::Camera,
colors::generate_rainbow,
hitable::Hit, hitable::Hit,
hitable_list::HitableList, hitable_list::HitableList,
kdtree::KDTree, kdtree::KDTree,
material::{Dielectric, Lambertian}, material::{Dielectric, Lambertian, Metal},
renderer::{Opt, Scene}, renderer::{Opt, Scene},
rotate::RotateY,
scale::Scale, scale::Scale,
sphere::Sphere, sphere::Sphere,
texture::{ConstantTexture, EnvMap}, texture::{ConstantTexture, EnvMap},
@ -18,8 +24,8 @@ use crate::{
}; };
pub fn new(opt: &Opt) -> Scene { pub fn new(opt: &Opt) -> Scene {
let lookfrom = Vec3::new(0., 40., -100.); let lookfrom = Vec3::new(0., 80., 80.);
let lookat = Vec3::new(0., 10., 0.); let lookat = Vec3::new(0., 0., 0.);
let dist_to_focus = 10.0; let dist_to_focus = 10.0;
let aperture = 0.0; let aperture = 0.0;
let time_min = 0.; let time_min = 0.;
@ -35,6 +41,10 @@ pub fn new(opt: &Opt) -> Scene {
time_min, time_min,
time_max, time_max,
); );
//let dragon_material = Dielectric::new(1.5);
let dragon_material = Metal::new(Vec3::new(0.6, 0.6, 0.6), 0.0);
//let dragon_material = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 1.0, 0.2)));
let ground_color = if opt.use_accel { let ground_color = if opt.use_accel {
ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)) ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4))
} else { } else {
@ -42,46 +52,51 @@ pub fn new(opt: &Opt) -> Scene {
}; };
let stl_cube = STL::parse( let stl_cube = STL::parse(
BufReader::new(Cursor::new(include_bytes!( BufReader::new(Cursor::new(include_bytes!("../../stls/dragon.stl"))),
"../../stls/stanford_dragon-lowres.stl" //"../../stls/stanford_dragon.stl" //BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))),
))),
false, false,
) )
.expect("failed to parse cube"); .expect("failed to parse cube");
let _light_size = 50.; let _light_size = 50.;
let _light_height = 200.; let _light_height = 200.;
let objects: Vec<Box<dyn Hit>> = vec![ let sphere_radius = 5.;
// Light from above - white let circle_radius = 40.;
let num_spheres = 16;
let palette = generate_rainbow(num_spheres);
let spheres: Vec<Box<dyn Hit>> = (0..num_spheres)
.map(|i| (i, i as f32, num_spheres as f32))
.map(|(idx, idx_f, n)| (idx, idx_f * 2. * PI / n))
.map(|(idx, rad)| -> Box<dyn Hit> {
let x = circle_radius * rad.cos();
let y = 4. * sphere_radius;
let z = circle_radius * rad.sin();
let c = palette[idx];
Box::new(Sphere::new(
[x, y, z],
sphere_radius,
Lambertian::new(ConstantTexture::new(c)),
))
})
.collect();
let mut objects: Vec<Box<dyn Hit>> = vec![
Box::new(Sphere::new(
Vec3::new(0., 0.1, -0.5),
0.1,
Lambertian::new([0., 1., 1.]),
)),
// Earth sized sphere // Earth sized sphere
Box::new(Sphere::new( //Box::new(Sphere::new( Vec3::new(0., -10000., 0.), 10000., Lambertian::new(ground_color),)),
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 // STL Mesh
Box::new(Translate::new( Box::new(crate::debug_hit::DebugHit::new(RotateY::new(
Scale::new(BVHTriangles::new(&stl_cube, Dielectric::new(1.5)), 250.), Translate::new(
[0., -10., 0.], Scale::new(BVHTriangles::new(&stl_cube, dragon_material), 250.),
)), [0., -10., 0.],
),
180.,
))),
]; ];
objects.extend(spheres);
let world: Box<dyn Hit> = if opt.use_accel { let world: Box<dyn Hit> = if opt.use_accel {
Box::new(KDTree::new(objects, time_min, time_max)) Box::new(KDTree::new(objects, time_min, time_max))
} else { } else {

View File

@ -16,6 +16,7 @@ use crate::{
renderer::{Opt, Scene}, renderer::{Opt, Scene},
sphere::Sphere, sphere::Sphere,
texture::{ConstantTexture, EnvMap}, texture::{ConstantTexture, EnvMap},
translate::Translate,
vec3::Vec3, vec3::Vec3,
}; };
@ -47,7 +48,7 @@ pub fn new(opt: &Opt) -> Scene {
let metal = Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2); let metal = Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2);
let red = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))); let red = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2)));
let box_material = glass; //let box_material = glass;
let _ = glass; let _ = glass;
let _ = metal; let _ = metal;
let _ = red; let _ = red;
@ -65,6 +66,11 @@ pub fn new(opt: &Opt) -> Scene {
10000., 10000.,
Lambertian::new(ground_color), Lambertian::new(ground_color),
)), )),
Box::new(Sphere::new(
Vec3::new(0., 20., -40.),
10.,
Lambertian::new(ConstantTexture::new(Vec3::new(1., 0.2, 1.))),
)),
// Blue sphere // Blue sphere
Box::new(Sphere::new( Box::new(Sphere::new(
Vec3::new(0., 20., 40.), Vec3::new(0., 20., 40.),
@ -84,11 +90,15 @@ pub fn new(opt: &Opt) -> Scene {
Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))), Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
)), )),
// STL Mesh // STL Mesh
Box::new(BVHTriangles::new(&stl_cube, box_material.clone())), Box::new(Translate::new(
BVHTriangles::new(&stl_cube, glass),
[0., 10., 0.],
)),
//Box::new(BVHTriangles::new(&stl_cube, box_material.clone())),
Box::new(Cuboid::new( Box::new(Cuboid::new(
[-20., 0., 0.].into(), [-20., 0., 0.].into(),
[0., 20., 20.].into(), [0., 20., 20.].into(),
Arc::new(box_material), Arc::new(red),
)), )),
]; ];
let world: Box<dyn Hit> = if opt.use_accel { let world: Box<dyn Hit> = if opt.use_accel {

View File

@ -1,48 +1,12 @@
#![allow(clippy::many_single_char_names)] #![allow(clippy::many_single_char_names)]
use rand::{self, Rng};
use crate::{texture::Texture, vec3::Vec3}; use crate::{colors::generate_palette, texture::Texture, vec3::Vec3};
#[derive(Debug)] #[derive(Debug)]
pub struct Mandelbrot { pub struct Mandelbrot {
palette: Vec<Vec3>, palette: Vec<Vec3>,
} }
// HSV values in [0..1]
// returns [r, g, b] values from 0 to 255
//From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 {
let h_i = (h * 6.) as i32;
let f = h * 6. - h_i as f32;
let p = v * (1. - s);
let q = v * (1. - f * s);
let t = v * (1. - (1. - f) * s);
match h_i {
0 => Vec3::new(v, t, p),
1 => Vec3::new(q, v, p),
2 => Vec3::new(p, v, t),
3 => Vec3::new(p, q, v),
4 => Vec3::new(t, p, v),
5 => Vec3::new(v, p, q),
_ => panic!("Unknown H value {}", h_i),
}
}
fn generate_palette(num: usize) -> Vec<Vec3> {
let mut rng = rand::thread_rng();
let mut random = || rng.gen();
// use golden ratio
let golden_ratio_conjugate = 0.618_034;
let mut h = random();
(0..num)
.map(|_| {
h += golden_ratio_conjugate;
h %= 1.0;
hsv_to_rgb(h, 0.99, 0.99)
})
.collect()
}
impl Default for Mandelbrot { impl Default for Mandelbrot {
fn default() -> Self { fn default() -> Self {
Mandelbrot { Mandelbrot {

View File

@ -29,6 +29,12 @@ impl Texture for Box<dyn Texture> {
} }
} }
impl Texture for [f32; 3] {
fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 {
(*self).into()
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@ -0,0 +1 @@
stanford_dragon.stl