use std::fmt::{Display, Formatter}; use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub}; use rand::distributions::{Distribution, Uniform}; #[derive(Debug, Clone, Copy)] pub struct Vec3 { x: f64, y: f64, z: f64 } pub type Point3 = Vec3; pub type Color = Vec3; impl Vec3 { pub fn new(x: f64, y: f64, z: f64) -> Vec3 { Vec3 {x, y, z} } pub fn x(&self) -> f64 { self.x } pub fn y(&self) -> f64 { self.y } pub fn z(&self) -> f64 { self.z } pub fn length_squared(&self) -> f64 { self.x * self.x + self.y * self.y + self.z * self.z } pub fn length(&self) -> f64 { self.distance(&Vec3::default()) } pub fn unit_vector(&self) -> Vec3 { let length = self.length(); Vec3::new(self.x / length, self.y / length, self.z / length) } pub fn dot(&self, v:&Vec3) -> f64 { self.x * v.x + self.y * v.y + self.z * v.z } pub fn cross(&self, v:&Vec3) -> Vec3 { Vec3::new( self.y * v.z - self.z * v.y, self.z * v.x - self.x * v.z, self.x * v.y - self.y * v.x ) } pub fn distance(&self, other: &Vec3) -> f64 { let dx = self.x - other.x(); let dy = self.y - other.y(); let dz = self.z - other.z(); (dx * dx + dy * dy + dz * dz).sqrt() } pub fn random(min: f64, max:f64) -> Self { let between = Uniform::from(min..max); let mut rng = rand::thread_rng(); Vec3::new( between.sample(&mut rng), between.sample(&mut rng), between.sample(&mut rng)) } pub fn random_in_unit_sphere() -> Self { loop { let v = Vec3::random(-1.0, 1.0); if v.length_squared() < 1.0 { return v; } } } pub fn random_in_hemisphere(normal: &Vec3) -> Self { let vec = Vec3::random_in_unit_sphere(); if vec.dot(normal) > 0.0 { vec } else { -vec } } pub fn random_unit_vector() -> Self { Vec3::random_in_unit_sphere().unit_vector() } pub fn near_zero(&self) -> bool { const MAXIMUM_DISTANCE_FROM_ZERO:f64 = 1e-8; self.x.abs() < MAXIMUM_DISTANCE_FROM_ZERO && self.y.abs() < MAXIMUM_DISTANCE_FROM_ZERO && self.z.abs() < MAXIMUM_DISTANCE_FROM_ZERO } pub fn reflected(&self, normal: &Vec3) -> Vec3 { let dp = self.dot(normal); let dp = dp * 2.0 * (*normal); *self - dp } pub fn refract(&self, normal: &Vec3, etai_over_etat: f64) -> Vec3 { let dot = (-(*self)).dot(normal); let cos_theta = dot.min(1.0); let out_perp = etai_over_etat * ((*self) + cos_theta * (*normal)); let inner = 1.0 - out_perp.length_squared(); let abs = inner.abs(); let r = -(abs.sqrt()); out_parallel = r * (*normal); out_perp + out_parallel } pub fn refract_sort_of_works(&self, normal: &Vec3, etai_over_etat: f64) -> Vec3 { let dot = (-(*self)).dot(normal); let cos_theta = dot.min(1.0); let out_perp = etai_over_etat * ((*self) + cos_theta * (*normal)); let inner = 1.0 - out_perp.length_squared(); let abs = inner.abs(); let r = -(abs.sqrt()); let out_parallel = r * (*normal); // Why? let mut res = out_perp + out_parallel; res.x = -res.x; //res.y = -res.y; res.z = -res.z; res } } #[test] fn test_refract() { let uv = Point3::new(1.0, 1.0, 0.0); let n = Point3::new(-1.0, 0.0, 0.0); let etai_over_etat = 1.0; let expected = Point3::new(0.0, 1.0, 0.0); let actual = uv.refract_orig( &n, etai_over_etat); assert_eq!(actual, expected); } impl Color { pub fn write_color(self: Color, samples_per_pixel: i32) { let scale = 1.0 / samples_per_pixel as f64; let r = f64::sqrt(scale * self.x); let g = f64::sqrt(scale * self.y); let b = f64::sqrt(scale * self.z); let r = 256.0 * f64::clamp(r, 0.0, 0.999); let g = 256.0 * f64::clamp(g, 0.0, 0.999); let b = 256.0 * f64::clamp(b, 0.0, 0.999); println!("{} {} {}", r as i32, g as i32, b as i32); } } impl Default for Vec3 { fn default() -> Self { Vec3 {x: 0.0, y: 0.0, z: 0.0} } } impl Display for Vec3 { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{} {} {}", self.x, self.y, self.z) } } impl Add for Vec3 { type Output = Vec3; fn add(self, other: Vec3) -> Vec3 { Vec3 { x: self.x + other.x(), y: self.y + other.y(), z: self.z + other.z(), } } } impl AddAssign for Vec3 { fn add_assign(&mut self, rhs: Self) { self.x += rhs.x; self.y += rhs.y; self.z += rhs.z; } } impl Sub for Vec3 { type Output = Vec3; fn sub(self, other: Vec3) -> Vec3 { Vec3 { x: self.x - other.x(), y: self.y - other.y(), z: self.z - other.z(), } } } impl Sub for &Vec3 { type Output = Vec3; fn sub(self, other: &Vec3) -> Vec3 { Vec3 { x: self.x - other.x(), y: self.y - other.y(), z: self.z - other.z(), } } } impl Neg for Vec3 { type Output = Vec3; fn neg(self) -> Vec3 { Vec3 { x: -self.x, y: -self.y, z: -self.z, } } } impl Mul for Vec3 { type Output = Vec3; fn mul(self, other: Vec3) -> Vec3 { Vec3 { x: self.x * other.x(), y: self.y * other.y(), z: self.z * other.z(), } } } impl Mul for Vec3 { type Output = Vec3; fn mul(self, other: f64) -> Vec3 { Vec3 { x: self.x * other, y: self.y * other, z: self.z * other, } } } impl Mul for f64 { type Output = Vec3; fn mul(self, other: Vec3) -> Vec3 { other * self } } impl Div for Vec3 { type Output = Vec3; fn div(self, other: Vec3) -> Vec3 { Vec3 { x: self.x / other.x(), y: self.y / other.y(), z: self.z / other.z(), } } } impl Div for Vec3 { type Output = Vec3; fn div(self, other: f64) -> Vec3 { Vec3 { x: self.x / other, y: self.y / other, z: self.z / other, } } } impl PartialEq for Vec3 { fn eq(&self, other: &Vec3) -> bool { self.x == other.x() && self.y == other.y() && self.z == other.z() } }