From e19ec20c7bc21a7a47f389d2d3ef1a6417446bc9 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Mon, 13 Feb 2023 20:57:10 -0800 Subject: [PATCH] rtiow: Many changes Add debugging hit DebugHit. Move some color helpers from mandelbrot to colors mod. Implement Texture trait for [f32;3] --- rtiow/Cargo.lock | 129 ++++++++++++++++++++++- rtiow/renderer/src/colors.rs | 46 ++++++++ rtiow/renderer/src/debug_hit.rs | 46 ++++++++ rtiow/renderer/src/lib.rs | 2 + rtiow/renderer/src/scenes/dragon.rs | 87 ++++++++------- rtiow/renderer/src/scenes/stltest.rs | 16 ++- rtiow/renderer/src/texture/mandelbrot.rs | 38 +------ rtiow/renderer/src/texture/mod.rs | 6 ++ rtiow/renderer/stls/dragon.stl | 1 + 9 files changed, 294 insertions(+), 77 deletions(-) create mode 100644 rtiow/renderer/src/colors.rs create mode 100644 rtiow/renderer/src/debug_hit.rs create mode 120000 rtiow/renderer/stls/dragon.stl diff --git a/rtiow/Cargo.lock b/rtiow/Cargo.lock index ac80c3d..4779af8 100644 --- a/rtiow/Cargo.lock +++ b/rtiow/Cargo.lock @@ -450,6 +450,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytecount" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" + [[package]] name = "byteorder" version = "1.4.3" @@ -467,6 +473,37 @@ dependencies = [ "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]] name = "cast" version = "0.3.0" @@ -1028,6 +1065,15 @@ dependencies = [ "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]] name = "failure" version = "0.1.8" @@ -1195,6 +1241,12 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "h2" version = "0.1.26" @@ -2015,6 +2067,33 @@ dependencies = [ "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]] name = "percent-encoding" version = "1.0.1" @@ -2094,6 +2173,18 @@ dependencies = [ "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]] name = "png" version = "0.15.3" @@ -2198,6 +2289,17 @@ dependencies = [ "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]] name = "quick-error" version = "1.2.3" @@ -2555,7 +2657,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -2636,6 +2738,15 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +dependencies = [ + "serde", +] + [[package]] name = "semver-parser" version = "0.7.0" @@ -2752,6 +2863,21 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "slab" version = "0.4.7" @@ -2807,6 +2933,7 @@ dependencies = [ "ansi_term", "anyhow", "byteorder", + "ply-rs", "structopt 0.3.26", "thiserror", "vec3", diff --git a/rtiow/renderer/src/colors.rs b/rtiow/renderer/src/colors.rs new file mode 100644 index 0000000..ef231d7 --- /dev/null +++ b/rtiow/renderer/src/colors.rs @@ -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 { + (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 { + 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() +} diff --git a/rtiow/renderer/src/debug_hit.rs b/rtiow/renderer/src/debug_hit.rs new file mode 100644 index 0000000..362bff3 --- /dev/null +++ b/rtiow/renderer/src/debug_hit.rs @@ -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 +where + H: Hit, +{ + hitable: H, + material: Lambertian<[f32; 3]>, +} + +impl DebugHit +where + H: Hit, +{ + pub fn new(hitable: H) -> DebugHit +where { + DebugHit { + hitable, + material: Lambertian::new([0.2, 0.2, 0.2]), + } + } +} + +impl Hit for DebugHit +where + H: Hit, +{ + fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option { + 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 { + self.hitable.bounding_box(t_min, t_max) + } +} diff --git a/rtiow/renderer/src/lib.rs b/rtiow/renderer/src/lib.rs index 0f40cbc..fe34e46 100644 --- a/rtiow/renderer/src/lib.rs +++ b/rtiow/renderer/src/lib.rs @@ -2,8 +2,10 @@ pub mod aabb; pub mod bvh; pub mod bvh_triangles; pub mod camera; +pub mod colors; pub mod constant_medium; pub mod cuboid; +pub mod debug_hit; pub mod flip_normals; pub mod glowybox; pub mod hitable; diff --git a/rtiow/renderer/src/scenes/dragon.rs b/rtiow/renderer/src/scenes/dragon.rs index ae6a71d..7a2170c 100644 --- a/rtiow/renderer/src/scenes/dragon.rs +++ b/rtiow/renderer/src/scenes/dragon.rs @@ -1,15 +1,21 @@ -use std::io::{BufReader, Cursor}; +use std::{ + f32::consts::PI, + io::{BufReader, Cursor}, + iter::Inspect, +}; use stl::STL; use crate::{ bvh_triangles::BVHTriangles, camera::Camera, + colors::generate_rainbow, hitable::Hit, hitable_list::HitableList, kdtree::KDTree, - material::{Dielectric, Lambertian}, + material::{Dielectric, Lambertian, Metal}, renderer::{Opt, Scene}, + rotate::RotateY, scale::Scale, sphere::Sphere, texture::{ConstantTexture, EnvMap}, @@ -18,8 +24,8 @@ use crate::{ }; pub fn new(opt: &Opt) -> Scene { - let lookfrom = Vec3::new(0., 40., -100.); - let lookat = Vec3::new(0., 10., 0.); + let lookfrom = Vec3::new(0., 80., 80.); + let lookat = Vec3::new(0., 0., 0.); let dist_to_focus = 10.0; let aperture = 0.0; let time_min = 0.; @@ -35,6 +41,10 @@ pub fn new(opt: &Opt) -> Scene { time_min, 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 { ConstantTexture::new(Vec3::new(1.0, 0.4, 0.4)) } else { @@ -42,46 +52,51 @@ pub fn new(opt: &Opt) -> Scene { }; let stl_cube = STL::parse( - BufReader::new(Cursor::new(include_bytes!( - "../../stls/stanford_dragon-lowres.stl" //"../../stls/stanford_dragon.stl" - ))), + BufReader::new(Cursor::new(include_bytes!("../../stls/dragon.stl"))), + //BufReader::new(Cursor::new(include_bytes!("../../stls/cube.stl"))), false, ) .expect("failed to parse cube"); let _light_size = 50.; let _light_height = 200.; - let objects: Vec> = vec![ - // Light from above - white + let sphere_radius = 5.; + let circle_radius = 40.; + let num_spheres = 16; + let palette = generate_rainbow(num_spheres); + let spheres: Vec> = (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 { + 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> = vec![ + Box::new(Sphere::new( + Vec3::new(0., 0.1, -0.5), + 0.1, + Lambertian::new([0., 1., 1.]), + )), // 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))), - )), + //Box::new(Sphere::new( Vec3::new(0., -10000., 0.), 10000., Lambertian::new(ground_color),)), // STL Mesh - Box::new(Translate::new( - Scale::new(BVHTriangles::new(&stl_cube, Dielectric::new(1.5)), 250.), - [0., -10., 0.], - )), + Box::new(crate::debug_hit::DebugHit::new(RotateY::new( + Translate::new( + Scale::new(BVHTriangles::new(&stl_cube, dragon_material), 250.), + [0., -10., 0.], + ), + 180., + ))), ]; + objects.extend(spheres); + let world: Box = if opt.use_accel { Box::new(KDTree::new(objects, time_min, time_max)) } else { diff --git a/rtiow/renderer/src/scenes/stltest.rs b/rtiow/renderer/src/scenes/stltest.rs index acc4e64..4a4ae65 100644 --- a/rtiow/renderer/src/scenes/stltest.rs +++ b/rtiow/renderer/src/scenes/stltest.rs @@ -16,6 +16,7 @@ use crate::{ renderer::{Opt, Scene}, sphere::Sphere, texture::{ConstantTexture, EnvMap}, + translate::Translate, 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 red = Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))); - let box_material = glass; + //let box_material = glass; let _ = glass; let _ = metal; let _ = red; @@ -65,6 +66,11 @@ pub fn new(opt: &Opt) -> Scene { 10000., 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 Box::new(Sphere::new( 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))), )), // 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( [-20., 0., 0.].into(), [0., 20., 20.].into(), - Arc::new(box_material), + Arc::new(red), )), ]; let world: Box = if opt.use_accel { diff --git a/rtiow/renderer/src/texture/mandelbrot.rs b/rtiow/renderer/src/texture/mandelbrot.rs index 12f7886..a0ee90f 100644 --- a/rtiow/renderer/src/texture/mandelbrot.rs +++ b/rtiow/renderer/src/texture/mandelbrot.rs @@ -1,48 +1,12 @@ #![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)] pub struct Mandelbrot { palette: Vec, } -// 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 { - 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 { fn default() -> Self { Mandelbrot { diff --git a/rtiow/renderer/src/texture/mod.rs b/rtiow/renderer/src/texture/mod.rs index c188520..baf67aa 100644 --- a/rtiow/renderer/src/texture/mod.rs +++ b/rtiow/renderer/src/texture/mod.rs @@ -29,6 +29,12 @@ impl Texture for Box { } } +impl Texture for [f32; 3] { + fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { + (*self).into() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/rtiow/renderer/stls/dragon.stl b/rtiow/renderer/stls/dragon.stl new file mode 120000 index 0000000..a7a5f93 --- /dev/null +++ b/rtiow/renderer/stls/dragon.stl @@ -0,0 +1 @@ +stanford_dragon.stl \ No newline at end of file