bs_trace/trace/
material.rs1use crate::image::prelude::Colour;
2use crate::linalg;
3use crate::trace::prelude::Vec3;
4use rand::RngCore;
5use std::fmt::Debug;
6
7pub trait Material: Debug + Send + Sync {
8 fn colour(&self) -> Colour;
9 fn bounce(
10 &self,
11 rng: &mut Box<dyn RngCore>,
12 incident_direction: Vec3,
13 surface_normal: Vec3,
14 ) -> Option<Vec3>;
15}
16
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub struct Lambertian {
19 pub colour: Colour,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq)]
23pub struct Metal {
24 pub colour: Colour,
25 pub fuzz: f64,
26}
27
28impl Lambertian {
29 pub const fn new(colour: Colour) -> Self {
30 Self { colour }
31 }
32}
33
34impl Material for Lambertian {
35 fn colour(&self) -> Colour {
36 self.colour
37 }
38
39 fn bounce(
40 &self,
41 rng: &mut Box<dyn RngCore>,
42 incident_direction: Vec3,
43 surface_normal: Vec3,
44 ) -> Option<Vec3> {
45 loop {
46 let bounce_direction = linalg::rand::random_unit3(rng) + surface_normal;
47 if bounce_direction.mag() < 1.0e-9 {
48 continue;
49 }
50 break Some(bounce_direction.normalised());
51 }
52 }
53}
54
55impl Metal {
56 pub const fn new(colour: Colour, fuzz: f64) -> Self {
57 Self { colour, fuzz }
58 }
59}
60
61impl Material for Metal {
62 fn colour(&self) -> Colour {
63 self.colour
64 }
65
66 fn bounce(
67 &self,
68 rng: &mut Box<dyn RngCore>,
69 incident_direction: Vec3,
70 surface_normal: Vec3,
71 ) -> Option<Vec3> {
72 let b_height = incident_direction.dot(surface_normal);
73 let pure_bounce = incident_direction - surface_normal * 2.0 * b_height;
74 let fuzz_displacement = linalg::rand::random_unit3(rng) * self.fuzz;
75 let bounce = pure_bounce + fuzz_displacement;
76 if bounce.dot(surface_normal) < 0.0 {
77 None
78 } else {
79 Some(bounce)
80 }
81 }
82}