From 73bbd64cc092c502f5218dd0360f73ef73fc564a Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Mon, 3 Apr 2023 02:01:51 -0500 Subject: [PATCH] got some transparency? --- assignment-1d/Cargo.lock | 36 +++++ assignment-1d/Cargo.toml | 2 +- assignment-1d/Makefile | 14 +- assignment-1d/examples/soft-shadow-demo.txt | 45 ++++++ .../examples/transparency-distance.txt | 11 ++ assignment-1d/src/main.rs | 32 +++- assignment-1d/src/scene/illumination.rs | 152 +++++++++++++----- assignment-1d/src/scene/input_file/mod.rs | 11 +- assignment-1d/src/scene/sphere.rs | 9 ++ assignment-1d/src/scene/tracing.rs | 3 + assignment-1d/src/scene/triangle.rs | 2 +- 11 files changed, 262 insertions(+), 55 deletions(-) create mode 100644 assignment-1d/examples/soft-shadow-demo.txt create mode 100644 assignment-1d/examples/transparency-distance.txt diff --git a/assignment-1d/Cargo.lock b/assignment-1d/Cargo.lock index 2ce421f..7d06198 100644 --- a/assignment-1d/Cargo.lock +++ b/assignment-1d/Cargo.lock @@ -311,6 +311,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + [[package]] name = "lazy_static" version = "1.4.0" @@ -677,6 +683,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + [[package]] name = "safe_arch" version = "0.6.0" @@ -698,6 +710,17 @@ version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -806,6 +829,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.16" @@ -813,11 +846,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ "nu-ansi-term", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] diff --git a/assignment-1d/Cargo.toml b/assignment-1d/Cargo.toml index a0371dc..a75aa13 100644 --- a/assignment-1d/Cargo.toml +++ b/assignment-1d/Cargo.toml @@ -32,4 +32,4 @@ ordered-float = "3.4.0" rand = "0.8.5" rayon = "1.6.1" tracing = "0.1.37" -tracing-subscriber = "0.3.16" +tracing-subscriber = { version = "0.3.16", features = ["json"] } diff --git a/assignment-1d/Makefile b/assignment-1d/Makefile index 27163f4..38331d7 100644 --- a/assignment-1d/Makefile +++ b/assignment-1d/Makefile @@ -3,18 +3,18 @@ .PRECIOUS: $(EXAMPLES_PPM) DEBUG := -RELEASE_FLAG := --release - -ifeq ($(DEBUG),1) - RELEASE_FLAG := -endif - +CARGO_FLAGS := --release RAYTRACER_FLAGS := DOCKER := docker ZIP := zip PANDOC := pandoc CONVERT := convert +ifeq ($(DEBUG),1) + RAYTRACER_FLAGS += -vvvv +else +endif + HANDIN := ./hw1d.michael.zhang.zip BINARY := ./raytracer1d SOURCES := Cargo.toml $(shell find -name "*.rs") @@ -42,7 +42,7 @@ $(HANDIN): $(BINARY) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $( $(ZIP) -r $@ src examples $^ examples/%.ppm: examples/%.txt $(SOURCES) - cargo run $(RELEASE_FLAG) -- -o $@ $(RAYTRACER_FLAGS) $< + cargo run $(CARGO_FLAGS) -- -o $@ $(RAYTRACER_FLAGS) $< examples/%.png: examples/%.ppm convert $< $@ diff --git a/assignment-1d/examples/soft-shadow-demo.txt b/assignment-1d/examples/soft-shadow-demo.txt new file mode 100644 index 000000000..893d249 --- /dev/null +++ b/assignment-1d/examples/soft-shadow-demo.txt @@ -0,0 +1,45 @@ +imsize 640 480 +eye 0 0 15 +viewdir 0 0 -1 +hfov 60 +updir 0 1 0 +bkgcolor 0.5 0.5 0.5 + +depthcueing 0.5 0.5 0.5 1 0.4 60 0 + +light 10 10 -10 1 1 1 1 + +mtlcolor 0.5 1 0.5 1 1 1 0.2 1 0.1 5 0.5 1 +sphere 4.5 4.5 -20 4.5 +sphere -4.5 -4.5 -20 4.5 + +mtlcolor 1 0.5 0.5 1 1 1 0.2 0.8 0 5 0.8 1 +sphere -10 0 -30 4 +sphere -20 0 -30 4 +sphere -30 0 -30 4 +sphere -40 0 -30 4 +sphere 0 0 -30 4 +sphere 10 0 -30 4 +sphere 20 0 -30 4 +sphere 30 0 -30 4 +sphere 40 0 -30 4 + +sphere -10 -10 -30 4 +sphere -20 -10 -30 4 +sphere -30 -10 -30 4 +sphere -40 -10 -30 4 +sphere 0 -10 -30 4 +sphere 10 -10 -30 4 +sphere 20 -10 -30 4 +sphere 30 -10 -30 4 +sphere 40 -10 -30 4 + +sphere -10 10 -30 4 +sphere -20 10 -30 4 +sphere -30 10 -30 4 +sphere -40 10 -30 4 +sphere 0 10 -30 4 +sphere 10 10 -30 4 +sphere 20 10 -30 4 +sphere 30 10 -30 4 +sphere 40 10 -30 4 diff --git a/assignment-1d/examples/transparency-distance.txt b/assignment-1d/examples/transparency-distance.txt new file mode 100644 index 000000000..3cfccf2 --- /dev/null +++ b/assignment-1d/examples/transparency-distance.txt @@ -0,0 +1,11 @@ +eye 0 0 10 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 512 +bkgcolor 0.5 0.7 0.9 1 +light 0 -1 0 0 1 1 1 + +mtlcolor 0.7 0.2 0.7 1 1 1 0 0.05 0.1 80 0.5 1.5 +sphere 1 1 -6 3 +sphere -1 -1 1 3 diff --git a/assignment-1d/src/main.rs b/assignment-1d/src/main.rs index 472348b..e1447f1 100644 --- a/assignment-1d/src/main.rs +++ b/assignment-1d/src/main.rs @@ -7,9 +7,14 @@ use std::path::PathBuf; use anyhow::Result; use assignment_1d::{image::Image, ray::Ray, scene::Scene}; -use clap::Parser; +use clap::{ArgAction, Parser}; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; +use tracing::metadata::LevelFilter; +use tracing_subscriber::{ + fmt::Layer, prelude::__tracing_subscriber_SubscriberExt, + util::SubscriberInitExt, +}; /// Simple raytracer with Blinn-Phong illumination and shadowing. #[derive(Parser)] @@ -31,16 +36,33 @@ struct Opt { /// Override distance from eye #[clap(long = "distance", default_value = "1.0")] distance: f64, + + /// Verbosity + #[clap(short, long, action = ArgAction::Count)] + verbosity: u8, } fn main() -> Result<()> { let opt = Opt::parse(); + let level_filter = match opt.verbosity { + 0 => LevelFilter::ERROR, + 1 => LevelFilter::WARN, + 2 => LevelFilter::INFO, + 3 => LevelFilter::DEBUG, + _ => LevelFilter::TRACE, + }; + // Set up logging - tracing_subscriber::fmt() + let layer = Layer::default() + .json() .with_target(false) .with_timer(tracing_subscriber::fmt::time::uptime()) - .with_level(true) + .with_level(true); + + tracing_subscriber::registry() + .with(layer) + .with(level_filter) .init(); // Rename the output file if it's not provided @@ -68,6 +90,9 @@ fn main() -> Result<()> { // Loop through every single pixel of the output file let pixels = pixels_iter .map(|(px, py)| { + let span = trace_span!("main_loop", px = px, py = py); + let _enter = span.enter(); + let pixel_in_space = translate_pixel(px, py); let ray_start = if scene.parallel_projection { @@ -84,6 +109,7 @@ fn main() -> Result<()> { let ray = Ray::from_endpoints(ray_start, pixel_in_space); + // let res= rayon::spawn(|| scene.trace_single_ray(ray, 0)); scene.trace_single_ray(ray, 0) }) .collect::>>()?; diff --git a/assignment-1d/src/scene/illumination.rs b/assignment-1d/src/scene/illumination.rs index 6944507..fc8bfcf 100644 --- a/assignment-1d/src/scene/illumination.rs +++ b/assignment-1d/src/scene/illumination.rs @@ -19,6 +19,8 @@ use super::{ // TODO: Is this a good constant? const JITTER_CONST: f64 = 0.05; +const ZERO_COLOR: Color = Color::new(0.0, 0.0, 0.0); + impl Scene { /// Determine the color that should be used to fill this pixel. /// @@ -35,6 +37,10 @@ impl Scene { intersection_context: IntersectionContext, depth: usize, ) -> Result { + let span = + trace_span!("compute_pixel_color", intersection = ?intersection_context); + let _enter = span.enter(); + let material = match self.materials.get(object.material_idx) { Some(v) => v, None => bail!("Material index not found."), @@ -138,49 +144,21 @@ impl Scene { }; let (eta_i, eta_t) = match intersection_context.exiting { - true => (material.eta, 1.0), - false => (1.0, material.eta), + // true => (material.eta, 1.0), + _ => (1.0, material.eta), }; let transparency = if eta_t < 1.0 { - Vector::default() + ZERO_COLOR } else { - let n = intersection_context.normal.normalize(); - let i = incident_ray.direction.normalize(); - - assert!(eta_t != 0.0, "wtf eta_t is 0"); - - // Slide 69 - let cos_theta_i = dot(i, n); - let sin_theta_i = (1.0 - cos_theta_i.powi(2)).sqrt(); - let sin_theta_t = (eta_i / eta_t) * sin_theta_i; - let cos_theta_t = (1.0 - sin_theta_t.powi(2)).sqrt(); - - let fresnel_coefficient = - self.compute_fresnel_coefficient(&material, i, n); - - // Calculate refraction direction - let a = (-n).normalize() * cos_theta_t; - let s_direction = cos_theta_i * n - i; - let m_unit = s_direction.normalize(); - let b = m_unit * sin_theta_t; - let t = a + b; - - // Jitter a bit to reduce acne - // TODO: Is this a good constant? - let origin = intersection_context.point; - let origin = origin + JITTER_CONST * t; - - let ray = Ray::new(origin, t); - assert!( - !ray.has_nan(), - "ray is nan WTF {cos_theta_i} {sin_theta_i} ({}) {sin_theta_t} {cos_theta_t} | normal: {:?}", - eta_i / eta_t, - intersection_context.normal, - ); - let t_lambda = self.trace_single_ray(ray, depth + 1)?; - - (1.0 - fresnel_coefficient) * (1.0 - material.alpha) * t_lambda + self.compute_transparency( + &intersection_context, + incident_ray, + material, + eta_i, + eta_t, + depth, + )? }; // This is the result of the Phong illumination equation. @@ -349,11 +327,22 @@ impl Scene { incident_ray: Vector, normal: Vector, ) -> f64 { - let cos_theta_i = dot(incident_ray, normal); + let mut cos_theta_i = dot(incident_ray, normal); + + if cos_theta_i < 0.0 { + cos_theta_i = dot(incident_ray, -normal); + } let f0 = ((material.eta - 1.0) / (material.eta + 1.0)).powi(2); let fr = f0 * 1.0 + (1.0 - f0) * (1.0 - cos_theta_i).powi(5); + if fr < 0.0 || fr > 1.0 { + warn!( + eta = material.eta, + cos_theta_i, f0, fr, "fresnel coefficient outside of 0 - 1" + ); + } + fr } @@ -370,6 +359,89 @@ impl Scene { r } + + fn compute_transparency( + &self, + intersection_context: &IntersectionContext, + incident_ray: Ray, + material: &Material, + eta_i: f64, + eta_t: f64, + depth: usize, + ) -> Result { + let span = + trace_span!("compute_transparency", eta_i = eta_i, eta_t = eta_t); + let _enter = span.enter(); + + let mut n = intersection_context.normal.normalize(); + if intersection_context.exiting { + n = -n; + } + + let i = incident_ray.direction.normalize(); + + assert!(eta_t != 0.0, "wtf eta_t is 0"); + + // Slide 69 + let mut cos_theta_i = dot(i, n); + + if cos_theta_i > 1.0 { + // warn!("[{depth}] cos_theta_i = {cos_theta_i}"); + cos_theta_i = 1.0; + } + + let sin_theta_i = (1.0 - cos_theta_i.powi(2)).sqrt(); + + // Total internal reflection check + if sin_theta_i * eta_i > eta_t { + warn!( + sin_theta_i, + eta_i, eta_t, "Total internal reflection check failed." + ); + return Ok(ZERO_COLOR); + } + + let sin_theta_t = (eta_i / eta_t) * sin_theta_i; + let cos_theta_t = (1.0 - sin_theta_t.powi(2)).sqrt(); + + let fresnel_coefficient = self.compute_fresnel_coefficient(&material, i, n); + + // Calculate refraction direction + let a = (-n).normalize() * cos_theta_t; + let s_direction = cos_theta_i * n - i; + let m_unit = s_direction.normalize(); + let b = m_unit * sin_theta_t; + let t = a + b; + + // Jitter a bit to reduce acne + // TODO: Is this a good constant? + let origin = intersection_context.point; + let origin = origin + JITTER_CONST * t; + + let ray = Ray::new(origin, t); + if ray.has_nan() { + warn!("WTF"); + } + /* assert!( + !ray.has_nan(), + "ray is nan WTF {cos_theta_i} {sin_theta_i} ({}) {sin_theta_t} {cos_theta_t} | normal: {:?}", + eta_i / eta_t, + intersection_context.normal, + ); */ + let t_lambda = self.trace_single_ray(ray, depth + 1)?; + + let value = (1.0 - fresnel_coefficient) * (1.0 - material.alpha) * t_lambda; + debug!( + depth, + fresnel_coefficient, + alpha = material.alpha, + ?t_lambda, + ?value, + "computing final value" + ); + + Ok(value) + } } /// Information about an intersection diff --git a/assignment-1d/src/scene/input_file/mod.rs b/assignment-1d/src/scene/input_file/mod.rs index 3320ff2..a6c98cc 100644 --- a/assignment-1d/src/scene/input_file/mod.rs +++ b/assignment-1d/src/scene/input_file/mod.rs @@ -61,12 +61,12 @@ impl Scene { macro_rules! r { ($ty:ty) => { <$ty>::construct(&mut parts, ()) - .with_context(|| format!("Could not parse {}", stringify!($ty)))? + .with_context(|| format!("Could not parse {} ({}:{})", stringify!($ty), file!(), line!()))? }; ($ty:ty, $($ex:expr),* $(,)?) => { <$ty>::construct(&mut parts, $($ex,)*) - .with_context(|| format!("Could not parse {}", stringify!($ty)))? + .with_context(|| format!("Could not parse {} ({}:{})", stringify!($ty), file!(), line!()))? }; } @@ -327,7 +327,12 @@ macro_rules! impl_construct { { let item = match it.next() { Some(v) => v, - None => bail!("Ran out of items"), + None => bail!( + "Ran out of items for {} ({}:{})", + stringify!($ty), + file!(), + line!() + ), }; Ok(item.parse()?) diff --git a/assignment-1d/src/scene/sphere.rs b/assignment-1d/src/scene/sphere.rs index c651609..7805e8f 100644 --- a/assignment-1d/src/scene/sphere.rs +++ b/assignment-1d/src/scene/sphere.rs @@ -36,6 +36,10 @@ impl Sphere { let discriminant = b * b - 4.0 * a * c; + if discriminant.is_nan() { + warn!("WTF NAN"); + } + let time = match discriminant { // Discriminant < 0, means the equation has no solutions. d if d < 0.0 => None, @@ -80,6 +84,11 @@ impl Sphere { dx.powi(2) + dy.powi(2) + dz.powi(2) < self.radius.powi(2) }; + /* let normal = match exiting { + true => -normal, + false => normal, + }; */ + Ok(Some(IntersectionContext { time, point, diff --git a/assignment-1d/src/scene/tracing.rs b/assignment-1d/src/scene/tracing.rs index 3617709..5d6cc63 100644 --- a/assignment-1d/src/scene/tracing.rs +++ b/assignment-1d/src/scene/tracing.rs @@ -12,6 +12,9 @@ impl Scene { return Ok(Color::new(0.0, 0.0, 0.0)); } + let span = trace_span!("trace_ray", ray = ?ray, depth = depth); + let _enter = span.enter(); + let intersections = self .objects .iter() diff --git a/assignment-1d/src/scene/triangle.rs b/assignment-1d/src/scene/triangle.rs index 367a434..be994a8 100644 --- a/assignment-1d/src/scene/triangle.rs +++ b/assignment-1d/src/scene/triangle.rs @@ -100,7 +100,7 @@ impl Triangle { time, point, normal, - exiting: todo!(), + exiting: false, })) }