ee5befae |
1 | // This file has been automatically generated from resource file src/Shaders/PathtraceBase.fs |
2 | |
3 | static const char Shaders_PathtraceBase_fs[] = |
6e728f3b |
4 | "#ifdef _MSC_VER\n" |
5 | " #define PATH_TRACING // just for editing in MS VS\n" |
6 | "\n" |
7 | " #define in\n" |
8 | " #define out\n" |
9 | " #define inout\n" |
10 | "\n" |
11 | " typedef struct { float x; float y; } vec2;\n" |
12 | " typedef struct { float x; float y; float z; } vec3;\n" |
13 | " typedef struct { float x; float y; float z; float w; } vec4;\n" |
14 | "#endif\n" |
15 | "\n" |
ee5befae |
16 | "#ifdef PATH_TRACING\n" |
17 | "\n" |
18 | "///////////////////////////////////////////////////////////////////////////////////////\n" |
19 | "// Specific data types\n" |
20 | "\n" |
21 | "//! Describes local space at the hit point (visualization space).\n" |
22 | "struct SLocalSpace\n" |
23 | "{\n" |
24 | " //! Local X axis.\n" |
25 | " vec3 AxisX;\n" |
26 | "\n" |
27 | " //! Local Y axis.\n" |
28 | " vec3 AxisY;\n" |
29 | "\n" |
30 | " //! Local Z axis.\n" |
31 | " vec3 AxisZ;\n" |
32 | "};\n" |
33 | "\n" |
34 | "//! Describes material properties (BSDF).\n" |
05aa616d |
35 | "struct SBSDF\n" |
ee5befae |
36 | "{\n" |
05aa616d |
37 | " //! Weight of coat specular/glossy BRDF.\n" |
38 | " vec4 Kc;\n" |
39 | "\n" |
40 | " //! Weight of base diffuse BRDF.\n" |
ee5befae |
41 | " vec4 Kd;\n" |
42 | "\n" |
05aa616d |
43 | " //! Weight of base specular/glossy BRDF.\n" |
44 | " vec4 Ks;\n" |
ee5befae |
45 | "\n" |
05aa616d |
46 | " //! Weight of base specular/glossy BTDF.\n" |
ee5befae |
47 | " vec3 Kt;\n" |
48 | "\n" |
05aa616d |
49 | " //! Fresnel coefficients of coat layer.\n" |
50 | " vec3 FresnelCoat;\n" |
ee5befae |
51 | "\n" |
05aa616d |
52 | " //! Fresnel coefficients of base layer.\n" |
53 | " vec3 FresnelBase;\n" |
ee5befae |
54 | "};\n" |
55 | "\n" |
56 | "///////////////////////////////////////////////////////////////////////////////////////\n" |
57 | "// Support subroutines\n" |
58 | "\n" |
59 | "//=======================================================================\n" |
6e728f3b |
60 | "// function : buildLocalSpace\n" |
ee5befae |
61 | "// purpose : Generates local space for the given normal\n" |
62 | "//=======================================================================\n" |
6e728f3b |
63 | "SLocalSpace buildLocalSpace (in vec3 theNormal)\n" |
ee5befae |
64 | "{\n" |
6e728f3b |
65 | " vec3 anAxisX = vec3 (theNormal.z, 0.f, -theNormal.x);\n" |
66 | " vec3 anAxisY = vec3 (0.f, -theNormal.z, theNormal.y);\n" |
ee5befae |
67 | "\n" |
68 | " float aSqrLenX = dot (anAxisX, anAxisX);\n" |
69 | " float aSqrLenY = dot (anAxisY, anAxisY);\n" |
70 | "\n" |
71 | " if (aSqrLenX > aSqrLenY)\n" |
72 | " {\n" |
73 | " anAxisX *= inversesqrt (aSqrLenX);\n" |
74 | " anAxisY = cross (anAxisX, theNormal);\n" |
75 | " }\n" |
76 | " else\n" |
77 | " {\n" |
78 | " anAxisY *= inversesqrt (aSqrLenY);\n" |
79 | " anAxisX = cross (anAxisY, theNormal);\n" |
80 | " }\n" |
81 | "\n" |
82 | " return SLocalSpace (anAxisX, anAxisY, theNormal);\n" |
83 | "}\n" |
84 | "\n" |
85 | "//=======================================================================\n" |
86 | "// function : toLocalSpace\n" |
87 | "// purpose : Transforms the vector to local space from world space\n" |
88 | "//=======================================================================\n" |
89 | "vec3 toLocalSpace (in vec3 theVector, in SLocalSpace theSpace)\n" |
90 | "{\n" |
91 | " return vec3 (dot (theVector, theSpace.AxisX),\n" |
92 | " dot (theVector, theSpace.AxisY),\n" |
93 | " dot (theVector, theSpace.AxisZ));\n" |
94 | "}\n" |
95 | "\n" |
96 | "//=======================================================================\n" |
97 | "// function : fromLocalSpace\n" |
98 | "// purpose : Transforms the vector from local space to world space\n" |
99 | "//=======================================================================\n" |
100 | "vec3 fromLocalSpace (in vec3 theVector, in SLocalSpace theSpace)\n" |
101 | "{\n" |
102 | " return theVector.x * theSpace.AxisX +\n" |
103 | " theVector.y * theSpace.AxisY +\n" |
104 | " theVector.z * theSpace.AxisZ;\n" |
105 | "}\n" |
106 | "\n" |
107 | "//=======================================================================\n" |
108 | "// function : convolve\n" |
109 | "// purpose : Performs a linear convolution of the vector components\n" |
110 | "//=======================================================================\n" |
111 | "float convolve (in vec3 theVector, in vec3 theFactor)\n" |
112 | "{\n" |
113 | " return dot (theVector, theFactor) * (1.f / max (theFactor.x + theFactor.y + theFactor.z, 1e-15f));\n" |
114 | "}\n" |
115 | "\n" |
116 | "//=======================================================================\n" |
ee5befae |
117 | "// function : fresnelSchlick\n" |
118 | "// purpose : Computes the Fresnel reflection formula using\n" |
119 | "// Schlick's approximation.\n" |
120 | "//=======================================================================\n" |
121 | "vec3 fresnelSchlick (in float theCosI, in vec3 theSpecularColor)\n" |
122 | "{\n" |
123 | " return theSpecularColor + (UNIT - theSpecularColor) * pow (1.f - theCosI, 5.f);\n" |
124 | "}\n" |
125 | "\n" |
126 | "//=======================================================================\n" |
127 | "// function : fresnelDielectric\n" |
128 | "// purpose : Computes the Fresnel reflection formula for dielectric in\n" |
129 | "// case of circularly polarized light (Based on PBRT code).\n" |
130 | "//=======================================================================\n" |
131 | "float fresnelDielectric (in float theCosI,\n" |
132 | " in float theCosT,\n" |
133 | " in float theEtaI,\n" |
134 | " in float theEtaT)\n" |
135 | "{\n" |
136 | " float aParl = (theEtaT * theCosI - theEtaI * theCosT) /\n" |
137 | " (theEtaT * theCosI + theEtaI * theCosT);\n" |
138 | "\n" |
139 | " float aPerp = (theEtaI * theCosI - theEtaT * theCosT) /\n" |
140 | " (theEtaI * theCosI + theEtaT * theCosT);\n" |
141 | "\n" |
142 | " return (aParl * aParl + aPerp * aPerp) * 0.5f;\n" |
143 | "}\n" |
144 | "\n" |
145 | "#define ENVIRONMENT_IOR 1.f\n" |
146 | "\n" |
147 | "//=======================================================================\n" |
148 | "// function : fresnelDielectric\n" |
149 | "// purpose : Computes the Fresnel reflection formula for dielectric in\n" |
150 | "// case of circularly polarized light (based on PBRT code)\n" |
151 | "//=======================================================================\n" |
152 | "float fresnelDielectric (in float theCosI, in float theIndex)\n" |
153 | "{\n" |
05aa616d |
154 | " float aFresnel = 1.f;\n" |
155 | "\n" |
ee5befae |
156 | " float anEtaI = theCosI > 0.f ? 1.f : theIndex;\n" |
157 | " float anEtaT = theCosI > 0.f ? theIndex : 1.f;\n" |
158 | "\n" |
05aa616d |
159 | " float aSinT2 = (anEtaI * anEtaI) / (anEtaT * anEtaT) * (1.f - theCosI * theCosI);\n" |
ee5befae |
160 | "\n" |
05aa616d |
161 | " if (aSinT2 < 1.f)\n" |
ee5befae |
162 | " {\n" |
05aa616d |
163 | " aFresnel = fresnelDielectric (abs (theCosI), sqrt (1.f - aSinT2), anEtaI, anEtaT);\n" |
ee5befae |
164 | " }\n" |
165 | "\n" |
05aa616d |
166 | " return aFresnel;\n" |
ee5befae |
167 | "}\n" |
168 | "\n" |
169 | "//=======================================================================\n" |
170 | "// function : fresnelConductor\n" |
171 | "// purpose : Computes the Fresnel reflection formula for conductor in case\n" |
172 | "// of circularly polarized light (based on PBRT source code)\n" |
173 | "//=======================================================================\n" |
174 | "float fresnelConductor (in float theCosI, in float theEta, in float theK)\n" |
175 | "{\n" |
176 | " float aTmp = 2.f * theEta * theCosI;\n" |
177 | "\n" |
178 | " float aTmp1 = theEta * theEta + theK * theK;\n" |
179 | "\n" |
180 | " float aSPerp = (aTmp1 - aTmp + theCosI * theCosI) /\n" |
181 | " (aTmp1 + aTmp + theCosI * theCosI);\n" |
182 | "\n" |
183 | " float aTmp2 = aTmp1 * theCosI * theCosI;\n" |
184 | "\n" |
185 | " float aSParl = (aTmp2 - aTmp + 1.f) /\n" |
186 | " (aTmp2 + aTmp + 1.f);\n" |
187 | "\n" |
188 | " return (aSPerp + aSParl) * 0.5f;\n" |
189 | "}\n" |
190 | "\n" |
191 | "#define FRESNEL_SCHLICK -0.5f\n" |
192 | "#define FRESNEL_CONSTANT -1.5f\n" |
193 | "#define FRESNEL_CONDUCTOR -2.5f\n" |
194 | "#define FRESNEL_DIELECTRIC -3.5f\n" |
195 | "\n" |
196 | "//=======================================================================\n" |
197 | "// function : fresnelMedia\n" |
198 | "// purpose : Computes the Fresnel reflection formula for general medium\n" |
199 | "// in case of circularly polarized light.\n" |
200 | "//=======================================================================\n" |
6e728f3b |
201 | "vec3 fresnelMedia (in float theCosI, in vec3 theFresnel)\n" |
ee5befae |
202 | "{\n" |
05aa616d |
203 | " vec3 aFresnel;\n" |
204 | "\n" |
6e728f3b |
205 | " if (theFresnel.x > FRESNEL_SCHLICK)\n" |
ee5befae |
206 | " {\n" |
05aa616d |
207 | " aFresnel = fresnelSchlick (abs (theCosI), theFresnel);\n" |
ee5befae |
208 | " }\n" |
05aa616d |
209 | " else if (theFresnel.x > FRESNEL_CONSTANT)\n" |
ee5befae |
210 | " {\n" |
05aa616d |
211 | " aFresnel = vec3 (theFresnel.z);\n" |
ee5befae |
212 | " }\n" |
05aa616d |
213 | " else if (theFresnel.x > FRESNEL_CONDUCTOR)\n" |
214 | " {\n" |
215 | " aFresnel = vec3 (fresnelConductor (abs (theCosI), theFresnel.y, theFresnel.z));\n" |
216 | " }\n" |
217 | " else\n" |
ee5befae |
218 | " {\n" |
05aa616d |
219 | " aFresnel = vec3 (fresnelDielectric (theCosI, theFresnel.y));\n" |
ee5befae |
220 | " }\n" |
221 | "\n" |
05aa616d |
222 | " return aFresnel;\n" |
ee5befae |
223 | "}\n" |
224 | "\n" |
225 | "//=======================================================================\n" |
226 | "// function : transmitted\n" |
227 | "// purpose : Computes transmitted direction in tangent space\n" |
228 | "// (in case of TIR returned result is undefined!)\n" |
229 | "//=======================================================================\n" |
230 | "void transmitted (in float theIndex, in vec3 theIncident, out vec3 theTransmit)\n" |
231 | "{\n" |
232 | " // Compute relative index of refraction\n" |
233 | " float anEta = (theIncident.z > 0.f) ? 1.f / theIndex : theIndex;\n" |
234 | "\n" |
6e728f3b |
235 | " // Handle total internal reflection (TIR)\n" |
ee5befae |
236 | " float aSinT2 = anEta * anEta * (1.f - theIncident.z * theIncident.z);\n" |
237 | "\n" |
6e728f3b |
238 | " // Compute direction of transmitted ray\n" |
239 | " float aCosT = sqrt (1.f - min (aSinT2, 1.f)) * sign (-theIncident.z);\n" |
ee5befae |
240 | "\n" |
241 | " theTransmit = normalize (vec3 (-anEta * theIncident.x,\n" |
242 | " -anEta * theIncident.y,\n" |
243 | " aCosT));\n" |
244 | "}\n" |
245 | "\n" |
246 | "//////////////////////////////////////////////////////////////////////////////////////////////\n" |
247 | "// Handlers and samplers for materials\n" |
248 | "//////////////////////////////////////////////////////////////////////////////////////////////\n" |
249 | "\n" |
250 | "//=======================================================================\n" |
b4327ba8 |
251 | "// function : EvalLambertianReflection\n" |
252 | "// purpose : Evaluates Lambertian BRDF, with cos(N, PSI)\n" |
ee5befae |
253 | "//=======================================================================\n" |
b4327ba8 |
254 | "float EvalLambertianReflection (in vec3 theWi, in vec3 theWo)\n" |
ee5befae |
255 | "{\n" |
b4327ba8 |
256 | " return (theWi.z <= 0.f || theWo.z <= 0.f) ? 0.f : theWi.z * (1.f / M_PI);\n" |
ee5befae |
257 | "}\n" |
258 | "\n" |
05aa616d |
259 | "#define FLT_EPSILON 1.0e-5f\n" |
260 | "\n" |
ee5befae |
261 | "//=======================================================================\n" |
6e728f3b |
262 | "// function : SmithG1\n" |
263 | "// purpose :\n" |
ee5befae |
264 | "//=======================================================================\n" |
6e728f3b |
265 | "float SmithG1 (in vec3 theDirection, in vec3 theM, in float theRoughness)\n" |
ee5befae |
266 | "{\n" |
05aa616d |
267 | " float aResult = 0.f;\n" |
ee5befae |
268 | "\n" |
05aa616d |
269 | " if (dot (theDirection, theM) * theDirection.z > 0.f)\n" |
6e728f3b |
270 | " {\n" |
05aa616d |
271 | " float aTanThetaM = sqrt (1.f - theDirection.z * theDirection.z) / theDirection.z;\n" |
ee5befae |
272 | "\n" |
05aa616d |
273 | " if (aTanThetaM == 0.f)\n" |
274 | " {\n" |
275 | " aResult = 1.f;\n" |
276 | " }\n" |
277 | " else\n" |
278 | " {\n" |
279 | " float aVal = 1.f / (theRoughness * aTanThetaM);\n" |
ee5befae |
280 | "\n" |
05aa616d |
281 | " // Use rational approximation to shadowing-masking function (from Mitsuba)\n" |
282 | " aResult = (3.535f + 2.181f * aVal) / (1.f / aVal + 2.276f + 2.577f * aVal);\n" |
283 | " }\n" |
6e728f3b |
284 | " }\n" |
ee5befae |
285 | "\n" |
05aa616d |
286 | " return min (aResult, 1.f);\n" |
6e728f3b |
287 | "}\n" |
ee5befae |
288 | "\n" |
6e728f3b |
289 | "//=======================================================================\n" |
b4327ba8 |
290 | "// function : EvalBlinnReflection\n" |
291 | "// purpose : Evaluates Blinn glossy BRDF, with cos(N, PSI)\n" |
6e728f3b |
292 | "//=======================================================================\n" |
b4327ba8 |
293 | "vec3 EvalBlinnReflection (in vec3 theWi, in vec3 theWo, in vec3 theFresnel, in float theRoughness)\n" |
6e728f3b |
294 | "{\n" |
295 | " // calculate the reflection half-vec\n" |
b4327ba8 |
296 | " vec3 aH = normalize (theWi + theWo);\n" |
ee5befae |
297 | "\n" |
6e728f3b |
298 | " // roughness value -> Blinn exponent\n" |
299 | " float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n" |
ee5befae |
300 | "\n" |
6e728f3b |
301 | " // calculate microfacet distribution\n" |
302 | " float aD = (aPower + 2.f) * (1.f / M_2_PI) * pow (aH.z, aPower);\n" |
ee5befae |
303 | "\n" |
6e728f3b |
304 | " // calculate shadow-masking function\n" |
b4327ba8 |
305 | " float aG = SmithG1 (theWo, aH, theRoughness) *\n" |
306 | " SmithG1 (theWi, aH, theRoughness);\n" |
ee5befae |
307 | "\n" |
6e728f3b |
308 | " // return total amount of reflection\n" |
b4327ba8 |
309 | " return (theWi.z <= 0.f || theWo.z <= 0.f) ? ZERO :\n" |
310 | " aD * aG / (4.f * theWo.z) * fresnelMedia (dot (theWo, aH), theFresnel);\n" |
ee5befae |
311 | "}\n" |
312 | "\n" |
313 | "//=======================================================================\n" |
05aa616d |
314 | "// function : EvalBsdfLayered\n" |
b4327ba8 |
315 | "// purpose : Evaluates BSDF for specified material, with cos(N, PSI)\n" |
ee5befae |
316 | "//=======================================================================\n" |
05aa616d |
317 | "vec3 EvalBsdfLayered (in SBSDF theBSDF, in vec3 theWi, in vec3 theWo)\n" |
ee5befae |
318 | "{\n" |
b4327ba8 |
319 | "#ifdef TWO_SIDED_BXDF\n" |
320 | " theWi.z *= sign (theWi.z);\n" |
321 | " theWo.z *= sign (theWo.z);\n" |
322 | "#endif\n" |
323 | "\n" |
05aa616d |
324 | " vec3 aBxDF = theBSDF.Kd.rgb * EvalLambertianReflection (theWi, theWo);\n" |
325 | "\n" |
326 | " if (theBSDF.Ks.w > FLT_EPSILON)\n" |
327 | " {\n" |
328 | " aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase, theBSDF.Ks.w);\n" |
329 | " }\n" |
330 | "\n" |
331 | " aBxDF *= UNIT - fresnelMedia (theWo.z, theBSDF.FresnelCoat);\n" |
332 | "\n" |
333 | " if (theBSDF.Kc.w > FLT_EPSILON)\n" |
334 | " {\n" |
335 | " aBxDF += theBSDF.Kc.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelCoat, theBSDF.Kc.w);\n" |
336 | " }\n" |
337 | "\n" |
338 | " return aBxDF;\n" |
ee5befae |
339 | "}\n" |
340 | "\n" |
341 | "//=======================================================================\n" |
6e728f3b |
342 | "// function : SampleLambertianReflection\n" |
ee5befae |
343 | "// purpose : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n" |
344 | "//=======================================================================\n" |
b4327ba8 |
345 | "vec3 SampleLambertianReflection (in vec3 theWo, out vec3 theWi, inout float thePDF)\n" |
ee5befae |
346 | "{\n" |
347 | " float aKsi1 = RandFloat();\n" |
348 | " float aKsi2 = RandFloat();\n" |
349 | "\n" |
b4327ba8 |
350 | " theWi = vec3 (cos (M_2_PI * aKsi1),\n" |
351 | " sin (M_2_PI * aKsi1),\n" |
352 | " sqrt (1.f - aKsi2));\n" |
353 | "\n" |
354 | " theWi.xy *= sqrt (aKsi2);\n" |
ee5befae |
355 | "\n" |
b4327ba8 |
356 | "#ifdef TWO_SIDED_BXDF\n" |
357 | " theWi.z *= sign (theWo.z);\n" |
358 | "#endif\n" |
ee5befae |
359 | "\n" |
b4327ba8 |
360 | " thePDF *= theWi.z * (1.f / M_PI);\n" |
ee5befae |
361 | "\n" |
b4327ba8 |
362 | "#ifdef TWO_SIDED_BXDF\n" |
363 | " return UNIT;\n" |
364 | "#else\n" |
06e06389 |
365 | " return UNIT * step (0.f, theWo.z);\n" |
b4327ba8 |
366 | "#endif\n" |
6e728f3b |
367 | "}\n" |
ee5befae |
368 | "\n" |
369 | "//=======================================================================\n" |
05aa616d |
370 | "// function : SampleGlossyBlinnReflection\n" |
6e728f3b |
371 | "// purpose : Samples Blinn BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n" |
372 | "// The BRDF is a product of three main terms, D, G, and F,\n" |
373 | "// which is then divided by two cosine terms. Here we perform\n" |
374 | "// importance sample the D part of the Blinn model; trying to\n" |
375 | "// develop a sampling procedure that accounted for all of the\n" |
376 | "// terms would be complex, and it is the D term that accounts\n" |
377 | "// for most of the variation.\n" |
ee5befae |
378 | "//=======================================================================\n" |
05aa616d |
379 | "vec3 SampleGlossyBlinnReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel, in float theRoughness, inout float thePDF)\n" |
ee5befae |
380 | "{\n" |
6e728f3b |
381 | " float aKsi1 = RandFloat();\n" |
382 | " float aKsi2 = RandFloat();\n" |
ee5befae |
383 | "\n" |
6e728f3b |
384 | " // roughness value --> Blinn exponent\n" |
385 | " float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n" |
ee5befae |
386 | "\n" |
6e728f3b |
387 | " // normal from microface distribution\n" |
388 | " float aCosThetaM = pow (aKsi1, 1.f / (aPower + 2.f));\n" |
ee5befae |
389 | "\n" |
6e728f3b |
390 | " vec3 aM = vec3 (cos (M_2_PI * aKsi2),\n" |
391 | " sin (M_2_PI * aKsi2),\n" |
392 | " aCosThetaM);\n" |
ee5befae |
393 | "\n" |
6e728f3b |
394 | " aM.xy *= sqrt (1.f - aCosThetaM * aCosThetaM);\n" |
ee5befae |
395 | "\n" |
6e728f3b |
396 | " // calculate PDF of sampled direction\n" |
397 | " thePDF *= (aPower + 2.f) * (1.f / M_2_PI) * pow (aCosThetaM, aPower + 1.f);\n" |
398 | "\n" |
b4327ba8 |
399 | "#ifdef TWO_SIDED_BXDF\n" |
400 | " bool toFlip = theWo.z < 0.f;\n" |
401 | "\n" |
402 | " if (toFlip)\n" |
403 | " theWo.z = -theWo.z;\n" |
404 | "#endif\n" |
405 | "\n" |
406 | " float aCosDelta = dot (theWo, aM);\n" |
6e728f3b |
407 | "\n" |
408 | " // pick input based on half direction\n" |
b4327ba8 |
409 | " theWi = -theWo + 2.f * aCosDelta * aM;\n" |
6e728f3b |
410 | "\n" |
b4327ba8 |
411 | " if (theWi.z <= 0.f || theWo.z <= 0.f)\n" |
6e728f3b |
412 | " {\n" |
413 | " return ZERO;\n" |
ee5befae |
414 | " }\n" |
415 | "\n" |
6e728f3b |
416 | " // Jacobian of half-direction mapping\n" |
05aa616d |
417 | " thePDF /= 4.f * aCosDelta;\n" |
6e728f3b |
418 | "\n" |
419 | " // compute shadow-masking coefficient\n" |
b4327ba8 |
420 | " float aG = SmithG1 (theWo, aM, theRoughness) *\n" |
421 | " SmithG1 (theWi, aM, theRoughness);\n" |
422 | "\n" |
423 | "#ifdef TWO_SIDED_BXDF\n" |
424 | " if (toFlip)\n" |
425 | " theWi.z = -theWi.z;\n" |
426 | "#endif\n" |
6e728f3b |
427 | "\n" |
b4327ba8 |
428 | " return (aG * aCosDelta) / (theWo.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n" |
ee5befae |
429 | "}\n" |
430 | "\n" |
431 | "//=======================================================================\n" |
05aa616d |
432 | "// function : BsdfPdfLayered\n" |
433 | "// purpose : Calculates BSDF of sampling input knowing output\n" |
ee5befae |
434 | "//=======================================================================\n" |
05aa616d |
435 | "float BsdfPdfLayered (in SBSDF theBSDF, in vec3 theWo, in vec3 theWi, in vec3 theWeight)\n" |
ee5befae |
436 | "{\n" |
05aa616d |
437 | " float aPDF = 0.f; // PDF of sampling input direction\n" |
ee5befae |
438 | "\n" |
05aa616d |
439 | " // We choose whether the light is reflected or transmitted\n" |
440 | " // by the coating layer according to the Fresnel equations\n" |
441 | " vec3 aCoatF = fresnelMedia (theWo.z, theBSDF.FresnelCoat);\n" |
ee5befae |
442 | "\n" |
05aa616d |
443 | " // Coat BRDF is scaled by its Fresnel reflectance term. For\n" |
444 | " // reasons of simplicity we scale base BxDFs only by coat's\n" |
445 | " // Fresnel transmittance term\n" |
446 | " vec3 aCoatT = UNIT - aCoatF;\n" |
ee5befae |
447 | "\n" |
05aa616d |
448 | " float aPc = dot (theBSDF.Kc.rgb * aCoatF, theWeight);\n" |
449 | " float aPd = dot (theBSDF.Kd.rgb * aCoatT, theWeight);\n" |
450 | " float aPs = dot (theBSDF.Ks.rgb * aCoatT, theWeight);\n" |
451 | " float aPt = dot (theBSDF.Kt.rgb * aCoatT, theWeight);\n" |
ee5befae |
452 | "\n" |
05aa616d |
453 | " if (theWi.z * theWo.z > 0.f)\n" |
ee5befae |
454 | " {\n" |
05aa616d |
455 | " vec3 aH = normalize (theWi + theWo);\n" |
6e728f3b |
456 | "\n" |
05aa616d |
457 | " aPDF = aPd * abs (theWi.z / M_PI);\n" |
ee5befae |
458 | "\n" |
05aa616d |
459 | " if (theBSDF.Kc.w > FLT_EPSILON)\n" |
460 | " {\n" |
461 | " float aPower = max (2.f / (theBSDF.Kc.w * theBSDF.Kc.w) - 2.f, 0.f); // roughness --> exponent\n" |
ee5befae |
462 | "\n" |
05aa616d |
463 | " aPDF += aPc * (aPower + 2.f) * (0.25f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / dot (theWi, aH);\n" |
464 | " }\n" |
ee5befae |
465 | "\n" |
05aa616d |
466 | " if (theBSDF.Ks.w > FLT_EPSILON)\n" |
467 | " {\n" |
468 | " float aPower = max (2.f / (theBSDF.Ks.w * theBSDF.Ks.w) - 2.f, 0.f); // roughness --> exponent\n" |
ee5befae |
469 | "\n" |
05aa616d |
470 | " aPDF += aPs * (aPower + 2.f) * (0.25f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / dot (theWi, aH);\n" |
471 | " }\n" |
6e728f3b |
472 | " }\n" |
ee5befae |
473 | "\n" |
05aa616d |
474 | " return aPDF / (aPc + aPd + aPs + aPt);\n" |
ee5befae |
475 | "}\n" |
476 | "\n" |
6e728f3b |
477 | "//! Tool macro to handle sampling of particular BxDF\n" |
05aa616d |
478 | "#define PICK_BXDF_LAYER(p, k) aPDF = p / aTotalR; theWeight *= k / aPDF;\n" |
6e728f3b |
479 | "\n" |
ee5befae |
480 | "//=======================================================================\n" |
05aa616d |
481 | "// function : SampleBsdfLayered\n" |
ee5befae |
482 | "// purpose : Samples specified composite material (BSDF)\n" |
483 | "//=======================================================================\n" |
05aa616d |
484 | "float SampleBsdfLayered (in SBSDF theBSDF, in vec3 theWo, out vec3 theWi, inout vec3 theWeight, inout bool theInside)\n" |
ee5befae |
485 | "{\n" |
05aa616d |
486 | " // NOTE: OCCT uses two-layer material model. We have base diffuse, glossy, or transmissive\n" |
487 | " // layer, covered by one glossy/specular coat. In the current model, the layers themselves\n" |
488 | " // have no thickness; they can simply reflect light or transmits it to the layer under it.\n" |
489 | " // We use actual BRDF model only for direct reflection by the coat layer. For transmission\n" |
490 | " // through this layer, we approximate it as a flat specular surface.\n" |
491 | "\n" |
492 | " float aPDF = 0.f; // PDF of sampled direction\n" |
493 | "\n" |
494 | " // We choose whether the light is reflected or transmitted\n" |
495 | " // by the coating layer according to the Fresnel equations\n" |
496 | " vec3 aCoatF = fresnelMedia (theWo.z, theBSDF.FresnelCoat);\n" |
497 | "\n" |
498 | " // Coat BRDF is scaled by its Fresnel term. According to\n" |
499 | " // Wilkie-Weidlich layered BSDF model, transmission term\n" |
500 | " // for light passing through the coat at direction I and\n" |
501 | " // leaving it in O is T = ( 1 - F (O) ) x ( 1 - F (I) ).\n" |
502 | " // For reasons of simplicity, we discard the second term\n" |
503 | " // and scale base BxDFs only by the first term.\n" |
504 | " vec3 aCoatT = UNIT - aCoatF;\n" |
505 | "\n" |
506 | " float aPc = dot (theBSDF.Kc.rgb * aCoatF, theWeight);\n" |
507 | " float aPd = dot (theBSDF.Kd.rgb * aCoatT, theWeight);\n" |
508 | " float aPs = dot (theBSDF.Ks.rgb * aCoatT, theWeight);\n" |
509 | " float aPt = dot (theBSDF.Kt.rgb * aCoatT, theWeight);\n" |
510 | "\n" |
511 | " // Calculate total reflection probability\n" |
512 | " float aTotalR = (aPc + aPd) + (aPs + aPt);\n" |
513 | "\n" |
514 | " // Generate random variable to select BxDF\n" |
515 | " float aKsi = aTotalR * RandFloat();\n" |
516 | "\n" |
517 | " if (aKsi < aPc) // REFLECTION FROM COAT\n" |
518 | " {\n" |
519 | " PICK_BXDF_LAYER (aPc, theBSDF.Kc.rgb)\n" |
ee5befae |
520 | "\n" |
05aa616d |
521 | " if (theBSDF.Kc.w < FLT_EPSILON)\n" |
522 | " {\n" |
523 | " theWeight *= aCoatF;\n" |
ee5befae |
524 | "\n" |
05aa616d |
525 | " theWi = vec3 (-theWo.x,\n" |
526 | " -theWo.y,\n" |
527 | " theWo.z);\n" |
528 | " }\n" |
529 | " else\n" |
530 | " {\n" |
531 | " theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelCoat, theBSDF.Kc.w, aPDF);\n" |
532 | " }\n" |
ee5befae |
533 | "\n" |
05aa616d |
534 | " aPDF = mix (aPDF, MAXFLOAT, theBSDF.Kc.w < FLT_EPSILON);\n" |
ee5befae |
535 | " }\n" |
05aa616d |
536 | " else if (aKsi < aTotalR) // REFLECTION FROM BASE\n" |
ee5befae |
537 | " {\n" |
05aa616d |
538 | " theWeight *= aCoatT;\n" |
6e728f3b |
539 | "\n" |
05aa616d |
540 | " if (aKsi < aPc + aPd) // diffuse BRDF\n" |
541 | " {\n" |
542 | " PICK_BXDF_LAYER (aPd, theBSDF.Kd.rgb)\n" |
543 | "\n" |
544 | " theWeight *= SampleLambertianReflection (theWo, theWi, aPDF);\n" |
545 | " }\n" |
546 | " else if (aKsi < (aPc + aPd) + aPs) // specular/glossy BRDF\n" |
547 | " {\n" |
548 | " PICK_BXDF_LAYER (aPs, theBSDF.Ks.rgb)\n" |
6e728f3b |
549 | "\n" |
05aa616d |
550 | " if (theBSDF.Ks.w < FLT_EPSILON)\n" |
551 | " {\n" |
552 | " theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase);\n" |
ee5befae |
553 | "\n" |
05aa616d |
554 | " theWi = vec3 (-theWo.x,\n" |
555 | " -theWo.y,\n" |
556 | " theWo.z);\n" |
557 | " }\n" |
558 | " else\n" |
559 | " {\n" |
560 | " theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase, theBSDF.Ks.w, aPDF);\n" |
561 | " }\n" |
6e728f3b |
562 | "\n" |
05aa616d |
563 | " aPDF = mix (aPDF, MAXFLOAT, theBSDF.Ks.w < FLT_EPSILON);\n" |
564 | " }\n" |
565 | " else // specular transmission\n" |
566 | " {\n" |
567 | " PICK_BXDF_LAYER (aPt, theBSDF.Kt.rgb)\n" |
6e728f3b |
568 | "\n" |
05aa616d |
569 | " // refracted direction should exist if we are here\n" |
570 | " transmitted (theBSDF.FresnelCoat.y, theWo, theWi);\n" |
571 | "\n" |
572 | " theInside = !theInside; aPDF = MAXFLOAT;\n" |
573 | " }\n" |
ee5befae |
574 | " }\n" |
575 | "\n" |
576 | " // path termination for extra small weights\n" |
05aa616d |
577 | " theWeight = mix (ZERO, theWeight, step (FLT_EPSILON, aTotalR));\n" |
6e728f3b |
578 | "\n" |
579 | " return aPDF;\n" |
ee5befae |
580 | "}\n" |
581 | "\n" |
582 | "//////////////////////////////////////////////////////////////////////////////////////////////\n" |
583 | "// Handlers and samplers for light sources\n" |
584 | "//////////////////////////////////////////////////////////////////////////////////////////////\n" |
585 | "\n" |
6e728f3b |
586 | "// =======================================================================\n" |
587 | "// function : Latlong\n" |
588 | "// purpose : Converts world direction to environment texture coordinates\n" |
589 | "// =======================================================================\n" |
590 | "vec2 Latlong (in vec3 thePoint)\n" |
ee5befae |
591 | "{\n" |
6e728f3b |
592 | " float aPsi = acos (-thePoint.z);\n" |
ee5befae |
593 | "\n" |
6e728f3b |
594 | " float aPhi = atan (thePoint.y, thePoint.x) + M_PI;\n" |
ee5befae |
595 | "\n" |
6e728f3b |
596 | " return vec2 (aPhi * 0.1591549f,\n" |
597 | " aPsi * 0.3183098f);\n" |
ee5befae |
598 | "}\n" |
599 | "\n" |
600 | "//=======================================================================\n" |
6e728f3b |
601 | "// function : SampleLight\n" |
ee5befae |
602 | "// purpose : General sampling function for directional and point lights\n" |
603 | "//=======================================================================\n" |
6e728f3b |
604 | "vec3 SampleLight (in vec3 theToLight, inout float theDistance, in bool isInfinite, in float theSmoothness, inout float thePDF)\n" |
ee5befae |
605 | "{\n" |
6e728f3b |
606 | " SLocalSpace aSpace = buildLocalSpace (theToLight * (1.f / theDistance));\n" |
ee5befae |
607 | "\n" |
608 | " // for point lights smoothness defines radius\n" |
609 | " float aCosMax = isInfinite ? theSmoothness :\n" |
610 | " inversesqrt (1.f + theSmoothness * theSmoothness / (theDistance * theDistance));\n" |
611 | "\n" |
612 | " float aKsi1 = RandFloat();\n" |
613 | " float aKsi2 = RandFloat();\n" |
614 | "\n" |
615 | " float aTmp = 1.f - aKsi2 * (1.f - aCosMax);\n" |
616 | "\n" |
6e728f3b |
617 | " vec3 anInput = vec3 (cos (M_2_PI * aKsi1),\n" |
618 | " sin (M_2_PI * aKsi1),\n" |
ee5befae |
619 | " aTmp);\n" |
620 | "\n" |
621 | " anInput.xy *= sqrt (1.f - aTmp * aTmp);\n" |
622 | "\n" |
6e728f3b |
623 | " thePDF = (aCosMax < 1.f) ? (thePDF / M_2_PI) / (1.f - aCosMax) : MAXFLOAT;\n" |
ee5befae |
624 | "\n" |
625 | " return normalize (fromLocalSpace (anInput, aSpace));\n" |
626 | "}\n" |
627 | "\n" |
6e728f3b |
628 | "//=======================================================================\n" |
629 | "// function : HandlePointLight\n" |
630 | "// purpose :\n" |
631 | "//=======================================================================\n" |
632 | "float HandlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance, inout float thePDF)\n" |
ee5befae |
633 | "{\n" |
6e728f3b |
634 | " float aCosMax = inversesqrt (1.f + theRadius * theRadius / (theDistance * theDistance));\n" |
ee5befae |
635 | "\n" |
6e728f3b |
636 | " float aVisibility = step (aCosMax, dot (theInput, theToLight));\n" |
ee5befae |
637 | "\n" |
6e728f3b |
638 | " thePDF *= step (-1.f, -aCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - aCosMax);\n" |
639 | "\n" |
640 | " return aVisibility;\n" |
641 | "}\n" |
642 | "\n" |
643 | "//=======================================================================\n" |
644 | "// function : HandleDistantLight\n" |
645 | "// purpose :\n" |
646 | "//=======================================================================\n" |
647 | "float HandleDistantLight (in vec3 theInput, in vec3 theToLight, in float theCosMax, inout float thePDF)\n" |
648 | "{\n" |
649 | " float aVisibility = step (theCosMax, dot (theInput, theToLight));\n" |
650 | "\n" |
651 | " thePDF *= step (-1.f, -theCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - theCosMax);\n" |
652 | "\n" |
653 | " return aVisibility;\n" |
ee5befae |
654 | "}\n" |
655 | "\n" |
656 | "// =======================================================================\n" |
6e728f3b |
657 | "// function: IntersectLight\n" |
ee5befae |
658 | "// purpose : Checks intersections with light sources\n" |
659 | "// =======================================================================\n" |
6e728f3b |
660 | "vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, out float thePDF)\n" |
ee5befae |
661 | "{\n" |
6e728f3b |
662 | " vec3 aTotalRadiance = ZERO;\n" |
ee5befae |
663 | "\n" |
6e728f3b |
664 | " thePDF = 0.f; // PDF of sampling light sources\n" |
ee5befae |
665 | "\n" |
6e728f3b |
666 | " for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)\n" |
ee5befae |
667 | " {\n" |
668 | " vec4 aLight = texelFetch (\n" |
669 | " uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n" |
670 | " vec4 aParam = texelFetch (\n" |
671 | " uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n" |
672 | "\n" |
6e728f3b |
673 | " // W component: 0 for infinite light and 1 for point light\n" |
674 | " aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n" |
675 | "\n" |
676 | " float aPDF = 1.f / uLightCount;\n" |
677 | "\n" |
ee5befae |
678 | " if (aLight.w != 0.f) // point light source\n" |
679 | " {\n" |
6e728f3b |
680 | " float aCenterDst = length (aLight.xyz);\n" |
681 | "\n" |
682 | " if (aCenterDst < theHitDistance)\n" |
683 | " {\n" |
684 | " float aVisibility = HandlePointLight (\n" |
685 | " theRay.Direct, normalize (aLight.xyz), aParam.w /* radius */, aCenterDst, aPDF);\n" |
686 | "\n" |
687 | " if (aVisibility > 0.f)\n" |
688 | " {\n" |
689 | " theHitDistance = aCenterDst;\n" |
690 | " aTotalRadiance = aParam.rgb;\n" |
691 | "\n" |
692 | " thePDF = aPDF;\n" |
693 | " }\n" |
694 | " }\n" |
ee5befae |
695 | " }\n" |
6e728f3b |
696 | " else if (theHitDistance == MAXFLOAT) // directional light source\n" |
ee5befae |
697 | " {\n" |
6e728f3b |
698 | " aTotalRadiance += aParam.rgb * HandleDistantLight (\n" |
699 | " theRay.Direct, aLight.xyz, aParam.w /* angle cosine */, aPDF);\n" |
700 | "\n" |
701 | " thePDF += aPDF;\n" |
ee5befae |
702 | " }\n" |
703 | " }\n" |
704 | "\n" |
6e728f3b |
705 | " if (thePDF == 0.f && theHitDistance == MAXFLOAT) // light source not found\n" |
706 | " {\n" |
707 | " if (theDepth + uSphereMapForBack == 0) // view ray and map is hidden\n" |
708 | " {\n" |
ba00aab7 |
709 | " aTotalRadiance = BackgroundColor().rgb;\n" |
6e728f3b |
710 | " }\n" |
711 | " else\n" |
712 | " {\n" |
ba00aab7 |
713 | " aTotalRadiance = FetchEnvironment (Latlong (theRay.Direct)).rgb;\n" |
6e728f3b |
714 | " }\n" |
ba00aab7 |
715 | " #ifdef THE_SHIFT_sRGB\n" |
716 | " aTotalRadiance = pow (aTotalRadiance, vec3 (2.f));\n" |
717 | " #endif\n" |
6e728f3b |
718 | " }\n" |
719 | " \n" |
720 | " return aTotalRadiance;\n" |
ee5befae |
721 | "}\n" |
722 | "\n" |
6e728f3b |
723 | "#define MIN_THROUGHPUT vec3 (1.0e-3f)\n" |
724 | "#define MIN_CONTRIBUTION vec3 (1.0e-2f)\n" |
ee5befae |
725 | "\n" |
05aa616d |
726 | "#define MATERIAL_KC(index) (19 * index + 11)\n" |
727 | "#define MATERIAL_KD(index) (19 * index + 12)\n" |
728 | "#define MATERIAL_KS(index) (19 * index + 13)\n" |
729 | "#define MATERIAL_KT(index) (19 * index + 14)\n" |
730 | "#define MATERIAL_LE(index) (19 * index + 15)\n" |
731 | "#define MATERIAL_FRESNEL_COAT(index) (19 * index + 16)\n" |
732 | "#define MATERIAL_FRESNEL_BASE(index) (19 * index + 17)\n" |
733 | "#define MATERIAL_ABSORPT_BASE(index) (19 * index + 18)\n" |
ee5befae |
734 | "\n" |
05aa616d |
735 | "//! Enables experimental Russian roulette sampling path termination.\n" |
4eaaf9d8 |
736 | "//! In most cases, it provides faster image convergence with minimal\n" |
737 | "//! bias, so it is enabled by default.\n" |
ee5befae |
738 | "#define RUSSIAN_ROULETTE\n" |
739 | "\n" |
4eaaf9d8 |
740 | "//! Frame step to increase number of bounces. This mode is used\n" |
741 | "//! for interaction with the model, when path length is limited\n" |
742 | "//! for the first samples, and gradually increasing when camera\n" |
743 | "//! is stabilizing.\n" |
744 | "#ifdef ADAPTIVE_SAMPLING\n" |
745 | " #define FRAME_STEP 4\n" |
746 | "#else\n" |
747 | " #define FRAME_STEP 5\n" |
748 | "#endif\n" |
383c6c9f |
749 | "\n" |
ee5befae |
750 | "//=======================================================================\n" |
05aa616d |
751 | "// function : IsNotZero\n" |
752 | "// purpose : Checks whether BSDF reflects direct light\n" |
753 | "//=======================================================================\n" |
754 | "bool IsNotZero (in SBSDF theBSDF, in vec3 theThroughput)\n" |
755 | "{\n" |
756 | " vec3 aGlossy = theBSDF.Kc.rgb * step (FLT_EPSILON, theBSDF.Kc.w) +\n" |
757 | " theBSDF.Ks.rgb * step (FLT_EPSILON, theBSDF.Ks.w);\n" |
758 | "\n" |
759 | " return convolve (theBSDF.Kd.rgb + aGlossy, theThroughput) > FLT_EPSILON;\n" |
760 | "}\n" |
761 | "\n" |
762 | "//=======================================================================\n" |
ee5befae |
763 | "// function : PathTrace\n" |
764 | "// purpose : Calculates radiance along the given ray\n" |
765 | "//=======================================================================\n" |
4eaaf9d8 |
766 | "vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)\n" |
ee5befae |
767 | "{\n" |
768 | " float aRaytraceDepth = MAXFLOAT;\n" |
769 | "\n" |
770 | " vec3 aRadiance = ZERO;\n" |
771 | " vec3 aThroughput = UNIT;\n" |
772 | "\n" |
6e728f3b |
773 | " int aTransfID = 0; // ID of object transformation\n" |
774 | " bool aInMedium = false; // is the ray inside an object\n" |
ee5befae |
775 | "\n" |
6e728f3b |
776 | " float aExpPDF = 1.f;\n" |
777 | " float aImpPDF = 1.f;\n" |
ee5befae |
778 | "\n" |
779 | " for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)\n" |
780 | " {\n" |
781 | " SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n" |
782 | "\n" |
6e728f3b |
783 | " ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n" |
ee5befae |
784 | "\n" |
785 | " // check implicit path\n" |
6e728f3b |
786 | " vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n" |
ee5befae |
787 | "\n" |
788 | " if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n" |
789 | " {\n" |
6e728f3b |
790 | " float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n" |
791 | " aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n" |
792 | "\n" |
793 | " aRadiance += aThroughput * aLe * aMIS; break; // terminate path\n" |
ee5befae |
794 | " }\n" |
795 | "\n" |
6e728f3b |
796 | " vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTransfID + 0).xyz;\n" |
797 | " vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTransfID + 1).xyz;\n" |
798 | " vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTransfID + 2).xyz;\n" |
ee5befae |
799 | "\n" |
800 | " // compute geometrical normal\n" |
801 | " aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),\n" |
802 | " dot (aInvTransf1, aHit.Normal),\n" |
803 | " dot (aInvTransf2, aHit.Normal)));\n" |
804 | "\n" |
805 | " theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point\n" |
806 | "\n" |
6e728f3b |
807 | " // evaluate depth on first hit\n" |
ee5befae |
808 | " if (aDepth == 0)\n" |
809 | " {\n" |
810 | " vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n" |
811 | "\n" |
812 | " float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n" |
813 | " aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n" |
814 | " }\n" |
815 | "\n" |
05aa616d |
816 | " SBSDF aBSDF;\n" |
817 | "\n" |
818 | " // fetch BxDF weights\n" |
819 | " aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));\n" |
820 | " aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));\n" |
821 | " aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));\n" |
822 | " aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w)).rgb;\n" |
823 | "\n" |
824 | " // compute smooth normal (in parallel with fetch)\n" |
825 | " vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n" |
826 | "\n" |
827 | " aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n" |
828 | " dot (aInvTransf1, aNormal),\n" |
829 | " dot (aInvTransf2, aNormal)));\n" |
830 | "\n" |
831 | " SLocalSpace aSpace = buildLocalSpace (aNormal);\n" |
ee5befae |
832 | "\n" |
833 | "#ifdef USE_TEXTURES\n" |
05aa616d |
834 | " if (aBSDF.Kd.w >= 0.f)\n" |
ee5befae |
835 | " {\n" |
836 | " vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n" |
a1a9b249 |
837 | " vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n" |
838 | " vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n" |
ee5befae |
839 | " aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n" |
840 | " dot (aTrsfRow2, aTexCoord));\n" |
841 | "\n" |
a1a9b249 |
842 | " vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.f);\n" |
843 | " aBSDF.Kd.rgb *= aTexColor.rgb * aTexColor.w;\n" |
f411f94f |
844 | " if (aTexColor.w != 1.0f)\n" |
845 | " {\n" |
846 | " // mix transparency BTDF with texture alpha-channel\n" |
05aa616d |
847 | " aBSDF.Kt = (UNIT - aTexColor.www) + aTexColor.w * aBSDF.Kt;\n" |
f411f94f |
848 | " }\n" |
ee5befae |
849 | " }\n" |
850 | "#endif\n" |
851 | "\n" |
05aa616d |
852 | " // fetch Fresnel reflectance for both layers\n" |
853 | " aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;\n" |
854 | " aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;\n" |
ee5befae |
855 | "\n" |
05aa616d |
856 | " if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n" |
ee5befae |
857 | " {\n" |
6e728f3b |
858 | " aExpPDF = 1.f / uLightCount;\n" |
859 | "\n" |
ee5befae |
860 | " int aLightIdx = min (int (floor (RandFloat() * uLightCount)), uLightCount - 1);\n" |
861 | "\n" |
862 | " vec4 aLight = texelFetch (\n" |
863 | " uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n" |
864 | " vec4 aParam = texelFetch (\n" |
865 | " uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n" |
866 | "\n" |
867 | " // 'w' component is 0 for infinite light and 1 for point light\n" |
868 | " aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n" |
869 | "\n" |
6e728f3b |
870 | " float aDistance = length (aLight.xyz);\n" |
ee5befae |
871 | "\n" |
6e728f3b |
872 | " aLight.xyz = SampleLight (aLight.xyz, aDistance,\n" |
873 | " aLight.w == 0.f /* is infinite */, aParam.w /* max cos or radius */, aExpPDF);\n" |
ee5befae |
874 | "\n" |
05aa616d |
875 | " aImpPDF = BsdfPdfLayered (aBSDF,\n" |
6e728f3b |
876 | " toLocalSpace (-theRay.Direct, aSpace), toLocalSpace (aLight.xyz, aSpace), aThroughput);\n" |
877 | "\n" |
878 | " // MIS weight including division by explicit PDF\n" |
879 | " float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n" |
880 | "\n" |
05aa616d |
881 | " vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalBsdfLayered (\n" |
882 | " aBSDF, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));\n" |
ee5befae |
883 | "\n" |
6e728f3b |
884 | " if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important\n" |
ee5befae |
885 | " {\n" |
886 | " SRay aShadow = SRay (theRay.Origin + aLight.xyz * uSceneEpsilon, aLight.xyz);\n" |
887 | "\n" |
888 | " aShadow.Origin += aHit.Normal * mix (\n" |
889 | " -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));\n" |
890 | "\n" |
891 | " float aVisibility = SceneAnyHit (aShadow,\n" |
892 | " InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);\n" |
893 | "\n" |
05aa616d |
894 | " aRadiance += aVisibility * (aThroughput * aContrib);\n" |
ee5befae |
895 | " }\n" |
896 | " }\n" |
897 | "\n" |
05aa616d |
898 | " // account for self-emission\n" |
899 | " aRadiance += aThroughput * texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;\n" |
900 | "\n" |
6e728f3b |
901 | " if (aInMedium) // handle attenuation\n" |
ee5befae |
902 | " {\n" |
05aa616d |
903 | " vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w));\n" |
904 | "\n" |
905 | " aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb));\n" |
ee5befae |
906 | " }\n" |
907 | "\n" |
6e728f3b |
908 | " vec3 anInput = UNIT; // sampled input direction\n" |
ee5befae |
909 | "\n" |
05aa616d |
910 | " aImpPDF = SampleBsdfLayered (aBSDF,\n" |
6e728f3b |
911 | " toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aInMedium);\n" |
912 | "\n" |
05aa616d |
913 | " float aSurvive = float (any (greaterThan (aThroughput, MIN_THROUGHPUT)));\n" |
6e728f3b |
914 | "\n" |
915 | "#ifdef RUSSIAN_ROULETTE\n" |
05aa616d |
916 | " aSurvive = aDepth < 3 ? aSurvive : min (dot (LUMA, aThroughput), 0.95f);\n" |
6e728f3b |
917 | "#endif\n" |
ee5befae |
918 | "\n" |
4eaaf9d8 |
919 | " // here, we additionally increase path length for non-diffuse bounces\n" |
920 | " if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n" |
ee5befae |
921 | " {\n" |
922 | " aDepth = INVALID_BOUNCES; // terminate path\n" |
923 | " }\n" |
924 | "\n" |
6e728f3b |
925 | "#ifdef RUSSIAN_ROULETTE\n" |
ee5befae |
926 | " aThroughput /= aSurvive;\n" |
927 | "#endif\n" |
928 | "\n" |
929 | " anInput = normalize (fromLocalSpace (anInput, aSpace));\n" |
930 | "\n" |
931 | " theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +\n" |
932 | " aHit.Normal * mix (-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, anInput))), anInput);\n" |
933 | "\n" |
934 | " theInverse = InverseDirection (anInput);\n" |
935 | " }\n" |
936 | "\n" |
937 | " gl_FragDepth = aRaytraceDepth;\n" |
938 | "\n" |
939 | " return vec4 (aRadiance, aRaytraceDepth);\n" |
940 | "}\n" |
941 | "\n" |
942 | "#endif\n"; |