rustracer/src/vec3.rs
2022-06-30 09:54:25 +02:00

254 lines
6.5 KiB
Rust

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<Vec3> 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<f64> 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<Vec3> for f64 {
type Output = Vec3;
fn mul(self, other: Vec3) -> Vec3 {
other * self
}
}
impl Div<Vec3> 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<f64> 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()
}
}