diff --git a/assignment-1/src/image.rs b/assignment-1/src/image.rs index 15329f4..1c78b06 100644 --- a/assignment-1/src/image.rs +++ b/assignment-1/src/image.rs @@ -2,7 +2,25 @@ use std::io::{Result, Write}; /// A 24-bit pixel represented by a red, green, and blue value. #[derive(Clone, Copy, Default, Debug)] -pub struct Pixel(pub u8, pub u8, pub u8); +pub struct Color { + pub red: u8, + pub green: u8, + pub blue: u8, +} + +impl Color { + pub fn new(r: u8, g: u8, b: u8) -> Self { + Color { + red: r, + green: g, + blue: b, + } + } + + pub fn from_01_float(r: f64, g: f64, b: f64) -> Self { + Color::new((r * 256.0) as u8, (g * 256.0) as u8, (b * 256.0) as u8) + } +} /// A representation of an image pub struct Image { @@ -13,7 +31,7 @@ pub struct Image { pub(crate) height: usize, /// Pixel data in row-major form. - pub(crate) data: Vec, + pub(crate) data: Vec, } impl Image { @@ -24,8 +42,10 @@ impl Image { w.write_all(header.as_bytes())?; // Pixel data + assert_eq!(self.data.len(), self.width * self.height); + for pixel in self.data.iter() { - let Pixel(red, green, blue) = pixel; + let Color { red, green, blue } = pixel; let pixel = format!("{red} {green} {blue}\n"); w.write_all(pixel.as_bytes())?; } diff --git a/assignment-1/src/input_file.rs b/assignment-1/src/input_file.rs index 0597e9c..772898c 100644 --- a/assignment-1/src/input_file.rs +++ b/assignment-1/src/input_file.rs @@ -3,6 +3,7 @@ use std::{fs::File, io::Read, path::Path}; use anyhow::Result; use crate::{ + image::Color, scene_data::{Object, Scene, Sphere}, vec3::Vec3, }; @@ -48,18 +49,25 @@ pub fn parse_input_file(path: impl AsRef) -> Result { Ok(Vec3::new(parts[0], parts[1], parts[2])) }; + let read_color = || { + if parts.len() < 3 { + bail!("Color requires 3 components."); + } + Ok(Color::from_01_float(parts[0], parts[1], parts[2])) + }; + match keyword { "eye" => scene.eye_pos = read_vec3()?, "viewdir" => scene.view_dir = read_vec3()?, "updir" => scene.up_dir = read_vec3()?, "hfov" => scene.hfov = parts[0], - "bkgcolor" => scene.bkg_color = read_vec3()?, + "bkgcolor" => scene.bkg_color = read_color()?, "mtlcolor" => { let idx = scene.material_colors.len(); material_color = Some(idx); - scene.material_colors.push(read_vec3()?); + scene.material_colors.push(read_color()?); } "sphere" => scene.objects.push(Object::Sphere(Sphere { diff --git a/assignment-1/src/main.rs b/assignment-1/src/main.rs index 31a2354..4b910cc 100644 --- a/assignment-1/src/main.rs +++ b/assignment-1/src/main.rs @@ -15,7 +15,9 @@ use anyhow::Result; use clap::Parser; use itertools::Itertools; use ordered_float::NotNan; -use rayon::prelude::{IntoParallelIterator, ParallelIterator}; +use rayon::prelude::{ + IndexedParallelIterator, IntoParallelIterator, ParallelIterator, +}; use crate::image::Image; use crate::input_file::parse_input_file; @@ -24,7 +26,7 @@ use crate::scene_data::Object; use crate::vec3::Vec3; use crate::view::Rect; -const ARBITRARY_D: f64 = 1.0; +const ARBITRARY_D: f64 = 2.0; /// Simple raycaster. #[derive(Parser)] @@ -74,7 +76,6 @@ fn main() -> Result<()> { let viewing_height = viewing_width / aspect_ratio; // Compute viewing window corners - // TODO: See slide 101 let n = scene.view_dir.unit(); #[rustfmt::skip] // Otherwise this line wraps over let view_window = Rect { @@ -103,14 +104,14 @@ fn main() -> Result<()> { }; // This is an L because par_bridge is unordered - let pixels = (0..scene.image_width) - .cartesian_product(0..scene.image_height) + let pixels = (0..scene.image_height) + .cartesian_product(0..scene.image_width) .collect_vec(); // Loop through every single pixel of the output file let pixels = pixels .into_par_iter() - .map(|(px, py)| { + .map(|(py, px)| { let pixel_in_space = translate_pixel(px, py); let ray = Ray::from_endpoints(scene.eye_pos, pixel_in_space); @@ -130,12 +131,12 @@ fn main() -> Result<()> { let pixel_color = match earliest_intersection { Some((_, sphere)) => scene.material_colors[sphere.material], - // There was no intersection, so this should default to the background - // color + // There was no intersection, so this should default to the scene's + // background color None => scene.bkg_color, }; - pixel_color.to_pixel() + pixel_color }) .collect::>(); diff --git a/assignment-1/src/scene_data.rs b/assignment-1/src/scene_data.rs index 3cc91e0..70b6baa 100644 --- a/assignment-1/src/scene_data.rs +++ b/assignment-1/src/scene_data.rs @@ -1,4 +1,4 @@ -use crate::vec3::Vec3; +use crate::{image::Color, vec3::Vec3}; #[derive(Debug)] pub struct Sphere { @@ -33,8 +33,8 @@ pub struct Scene { pub image_height: usize, /// Background color - pub bkg_color: Vec3, + pub bkg_color: Color, - pub material_colors: Vec, + pub material_colors: Vec, pub objects: Vec, } diff --git a/assignment-1/src/vec3.rs b/assignment-1/src/vec3.rs index 7885925..88b5840 100644 --- a/assignment-1/src/vec3.rs +++ b/assignment-1/src/vec3.rs @@ -1,9 +1,9 @@ -use std::ops::{Add, Div, Mul, Sub}; use std::fmt; +use std::ops::{Add, Div, Mul, Sub}; use num::Float; -use crate::image::Pixel; +use crate::image::Color; #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] pub struct Vec3 { @@ -54,16 +54,6 @@ impl Vec3 { } } -impl Vec3 { - /// Convert into an RGB color - pub fn to_pixel(&self) -> Pixel { - let r = (self.x * 256.0) as u8; - let g = (self.y * 256.0) as u8; - let b = (self.z * 256.0) as u8; - Pixel(r, g, b) - } -} - /// Vector addition impl Add> for Vec3 where