-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaterial.h
189 lines (160 loc) · 5.99 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#ifndef MATERIALH
#define MATERIALH
#include <bits/stdc++.h>
#include <cmath>
#include "hip-commons.h"
#include "vector.h"
#include "ray.h"
#include "hitable.h"
class Material
{
public:
__device__ bool virtual scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const { return false; };
};
// Diffuse -- Lambertian diffuse material. Simulates a rough, matte material.
class Diffuse : public Material
{
public:
__device__ Diffuse(const vec3& a) : albedo(a) {}
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const override
{
vec3 target = pRec.p + pRec.normal + random_in_unit_sphere(pRandState);
*pRay = ray(pRec.p, target-pRec.p);
pAttenuation = albedo;
isLightSource = false;
return true;
}
vec3 albedo;
};
// Metal -- Reflects incoming rays mirrored across the normal vector.
// Simulates a mirror finish.
class Metal : public Material
{
public:
__device__ Metal(const vec3& a, const float f) : albedo(a) { fuzz = __saturatef(f); }
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const override
{
vec3 reflected = reflect(unit_vector(pRay->direction()), pRec.normal);
*pRay = ray(pRec.p, reflected + fuzz*random_in_unit_sphere(pRandState));
pAttenuation = albedo;
isLightSource = false;
return (dot(pRay->direction(), pRec.normal) > 0);
}
vec3 albedo;
float fuzz;
};
// Emmissive-- Emits more light than it receives
class Emmissive : public Material
{
public:
__device__ Emmissive(const vec3& a, const float s, const bool c) : albedo(a), strength(s), continueTracing(c) {}
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const override
{
vec3 target = pRec.p + pRec.normal + random_in_unit_sphere(pRandState);
*pRay = ray(pRec.p, target-pRec.p);
pAttenuation = albedo * strength;
isLightSource = true;
return continueTracing;
}
vec3 albedo;
float strength;
bool continueTracing;
};
// Glass - Calculates internal reflections and refractions
class Glass : public Material
{
public:
__device__ Glass(const vec3& a, const float ri) : albedo(a), ref_idx(ri) {}
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const override
{
vec3 outward_normal;
vec3 reflected = reflect(pRay->direction(), pRec.normal);
float ni_over_nt;
pAttenuation = albedo;
vec3 refracted;
float cosine;
if (dot(pRay->direction(), pRec.normal) > 0)
{
outward_normal = -pRec.normal;
ni_over_nt = ref_idx;
cosine = ref_idx * dot(pRay->direction(), pRec.normal) / pRay->direction().length();
}
else
{
outward_normal = pRec.normal;
ni_over_nt = 1.0f / ref_idx;
cosine = -dot(pRay->direction(), pRec.normal) / pRay->direction().length();
}
if (this->refract(pRay->direction(), outward_normal, ni_over_nt, refracted))
{
float reflect_prob = this->schlick(1-cosine, ref_idx);
*pRay = ray(pRec.p, (hiprand_uniform(pRandState) < reflect_prob)? reflected : refracted);
}
else *pRay = ray(pRec.p, reflected);
isLightSource = false;
return true;
}
// Glass has reflectivity that varies with viewing angle. This is a
// massive ugly equation, but luckily Christophe Schlick came up with this
// simple polynomial approximation. :)
__device__ float schlick(float cosine, float ref_idx) const
{
float r0 = (1-ref_idx) / (1+ref_idx);
r0 = r0*r0;
return r0 + (1-r0)*cosine*cosine*cosine*cosine*cosine;
}
// Determines whether the viewing angle is steep enough for total internal
// reflection (zero refraction) and refracts. this is based on snell's law:
// n sin(theta) = n' sin(theta')
// common values: air=1, glass=1.3-1.7, diamond=2.4
__device__ bool refract(const vec3& v, const vec3& n, float ni_over_nt, vec3& refracted) const
{
vec3 uv = unit_vector(v);
float dt = dot(uv, n);
float discriminant = ni_over_nt*ni_over_nt*(1-dt*dt);
if (discriminant < 1) {
refracted = ni_over_nt*(uv - n*dt) - n*sqrt(1-discriminant);
return true;
}
else return false;
}
vec3 albedo;
float ref_idx;
};
// Translucent -- Somewhat transparent, tints incoming light
class Translucent : public Material
{
public:
__device__ Translucent(const vec3& a, const float t, const float s) : albedo(a) {
translucency = __saturatef(t);
scattering = __saturatef(t);
}
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const override
{
float cosine = (dot(pRay->direction(), pRec.normal)) / (pRay->direction().length());
cosine = 0.5f*(cosine+1);
*pRay = ray(pRec.p, pRec.p + pRay->direction() + scattering*random_in_unit_sphere(pRandState));
pAttenuation = albedo;
pAttenuation[0] = fma(pAttenuation[0], cosine, translucency);
pAttenuation[1] = fma(pAttenuation[1], cosine, translucency);
pAttenuation[2] = fma(pAttenuation[2], cosine, translucency);
isLightSource = false;
return true;
}
vec3 albedo;
float translucency;
float scattering;
};
// Normals -- Visualizes normals
class Normals : public Material
{
public:
__device__ Normals() {}
__device__ bool scatter(ray *pRay, const hit_record &pRec, vec3 &pAttenuation, hiprandState *pRandState, bool &isLightSource) const
{
pAttenuation = pRec.normal;
isLightSource = true;
return false;
}
};
#endif