stocking

git clone https://git.bradleygannon.com/stocking.git
Log | Files | Refs

vec3.rs (5044B)


      1 use std::{
      2     fmt::{Debug, Display},
      3     ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub},
      4 };
      5 
      6 use crate::random::RandomNumberGenerator;
      7 
      8 #[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
      9 pub struct Vec3 {
     10     x: f64,
     11     y: f64,
     12     z: f64,
     13 }
     14 
     15 impl Vec3 {
     16     pub const fn new(x: f64, y: f64, z: f64) -> Self {
     17         Vec3 { x, y, z }
     18     }
     19 
     20     pub fn random(rng: &mut RandomNumberGenerator, min: f64, max: f64) -> Self {
     21         Vec3::new(
     22             rng.next_f64_in_range(min, max),
     23             rng.next_f64_in_range(min, max),
     24             rng.next_f64_in_range(min, max),
     25         )
     26     }
     27 
     28     pub fn random_unit(rng: &mut RandomNumberGenerator) -> Self {
     29         loop {
     30             let p = Vec3::random(rng, -1., 1.);
     31             let length_squared = p.length_squared();
     32             if 1e-160 < length_squared && length_squared <= 1. {
     33                 return p / length_squared.sqrt();
     34             }
     35         }
     36     }
     37 
     38     pub fn random_on_hemisphere(rng: &mut RandomNumberGenerator, normal: &Vec3) -> Self {
     39         let on_unit_sphere = Vec3::random_unit(rng);
     40         if on_unit_sphere.dot(normal) > 0. {
     41             on_unit_sphere
     42         } else {
     43             -on_unit_sphere
     44         }
     45     }
     46 
     47     pub fn random_in_unit_disk(rng: &mut RandomNumberGenerator) -> Self {
     48         loop {
     49             let p = Vec3::new(
     50                 rng.next_f64_in_range(-1., 1.),
     51                 rng.next_f64_in_range(-1., 1.),
     52                 0.,
     53             );
     54             if p.length_squared() < 1. {
     55                 return p;
     56             }
     57         }
     58     }
     59 
     60     pub const fn x(&self) -> f64 {
     61         self.x
     62     }
     63 
     64     pub const fn y(&self) -> f64 {
     65         self.y
     66     }
     67 
     68     pub const fn z(&self) -> f64 {
     69         self.z
     70     }
     71 
     72     pub const fn cross(&self, other: &Vec3) -> Vec3 {
     73         Vec3 {
     74             x: self.y * other.z - self.z * other.y,
     75             y: self.z * other.x - self.x * other.z,
     76             z: self.x * other.y - self.y * other.x,
     77         }
     78     }
     79 
     80     pub const fn dot(&self, other: &Vec3) -> f64 {
     81         self.x * other.x + self.y * other.y + self.z * other.z
     82     }
     83 
     84     pub fn length(&self) -> f64 {
     85         self.length_squared().sqrt()
     86     }
     87 
     88     pub fn length_squared(&self) -> f64 {
     89         self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
     90     }
     91 
     92     pub fn unit(&self) -> Vec3 {
     93         *self / self.length()
     94     }
     95 
     96     pub fn near_zero(&self) -> bool {
     97         const THRESHOLD: f64 = 1e-8;
     98         self.x().abs() < THRESHOLD && self.y().abs() < THRESHOLD && self.z().abs() < THRESHOLD
     99     }
    100 
    101     pub fn reflect(&self, normal: &Vec3) -> Vec3 {
    102         *self - 2. * self.dot(normal) * *normal
    103     }
    104 
    105     pub fn refract(&self, normal: &Vec3, refractive_index_ratio: f64) -> Vec3 {
    106         let cosine_theta = (-*self).dot(normal).min(1.);
    107         let r_out_perpendicular = refractive_index_ratio * (*self + cosine_theta * *normal);
    108         let r_out_parallel = -(1. - r_out_perpendicular.length_squared()).abs().sqrt() * *normal;
    109         r_out_perpendicular + r_out_parallel
    110     }
    111 }
    112 
    113 impl Add for Vec3 {
    114     type Output = Self;
    115 
    116     fn add(self, rhs: Self) -> Self::Output {
    117         Vec3 {
    118             x: self.x + rhs.x,
    119             y: self.y + rhs.y,
    120             z: self.z + rhs.z,
    121         }
    122     }
    123 }
    124 
    125 impl AddAssign for Vec3 {
    126     fn add_assign(&mut self, rhs: Self) {
    127         self.x += rhs.x;
    128         self.y += rhs.y;
    129         self.z += rhs.z;
    130     }
    131 }
    132 
    133 impl Display for Vec3 {
    134     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    135         write!(f, "{} {} {}", self.x, self.y, self.z)
    136     }
    137 }
    138 
    139 impl DivAssign<f64> for Vec3 {
    140     fn div_assign(&mut self, rhs: f64) {
    141         self.x /= rhs;
    142         self.y /= rhs;
    143         self.z /= rhs;
    144     }
    145 }
    146 
    147 impl Div<f64> for Vec3 {
    148     type Output = Vec3;
    149 
    150     fn div(self, rhs: f64) -> Self::Output {
    151         Vec3 {
    152             x: self.x / rhs,
    153             y: self.y / rhs,
    154             z: self.z / rhs,
    155         }
    156     }
    157 }
    158 
    159 impl MulAssign<f64> for Vec3 {
    160     fn mul_assign(&mut self, rhs: f64) {
    161         self.x *= rhs;
    162         self.y *= rhs;
    163         self.z *= rhs;
    164     }
    165 }
    166 
    167 impl Mul<f64> for Vec3 {
    168     type Output = Vec3;
    169 
    170     fn mul(self, rhs: f64) -> Self::Output {
    171         Vec3 {
    172             x: self.x * rhs,
    173             y: self.y * rhs,
    174             z: self.z * rhs,
    175         }
    176     }
    177 }
    178 
    179 impl Mul<Vec3> for f64 {
    180     type Output = Vec3;
    181 
    182     fn mul(self, rhs: Vec3) -> Self::Output {
    183         rhs * self
    184     }
    185 }
    186 
    187 impl Mul<Vec3> for Vec3 {
    188     type Output = Vec3;
    189 
    190     fn mul(self, rhs: Vec3) -> Self::Output {
    191         Vec3 {
    192             x: self.x * rhs.x,
    193             y: self.y * rhs.y,
    194             z: self.z * rhs.z,
    195         }
    196     }
    197 }
    198 
    199 impl Neg for Vec3 {
    200     type Output = Self;
    201 
    202     fn neg(self) -> Self::Output {
    203         Vec3 {
    204             x: -self.x,
    205             y: -self.y,
    206             z: -self.z,
    207         }
    208     }
    209 }
    210 
    211 impl Sub for Vec3 {
    212     type Output = Vec3;
    213 
    214     fn sub(self, rhs: Self) -> Self::Output {
    215         Vec3 {
    216             x: self.x - rhs.x,
    217             y: self.y - rhs.y,
    218             z: self.z - rhs.z,
    219         }
    220     }
    221 }