346 |
awk |
1 |
#ifndef __PATHTRACER_CORE__HPP__
|
|
|
2 |
#define __PATHTRACER_CORE__HPP__
|
|
|
3 |
|
|
|
4 |
#include "CGLA/Vec2f.h"
|
|
|
5 |
#include "CGLA/Vec3f.h"
|
|
|
6 |
|
|
|
7 |
#include <limits>
|
|
|
8 |
|
|
|
9 |
struct ray
|
|
|
10 |
{
|
|
|
11 |
ray(void) : origin(0.f), direction(0.f), distance(0.f), depth(0) {}
|
|
|
12 |
|
|
|
13 |
CGLA::Vec3f origin;
|
|
|
14 |
CGLA::Vec3f direction;
|
|
|
15 |
|
|
|
16 |
float distance;
|
|
|
17 |
int depth;
|
|
|
18 |
};
|
|
|
19 |
|
|
|
20 |
struct hit_info
|
|
|
21 |
{
|
|
|
22 |
hit_info(void) :
|
|
|
23 |
distance(0.f),
|
|
|
24 |
position(0.f), geometric_normal(0.f), shading_normal(0.f),
|
|
|
25 |
inside(false),
|
|
|
26 |
emitted(0.f),
|
|
|
27 |
diffuse(0.f), glossy(0.f), shininess(0.f),
|
|
|
28 |
reflection(0.f), refraction(0.f),
|
|
|
29 |
ior(0.f), extinction(0.f) {}
|
|
|
30 |
|
|
|
31 |
float distance;
|
|
|
32 |
CGLA::Vec3f position;
|
|
|
33 |
CGLA::Vec3f geometric_normal;
|
|
|
34 |
CGLA::Vec3f shading_normal;
|
|
|
35 |
|
|
|
36 |
//The tangent, bitangent, and shading_normal form an orthonormal basis
|
|
|
37 |
CGLA::Vec3f tangent;
|
|
|
38 |
CGLA::Vec3f bitangent;
|
|
|
39 |
|
|
|
40 |
//texture coordinates
|
|
|
41 |
CGLA::Vec2f texcoords;
|
|
|
42 |
|
|
|
43 |
//flag to indicate if the inside of the object (wrt the normal) was hit
|
|
|
44 |
bool inside;
|
|
|
45 |
|
|
|
46 |
//emitted radiance
|
|
|
47 |
CGLA::Vec3f emitted;
|
|
|
48 |
|
|
|
49 |
//diffuse reflectivity (rho)
|
|
|
50 |
CGLA::Vec3f diffuse;
|
|
|
51 |
|
|
|
52 |
//parameters for the modified Phong reflectance model
|
|
|
53 |
CGLA::Vec3f glossy;
|
|
|
54 |
float shininess;
|
|
|
55 |
|
|
|
56 |
//parameters for perfect specular reflection/refraction
|
|
|
57 |
CGLA::Vec3f reflection;
|
|
|
58 |
CGLA::Vec3f refraction;
|
|
|
59 |
|
|
|
60 |
//index of refraction + complex part
|
|
|
61 |
float ior;
|
|
|
62 |
float extinction;
|
|
|
63 |
};
|
|
|
64 |
|
|
|
65 |
//RGB to intensity
|
|
|
66 |
inline float intensity(const CGLA::Vec3f& v)
|
|
|
67 |
{
|
|
|
68 |
return v[0] * 0.27f + v[1] * 0.67f + v[2] * 0.06f;
|
|
|
69 |
}
|
|
|
70 |
|
|
|
71 |
//standard fresnel formula (see eg. Jensen p. 23)
|
|
|
72 |
inline float fresnel_dielectric(float cosi, float cost, float eta)
|
|
|
73 |
{
|
|
|
74 |
assert(cosi>0.f && cost>0.f);
|
|
|
75 |
|
|
|
76 |
float etai = 1.f;
|
|
|
77 |
float etat = eta;
|
|
|
78 |
|
|
|
79 |
float Fs = (etai*cosi - etat*cost) / (etai*cosi + etat*cost);
|
|
|
80 |
float Fp = (etat*cosi - etai*cost) / (etat*cosi + etai*cost);
|
|
|
81 |
|
|
|
82 |
float F = 0.5f * (Fs*Fs + Fp*Fp);
|
|
|
83 |
assert(F>=0.f && F<=1.f);
|
|
|
84 |
return F;
|
|
|
85 |
}
|
|
|
86 |
|
|
|
87 |
//standard fresnel formula (see eg. Pharr et all p. 422)
|
|
|
88 |
inline float fresnel_conductor(float cosi, float eta, float extinction)
|
|
|
89 |
{
|
|
|
90 |
assert(cosi >= 0.f);
|
|
|
91 |
|
|
|
92 |
float z = eta*eta + extinction*extinction;
|
|
|
93 |
|
|
|
94 |
float Fp = (z * cosi*cosi - 2.f * eta * cosi + 1.f) /
|
|
|
95 |
(z + 2.f * eta * cosi + 1.f);
|
|
|
96 |
|
|
|
97 |
float Fs = (z - 2.f * eta * cosi + cosi * cosi) /
|
|
|
98 |
(z + 2.f * eta * cosi + cosi * cosi);
|
|
|
99 |
|
|
|
100 |
float F = (Fp + Fs) * 0.5f;
|
|
|
101 |
assert(F>=0.f && F<=1.f);
|
|
|
102 |
return F;
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
//reflect vector around normal. n should be normalized.
|
|
|
106 |
inline CGLA::Vec3f reflect(const CGLA::Vec3f& n, const CGLA::Vec3f& r)
|
|
|
107 |
{
|
|
|
108 |
return 2.f * n * dot(n, r) - r;
|
|
|
109 |
}
|
|
|
110 |
|
|
|
111 |
//eta = eta_from / eta_to
|
|
|
112 |
inline bool refract(const CGLA::Vec3f & n, const CGLA::Vec3f & i,
|
|
|
113 |
float eta, CGLA::Vec3f & t)
|
|
|
114 |
{
|
|
|
115 |
float c1 = dot(i,n);
|
|
|
116 |
float c2 = 1.f - eta*eta * (1.f - c1*c1);
|
|
|
117 |
|
|
|
118 |
if (c2 < 0.f)
|
|
|
119 |
return false;
|
|
|
120 |
|
|
|
121 |
float c3 = std::sqrt(c2);
|
|
|
122 |
t = -eta*i + (eta*c1 - c3) * n;
|
|
|
123 |
|
|
|
124 |
return true;
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
//helper function, clamps v to range [i; a]
|
|
|
128 |
template <class T>
|
|
|
129 |
T clamp(const T& v, const T& i, const T& a)
|
|
|
130 |
{
|
|
|
131 |
return std::min(std::max(v, i), a);
|
|
|
132 |
}
|
|
|
133 |
|
|
|
134 |
//mersenne twister
|
|
|
135 |
extern "C" double genrand_real2(void);
|
|
|
136 |
inline float random(void)
|
|
|
137 |
{
|
|
|
138 |
return float(genrand_real2());
|
|
|
139 |
}
|
|
|
140 |
|
|
|
141 |
//evaluation of the diffuse brdf
|
|
|
142 |
inline CGLA::Vec3f lambertian_brdf(const hit_info& hi,
|
|
|
143 |
const CGLA::Vec3f& wi,
|
|
|
144 |
const CGLA::Vec3f& wo)
|
|
|
145 |
{
|
|
|
146 |
return hi.diffuse / float(M_PI);
|
|
|
147 |
}
|
|
|
148 |
|
|
|
149 |
//sampling of diffuse brdf, wi = sampled direction, should return probability
|
|
|
150 |
inline float sample_lambertian(const hit_info& hi,
|
|
|
151 |
const CGLA::Vec3f& wo, CGLA::Vec3f& wi)
|
|
|
152 |
{
|
|
|
153 |
CGLA::Vec3f x, y, z = hi.shading_normal;
|
|
|
154 |
orthogonal(z, x, y);
|
|
|
155 |
float e0 = random();
|
|
|
156 |
float e1 = random();
|
|
|
157 |
float cost = std::sqrt(e0);
|
|
|
158 |
float sint = std::sqrt(1.f - e0);
|
|
|
159 |
float cosp = std::cos(e1 * 2.f * float(M_PI));
|
|
|
160 |
float sinp = std::sin(e1 * 2.f * float(M_PI));
|
|
|
161 |
CGLA::Vec3f dir(sint*cosp, sint*sinp, cost);
|
|
|
162 |
|
|
|
163 |
wi = dir(0) * x + dir(1) * y + dir(2) * z;
|
|
|
164 |
return 1.f / float(M_PI) * cost;
|
|
|
165 |
}
|
|
|
166 |
|
|
|
167 |
//evaluation of the phong brdf
|
|
|
168 |
inline CGLA::Vec3f phong_brdf(const hit_info& hi,
|
|
|
169 |
const CGLA::Vec3f& wi,const CGLA::Vec3f& wo)
|
|
|
170 |
{
|
|
|
171 |
float dwi = dot(wi, hi.geometric_normal);
|
|
|
172 |
float dwo = dot(wo, hi.geometric_normal);
|
|
|
173 |
float same_hemisphere = dwi * dwo > 0.f;
|
|
|
174 |
|
|
|
175 |
if (same_hemisphere)
|
|
|
176 |
{
|
|
|
177 |
//glossy contribution
|
|
|
178 |
if (intensity(hi.glossy) > 0.f)
|
|
|
179 |
{
|
|
|
180 |
float cost = std::max(dot(reflect(hi.shading_normal, wi), wo),
|
|
|
181 |
0.f);
|
|
|
182 |
float cosn = std::pow(cost, hi.shininess);
|
|
|
183 |
return hi.glossy * (hi.shininess+2.f)/(2.f * float(M_PI))*cosn;
|
|
|
184 |
}
|
|
|
185 |
}
|
|
|
186 |
return CGLA::Vec3f(0.f);
|
|
|
187 |
}
|
|
|
188 |
|
|
|
189 |
//sampling of phong brdf, wi = sampled direction, should return probability
|
|
|
190 |
inline float sample_phong(const hit_info& hi,
|
|
|
191 |
const CGLA::Vec3f& wo, CGLA::Vec3f& wi)
|
|
|
192 |
{
|
|
|
193 |
float e0 = random();
|
|
|
194 |
float e1 = random();
|
|
|
195 |
|
|
|
196 |
float cost = std::pow(e0, 1.f/(hi.shininess + 1.f));
|
|
|
197 |
float sint = std::sqrt(1.f - std::pow(e0, 2.f/(hi.shininess + 1.f)));
|
|
|
198 |
float cosp = std::cos(e1 * 2.f * float(M_PI));
|
|
|
199 |
float sinp = std::sin(e1 * 2.f * float(M_PI));
|
|
|
200 |
|
|
|
201 |
CGLA::Vec3f dir(sint*cosp, sint*sinp, cost);
|
|
|
202 |
|
|
|
203 |
CGLA::Vec3f x, y, z = reflect(hi.shading_normal, wo);
|
|
|
204 |
orthogonal(z, x, y);
|
|
|
205 |
|
|
|
206 |
float cosn = std::pow(dir(2), hi.shininess);
|
|
|
207 |
wi = dir(0) * x + dir(1) * y + dir(2) * z;
|
|
|
208 |
|
|
|
209 |
return (hi.shininess+1.f) / (2.f * float(M_PI)) * cosn;
|
|
|
210 |
}
|
|
|
211 |
|
|
|
212 |
//convenience function to evaluate the non-specular parts of the bsdf
|
|
|
213 |
inline CGLA::Vec3f bsdf_evaluate(const hit_info& hi,
|
|
|
214 |
const CGLA::Vec3f& wi, const CGLA::Vec3f& wo)
|
|
|
215 |
{
|
|
|
216 |
CGLA::Vec3f fs(0.f);
|
|
|
217 |
|
|
|
218 |
fs += lambertian_brdf(hi, wi, wo);
|
|
|
219 |
fs += phong_brdf(hi, wi, wo);
|
|
|
220 |
|
|
|
221 |
return fs;
|
|
|
222 |
}
|
|
|
223 |
|
|
|
224 |
//epsilon for shadow testing
|
|
|
225 |
static const float epsilon = 1e-5f;
|
|
|
226 |
|
|
|
227 |
static const float step = 1e-1f;
|
|
|
228 |
|
|
|
229 |
#endif
|
|
|
230 |
|
|
|
231 |
//02566 framework, Anders Wang Kristensen, awk@imm.dtu.dk, 2007
|