1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
pub mod calculus {
use rand::Rng;
#[derive(Copy, Clone, Debug)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
// cached: Vec3Cache,
}
pub type Point3 = Vec3;
impl Vec3 {
pub fn new(x: f32, y: f32, z: f32) -> Self {
Self { x, y, z }
}
fn random() -> Self {
let mut rng = rand::rng();
Self::new(
rng.random(),
rng.random(),
rng.random(),
)
}
fn random_range(min: f32, max: f32) -> Self {
let mut rng = rand::rng();
Self::new(
rng.random_range(min..max),
rng.random_range(min..max),
rng.random_range(min..max),
)
}
pub fn random_unit() -> Vec3 {
loop {
let p = Self::random_range(-1.0, 1.0);
let lensq = p.mag_sqr();
if f32::EPSILON < lensq && lensq <= 1.0 {
return p.scalar_mul(1.0 / lensq.sqrt())
}
}
}
pub fn random_on_hemisphere(normal: &Vec3) -> Vec3 {
let on_unit_sphere = Self::random_unit();
if on_unit_sphere.dot_prod(normal) > 0.0 {
on_unit_sphere
} else {
on_unit_sphere.scalar_mul(-1.0)
}
}
pub fn add(&self, other: &Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z
}
}
pub fn sub(&self, other: &Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z
}
}
pub fn scalar_mul(&self, multiplier: f32) -> Self {
Self {
x: self.x * multiplier,
y: self.y * multiplier,
z: self.z * multiplier,
}
}
pub fn mag_sqr(&self) -> f32 {
self.x * self.x + self.y * self.y + self.z * self.z
}
pub fn mag(&self) -> f32 {
self.mag_sqr().sqrt()
}
pub fn dot_prod(&self, other: &Self) -> f32 {
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross_prod(&self, other: &Self) -> Self {
Self {
x: self.y * other.z - self.z - other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
pub fn unit(&self) -> Self {
let mag = self.mag();
Self {
x: self.x / mag,
y: self.y / mag,
z: self.z / mag,
}
}
pub fn is_near_zero(&self) -> bool {
self.x.abs() < f32::EPSILON &&
self.y.abs() < f32::EPSILON &&
self.z.abs() < f32::EPSILON
}
pub fn reflect(&self, normal: &Self) -> Self {
self.sub(
&normal.scalar_mul(
2.0 * self.dot_prod(&normal)
)
)
}
}
pub struct Ray {
pub origin: Point3,
pub direction: Vec3,
}
impl Ray {
pub fn at(&self, t: f32) -> Point3 {
// Get parametric location
self.origin.add(&self.direction.scalar_mul(t))
}
pub fn reflect(&self, normal: &Vec3) -> Vec3 {
self.direction.reflect(&normal)
}
}
pub fn deg2rad(deg: f32) -> f32 {
deg * std::f32::consts::PI / 180.0
}
pub fn sample_square() -> Vec3 {
// Returns the vector to a random point in the [-.5,-.5]-[+.5,+.5] unit square.
let mut rng = rand::rng();
Vec3::new(
rng.random_range(0.0..1.0) - 0.5,
rng.random_range(0.0..1.0) - 0.5,
0.0)
}
}
|