Refactor Vector3<f64> -> Point

This commit is contained in:
Michael Zhang 2023-02-20 17:40:19 -06:00
parent 1774fbc0de
commit 800eb68134
17 changed files with 128 additions and 68 deletions

View file

@ -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

View file

@ -18,7 +18,7 @@ dependencies = [
]
[[package]]
name = "assignment-1b"
name = "assignment-1c"
version = "0.1.0"
dependencies = [
"anyhow",

View file

@ -1,5 +1,5 @@
[package]
name = "assignment-1b"
name = "assignment-1c"
authors = ["Michael Zhang <zhan4854@umn.edu>"]
version = "0.1.0"
edition = "2021"
@ -15,7 +15,7 @@ strip = true
lto = true
[[bin]]
name = "raytracer1b"
name = "raytracer1c"
path = "src/main.rs"
[dependencies]

View file

@ -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 $^

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<f64>;

View file

@ -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;

View file

@ -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<f64>,
pub direction: Vector3<f64>,
pub origin: Point,
pub direction: Point,
}
impl Ray {
/// Construct a ray from endpoints
pub fn from_endpoints(start: Vector3<f64>, end: Vector3<f64>) -> 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<f64> {
pub fn eval(&self, time: f64) -> Point {
self.origin + self.direction * time
}
}

View file

@ -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<f64>,
pub direction: Vector3<f64>,
pub center: Point,
pub direction: Point,
pub radius: f64,
pub length: f64,
}
@ -26,7 +26,7 @@ impl Cylinder {
) -> Result<Option<IntersectionContext>> {
// 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);

View file

@ -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<f64>,
pub upper_right: Vector3<f64>,
pub lower_left: Vector3<f64>,
pub lower_right: Vector3<f64>,
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<f64>,
pub specular_color: Vector3<f64>,
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<f64>,
location: Point,
/// Whether light attenuation is enabled for this light
attenuation: Option<Attenuation>,
@ -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<f64> },
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<f64>,
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<f64>) -> Vector3<f64> {
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<f64> {
) -> impl Fn(usize, usize) -> Point {
let view_window = self.compute_viewing_window(distance);
let dx = view_window.upper_right - view_window.upper_left;

View file

@ -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<f64> = 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<f64>,
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<f64>,
original_intersection_point: Vector3<f64>,
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<f64>,
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<f64>,
pub normal: Point,
}
impl Eq for IntersectionContext {}

View file

@ -1,13 +1,15 @@
use std::{fs::File, io::Read, path::Path};
use anyhow::Result;
use nalgebra::Vector3;
use crate::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 {

View file

@ -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<Material>,
pub lights: Vec<Light>,
pub objects: Vec<Object>,
pub vertices: Vec<Point>,
}

View file

@ -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<f64>,
pub center: Point,
pub radius: f64,
}

View file

@ -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: I) -> Option<f64>
@ -28,17 +30,17 @@ where
/// Dot-product between two 3D vectors.
#[inline]
pub fn dot(a: Vector3<f64>, b: Vector3<f64>) -> 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<f64>, b: Vector3<f64>) -> Vector3<f64> {
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