diff --git a/assignment-1b/examples/Hw1bSample2.txt b/assignment-1b/examples/Hw1bSample2.txt new file mode 100755 index 000000000..9ea65ed --- /dev/null +++ b/assignment-1b/examples/Hw1bSample2.txt @@ -0,0 +1,10 @@ +eye 0 0 0 +viewdir 0 -0.3 -1 +updir 0 1 0 +hfov 60 +imsize 256 512 +bkgcolor 0.1 0.1 0.1 +light 0 -1 0 0 1 1 1 +mtlcolor 1 1 0 1 1 1 0.2 0.6 0.2 20 +sphere 0 -2 -3 1 +sphere 0 0 -3 0.5 diff --git a/assignment-1c/Cargo.lock b/assignment-1c/Cargo.lock index bc1bc4f..126c06c 100644 --- a/assignment-1c/Cargo.lock +++ b/assignment-1c/Cargo.lock @@ -18,7 +18,7 @@ dependencies = [ ] [[package]] -name = "assignment-1b" +name = "assignment-1c" version = "0.1.0" dependencies = [ "anyhow", diff --git a/assignment-1c/Cargo.toml b/assignment-1c/Cargo.toml index bd9ba71..0fe39cd 100644 --- a/assignment-1c/Cargo.toml +++ b/assignment-1c/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "assignment-1b" +name = "assignment-1c" authors = ["Michael Zhang "] version = "0.1.0" edition = "2021" @@ -15,7 +15,7 @@ strip = true lto = true [[bin]] -name = "raytracer1b" +name = "raytracer1c" path = "src/main.rs" [dependencies] diff --git a/assignment-1c/Makefile b/assignment-1c/Makefile index 6355786..377d91c 100644 --- a/assignment-1c/Makefile +++ b/assignment-1c/Makefile @@ -8,8 +8,8 @@ ZIP := zip PANDOC := pandoc CONVERT := convert -HANDIN := ./hw1b.michael.zhang.zip -BINARY := ./raytracer1b +HANDIN := ./hw1c.michael.zhang.zip +BINARY := ./raytracer1c WRITEUP := ./writeup.pdf SHOWCASE := ./showcase.png SOURCES := Cargo.toml $(shell find -name "*.rs") @@ -31,7 +31,7 @@ $(BINARY): $(SOURCES) -e CARGO_TARGET_DIR=/usr/src/myapp/target/docker \ rust \ cargo build --profile release-handin - mv target/docker/release-handin/raytracer1b $@ + mv target/docker/release-handin/raytracer1c $@ $(HANDIN): $(BINARY) $(WRITEUP) Makefile Cargo.toml Cargo.lock README.md $(EXAMPLES_PNG) $(EXAMPLES_PPM) $(SHOWCASE) $(ZIP) -r $@ src examples $^ diff --git a/assignment-1c/examples/Hw1cSample1.txt b/assignment-1c/examples/Hw1cSample1.txt new file mode 100755 index 000000000..3411fc7 --- /dev/null +++ b/assignment-1c/examples/Hw1cSample1.txt @@ -0,0 +1,17 @@ +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 0 1 1 1 1 0.1 0.4 0.4 20 + + +v -2 1 -5 +v -1 -1 -4 +v 1 -1 -4 +v 2 1 -6 + +f 1 2 3 +f 1 3 4 \ No newline at end of file diff --git a/assignment-1c/examples/Hw1cSample2.txt b/assignment-1c/examples/Hw1cSample2.txt new file mode 100755 index 000000000..6fcd31e --- /dev/null +++ b/assignment-1c/examples/Hw1cSample2.txt @@ -0,0 +1,21 @@ +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 0 1 1 1 1 0.1 0.4 0.4 20 + + +v -2 1 -5 +v -1 -1 -4 +v 1 -1 -4 +v 2 1 -6 + +vn -2 1 1 +vn -1 -1 1 +vn 2 1 1 + +f 1//1 2//2 3//3 +f 1 3 4 \ No newline at end of file diff --git a/assignment-1c/examples/Hw1cSample3.txt b/assignment-1c/examples/Hw1cSample3.txt new file mode 100755 index 000000000..aeb6e63 --- /dev/null +++ b/assignment-1c/examples/Hw1cSample3.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/src/lib.rs b/assignment-1c/src/lib.rs index aa6a64d..7de590e 100644 --- a/assignment-1c/src/lib.rs +++ b/assignment-1c/src/lib.rs @@ -1,5 +1,7 @@ #![doc = include_str!("../README.md")] +use nalgebra::Vector3; + #[macro_use] extern crate anyhow; #[macro_use] @@ -11,3 +13,5 @@ pub mod image; pub mod ray; pub mod scene; pub mod utils; + +pub type Point = Vector3; diff --git a/assignment-1c/src/main.rs b/assignment-1c/src/main.rs index 8334beb..be5cf87 100644 --- a/assignment-1c/src/main.rs +++ b/assignment-1c/src/main.rs @@ -5,9 +5,9 @@ use std::fs::File; use std::path::PathBuf; use anyhow::Result; -use assignment_1b::image::Image; -use assignment_1b::ray::Ray; -use assignment_1b::scene::Scene; +use assignment_1c::image::Image; +use assignment_1c::ray::Ray; +use assignment_1c::scene::Scene; use clap::Parser; diff --git a/assignment-1c/src/ray.rs b/assignment-1c/src/ray.rs index a722ddf..851e201 100644 --- a/assignment-1c/src/ray.rs +++ b/assignment-1c/src/ray.rs @@ -1,4 +1,4 @@ -use nalgebra::Vector3; +use crate::Point; /// A normalized parametric Ray of the form (origin + direction * time) /// @@ -6,13 +6,13 @@ use nalgebra::Vector3; /// time occurs on the ray. #[derive(Debug)] pub struct Ray { - pub origin: Vector3, - pub direction: Vector3, + pub origin: Point, + pub direction: Point, } impl Ray { /// Construct a ray from endpoints - pub fn from_endpoints(start: Vector3, end: Vector3) -> Self { + pub fn from_endpoints(start: Point, end: Point) -> Self { let delta = (end - start).normalize(); Ray { origin: start, @@ -21,7 +21,7 @@ impl Ray { } /// Evaluate the ray at a certain point in time, yielding a point - pub fn eval(&self, time: f64) -> Vector3 { + pub fn eval(&self, time: f64) -> Point { self.origin + self.direction * time } } diff --git a/assignment-1c/src/scene/cylinder.rs b/assignment-1c/src/scene/cylinder.rs index 18a52fb..2ce1d3f 100644 --- a/assignment-1c/src/scene/cylinder.rs +++ b/assignment-1c/src/scene/cylinder.rs @@ -1,16 +1,16 @@ use anyhow::Result; -use nalgebra::Vector3; + use ordered_float::NotNan; -use crate::ray::Ray; use crate::utils::compute_rotation_matrix; +use crate::{ray::Ray, Point}; -use super::{illumination::IntersectionContext}; +use super::illumination::IntersectionContext; #[derive(Debug)] pub struct Cylinder { - pub center: Vector3, - pub direction: Vector3, + pub center: Point, + pub direction: Point, pub radius: f64, pub length: f64, } @@ -26,7 +26,7 @@ impl Cylinder { ) -> Result> { // Determine rotation matrix for turning the cylinder upright along the // Z-axis - let target_direction = Vector3::new(0.0, 0.0, 1.0); + let target_direction = Point::new(0.0, 0.0, 1.0); let rotation_matrix = compute_rotation_matrix(self.direction, target_direction)?; let inverse_rotation_matrix = @@ -153,7 +153,7 @@ impl Cylinder { } let normal_rotated = - Vector3::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z) + Point::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z) .normalize(); let normal = inverse_rotation_matrix * normal_rotated; @@ -179,23 +179,21 @@ impl Cylinder { #[cfg(test)] mod tests { - use nalgebra::Vector3; - - use crate::{ray::Ray}; + use crate::{ray::Ray, Point}; use super::Cylinder; #[test] fn test_cylinder() { let cylinder = Cylinder { - center: Vector3::new(0.0, 0.0, 0.0), - direction: Vector3::new(0.0, 1.0, 0.0), + center: Point::new(0.0, 0.0, 0.0), + direction: Point::new(0.0, 1.0, 0.0), radius: 3.0, length: 4.0, }; - let eye = Vector3::new(0.0, 3.0, 3.0); - let end = Vector3::new(0.0, 2.0, 2.0); + let eye = Point::new(0.0, 3.0, 3.0); + let end = Point::new(0.0, 2.0, 2.0); let ray = Ray::from_endpoints(eye, end); let res = cylinder.intersects_ray_at(&ray); diff --git a/assignment-1c/src/scene/data.rs b/assignment-1c/src/scene/data.rs index 45e5fdd..02aef1f 100644 --- a/assignment-1c/src/scene/data.rs +++ b/assignment-1c/src/scene/data.rs @@ -1,11 +1,11 @@ use std::fmt::Debug; use anyhow::Result; -use nalgebra::Vector3; use crate::image::Color; use crate::ray::Ray; use crate::utils::cross; +use crate::Point; use super::cylinder::Cylinder; use super::illumination::IntersectionContext; @@ -46,16 +46,16 @@ pub struct Object { #[derive(Debug)] pub struct Rect { - pub upper_left: Vector3, - pub upper_right: Vector3, - pub lower_left: Vector3, - pub lower_right: Vector3, + pub upper_left: Point, + pub upper_right: Point, + pub lower_left: Point, + pub lower_right: Point, } #[derive(Debug)] pub struct Material { - pub diffuse_color: Vector3, - pub specular_color: Vector3, + pub diffuse_color: Point, + pub specular_color: Point, pub k_a: f64, pub k_d: f64, @@ -67,7 +67,7 @@ pub struct Material { pub enum LightKind { /// A point light source exists at a point and emits light in all directions Point { - location: Vector3, + location: Point, /// Whether light attenuation is enabled for this light attenuation: Option, @@ -75,7 +75,7 @@ pub enum LightKind { /// A directional light source exists at an infinitely far location but emits /// light in a specific direction - Directional { direction: Vector3 }, + Directional { direction: Point }, } #[derive(Debug)] @@ -84,13 +84,13 @@ pub struct Light { pub kind: LightKind, /// The color, or intensity, of the light source - pub color: Vector3, + pub color: Point, } impl Light { /// Get the unit directional vector pointing from the given point to this /// light source - pub fn direction_from(&self, point: Vector3) -> Vector3 { + pub fn direction_from(&self, point: Point) -> Point { match self.kind { LightKind::Point { location, .. } => location - point, LightKind::Directional { direction } => -direction, @@ -200,7 +200,7 @@ impl Scene { pub fn pixel_translation_function( &self, distance: f64, - ) -> impl Fn(usize, usize) -> Vector3 { + ) -> impl Fn(usize, usize) -> Point { let view_window = self.compute_viewing_window(distance); let dx = view_window.upper_right - view_window.upper_left; diff --git a/assignment-1c/src/scene/illumination.rs b/assignment-1c/src/scene/illumination.rs index 446bf85..b9f9e01 100644 --- a/assignment-1c/src/scene/illumination.rs +++ b/assignment-1c/src/scene/illumination.rs @@ -1,6 +1,5 @@ use std::iter; -use nalgebra::Vector3; use ordered_float::NotNan; use rand::Rng; use rayon::prelude::{ @@ -8,7 +7,7 @@ use rayon::prelude::{ ParallelIterator, }; -use crate::{image::Color, ray::Ray, utils::dot}; +use crate::{image::Color, ray::Ray, utils::dot, Point}; use super::{ data::{DepthCueing, Light, LightKind, Object}, @@ -39,7 +38,7 @@ impl Scene { let ambient_component = material.k_a * material.diffuse_color; // Diffuse and specular lighting for each separate light - let diffuse_and_specular: Vector3 = self + let diffuse_and_specular: Point = self .lights .par_iter() .map(|light| { @@ -131,7 +130,7 @@ impl Scene { pub fn compute_shadow_coefficient( &self, obj_idx: usize, - point: Vector3, + point: Point, light: &Light, ) -> f64 { let light_direction = light.direction_from(point); @@ -200,8 +199,8 @@ impl Scene { fn compute_soft_shadow_coefficient( &self, - light_location: Vector3, - original_intersection_point: Vector3, + light_location: Point, + original_intersection_point: Point, object: &Object, ) -> f64 { // Soft shadows: jitter some rays here to somewhere close to the @@ -215,7 +214,7 @@ impl Scene { let x = rng.gen_range(0.0..JITTER_RADIUS); let y = rng.gen_range(0.0..JITTER_RADIUS); let z = rng.gen_range(0.0..JITTER_RADIUS); - let delta = Vector3::new(x, y, z); + let delta = Point::new(x, y, z); light_location + delta }) .take(JITTER_RAYS) @@ -263,12 +262,12 @@ pub struct IntersectionContext { /// The intersection point. #[derivative(PartialEq = "ignore", Ord = "ignore")] - pub point: Vector3, + pub point: Point, /// The normal vector protruding from the surface of the object at the /// intersection point #[derivative(PartialEq = "ignore", Ord = "ignore")] - pub normal: Vector3, + pub normal: Point, } impl Eq for IntersectionContext {} diff --git a/assignment-1c/src/scene/input_file.rs b/assignment-1c/src/scene/input_file.rs index c6882d2..cfd02b0 100644 --- a/assignment-1c/src/scene/input_file.rs +++ b/assignment-1c/src/scene/input_file.rs @@ -1,13 +1,15 @@ use std::{fs::File, io::Read, path::Path}; use anyhow::Result; -use nalgebra::Vector3; -use crate::scene::{ - cylinder::Cylinder, - data::{Attenuation, Light, LightKind, Material, Object}, - sphere::Sphere, - Scene, +use crate::{ + scene::{ + cylinder::Cylinder, + data::{Attenuation, Light, LightKind, Material, Object}, + sphere::Sphere, + Scene, + }, + Point, }; use super::data::{DepthCueing, ObjectKind}; @@ -56,11 +58,7 @@ impl Scene { let read_vec3 = |start: usize| { ensure!(parts.len() >= start + 3, "Vec3 requires 3 components."); - Ok(Vector3::new( - parts[start], - parts[start + 1], - parts[start + 2], - )) + Ok(Point::new(parts[start], parts[start + 1], parts[start + 2])) }; match keyword { diff --git a/assignment-1c/src/scene/mod.rs b/assignment-1c/src/scene/mod.rs index cc683ab..9d70991 100644 --- a/assignment-1c/src/scene/mod.rs +++ b/assignment-1c/src/scene/mod.rs @@ -6,9 +6,9 @@ pub mod sphere; use nalgebra::Vector3; -use crate::image::Color; +use crate::{image::Color, Point}; -use self::data::{DepthCueing, Light, Material, Object, Attenuation}; +use self::data::{Attenuation, DepthCueing, Light, Material, Object}; #[derive(Debug, Default)] pub struct Scene { @@ -31,4 +31,6 @@ pub struct Scene { pub materials: Vec, pub lights: Vec, pub objects: Vec, + + pub vertices: Vec, } diff --git a/assignment-1c/src/scene/sphere.rs b/assignment-1c/src/scene/sphere.rs index a9bcd1d..aa24e49 100644 --- a/assignment-1c/src/scene/sphere.rs +++ b/assignment-1c/src/scene/sphere.rs @@ -1,14 +1,13 @@ use anyhow::Result; -use nalgebra::Vector3; use ordered_float::NotNan; -use crate::{ray::Ray, utils::min_f64}; +use crate::{ray::Ray, utils::min_f64, Point}; use super::illumination::IntersectionContext; #[derive(Debug)] pub struct Sphere { - pub center: Vector3, + pub center: Point, pub radius: f64, } diff --git a/assignment-1c/src/utils.rs b/assignment-1c/src/utils.rs index 95b1e0b..153be4d 100644 --- a/assignment-1c/src/utils.rs +++ b/assignment-1c/src/utils.rs @@ -2,6 +2,8 @@ use anyhow::Result; use nalgebra::{Matrix3, Vector3}; use ordered_float::NotNan; +use crate::Point; + /// Finds the minimum of an iterator of f64s, ignoring any NaN values #[inline] pub fn min_f64(i: I) -> Option @@ -28,17 +30,17 @@ where /// Dot-product between two 3D vectors. #[inline] -pub fn dot(a: Vector3, b: Vector3) -> f64 { +pub fn dot(a: Point, b: Point) -> f64 { a.x * b.x + a.y * b.y + a.z * b.z } /// Cross-product between two 3D vectors. #[inline] -pub fn cross(a: Vector3, b: Vector3) -> Vector3 { +pub fn cross(a: Point, b: Point) -> Point { let x = a.y * b.z - a.z * b.y; let y = a.z * b.x - a.x * b.z; let z = a.x * b.y - a.y * b.x; - Vector3::new(x, y, z) + Point::new(x, y, z) } /// Calculate the rotation matrix between the 2 given vectors