-
Notifications
You must be signed in to change notification settings - Fork 0
/
material.h
136 lines (121 loc) · 2.97 KB
/
material.h
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
#ifndef MATERIALH
#define MATERIALH
struct hit_record;
#include "ray.h"
#include "hitable.h"
vec3 random_in_unit_sphere()
{
vec3 p;
do
{
p = 2.0 * vec3(drand48(), drand48(), drand48()) - vec3(1, 1, 1);
} while (p.squared_length() >= 1.0);
return p;
}
vec3 reflect(const vec3 &v, const vec3 &n)
{
return v - 2 * dot(v, n) * n;
}
bool refract(const vec3 &v, const vec3 &n, float ni_over_nt, vec3 &refracted)
{
vec3 uv = unit_vector(v);
float dt = dot(uv, n);
float discriminant = 1.0 - ni_over_nt * ni_over_nt * (1 - dt * dt);
if (discriminant > 0)
{
refracted = ni_over_nt * (uv - n * dt) - n * sqrt(discriminant);
return true;
}
else
return false;
}
float schlick(float cosine, float ref_idx)
{
float r0 = (1 - ref_idx) / (1 + ref_idx);
r0 = r0 * r0;
return r0 + (1 - r0) * pow((1 - cosine), 5);
}
class material
{
public:
virtual bool scatter(const ray &r_in, const hit_record &rec, vec3 &attenuation, ray &scattered) const = 0;
};
class lambertian : public material
{
public:
lambertian(const vec3 &a) : albedo(a) {}
virtual bool scatter(const ray &r_in, const hit_record &rec, vec3 &attenuation, ray &scattered) const
{
vec3 target = rec.p + rec.normal + random_in_unit_sphere();
scattered = ray(rec.p, target - rec.p);
attenuation = albedo;
return true;
}
vec3 albedo;
};
class metal : public material
{
public:
metal(const vec3 &a, float f) : albedo(a)
{
if (f < 1)
fuzz = f;
else
fuzz = 1;
}
virtual bool scatter(const ray &r_in, const hit_record &rec, vec3 &attenuation, ray &scattered) const
{
vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
scattered = ray(rec.p, reflected + fuzz * random_in_unit_sphere());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
vec3 albedo;
float fuzz;
};
class dielectric : public material
{
public:
dielectric(float ri) : ref_idx(ri) {}
virtual bool scatter(const ray &r_in, const hit_record &rec, vec3 &attenuation, ray &scattered) const
{
vec3 outward_normal;
vec3 reflected = reflect(r_in.direction(), rec.normal);
float ni_over_nt;
attenuation = vec3(1.0, 1.0, 1.0);
vec3 refracted;
float reflect_prob;
float cosine;
if (dot(r_in.direction(), rec.normal) > 0)
{
outward_normal = -rec.normal;
ni_over_nt = ref_idx;
cosine = ref_idx * dot(r_in.direction(), rec.normal) / r_in.direction().length();
}
else
{
outward_normal = rec.normal;
ni_over_nt = 1.0 / ref_idx;
cosine = -dot(r_in.direction(), rec.normal) / r_in.direction().length();
}
if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted))
{
reflect_prob = schlick(cosine, ref_idx);
}
else
{
reflect_prob = 1.0;
}
if (drand48() < reflect_prob)
{
scattered = ray(rec.p, reflected);
}
else
{
scattered = ray(rec.p, refracted);
}
return true;
}
float ref_idx;
};
#endif