forked from RayTracing/TheNextWeek
-
Notifications
You must be signed in to change notification settings - Fork 0
/
material.h
141 lines (117 loc) · 4.32 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
137
#ifndef MATERIALH
#define MATERIALH
struct hit_record;
#include "ray.h"
#include "hitable.h"
#include "texture.h"
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);
}
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;
}
vec3 reflect(const vec3& v, const vec3& n) {
return v - 2*dot(v,n)*n;
}
vec3 random_in_unit_sphere() {
vec3 p;
do {
p = 2.0*vec3(drand48(),drand48(),drand48()) - vec3(1,1,1);
} while (dot(p,p) >= 1.0);
return p;
}
class material {
public:
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const = 0;
virtual vec3 emitted(float u, float v, const vec3& p) const {
return vec3(0,0,0); }
};
class diffuse_light : public material {
public:
diffuse_light(texture *a) : emit(a) {}
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const { return false; }
virtual vec3 emitted(float u, float v, const vec3& p) const { return emit->value(u, v, p); }
texture *emit;
};
class isotropic : public material {
public:
isotropic(texture *a) : albedo(a) {}
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
scattered = ray(rec.p, random_in_unit_sphere());
attenuation = albedo->value(rec.u, rec.v, rec.p);
return true;
}
texture *albedo;
};
class lambertian : public material {
public:
lambertian(texture *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, r_in.time());
attenuation = albedo->value(rec.u, rec.v, rec.p);
return true;
}
texture *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 {
scattered = ray(rec.p, reflected);
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