raytracing-rs

https://raytracing.github.io in Rust

git clone https://code.pdelong.com/raytracing-rs.git

  1use std::ops::Deref;
  2use std::ops::Neg;
  3
  4use crate::math::Interval;
  5
  6#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Default)]
  7pub struct Vec3 {
  8    pub x: f64,
  9    pub y: f64,
 10    pub z: f64,
 11}
 12
 13impl Vec3 {
 14    pub fn length(&self) -> f64 {
 15        self.length_squared().sqrt()
 16    }
 17
 18    pub fn length_squared(&self) -> f64 {
 19        self.x * self.x + self.y * self.y + self.z * self.z
 20    }
 21
 22    pub fn dot(self, rhs: &Self) -> f64 {
 23        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
 24    }
 25
 26    pub fn cross(self, rhs: &Self) -> Vec3 {
 27        Vec3 {
 28            x: self.y * rhs.z - self.z * rhs.y,
 29            y: self.z * rhs.x - self.x * rhs.z,
 30            z: self.x * rhs.y - self.y * rhs.x,
 31        }
 32    }
 33
 34    pub fn normalize(self) -> NormalizedVec3 {
 35        let length = self.length();
 36        NormalizedVec3(self / length)
 37    }
 38
 39    pub fn random<R: rand::Rng>(rng: &mut R, range: &Interval) -> Vec3 {
 40        Vec3 {
 41            x: rng.random_range(range.min..=range.max),
 42            y: rng.random_range(range.min..=range.max),
 43            z: rng.random_range(range.min..=range.max),
 44        }
 45    }
 46
 47    pub fn random_on_unit_sphere<R: rand::Rng>(rng: &mut R) -> NormalizedVec3 {
 48        loop {
 49            let v = Self::random(rng, &Interval::new(-1., 1.).unwrap());
 50            let lensq = v.length_squared();
 51            if lensq > 1e-160 && lensq <= 1. {
 52                return v.normalize();
 53            }
 54        }
 55    }
 56
 57    pub fn random_on_unit_hemisphere<R: rand::Rng>(
 58        rng: &mut R,
 59        normal: &NormalizedVec3,
 60    ) -> NormalizedVec3 {
 61        let on_unit_sphere = Self::random_on_unit_sphere(rng);
 62        if on_unit_sphere.dot(normal) > 0. {
 63            on_unit_sphere
 64        } else {
 65            -on_unit_sphere
 66        }
 67    }
 68}
 69
 70#[derive(Debug, Copy, Clone)]
 71pub struct NormalizedVec3(Vec3);
 72
 73impl NormalizedVec3 {
 74    pub fn get(self) -> Vec3 {
 75        self.0
 76    }
 77
 78    pub fn x(&self) -> f64 {
 79        self.0.x
 80    }
 81
 82    pub fn y(&self) -> f64 {
 83        self.0.y
 84    }
 85
 86    pub fn z(&self) -> f64 {
 87        self.0.z
 88    }
 89}
 90
 91impl Deref for NormalizedVec3 {
 92    type Target = Vec3;
 93
 94    fn deref(&self) -> &Self::Target {
 95        &self.0
 96    }
 97}
 98
 99impl Neg for NormalizedVec3 {
100    type Output = Self;
101
102    fn neg(self) -> Self::Output {
103        Self(self.0.neg())
104    }
105}
106
107impl std::ops::Add for Vec3 {
108    type Output = Vec3;
109
110    fn add(self, rhs: Self) -> Self::Output {
111        Vec3 {
112            x: self.x + rhs.x,
113            y: self.y + rhs.y,
114            z: self.z + rhs.z,
115        }
116    }
117}
118
119impl std::ops::AddAssign for Vec3 {
120    fn add_assign(&mut self, rhs: Self) {
121        self.x += rhs.x;
122        self.y += rhs.y;
123        self.z += rhs.z;
124    }
125}
126
127impl std::ops::Add<f64> for Vec3 {
128    type Output = Vec3;
129
130    fn add(self, rhs: f64) -> Self::Output {
131        Vec3 {
132            x: self.x + rhs,
133            y: self.y + rhs,
134            z: self.z + rhs,
135        }
136    }
137}
138
139impl std::ops::AddAssign<f64> for Vec3 {
140    fn add_assign(&mut self, rhs: f64) {
141        self.x += rhs;
142        self.y += rhs;
143        self.z += rhs;
144    }
145}
146
147impl std::ops::Sub for Vec3 {
148    type Output = Vec3;
149
150    fn sub(self, rhs: Self) -> Self::Output {
151        Vec3 {
152            x: self.x - rhs.x,
153            y: self.y - rhs.y,
154            z: self.z - rhs.z,
155        }
156    }
157}
158
159impl std::ops::SubAssign for Vec3 {
160    fn sub_assign(&mut self, rhs: Self) {
161        self.x -= rhs.x;
162        self.y -= rhs.y;
163        self.z -= rhs.z;
164    }
165}
166
167impl std::ops::Sub<f64> for Vec3 {
168    type Output = Vec3;
169
170    fn sub(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
179impl std::ops::SubAssign<f64> for Vec3 {
180    fn sub_assign(&mut self, rhs: f64) {
181        self.x -= rhs;
182        self.y -= rhs;
183        self.z -= rhs;
184    }
185}
186
187impl std::ops::Mul<f64> for Vec3 {
188    type Output = Vec3;
189
190    fn mul(self, rhs: f64) -> Self::Output {
191        Vec3 {
192            x: self.x * rhs,
193            y: self.y * rhs,
194            z: self.z * rhs,
195        }
196    }
197}
198
199impl std::ops::MulAssign<f64> for Vec3 {
200    fn mul_assign(&mut self, rhs: f64) {
201        self.x *= rhs;
202        self.y *= rhs;
203        self.z *= rhs;
204    }
205}
206
207impl std::ops::Div<f64> for Vec3 {
208    type Output = Vec3;
209
210    fn div(self, rhs: f64) -> Self::Output {
211        Vec3 {
212            x: self.x / rhs,
213            y: self.y / rhs,
214            z: self.z / rhs,
215        }
216    }
217}
218
219impl std::ops::DivAssign<f64> for Vec3 {
220    fn div_assign(&mut self, rhs: f64) {
221        self.x /= rhs;
222        self.y /= rhs;
223        self.z /= rhs;
224    }
225}
226
227impl std::ops::Neg for Vec3 {
228    type Output = Vec3;
229
230    fn neg(self) -> Self::Output {
231        Vec3 {
232            x: -self.x,
233            y: -self.y,
234            z: -self.z,
235        }
236    }
237}
238
239pub type Color = Vec3;
240pub type Point = Vec3;
241
242impl Color {
243    pub fn bytes(&self) -> [u8; 6] {
244        let r = (self.x * 65535.).round() as u16;
245        let g = (self.y * 65535.).round() as u16;
246        let b = (self.z * 65535.).round() as u16;
247
248        [
249            (r >> 8) as u8,
250            (r & 0xFF) as u8,
251            (g >> 8) as u8,
252            (g & 0xFF) as u8,
253            (b >> 8) as u8,
254            (b & 0xFF) as u8,
255        ]
256    }
257}
258
259#[cfg(test)]
260mod tests {
261    use super::Vec3;
262
263    #[test]
264    fn vec3_add() {
265        let l = Vec3 {
266            x: 1.,
267            y: 2.,
268            z: 3.,
269        };
270        let r = Vec3 {
271            x: 30.,
272            y: 20.,
273            z: 10.,
274        };
275
276        let sum = l + r;
277        assert_eq!(
278            sum,
279            Vec3 {
280                x: 31.,
281                y: 22.,
282                z: 13.,
283            }
284        );
285    }
286
287    #[test]
288    fn vec3_add_assign() {
289        let mut l = Vec3 {
290            x: 1.,
291            y: 2.,
292            z: 3.,
293        };
294        let r = Vec3 {
295            x: 30.,
296            y: 20.,
297            z: 10.,
298        };
299
300        l += r;
301        assert_eq!(
302            l,
303            Vec3 {
304                x: 31.,
305                y: 22.,
306                z: 13.,
307            }
308        );
309    }
310
311    #[test]
312    fn vec3_sub() {
313        let l = Vec3 {
314            x: 30.,
315            y: 20.,
316            z: 10.,
317        };
318        let r = Vec3 {
319            x: 1.,
320            y: 2.,
321            z: 3.,
322        };
323
324        let dif = l - r;
325        assert_eq!(
326            dif,
327            Vec3 {
328                x: 29.,
329                y: 18.,
330                z: 7.,
331            }
332        );
333    }
334
335    #[test]
336    fn vec3_sub_assign() {
337        let mut l = Vec3 {
338            x: 30.,
339            y: 20.,
340            z: 10.,
341        };
342        let r = Vec3 {
343            x: 1.,
344            y: 2.,
345            z: 3.,
346        };
347
348        l -= r;
349        assert_eq!(
350            l,
351            Vec3 {
352                x: 29.,
353                y: 18.,
354                z: 7.,
355            }
356        );
357    }
358
359    #[test]
360    fn vec3_mul_vec3() {
361        let l = Vec3 {
362            x: 2.,
363            y: 3.,
364            z: 4.,
365        };
366
367        let prod = l * 10.;
368        assert_eq!(
369            prod,
370            Vec3 {
371                x: 20.,
372                y: 30.,
373                z: 40.,
374            }
375        );
376    }
377
378    #[test]
379    fn vec3_mul_assign() {
380        let mut l = Vec3 {
381            x: 2.,
382            y: 3.,
383            z: 4.,
384        };
385
386        l *= 10.;
387        assert_eq!(
388            l,
389            Vec3 {
390                x: 20.,
391                y: 30.,
392                z: 40.,
393            }
394        );
395    }
396
397    #[test]
398    fn vec3_div() {
399        let l = Vec3 {
400            x: 20.,
401            y: 30.,
402            z: 40.,
403        };
404
405        let div = l / 10.;
406        assert_eq!(
407            div,
408            Vec3 {
409                x: 2.,
410                y: 3.,
411                z: 4.,
412            }
413        );
414    }
415
416    #[test]
417    fn vec3_div_assign() {
418        let mut l = Vec3 {
419            x: 20.,
420            y: 30.,
421            z: 40.,
422        };
423
424        l /= 10.;
425        assert_eq!(
426            l,
427            Vec3 {
428                x: 2.,
429                y: 3.,
430                z: 4.,
431            }
432        );
433    }
434}