Path Tracer
vec3.hpp
1 #pragma once
2 #include <common.hpp>
3 #include <utils.hpp>
4 
5 namespace ptracey {
6 
7 class vec3 {
8 public:
9  vec3() : e{0, 0, 0} {}
10  vec3(Real e0, Real e1, Real e2) : e{e0, e1, e2} {}
11  vec3(Real e0) : e{e0, e0, e0} {}
12  vec3(const Real e1[3]) : e{e1[0], e1[1], e1[2]} {}
13 
14  Real x() const { return e[0]; }
15  Real y() const { return e[1]; }
16  Real z() const { return e[2]; }
17  Real r() const { return x(); }
18  Real g() const { return y(); }
19  Real b() const { return z(); }
20 
21  vec3 operator-() const {
22  return vec3(-e[0], -e[1], -e[2]);
23  }
24  Real operator[](int i) const { return e[i]; }
25  Real &operator[](int i) { return e[i]; }
26  vec3 &operator+=(const vec3 &v) {
27  e[0] += v.e[0];
28  e[1] += v.e[1];
29  e[2] += v.e[2];
30  return *this;
31  }
32  vec3 &operator*=(const Real t) {
33  e[0] *= t;
34  e[1] *= t;
35  e[2] *= t;
36  return *this;
37  }
38  vec3 &operator/=(const Real t) { return *this *= 1 / t; }
39  vec3 add(const vec3 &v) {
40  return vec3(x() + v.x(), y() + v.y(), z() + v.z());
41  }
42  Real sum() { return x() + y() + z(); }
43  Real average() { return sum() / 3.0; }
44  vec3 add(const Real &v) {
45  return vec3(x() + v, y() + v, z() + v);
46  }
47  vec3 subt(const Real &v) {
48  return vec3(x() - v, y() - v, z() - v);
49  }
50  vec3 subt(const vec3 &v) {
51  return vec3(x() - v.x(), y() - v.y(), z() - v.z());
52  }
53  vec3 multip(const vec3 &v) {
54  return vec3(x() * v.x(), y() * v.y(), z() * v.z());
55  }
56  vec3 multip(const Real &v) {
57  return vec3(x() * v, y() * v, z() * v);
58  }
59  vec3 div(const Real &v) {
60  if (v == 0.0)
61  throw std::runtime_error("no zero division");
62  return vec3(x() / v, y() / v, z() / v);
63  }
64  vec3 div(const vec3 &v) {
65  if (v.x() == 0.0)
66  throw std::runtime_error(
67  "no zero division x is zero");
68  if (v.y() == 0.0)
69  throw std::runtime_error(
70  "no zero division y is zero");
71  if (v.z() == 0.0)
72  throw std::runtime_error(
73  "no zero division z is zero");
74  return vec3(x() / v.x(), y() / v.y(), z() / v.z());
75  }
76  Real length() const { return sqrt(length_squared()); }
77  Real length_squared() const {
78  return e[0] * e[0] + e[1] * e[1] + e[2] * e[2];
79  }
80  inline Real min() const {
81  return fmin(fmin(x(), y()), z());
82  }
83  inline Real max() const {
84  return fmax(fmax(x(), y()), z());
85  }
86  bool near_zero() const {
87  // Return true if the vector is close to zero in all
88  // dimensions.
89  const auto s = 1e-8;
90  return (fabs(e[0]) < s) && (fabs(e[1]) < s) &&
91  (fabs(e[2]) < s);
92  }
93  inline static vec3 random() {
94  return vec3(random_real(), random_real(),
95  random_real());
96  }
97  inline static vec3 random(Real min, Real max) {
98  return vec3(random_real(min, max),
99  random_real(min, max),
100  random_real(min, max));
101  }
102  std::vector<Real> to_vector() const {
103  std::vector<Real> vdata(3);
104  vdata[0] = x();
105  vdata[1] = y();
106  vdata[2] = z();
107  return vdata;
108  }
109  void conditional_set(
110  Real setval, int index,
111  const std::function<bool(Real indval)> &fn) {
112  if (fn(e[index])) {
113  e[index] = setval;
114  }
115  }
116  void conditional_set(
117  Real setval,
118  const std::function<bool(Real indval)> &fn) {
119  for (int index = 0; index < 3; index++) {
120  if (fn(e[index])) {
121  e[index] = setval;
122  }
123  }
124  }
125 
126 public:
127  Real e[3];
128 };
129 
130 // Type aliases for vec3
131 using point3 = vec3; // 3D point
132 
133 // vec3 Utility Functions
134 
135 inline std::ostream &operator<<(std::ostream &out,
136  const vec3 &v) {
137  return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
138 }
139 inline vec3 operator+(const vec3 &u, const vec3 &v) {
140  return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1],
141  u.e[2] + v.e[2]);
142 }
143 inline vec3 operator-(const vec3 &u, const vec3 &v) {
144  return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1],
145  u.e[2] - v.e[2]);
146 }
147 inline vec3 operator*(const vec3 &u, const vec3 &v) {
148  return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1],
149  u.e[2] * v.e[2]);
150 }
151 inline vec3 operator*(Real t, const vec3 &v) {
152  return vec3(t * v.e[0], t * v.e[1], t * v.e[2]);
153 }
154 inline vec3 operator*(const vec3 &v, Real t) {
155  return t * v;
156 }
157 inline vec3 operator/(vec3 v, Real t) {
158  return (1 / t) * v;
159 }
160 inline vec3 operator/(Real t, vec3 v) {
161  return (1 / t) * v;
162 }
163 inline vec3 operator/(vec3 v, vec3 t) {
164  return (1 / t) * v;
165 }
166 
167 inline Real dot(const vec3 &u, const vec3 &v) {
168  return u.e[0] * v.e[0] + u.e[1] * v.e[1] +
169  u.e[2] * v.e[2];
170 }
171 vec3 sqrt_vec(const vec3 &v) {
172  auto r = sqrt(v.x());
173  auto g = sqrt(v.y());
174  auto b = sqrt(v.z());
175  vec3 rgb = vec3(r, g, b);
176  return rgb;
177 }
178 vec3 clamp(const vec3 &v, Real mn, Real mx) {
179  auto r = clamp(v.x(), mn, mx);
180  auto g = clamp(v.y(), mn, mx);
181  auto b = clamp(v.z(), mn, mx);
182  return vec3(r, g, b);
183 }
184 inline vec3 cross(const vec3 &u, const vec3 &v) {
185  return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
186  u.e[2] * v.e[0] - u.e[0] * v.e[2],
187  u.e[0] * v.e[1] - u.e[1] * v.e[0]);
188 }
189 
190 inline vec3 unit_vector(vec3 v) { return v / v.length(); }
191 inline vec3 min_vec(const vec3 &v1, const vec3 &v2) {
192  float x = fmin(v1.x(), v2.x());
193  float y = fmin(v1.y(), v2.y());
194  float z = fmin(v1.z(), v2.z());
195  return vec3(x, y, z);
196 }
197 inline vec3 max_vec(const vec3 &v1, const vec3 &v2) {
198  float x = fmax(v1.x(), v2.x());
199  float y = fmax(v1.y(), v2.y());
200  float z = fmax(v1.z(), v2.z());
201  return vec3(x, y, z);
202 }
203 
204 inline vec3 random_in_unit_disk() {
205  while (true) {
206  auto p =
207  vec3(random_real(-1, 1), random_real(-1, 1), 0);
208  if (p.length_squared() >= 1)
209  continue;
210  return p;
211  }
212 }
213 
214 inline vec3 random_in_unit_sphere() {
215  while (true) {
216  auto p = vec3::random(-1, 1);
217  if (p.length_squared() >= 1)
218  continue;
219  return p;
220  }
221 }
222 
223 inline vec3 random_unit_vector() {
224  return unit_vector(random_in_unit_sphere());
225 }
226 
227 inline vec3 random_in_hemisphere(const vec3 &normal) {
228  vec3 in_unit_sphere = random_in_unit_sphere();
229  if (dot(in_unit_sphere, normal) >
230  0.0) // In the same hemisphere as the normal
231  return in_unit_sphere;
232  else
233  return -in_unit_sphere;
234 }
235 
236 inline vec3 reflect(const vec3 &v, const vec3 &n) {
237  return v - 2 * dot(v, n) * n;
238 }
239 
240 inline vec3 refract(const vec3 &uv, const vec3 &n,
241  Real etai_over_etat) {
242  auto cos_theta = fmin(dot(-uv, n), 1.0);
243  vec3 r_out_perp = etai_over_etat * (uv + cos_theta * n);
244  vec3 r_out_parallel =
245  -sqrt(fabs(1.0 - r_out_perp.length_squared())) * n;
246  return r_out_perp + r_out_parallel;
247 }
248 
249 inline vec3 random_cosine_direction() {
250  auto r1 = random_real();
251  auto r2 = random_real();
252  auto z = sqrt(1 - r2);
253 
254  auto phi = 2 * M_PI * r1;
255  auto x = cos(phi) * sqrt(r2);
256  auto y = sin(phi) * sqrt(r2);
257 
258  return vec3(x, y, z);
259 }
260 
261 inline vec3 random_to_sphere(Real radius,
262  Real distance_squared) {
263  auto r1 = random_real();
264  auto r2 = random_real();
265  auto z =
266  1 +
267  r2 * (sqrt(1 - radius * radius / distance_squared) -
268  1);
269 
270  auto phi = 2 * M_PI * r1;
271  auto x = cos(phi) * sqrt(1 - z * z);
272  auto y = sin(phi) * sqrt(1 - z * z);
273 
274  return vec3(x, y, z);
275 }
276 }
ptracey::vec3
Definition: vec3.hpp:7