-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmaterial.h
More file actions
130 lines (101 loc) · 3.76 KB
/
material.h
File metadata and controls
130 lines (101 loc) · 3.76 KB
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
#ifndef MATERIAL_H
#define MATERIAL_H
#include "rtweekend.h"
#include "hittable.h"
#include "texture.h"
class material {
public:
virtual ~material() = default;
virtual color emitted(double u, double v, const point3& p) const {
return color(0, 0, 0);
}
virtual bool scatter(
const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered
) const = 0;
};
class diffuse_light : public material {
public:
diffuse_light(shared_ptr<texture> tex) : tex(tex) {}
diffuse_light(const color& emit) : tex(make_shared<solid_color>(emit)) {}
color emitted(double u, double v, const point3& p) const override {
return tex->value(u, v, p);
}
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
const override {
return false;
}
private:
shared_ptr<texture> tex;
};
class lambertian : public material {
public:
lambertian(const color& albedo) : tex(make_shared<solid_color>(albedo)) {}
lambertian(shared_ptr<texture> tex) : tex(tex) {}
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
const override {
auto scatter_direction = rec.normal + random_unit_vector();
if (scatter_direction.near_zero())
scatter_direction = rec.normal;
scattered = ray(rec.p, scatter_direction, r_in.time());
attenuation = tex->value(rec.u, rec.v, rec.p);
return true;
}
private:
shared_ptr<texture> tex;
};
class metal : public material {
public:
metal(const color& albedo, double fuzz) : albedo(albedo), fuzz(fuzz < 1 ? fuzz : 1) {}
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
const override {
vec3 reflected = reflect(r_in.direction(), rec.normal);
reflected = unit_vector(reflected) + (fuzz * random_unit_vector());
scattered = ray(rec.p, reflected, r_in.time());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
private:
color albedo;
double fuzz;
};
class dielectric : public material {
public:
dielectric(double refraction_index) : refraction_index(refraction_index) {}
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
const override {
attenuation = color(1.0, 1.0, 1.0);
double ri = rec.front_face ? (1.0 / refraction_index) : refraction_index;
vec3 unit_direction = unit_vector(r_in.direction());
double cos_theta = std::fmin(dot(-unit_direction, rec.normal), 1.0);
double sin_theta = std::sqrt(1.0 - cos_theta * cos_theta);
bool cannot_refract = ri * sin_theta > 1.0;
vec3 direction;
if (cannot_refract || reflectance(cos_theta, ri) > random_double())
direction = reflect(unit_direction, rec.normal);
else
direction = refract(unit_direction, rec.normal, ri);
scattered = ray(rec.p, direction, r_in.time());
return true;
}
private:
double refraction_index;
static double reflectance(double cosine, double refraction_index) {
auto r0 = (1 - refraction_index) / (1 + refraction_index);
r0 = r0 * r0;
return r0 + (1 - r0) * std::pow((1 - cosine), 5);
}
};
class isotropic : public material {
public:
isotropic(const color& albedo) : tex(make_shared<solid_color>(albedo)) {}
isotropic(shared_ptr<texture> tex) : tex(tex) {}
bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered)
const override {
scattered = ray(rec.p, random_unit_vector(), r_in.time());
attenuation = tex->value(rec.u, rec.v, rec.p);
return true;
}
private:
shared_ptr<texture> tex;
};
#endif