diff --git a/assignment-1c/examples/hw1c_grading_files/Test1.png b/assignment-1c/examples/hw1c_grading_files/Test1.png new file mode 100644 index 000000000..e382339 Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test1.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test1.txt b/assignment-1c/examples/hw1c_grading_files/Test1.txt new file mode 100644 index 000000000..f64394c --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test1.txt @@ -0,0 +1,14 @@ +eye 0 0 0 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 256 +bkgcolor 0.1 0.1 0.1 +light -2 1 0 1 1 1 1 +mtlcolor 0 1 0 1 1 1 0.2 0.6 0.2 20 +v 0 1 -4 +v -1 -1 -4 +v 1 -1 -4 +v 2 1 -6 +f 1 2 3 +f 1 3 4 diff --git a/assignment-1c/examples/hw1c_grading_files/Test2.png b/assignment-1c/examples/hw1c_grading_files/Test2.png new file mode 100644 index 000000000..3292dc0 Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test2.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test2.txt b/assignment-1c/examples/hw1c_grading_files/Test2.txt new file mode 100644 index 000000000..d77eb90 --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test2.txt @@ -0,0 +1,18 @@ +eye 0 0 0 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 256 +bkgcolor 0.1 0.1 0.1 +light -2 1 0 1 1 1 1 +mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20 +v -1 1 -4 +v -1 -1 -4 +v 1 -1 -4 +v 1 1 -4 +vn -1 1 1 +vn -1 -1 1 +vn 1 -1 1 +vn 1 1 1 +f 1//1 2//2 3//3 +f 1//1 3//3 4//4 diff --git a/assignment-1c/examples/hw1c_grading_files/Test3.png b/assignment-1c/examples/hw1c_grading_files/Test3.png new file mode 100644 index 000000000..2114a78 Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test3.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test3.txt b/assignment-1c/examples/hw1c_grading_files/Test3.txt new file mode 100644 index 000000000..aeb6e63 --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test3.txt @@ -0,0 +1,10 @@ +eye 2 -6 1 +viewdir -1 3 -0.5 +updir 0 0 1 +hfov 50 +imsize 512 512 +bkgcolor 0.5 0.7 0.9 +light 0 1 -1 0 1 1 1 +mtlcolor 0 1 0 1 1 1 0.2 0.8 0.1 20 +texture earthtexture.ppm +sphere 0 0 0 2 \ No newline at end of file diff --git a/assignment-1c/examples/hw1c_grading_files/Test4.png b/assignment-1c/examples/hw1c_grading_files/Test4.png new file mode 100644 index 000000000..f2fea5c Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test4.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test4.txt b/assignment-1c/examples/hw1c_grading_files/Test4.txt new file mode 100644 index 000000000..3d4dd34 --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test4.txt @@ -0,0 +1,19 @@ +eye 0 0 0 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 256 +bkgcolor 0.1 0.1 0.1 +light -2 1 0 1 1 1 1 +mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20 +texture umn.ppm +v -1 1 -4 +v -1 -1 -4 +v 1 -1 -4 +v 1 1 -4 +vt 0 0 +vt 0 1 +vt 1 1 +vt 1 0 +f 1/1 2/2 3/3 +f 1/1 3/3 4/4 diff --git a/assignment-1c/examples/hw1c_grading_files/Test5.png b/assignment-1c/examples/hw1c_grading_files/Test5.png new file mode 100644 index 000000000..e02854a Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test5.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test5.txt b/assignment-1c/examples/hw1c_grading_files/Test5.txt new file mode 100644 index 000000000..68aa98c --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test5.txt @@ -0,0 +1,25 @@ +eye 0 0 0 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 256 +bkgcolor 0.1 0.1 0.1 +light -2 1 0 1 1 1 1 +mtlcolor 0 0 1 1 1 1 0.2 0.6 0.2 20 +texture umn.ppm +v -1 1 -4 +v -1 -1 -4 +v 1 -1 -4 +v 1 1 -4 +vn -1 1 1 +vn -1 -1 1 +vn 1 -1 1 +vn 1 1 1 +vt 0 0 +vt 0 1 +vt 1 1 +vt 1 0 +f 1/1/1 2/2/2 3/3/3 +f 1/1/1 3/3/3 4/4/4 + + diff --git a/assignment-1c/examples/hw1c_grading_files/Test6.png b/assignment-1c/examples/hw1c_grading_files/Test6.png new file mode 100644 index 000000000..e0d0661 Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/Test6.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/Test6.txt b/assignment-1c/examples/hw1c_grading_files/Test6.txt new file mode 100644 index 000000000..a441199 --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/Test6.txt @@ -0,0 +1,56 @@ +eye 12.5 5 2.5 +viewdir -2 -0.5 2 +updir 0 1 0 +hfov 60 +imsize 900 600 +bkgcolor 0.5 0.7 0.9 +light 1 -1 1 0 1 1 1 +mtlcolor 0 1 0 1 1 1 0.2 0.8 0 20 +v 10 0 5 +v -10 0 5 +v -10 0 25 +v 10 0 25 +v 5 0 12.5 +v -5 0 12.5 +v -5 5 12.5 +v 5 5 12.5 +v 5 0 17.5 +v -5 0 17.5 +v -5 5 17.5 +v 5 5 17.5 +v 5 7.5 15 +v -5 7.5 15 +v 5 4.5 12 +v -5 4.5 12 +v 5 4.5 18 +v -5 4.5 18 +vt 0 0 +vt 0 1 +vt 1 1 +vt 1 0 +vt 2 0 +vt 2 1 +vt 0.5 0 +vt 4 0 +vt 4 1 +texture grass.ppm +f 1/2 2/3 3/4 +f 1/2 3/4 4/1 +texture wood.ppm +f 5/2 6/6 7/5 +f 5/2 7/5 8/1 +f 9/2 11/5 10/6 +f 9/2 12/1 11/5 +f 6/2 10/3 11/4 +f 6/2 11/4 7/1 +f 5/3 12/1 9/2 +f 5/3 8/4 12/1 +f 7/2 11/3 14/7 +f 8/3 13/7 12/2 +texture redwood.ppm +f 13/1 15/2 16/9 +f 13/1 16/9 14/8 +f 13/8 14/1 18/2 +f 13/8 18/2 17/9 +texture soccerball.ppm +sphere -2.5 0.5 9 0.5 diff --git a/assignment-1c/examples/hw1c_grading_files/TestE.png b/assignment-1c/examples/hw1c_grading_files/TestE.png new file mode 100644 index 000000000..e06d2d4 Binary files /dev/null and b/assignment-1c/examples/hw1c_grading_files/TestE.png differ diff --git a/assignment-1c/examples/hw1c_grading_files/TestE.txt b/assignment-1c/examples/hw1c_grading_files/TestE.txt new file mode 100644 index 000000000..98864de --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/TestE.txt @@ -0,0 +1,20 @@ +eye 0 0 0 +viewdir 0 0 -1 +updir 0 1 0 +hfov 60 +imsize 512 256 +bkgcolor 0.1 0.1 0.1 +light -2 1 0 1 1 1 1 +mtlcolor 1 1 1 1 1 1 0.2 0.6 0.2 20 1 0 +bump normalmap.ppm +sphere -1.6 0 -4 0.5 +v -1 1 -4 +v -1 -1 -4 +v 1 -1 -4 +v 1 1 -4 +vt 0 0 +vt 0 1 +vt 1 1 +vt 1 0 +f 1/1 2/2 3/3 +f 1/1 3/3 4/4 diff --git a/assignment-1c/examples/hw1c_grading_files/grading.sh b/assignment-1c/examples/hw1c_grading_files/grading.sh new file mode 100755 index 000000000..d6c15f8 --- /dev/null +++ b/assignment-1c/examples/hw1c_grading_files/grading.sh @@ -0,0 +1,2 @@ +#! /bin/sh +PROGRAM_NAME="raytracer1c"; echo "-------- Running Test1.txt --------"; ./$PROGRAM_NAME Test1.txt; echo "-------- Running Test2.txt --------";./$PROGRAM_NAME Test2.txt; echo "-------- Running Test3.txt --------";./$PROGRAM_NAME Test3.txt; echo "-------- Running Test4.txt --------";./$PROGRAM_NAME Test4.txt; echo "-------- Running Test5.txt --------";./$PROGRAM_NAME Test5.txt; echo "-------- Running Test6.txt --------";./$PROGRAM_NAME Test6.txt; echo "-------- Running TestE.txt --------";./$PROGRAM_NAME TestE.txt; diff --git a/assignment-1c/src/main.rs b/assignment-1c/src/main.rs index 91fe7e4..2d6dba7 100644 --- a/assignment-1c/src/main.rs +++ b/assignment-1c/src/main.rs @@ -4,7 +4,7 @@ extern crate tracing; use std::fs::File; use std::path::PathBuf; -use anyhow::Result; +use anyhow::{Context, Result}; use assignment_1c::image::Image; use assignment_1c::ray::Ray; use assignment_1c::scene::Scene; @@ -112,9 +112,9 @@ fn main() -> Result<()> { Ok(match earliest_intersection { // Take the object's material color - Some((obj_idx, intersection_context, object)) => { - scene.compute_pixel_color(obj_idx, object, intersection_context)? - } + Some((obj_idx, intersection_context, object)) => scene + .compute_pixel_color(obj_idx, object, intersection_context) + .context("Could not compute pixel color.")?, // There was no intersection, so this should default to the scene's // background color diff --git a/assignment-1c/src/scene/illumination.rs b/assignment-1c/src/scene/illumination.rs index c563612..68b6375 100644 --- a/assignment-1c/src/scene/illumination.rs +++ b/assignment-1c/src/scene/illumination.rs @@ -43,7 +43,7 @@ impl Scene { let texture = match self.textures.get(texture_idx) { Some(v) => v, - None => bail!("Texture index not found."), + None => bail!("Texture index {texture_idx} not found."), }; texture.pixel_at(u, v) diff --git a/assignment-1c/src/scene/input_file.rs b/assignment-1c/src/scene/input_file.rs index 1b192cf..c903d70 100644 --- a/assignment-1c/src/scene/input_file.rs +++ b/assignment-1c/src/scene/input_file.rs @@ -4,7 +4,7 @@ use std::path::Path; use anyhow::{Context, Result}; use itertools::Itertools; -use nalgebra::Vector3; +use nalgebra::{Vector2, Vector3}; use crate::{ image::{Color, Image}, @@ -13,7 +13,7 @@ use crate::{ data::{Attenuation, Light, LightKind, Material}, object::{Object, ObjectKind}, sphere::Sphere, - texture::{Texture, NormalMap}, + texture::Texture, triangle::Triangle, Scene, }, @@ -209,6 +209,9 @@ impl Scene { // vn nx ny nz "vn" => scene.vertex_normals.push(r!(Vector)), + // vt u v + "vt" => scene.texture_vertices.push(r!(Vector2)), + // f v1 v2 v3 // f v1//n1 v2//n2 v3//n3 "f" => { @@ -230,7 +233,7 @@ impl Scene { let textures = match textures.iter().filter(|o| o.is_some()).count() { 0 => None, n if n == vs.len() => Some(textures.map(|o| o.unwrap())), - _ => bail!("Cannot mix and match having a normal index"), + _ => bail!("Cannot mix and match having a texture index"), }; let triangle = Triangle { @@ -256,7 +259,7 @@ impl Scene { texture_idx = Some(idx); let image = Image::from_file(path)?; - let texture = Texture::new(image); + let texture = Texture::new(image, false); scene.textures.push(texture); } @@ -271,8 +274,8 @@ impl Scene { texture_idx = Some(idx); let image = Image::from_file(path)?; - let normal_map = NormalMap::new(image); - scene.normal_maps.push(normal_map); + let normal_map = Texture::new(image, true); + scene.textures.push(normal_map); } _ => bail!("Unknown keyword {keyword}"), @@ -332,6 +335,25 @@ macro_rules! impl_construct { impl_construct!(f64); impl_construct!(usize); +impl Construct for Vector2 { + type Args = (); + + fn construct<'a, I>(it: &mut I, _: Self::Args) -> Result + where + I: Iterator, + { + let (x, y) = match it.next_tuple() { + Some(v) => v, + None => bail!("Expected 2 values"), + }; + + let x: f64 = x.parse()?; + let y: f64 = y.parse()?; + + Ok(Vector2::new(x, y)) + } +} + impl Construct for Vector3 { type Args = (); diff --git a/assignment-1c/src/scene/mod.rs b/assignment-1c/src/scene/mod.rs index e610ea1..2bb379d 100644 --- a/assignment-1c/src/scene/mod.rs +++ b/assignment-1c/src/scene/mod.rs @@ -7,12 +7,14 @@ pub mod sphere; pub mod texture; pub mod triangle; +use nalgebra::Vector2; + use crate::image::Color; use crate::{Point, Point2, Vector}; use self::data::{Attenuation, DepthCueing, Light, Material}; use self::object::Object; -use self::texture::{Texture, NormalMap}; +use self::texture::{Texture}; #[derive(Debug, Default)] pub struct Scene { @@ -40,7 +42,7 @@ pub struct Scene { pub textures: Vec, /// List of normal maps (Extra credit) - pub normal_maps: Vec, + pub normal_maps: Vec, /// Coordinates into a texture image pub texture_vertices: Vec, diff --git a/assignment-1c/src/scene/texture.rs b/assignment-1c/src/scene/texture.rs index b94bfb9..7d098c7 100644 --- a/assignment-1c/src/scene/texture.rs +++ b/assignment-1c/src/scene/texture.rs @@ -4,17 +4,33 @@ use crate::{ }; #[derive(Debug)] -pub struct Texture(Image); +pub struct Texture { + image: Image, + is_normal_map: bool, +} impl Texture { - pub fn new(image: Image) -> Self { - Self(image) + pub fn new(image: Image, is_normal_map: bool) -> Self { + Self { + image, + is_normal_map, + } } pub fn pixel_at_exact(&self, x: usize, y: usize) -> Color { // TODO: Debug asserts? - self.0.data[y * self.0.width + x] + let x = match x { + n if n < self.image.width => n, + _ => self.image.width - 1, + }; + + let y = match y { + n if n < self.image.height => n, + _ => self.image.height - 1, + }; + + self.image.data[y * self.image.width + x] } /// Returns a pixel at the given coordinate. For non-lattice coordinates, @@ -24,8 +40,8 @@ impl Texture { debug_assert!(0.0 <= v && v <= 1.0, "u must be between 0 and 1"); // Slide 121 - let x = u * (self.0.width - 1) as f64; - let y = v * (self.0.height - 1) as f64; + let x = u * (self.image.width - 1) as f64; + let y = v * (self.image.height - 1) as f64; let i = x.floor(); let j = y.floor(); @@ -42,23 +58,3 @@ impl Texture { + (alpha) * (beta) * self.pixel_at_exact(i + 1, j + 1) } } - -#[derive(Debug)] -pub struct NormalMap(Image); - -impl NormalMap { - pub fn new(image: Image) -> Self { - Self(image) - } - - pub fn normal_vector_at_exact(&self, x: usize, y: usize) -> Vector { - let vec = self.0.data[y * self.0.width + x]; - - // So, according to the instructions, this should actually be a value - // between -1 and 1. However, we're reading this in through an image. - // I'm just going to do the lazy thing here (which theoretically - // actually saves cycles) by only doing the transformation when loading - // out of the image - vec.map(|value| 2.0 * value / 255.0 - 1.0) - } -}