Path Tracer
material.hpp
1 #pragma once
2 
3 #include <color/spectrum.hpp>
4 #include <common.hpp>
5 #include <hittable/pdf.hpp>
6 #include <texture/texture.hpp>
7 #include <utils.hpp>
8 using namespace ptracey;
9 namespace ptracey {
10 
12  ray specular_ray;
13  bool is_specular;
14  color attenuation;
15  shared_ptr<pdf> pdf_ptr;
16 };
17 class material {
18 public:
19  virtual color emitted(const ray &r_in,
20  const hit_record &rec, Real u,
21  Real v, const point3 &p) const {
22  return color(0.0);
23  }
24  virtual bool scatter(const ray &r_in,
25  const hit_record &rec,
26  scatter_record &srec) const {
27  return false;
28  }
29  virtual Real scattering_pdf(const ray &r_in,
30  const hit_record &rec,
31  const ray &scattered) const {
32  return 0.0;
33  }
34 };
35 class lambertian : public material {
36 public:
37  lambertian(const spectrum &a)
38  : albedo(make_shared<solid_color>(a)) {}
39  lambertian(shared_ptr<texture> a) : albedo(a) {}
40  bool scatter(const ray &r_in, const hit_record &rec,
41  scatter_record &srec) const override {
42  srec.is_specular = false;
43  srec.attenuation = albedo->value(rec.u, rec.v, rec.p,
44  r_in.wavelength());
45  srec.pdf_ptr = make_shared<cosine_pdf>(rec.normal);
46  return true;
47  }
48  Real scattering_pdf(const ray &r_in,
49  const hit_record &rec,
50  const ray &scattered) const override {
51  auto cosine =
52  dot(rec.normal, unit_vector(scattered.direction()));
53  return cosine < 0 ? 0 : cosine / M_PI;
54  }
55 
56 public:
57  shared_ptr<texture> albedo;
58 };
59 class metal : public material {
60 public:
61  metal(const spectrum &a, Real f)
62  : albedo(make_shared<solid_color>(a)),
63  fuzz(f < 1 ? f : 1) {}
64 
65  bool scatter(const ray &r_in, const hit_record &rec,
66  scatter_record &srec) const override {
67  vec3 reflected =
68  reflect(unit_vector(r_in.direction()), rec.normal);
69  srec.specular_ray = ray(
70  rec.p, reflected + fuzz * random_in_unit_sphere(),
71  r_in.time(), r_in.wavelength());
72  srec.attenuation =
73  albedo->value(rec.u, rec.v, rec.p,
74  srec.specular_ray.wavelength());
75  srec.is_specular = true;
76  srec.pdf_ptr = nullptr;
77  return true;
78  }
79 
80 public:
81  shared_ptr<texture> albedo;
82  Real fuzz;
83 };
84 class dielectric : public material {
85 public:
86  dielectric(Real index_of_refraction)
87  : ir(index_of_refraction) {}
88 
89  bool scatter(const ray &r_in, const hit_record &rec,
90  scatter_record &srec) const override {
91  srec.is_specular = true;
92  srec.pdf_ptr = nullptr;
93  color white(1.0);
94  srec.attenuation = white;
95  Real refraction_ratio =
96  rec.front_face ? (1.0 / ir) : ir;
97 
98  vec3 unit_direction = unit_vector(r_in.direction());
99  Real cos_theta =
100  fmin(dot(-unit_direction, rec.normal), 1.0);
101  Real sin_theta = sqrt(1.0 - cos_theta * cos_theta);
102 
103  bool cannot_refract =
104  refraction_ratio * sin_theta > 1.0;
105  vec3 direction;
106 
107  if (cannot_refract ||
108  reflectance(cos_theta, refraction_ratio) >
109  random_real())
110  direction = reflect(unit_direction, rec.normal);
111  else
112  direction = refract(unit_direction, rec.normal,
113  refraction_ratio);
114 
115  srec.specular_ray = ray(rec.p, direction, r_in.time(),
116  r_in.wavelength());
117  return true;
118  }
119 
120 public:
121  Real ir; // Index of Refraction
122 
123 private:
124  static Real reflectance(Real cosine, Real ref_idx) {
125  // Use Schlick's approximation for reflectance.
126  auto r0 = (1 - ref_idx) / (1 + ref_idx);
127  r0 = r0 * r0;
128  return r0 + (1 - r0) * pow((1 - cosine), 5);
129  }
130 };
131 class diffuse_light : public material {
132 public:
133  diffuse_light(shared_ptr<texture> a) : emit(a) {}
134  diffuse_light(const spectrum &c)
135  : emit(make_shared<solid_color>(c)) {}
136 
137  color emitted(const ray &r_in, const hit_record &rec,
138  Real u, Real v,
139  const point3 &p) const override {
140  if (!rec.front_face)
141  return color(0.0);
142  return emit->value(u, v, p, r_in.wavelength());
143  }
144 
145 public:
146  shared_ptr<texture> emit;
147 };
148 class isotropic : public material {
149 public:
150  isotropic(const spectrum &c)
151  : albedo(make_shared<solid_color>(c)) {}
152  isotropic(shared_ptr<texture> a) : albedo(a) {}
153 
154  bool scatter(const ray &r_in, const hit_record &rec,
155  scatter_record &srec) const override {
156  srec.specular_ray = ray(rec.p, random_in_unit_sphere(),
157  r_in.time(), r_in.wavelength());
158  srec.attenuation =
159  albedo->value(rec.u, rec.v, rec.p,
160  srec.specular_ray.wavelength());
161  srec.is_specular = true;
162  srec.pdf_ptr = nullptr;
163  return true;
164  }
165 
166 public:
167  shared_ptr<texture> albedo;
168 };
169 }
ptracey::diffuse_light
Definition: material.hpp:131
ptracey::ray
Definition: ray.hpp:8
ptracey::hit_record
Definition: hittable.hpp:11
ptracey::lambertian
Definition: material.hpp:35
ptracey::metal
Definition: material.hpp:59
ptracey::scatter_record
Definition: material.hpp:11
ptracey::vec3
Definition: vec3.hpp:7
ptracey::sampled_spectrum
Definition: sampled_spectrum.hpp:126
ptracey::color
Definition: color.hpp:9
ptracey::dielectric
Definition: material.hpp:84
ptracey::isotropic
Definition: material.hpp:148
ptracey::material
Definition: material.hpp:17