Path Tracer
hittable.hpp
1 #pragma once
2 #include <acceleration/aabb.hpp>
3 #include <common.hpp>
4 #include <camera/ray.hpp>
5 #include <utils.hpp>
6 #include <math3d/vec3.hpp>
7 using namespace ptracey;
8 namespace ptracey {
9 class material;
10 
11 struct hit_record {
12  point3 p;
13  vec3 normal;
14  shared_ptr<material> mat_ptr;
15  Real t;
16  Real u;
17  Real v;
18  bool front_face;
19 
20  inline void set_face_normal(const ray &r,
21  const vec3 &outward_normal) {
22  front_face = dot(r.direction(), outward_normal) < 0;
23  normal = front_face ? outward_normal : -outward_normal;
24  }
25 };
26 
27 Real get_pdf_surface(point3 dir, vec3 normal, Real dist,
28  Real area) {
29  auto distance_squared =
30  dist * dist * dir.length_squared();
31  Real cosine = fabs(dot(dir, normal) / dir.length());
32 
33  return distance_squared / (cosine * area);
34 }
35 class hittable {
36 public:
37  shared_ptr<material> mat_ptr;
38  virtual bool hit(const ray &r, Real t_min, Real t_max,
39  hit_record &rec) const = 0;
40  virtual bool bounding_box(Real time0, Real time1,
41  aabb &output_box) const = 0;
42 
43  virtual Real pdf_value(const vec3 &o,
44  const vec3 &v) const {
45  return 0.0;
46  }
47 
48  virtual vec3 random(const vec3 &o) const {
49  return vec3(1, 0, 0);
50  }
51 };
52 class flip_face : public hittable {
53 public:
54  flip_face(shared_ptr<hittable> p) : ptr(p) {}
55 
56  virtual bool hit(const ray &r, Real t_min, Real t_max,
57  hit_record &rec) const override {
58 
59  if (!ptr->hit(r, t_min, t_max, rec))
60  return false;
61 
62  rec.front_face = !rec.front_face;
63  return true;
64  }
65 
66  virtual bool
67  bounding_box(Real time0, Real time1,
68  aabb &output_box) const override {
69  return ptr->bounding_box(time0, time1, output_box);
70  }
71 
72 public:
73  shared_ptr<hittable> ptr;
74 };
75 class translate : public hittable {
76 public:
77  translate() {}
78  translate(shared_ptr<hittable> p,
79  const vec3 &displacement)
80  : ptr(p), offset(displacement) {}
81 
82  virtual bool hit(const ray &r, Real t_min, Real t_max,
83  hit_record &rec) const override;
84 
85  virtual bool
86  bounding_box(Real time0, Real time1,
87  aabb &output_box) const override;
88 
89 public:
90  shared_ptr<hittable> ptr;
91  vec3 offset;
92 };
93 bool translate::hit(const ray &r, Real t_min, Real t_max,
94  hit_record &rec) const {
95  ray moved_r(r.origin() - offset, r.direction(), r.time(),
96  r.wavelength());
97  if (!ptr->hit(moved_r, t_min, t_max, rec))
98  return false;
99 
100  rec.p += offset;
101  rec.set_face_normal(moved_r, rec.normal);
102 
103  return true;
104 }
105 bool translate::bounding_box(Real time0, Real time1,
106  aabb &output_box) const {
107  if (!ptr->bounding_box(time0, time1, output_box))
108  return false;
109 
110  output_box = aabb(output_box.min() + offset,
111  output_box.max() + offset);
112 
113  return true;
114 }
115 class rotate_y : public hittable {
116 public:
117  rotate_y(shared_ptr<hittable> p, Real angle);
118 
119  bool hit(const ray &r, Real t_min, Real t_max,
120  hit_record &rec) const override;
121 
122  bool bounding_box(Real time0, Real time1,
123  aabb &output_box) const override {
124  output_box = bbox;
125  return hasbox;
126  }
127 
128 public:
129  shared_ptr<hittable> ptr;
130  Real sin_theta;
131  Real cos_theta;
132  bool hasbox;
133  aabb bbox;
134 };
135 rotate_y::rotate_y(shared_ptr<hittable> p, Real angle)
136  : ptr(p) {
137  auto radians = degrees_to_radians(angle);
138  sin_theta = sin(radians);
139  cos_theta = cos(radians);
140  hasbox = ptr->bounding_box(0, 1, bbox);
141 
142  point3 min(FLT_MAX);
143  point3 max(-FLT_MAX);
144 
145  for (int i = 0; i < 2; i++) {
146  for (int j = 0; j < 2; j++) {
147  for (int k = 0; k < 2; k++) {
148  auto x =
149  i * bbox.max().x() + (1 - i) * bbox.min().x();
150  auto y =
151  j * bbox.max().y() + (1 - j) * bbox.min().y();
152  auto z =
153  k * bbox.max().z() + (1 - k) * bbox.min().z();
154 
155  auto newx = cos_theta * x + sin_theta * z;
156  auto newz = -sin_theta * x + cos_theta * z;
157 
158  vec3 tester(newx, y, newz);
159 
160  for (int c = 0; c < 3; c++) {
161  min[c] = fmin(min[c], tester[c]);
162  max[c] = fmax(max[c], tester[c]);
163  }
164  }
165  }
166  }
167 
168  bbox = aabb(min, max);
169 }
170 bool rotate_y::hit(const ray &r, Real t_min, Real t_max,
171  hit_record &rec) const {
172  auto origin = r.origin();
173  auto direction = r.direction();
174 
175  origin[0] =
176  cos_theta * r.origin()[0] - sin_theta * r.origin()[2];
177  origin[2] =
178  sin_theta * r.origin()[0] + cos_theta * r.origin()[2];
179 
180  direction[0] = cos_theta * r.direction()[0] -
181  sin_theta * r.direction()[2];
182  direction[2] = sin_theta * r.direction()[0] +
183  cos_theta * r.direction()[2];
184 
185  ray rotated_r(origin, direction, r.time(),
186  r.wavelength());
187 
188  if (!ptr->hit(rotated_r, t_min, t_max, rec))
189  return false;
190 
191  auto p = rec.p;
192  auto normal = rec.normal;
193 
194  p[0] = cos_theta * rec.p[0] + sin_theta * rec.p[2];
195  p[2] = -sin_theta * rec.p[0] + cos_theta * rec.p[2];
196 
197  normal[0] =
198  cos_theta * rec.normal[0] + sin_theta * rec.normal[2];
199  normal[2] = -sin_theta * rec.normal[0] +
200  cos_theta * rec.normal[2];
201 
202  rec.p = p;
203  rec.set_face_normal(rotated_r, normal);
204 
205  return true;
206 }
207 }
ptracey::translate
Definition: hittable.hpp:75
ptracey::rotate_y
Definition: hittable.hpp:115
ptracey::ray
Definition: ray.hpp:8
ptracey::hit_record
Definition: hittable.hpp:11
ptracey::hittable
Definition: hittable.hpp:35
ptracey::vec3
Definition: vec3.hpp:7
ptracey::flip_face
Definition: hittable.hpp:52
ptracey::aabb
Definition: aabb.hpp:12
ptracey::material
Definition: material.hpp:17