This commit is contained in:
Michael Zhang 2023-02-20 22:03:36 -06:00
parent 0000053097
commit 00000540b4
11 changed files with 1262 additions and 26 deletions

View file

@ -25,6 +25,8 @@ dependencies = [
"base64",
"clap",
"derivative",
"generator",
"itertools",
"nalgebra",
"num",
"ordered-float",
@ -188,6 +190,19 @@ dependencies = [
"libc",
]
[[package]]
name = "generator"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e"
dependencies = [
"cc",
"libc",
"log",
"rustversion",
"windows",
]
[[package]]
name = "getrandom"
version = "0.2.8"
@ -236,6 +251,15 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -566,6 +590,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "safe_arch"
version = "0.6.0"
@ -780,6 +810,19 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a"
dependencies = [
"windows_aarch64_msvc 0.39.0",
"windows_i686_gnu 0.39.0",
"windows_i686_msvc 0.39.0",
"windows_x86_64_gnu 0.39.0",
"windows_x86_64_msvc 0.39.0",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
@ -787,12 +830,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
@ -801,24 +844,48 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
@ -831,6 +898,12 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"

View file

@ -23,6 +23,8 @@ anyhow = "1.0.68"
base64 = "0.21.0"
clap = { version = "4.1.4", features = ["cargo", "derive"] }
derivative = "2.2.0"
generator = "0.7.2"
itertools = "0.10.5"
nalgebra = "0.32.1"
num = { version = "0.4.0", features = ["serde"] }
ordered-float = "3.4.0"

2
assignment-1c/examples/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# Necessary files
!/earthtexture.ppm

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,20 @@
use std::io::{Result, Write};
use generator::{done, Gn};
use itertools::Itertools;
use std::{
fs::File,
io::{BufRead, BufReader, Read, Write},
path::Path,
};
use anyhow::Result;
use nalgebra::Vector3;
/// A pixel color represented by a red, green, and blue value in the range 0-1.
pub type Color = Vector3<f64>;
/// A representation of an image
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Image {
/// Width in pixels
pub width: usize,
@ -14,10 +23,71 @@ pub struct Image {
pub height: usize,
/// Pixel data in row-major form.
#[derivative(Debug = "ignore")]
pub data: Vec<Color>,
}
impl Image {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self> {
let file = File::open(path.as_ref())?;
Self::read(file)
}
/// Parse image from a Read
pub fn read(r: impl Read + Send) -> Result<Self> {
let mut line_reader = BufReader::new(r);
let mut header = String::new();
line_reader.read_line(&mut header)?;
let parts = header.split(" ").collect::<Vec<_>>();
let width = parts[1].parse::<usize>()?;
let height = parts[2].parse::<usize>()?;
let numbers = Gn::<()>::new_scoped(move |mut s| {
macro_rules! gen_try {
($expr:expr) => {
match $expr {
Ok(v) => v,
Err(e) => {
s.yield_(Err(anyhow::Error::from(e)));
done!();
}
}
};
}
for line in line_reader.lines() {
let line = gen_try!(line);
let parts = line.split_whitespace();
for part in parts {
let int = gen_try!(part.parse::<f64>());
s.yield_(Ok(int));
}
}
done!()
});
let mut data = Vec::with_capacity(width * height);
for mut chunk in &(numbers).chunks(3) {
let (r, g, b) = match chunk.next_tuple() {
Some(v) => v,
None => bail!("Not enough elements"),
};
let color = Color::new(r?, g?, b?);
data.push(color);
}
Ok(Image {
width,
height,
data,
})
}
/// Write the image in PPM format to a file.
pub fn write(&self, mut w: impl Write) -> Result<()> {
// Header

View file

@ -15,3 +15,4 @@ pub mod scene;
pub mod utils;
pub type Point = Vector3<f64>;
pub type Vector = Vector3<f64>;

View file

@ -1,4 +1,4 @@
use crate::Point;
use crate::{Point, Vector};
/// A normalized parametric Ray of the form (origin + direction * time)
///
@ -7,7 +7,7 @@ use crate::Point;
#[derive(Debug)]
pub struct Ray {
pub origin: Point,
pub direction: Point,
pub direction: Vector,
}
impl Ray {

View file

@ -3,6 +3,7 @@ use anyhow::Result;
use ordered_float::NotNan;
use crate::utils::compute_rotation_matrix;
use crate::Vector;
use crate::{ray::Ray, Point};
use super::illumination::IntersectionContext;
@ -10,7 +11,7 @@ use super::illumination::IntersectionContext;
#[derive(Debug)]
pub struct Cylinder {
pub center: Point,
pub direction: Point,
pub direction: Vector,
pub radius: f64,
pub length: f64,
}
@ -26,7 +27,7 @@ impl Cylinder {
) -> Result<Option<IntersectionContext>> {
// Determine rotation matrix for turning the cylinder upright along the
// Z-axis
let target_direction = Point::new(0.0, 0.0, 1.0);
let target_direction = Vector::new(0.0, 0.0, 1.0);
let rotation_matrix =
compute_rotation_matrix(self.direction, target_direction)?;
let inverse_rotation_matrix =
@ -153,7 +154,7 @@ impl Cylinder {
}
let normal_rotated =
Point::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z)
Vector::new(0.0, 0.0, rotated_point.z - rotated_cylinder_center.z)
.normalize();
let normal = inverse_rotation_matrix * normal_rotated;
@ -179,7 +180,7 @@ impl Cylinder {
#[cfg(test)]
mod tests {
use crate::{ray::Ray, Point};
use crate::{ray::Ray, Point, Vector};
use super::Cylinder;
@ -187,7 +188,7 @@ mod tests {
fn test_cylinder() {
let cylinder = Cylinder {
center: Point::new(0.0, 0.0, 0.0),
direction: Point::new(0.0, 1.0, 0.0),
direction: Vector::new(0.0, 1.0, 0.0),
radius: 3.0,
length: 4.0,
};

View file

@ -7,7 +7,7 @@ use rayon::prelude::{
ParallelIterator,
};
use crate::{image::Color, ray::Ray, utils::dot, Point};
use crate::{image::Color, ray::Ray, utils::dot, Point, Vector};
use super::{
data::{DepthCueing, Light, LightKind, Object},
@ -38,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: Point = self
let diffuse_and_specular: Color = self
.lights
.par_iter()
.map(|light| {
@ -214,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 = Point::new(x, y, z);
let delta = Vector::new(x, y, z);
light_location + delta
})
.take(JITTER_RAYS)
@ -267,7 +267,7 @@ pub struct IntersectionContext {
/// The normal vector protruding from the surface of the object at the
/// intersection point
#[derivative(PartialEq = "ignore", Ord = "ignore")]
pub normal: Point,
pub normal: Vector,
}
impl Eq for IntersectionContext {}

View file

@ -4,17 +4,18 @@ pub mod illumination;
pub mod input_file;
pub mod sphere;
use nalgebra::Vector3;
use nalgebra::{Matrix2x3, Vector3};
use crate::{image::Color, Point};
use crate::image::{Color, Image};
use crate::{Point, Vector};
use self::data::{Attenuation, DepthCueing, Light, Material, Object};
#[derive(Debug, Default)]
pub struct Scene {
pub eye_pos: Vector3<f64>,
pub view_dir: Vector3<f64>,
pub up_dir: Vector3<f64>,
pub eye_pos: Point,
pub view_dir: Vector,
pub up_dir: Vector,
/// Horizontal field of view (in degrees)
pub hfov: f64,
@ -32,5 +33,10 @@ pub struct Scene {
pub lights: Vec<Light>,
pub objects: Vec<Object>,
pub textures: Vec<Image>,
pub vertices: Vec<Point>,
pub flat_triangles: Vec<Vector3<usize>>,
pub normals: Vec<Vector>,
pub smooth_triangles: Vec<Matrix2x3<usize>>,
}

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use nalgebra::{Matrix3, Vector3};
use ordered_float::NotNan;
use crate::Point;
use crate::{Vector};
/// Finds the minimum of an iterator of f64s, ignoring any NaN values
#[inline]
@ -30,17 +30,17 @@ where
/// Dot-product between two 3D vectors.
#[inline]
pub fn dot(a: Point, b: Point) -> f64 {
pub fn dot(a: Vector, b: Vector) -> f64 {
a.x * b.x + a.y * b.y + a.z * b.z
}
/// Cross-product between two 3D vectors.
#[inline]
pub fn cross(a: Point, b: Point) -> Point {
pub fn cross(a: Vector, b: Vector) -> Vector {
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;
Point::new(x, y, z)
Vector::new(x, y, z)
}
/// Calculate the rotation matrix between the 2 given vectors