-
Notifications
You must be signed in to change notification settings - Fork 0
/
material.h
110 lines (94 loc) · 2.87 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
#ifndef MATERIALH
#define MATERIALH
struct hit_record;
#include "ray.h"
#include "hitable.h"
vec3 randomInUnitSphere() {
vec3 p;
do {
p = 2.0 * vec3(drand48(),drand48(), drand48()) - vec3(1,1,1);
} while(p.squaredLength() >= 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, double niOverNt, vec3& refracted) {
vec3 uv = unitVector(v);
double dt = dot(uv, n);
double discriminant = 1.0 - niOverNt*niOverNt*(1-dt*dt);
if(discriminant > 0) {
refracted = niOverNt*(uv - n*dt) - n*sqrt(discriminant);
return true;
} else {
return false;
}
}
double schlick(double cosine, double refIdx) {
double r0 = (1-refIdx) / (1+refIdx);
r0 = r0 * r0;
return r0 + (1-r0)*pow((1- cosine), 5);
}
class material {
public:
virtual bool scatter(const ray& rIn, 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& rIn, const hit_record& rec, vec3& attenuation, ray& scattered) const {
vec3 target = rec.p + rec.normal + randomInUnitSphere();
scattered = ray(rec.p, target-rec.p);
attenuation = albedo;
return true;
}
vec3 albedo;
};
class metal : public material {
public:
metal(const vec3& a, double f) : albedo(a) {if(f < 1) fuzz = f; else fuzz = 1;}
virtual bool scatter(const ray& rIn, const hit_record& rec, vec3& attenuation, ray& scattered) const {
vec3 reflected = reflect(unitVector(rIn.direction()), rec.normal);
scattered = ray(rec.p, reflected+fuzz*randomInUnitSphere());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
vec3 albedo;
double fuzz;
};
class dielectric : public material {
public:
dielectric(double ri) : refIdx(ri) {}
virtual bool scatter(const ray& rIn, const hit_record& rec, vec3& attenuation, ray& scattered) const {
vec3 outwardNormal;
vec3 reflected = reflect(rIn.direction(), rec.normal);
double niOverNt;
attenuation = vec3(1.0, 1.0, 1.0);
vec3 refracted;
double reflectProb;
double cosine;
if(dot(rIn.direction(), rec.normal) > 0) {
outwardNormal = -rec.normal;
niOverNt = refIdx;
cosine = refIdx * dot(rIn.direction(), rec.normal) / rIn.direction().length();
} else {
outwardNormal = rec.normal;
niOverNt = 1.0 / refIdx;
cosine = -dot(rIn.direction(), rec.normal) / rIn.direction().length();
}
if(refract(rIn.direction(), outwardNormal, niOverNt, refracted)) {
reflectProb = schlick(cosine, refIdx);
} else {
scattered = ray(rec.p, reflected);
reflectProb = 1.0;
}
if(drand48() < reflectProb) {
scattered = ray(rec.p, reflected);
} else {
scattered = ray(rec.p, refracted);
}
return true;
}
double refIdx;
};
#endif