3db4426aebac9df97e3b5828ae12c9d8adad89a7
[occt.git] / src / Shaders / Shaders_PathtraceBase_fs.pxx
1 // This file has been automatically generated from resource file src/Shaders/PathtraceBase.fs
2
3 static const char Shaders_PathtraceBase_fs[] =
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"
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"
35   "struct SBSDF\n"
36   "{\n"
37   "  //! Weight of coat specular/glossy BRDF.\n"
38   "  vec4 Kc;\n"
39   "\n"
40   "  //! Weight of base diffuse BRDF + base color texture index in W.\n"
41   "  vec4 Kd;\n"
42   "\n"
43   "  //! Weight of base specular/glossy BRDF.\n"
44   "  vec4 Ks;\n"
45   "\n"
46   "  //! Weight of base specular/glossy BTDF + metallic-roughness texture index in W.\n"
47   "  vec4 Kt;\n"
48   "\n"
49   "  //! Fresnel coefficients of coat layer.\n"
50   "  vec3 FresnelCoat;\n"
51   "\n"
52   "  //! Fresnel coefficients of base layer.\n"
53   "  vec3 FresnelBase;\n"
54   "};\n"
55   "\n"
56   "///////////////////////////////////////////////////////////////////////////////////////\n"
57   "// Support subroutines\n"
58   "\n"
59   "//=======================================================================\n"
60   "// function : buildLocalSpace\n"
61   "// purpose  : Generates local space for the given normal\n"
62   "//=======================================================================\n"
63   "SLocalSpace buildLocalSpace (in vec3 theNormal)\n"
64   "{\n"
65   "  vec3 anAxisX = vec3 (theNormal.z, 0.f, -theNormal.x);\n"
66   "  vec3 anAxisY = vec3 (0.f, -theNormal.z, theNormal.y);\n"
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"
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"
154   "  float aFresnel = 1.f;\n"
155   "\n"
156   "  float anEtaI = theCosI > 0.f ? 1.f : theIndex;\n"
157   "  float anEtaT = theCosI > 0.f ? theIndex : 1.f;\n"
158   "\n"
159   "  float aSinT2 = (anEtaI * anEtaI) / (anEtaT * anEtaT) * (1.f - theCosI * theCosI);\n"
160   "\n"
161   "  if (aSinT2 < 1.f)\n"
162   "  {\n"
163   "    aFresnel = fresnelDielectric (abs (theCosI), sqrt (1.f - aSinT2), anEtaI, anEtaT);\n"
164   "  }\n"
165   "\n"
166   "  return aFresnel;\n"
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"
201   "vec3 fresnelMedia (in float theCosI, in vec3 theFresnel)\n"
202   "{\n"
203   "  vec3 aFresnel;\n"
204   "\n"
205   "  if (theFresnel.x > FRESNEL_SCHLICK)\n"
206   "  {\n"
207   "    aFresnel = fresnelSchlick (abs (theCosI), theFresnel);\n"
208   "  }\n"
209   "  else if (theFresnel.x > FRESNEL_CONSTANT)\n"
210   "  {\n"
211   "    aFresnel = vec3 (theFresnel.z);\n"
212   "  }\n"
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"
218   "  {\n"
219   "    aFresnel = vec3 (fresnelDielectric (theCosI, theFresnel.y));\n"
220   "  }\n"
221   "\n"
222   "  return aFresnel;\n"
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"
235   "  // Handle total internal reflection (TIR)\n"
236   "  float aSinT2 = anEta * anEta * (1.f - theIncident.z * theIncident.z);\n"
237   "\n"
238   "  // Compute direction of transmitted ray\n"
239   "  float aCosT = sqrt (1.f - min (aSinT2, 1.f)) * sign (-theIncident.z);\n"
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"
251   "// function : EvalLambertianReflection\n"
252   "// purpose  : Evaluates Lambertian BRDF, with cos(N, PSI)\n"
253   "//=======================================================================\n"
254   "float EvalLambertianReflection (in vec3 theWi, in vec3 theWo)\n"
255   "{\n"
256   "  return (theWi.z <= 0.f || theWo.z <= 0.f) ? 0.f : theWi.z * (1.f / M_PI);\n"
257   "}\n"
258   "\n"
259   "#define FLT_EPSILON 1.0e-5f\n"
260   "\n"
261   "//=======================================================================\n"
262   "// function : SmithG1\n"
263   "// purpose  :\n"
264   "//=======================================================================\n"
265   "float SmithG1 (in vec3 theDirection, in vec3 theM, in float theRoughness)\n"
266   "{\n"
267   "  float aResult = 0.f;\n"
268   "\n"
269   "  if (dot (theDirection, theM) * theDirection.z > 0.f)\n"
270   "  {\n"
271   "    float aTanThetaM = sqrt (1.f - theDirection.z * theDirection.z) / theDirection.z;\n"
272   "\n"
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"
280   "\n"
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"
284   "  }\n"
285   "\n"
286   "  return min (aResult, 1.f);\n"
287   "}\n"
288   "\n"
289   "//=======================================================================\n"
290   "// function : EvalBlinnReflection\n"
291   "// purpose  : Evaluates Blinn glossy BRDF, with cos(N, PSI)\n"
292   "//=======================================================================\n"
293   "vec3 EvalBlinnReflection (in vec3 theWi, in vec3 theWo, in vec3 theFresnel, in float theRoughness)\n"
294   "{\n"
295   "  // calculate the reflection half-vec\n"
296   "  vec3 aH = normalize (theWi + theWo);\n"
297   "\n"
298   "  // roughness value -> Blinn exponent\n"
299   "  float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n"
300   "\n"
301   "  // calculate microfacet distribution\n"
302   "  float aD = (aPower + 2.f) * (1.f / M_2_PI) * pow (aH.z, aPower);\n"
303   "\n"
304   "  // calculate shadow-masking function\n"
305   "  float aG = SmithG1 (theWo, aH, theRoughness) *\n"
306   "             SmithG1 (theWi, aH, theRoughness);\n"
307   "\n"
308   "  // return total amount of reflection\n"
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"
311   "}\n"
312   "\n"
313   "//=======================================================================\n"
314   "// function : EvalBsdfLayered\n"
315   "// purpose  : Evaluates BSDF for specified material, with cos(N, PSI)\n"
316   "//=======================================================================\n"
317   "vec3 EvalBsdfLayered (in SBSDF theBSDF, in vec3 theWi, in vec3 theWo)\n"
318   "{\n"
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"
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"
339   "}\n"
340   "\n"
341   "//=======================================================================\n"
342   "// function : SampleLambertianReflection\n"
343   "// purpose  : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
344   "//=======================================================================\n"
345   "vec3 SampleLambertianReflection (in vec3 theWo, out vec3 theWi, inout float thePDF)\n"
346   "{\n"
347   "  float aKsi1 = RandFloat();\n"
348   "  float aKsi2 = RandFloat();\n"
349   "\n"
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"
355   "\n"
356   "#ifdef TWO_SIDED_BXDF\n"
357   "  theWi.z *= sign (theWo.z);\n"
358   "#endif\n"
359   "\n"
360   "  thePDF *= theWi.z * (1.f / M_PI);\n"
361   "\n"
362   "#ifdef TWO_SIDED_BXDF\n"
363   "  return UNIT;\n"
364   "#else\n"
365   "  return UNIT * step (0.f, theWo.z);\n"
366   "#endif\n"
367   "}\n"
368   "\n"
369   "//=======================================================================\n"
370   "// function : SampleGlossyBlinnReflection\n"
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"
378   "//=======================================================================\n"
379   "vec3 SampleGlossyBlinnReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel, in float theRoughness, inout float thePDF)\n"
380   "{\n"
381   "  float aKsi1 = RandFloat();\n"
382   "  float aKsi2 = RandFloat();\n"
383   "\n"
384   "  // roughness value --> Blinn exponent\n"
385   "  float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n"
386   "\n"
387   "  // normal from microface distribution\n"
388   "  float aCosThetaM = pow (aKsi1, 1.f / (aPower + 2.f));\n"
389   "\n"
390   "  vec3 aM = vec3 (cos (M_2_PI * aKsi2),\n"
391   "                  sin (M_2_PI * aKsi2),\n"
392   "                  aCosThetaM);\n"
393   "\n"
394   "  aM.xy *= sqrt (1.f - aCosThetaM * aCosThetaM);\n"
395   "\n"
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"
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"
407   "\n"
408   "  // pick input based on half direction\n"
409   "  theWi = -theWo + 2.f * aCosDelta * aM;\n"
410   "\n"
411   "  if (theWi.z <= 0.f || theWo.z <= 0.f)\n"
412   "  {\n"
413   "    return ZERO;\n"
414   "  }\n"
415   "\n"
416   "  // Jacobian of half-direction mapping\n"
417   "  thePDF /= 4.f * aCosDelta;\n"
418   "\n"
419   "  // compute shadow-masking coefficient\n"
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"
427   "\n"
428   "  return (aG * aCosDelta) / (theWo.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n"
429   "}\n"
430   "\n"
431   "//=======================================================================\n"
432   "// function : BsdfPdfLayered\n"
433   "// purpose  : Calculates BSDF of sampling input knowing output\n"
434   "//=======================================================================\n"
435   "float BsdfPdfLayered (in SBSDF theBSDF, in vec3 theWo, in vec3 theWi, in vec3 theWeight)\n"
436   "{\n"
437   "  float aPDF = 0.f; // PDF of sampling input direction\n"
438   "\n"
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"
442   "\n"
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"
447   "\n"
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"
452   "\n"
453   "  if (theWi.z * theWo.z > 0.f)\n"
454   "  {\n"
455   "    vec3 aH = normalize (theWi + theWo);\n"
456   "\n"
457   "    aPDF = aPd * abs (theWi.z / M_PI);\n"
458   "\n"
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"
462   "\n"
463   "      aPDF += aPc * (aPower + 2.f) * (0.25f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / dot (theWi, aH);\n"
464   "    }\n"
465   "\n"
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"
469   "\n"
470   "      aPDF += aPs * (aPower + 2.f) * (0.25f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / dot (theWi, aH);\n"
471   "    }\n"
472   "  }\n"
473   "\n"
474   "  return aPDF / (aPc + aPd + aPs + aPt);\n"
475   "}\n"
476   "\n"
477   "//! Tool macro to handle sampling of particular BxDF\n"
478   "#define PICK_BXDF_LAYER(p, k) aPDF = p / aTotalR; theWeight *= k / aPDF;\n"
479   "\n"
480   "//=======================================================================\n"
481   "// function : SampleBsdfLayered\n"
482   "// purpose  : Samples specified composite material (BSDF)\n"
483   "//=======================================================================\n"
484   "float SampleBsdfLayered (in SBSDF theBSDF, in vec3 theWo, out vec3 theWi, inout vec3 theWeight, inout bool theInside)\n"
485   "{\n"
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"
520   "\n"
521   "    if (theBSDF.Kc.w < FLT_EPSILON)\n"
522   "    {\n"
523   "      theWeight *= aCoatF;\n"
524   "\n"
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"
533   "\n"
534   "    aPDF = mix (aPDF, MAXFLOAT, theBSDF.Kc.w < FLT_EPSILON);\n"
535   "  }\n"
536   "  else if (aKsi < aTotalR) // REFLECTION FROM BASE\n"
537   "  {\n"
538   "    theWeight *= aCoatT;\n"
539   "\n"
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"
549   "\n"
550   "      if (theBSDF.Ks.w < FLT_EPSILON)\n"
551   "      {\n"
552   "        theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase);\n"
553   "\n"
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"
562   "\n"
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"
568   "\n"
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"
574   "  }\n"
575   "\n"
576   "  // path termination for extra small weights\n"
577   "  theWeight = mix (ZERO, theWeight, step (FLT_EPSILON, aTotalR));\n"
578   "\n"
579   "  return aPDF;\n"
580   "}\n"
581   "\n"
582   "//////////////////////////////////////////////////////////////////////////////////////////////\n"
583   "// Handlers and samplers for light sources\n"
584   "//////////////////////////////////////////////////////////////////////////////////////////////\n"
585   "\n"
586   "//=======================================================================\n"
587   "// function : SampleLight\n"
588   "// purpose  : General sampling function for directional and point lights\n"
589   "//=======================================================================\n"
590   "vec3 SampleLight (in vec3 theToLight, inout float theDistance, in bool isInfinite, in float theSmoothness, inout float thePDF)\n"
591   "{\n"
592   "  SLocalSpace aSpace = buildLocalSpace (theToLight * (1.f / theDistance));\n"
593   "\n"
594   "  // for point lights smoothness defines radius\n"
595   "  float aCosMax = isInfinite ? theSmoothness :\n"
596   "    inversesqrt (1.f + theSmoothness * theSmoothness / (theDistance * theDistance));\n"
597   "\n"
598   "  float aKsi1 = RandFloat();\n"
599   "  float aKsi2 = RandFloat();\n"
600   "\n"
601   "  float aTmp = 1.f - aKsi2 * (1.f - aCosMax);\n"
602   "\n"
603   "  vec3 anInput = vec3 (cos (M_2_PI * aKsi1),\n"
604   "                       sin (M_2_PI * aKsi1),\n"
605   "                       aTmp);\n"
606   "\n"
607   "  anInput.xy *= sqrt (1.f - aTmp * aTmp);\n"
608   "\n"
609   "  thePDF = (aCosMax < 1.f) ? (thePDF / M_2_PI) / (1.f - aCosMax) : MAXFLOAT;\n"
610   "\n"
611   "  return normalize (fromLocalSpace (anInput, aSpace));\n"
612   "}\n"
613   "\n"
614   "//=======================================================================\n"
615   "// function : HandlePointLight\n"
616   "// purpose  :\n"
617   "//=======================================================================\n"
618   "float HandlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance, inout float thePDF)\n"
619   "{\n"
620   "  float aCosMax = inversesqrt (1.f + theRadius * theRadius / (theDistance * theDistance));\n"
621   "\n"
622   "  float aVisibility = step (aCosMax, dot (theInput, theToLight));\n"
623   "\n"
624   "  thePDF *= step (-1.f, -aCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - aCosMax);\n"
625   "\n"
626   "  return aVisibility;\n"
627   "}\n"
628   "\n"
629   "//=======================================================================\n"
630   "// function : HandleDistantLight\n"
631   "// purpose  :\n"
632   "//=======================================================================\n"
633   "float HandleDistantLight (in vec3 theInput, in vec3 theToLight, in float theCosMax, inout float thePDF)\n"
634   "{\n"
635   "  float aVisibility = step (theCosMax, dot (theInput, theToLight));\n"
636   "\n"
637   "  thePDF *= step (-1.f, -theCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - theCosMax);\n"
638   "\n"
639   "  return aVisibility;\n"
640   "}\n"
641   "\n"
642   "// =======================================================================\n"
643   "// function: IntersectLight\n"
644   "// purpose : Checks intersections with light sources\n"
645   "// =======================================================================\n"
646   "vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, out float thePDF)\n"
647   "{\n"
648   "  vec3 aTotalRadiance = ZERO;\n"
649   "\n"
650   "  thePDF = 0.f; // PDF of sampling light sources\n"
651   "\n"
652   "  for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)\n"
653   "  {\n"
654   "    vec4 aLight = texelFetch (\n"
655   "      uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n"
656   "    vec4 aParam = texelFetch (\n"
657   "      uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n"
658   "\n"
659   "    // W component: 0 for infinite light and 1 for point light\n"
660   "    aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n"
661   "\n"
662   "    float aPDF = 1.f / uLightCount;\n"
663   "\n"
664   "    if (aLight.w != 0.f) // point light source\n"
665   "    {\n"
666   "      float aCenterDst = length (aLight.xyz);\n"
667   "\n"
668   "      if (aCenterDst < theHitDistance)\n"
669   "      {\n"
670   "        float aVisibility = HandlePointLight (\n"
671   "          theRay.Direct, normalize (aLight.xyz), aParam.w /* radius */, aCenterDst, aPDF);\n"
672   "\n"
673   "        if (aVisibility > 0.f)\n"
674   "        {\n"
675   "          theHitDistance = aCenterDst;\n"
676   "          aTotalRadiance = aParam.rgb;\n"
677   "\n"
678   "          thePDF = aPDF;\n"
679   "        }\n"
680   "      }\n"
681   "    }\n"
682   "    else if (theHitDistance == MAXFLOAT) // directional light source\n"
683   "    {\n"
684   "      aTotalRadiance += aParam.rgb * HandleDistantLight (\n"
685   "        theRay.Direct, aLight.xyz, aParam.w /* angle cosine */, aPDF);\n"
686   "\n"
687   "      thePDF += aPDF;\n"
688   "    }\n"
689   "  }\n"
690   "\n"
691   "  if (thePDF == 0.f && theHitDistance == MAXFLOAT) // light source not found\n"
692   "  {\n"
693   "    if (theDepth + uEnvMapForBack == 0) // view ray and map is hidden\n"
694   "    {\n"
695   "      aTotalRadiance = BackgroundColor().rgb;\n"
696   "    }\n"
697   "    else\n"
698   "    {\n"
699   "    #ifdef BACKGROUND_CUBEMAP\n"
700   "      if (theDepth == 0)\n"
701   "      {\n"
702   "        vec2 aPixel = uEyeSize * (vPixel - vec2 (0.5)) * 2.0;\n"
703   "        vec2 anAperturePnt = sampleUniformDisk() * uApertureRadius;\n"
704   "        vec3 aLocalDir = normalize (vec3 (aPixel * uFocalPlaneDist - anAperturePnt, uFocalPlaneDist));\n"
705   "        vec3 aDirect = uEyeView * aLocalDir.z +\n"
706   "                       uEyeSide * aLocalDir.x +\n"
707   "                       uEyeVert * aLocalDir.y;\n"
708   "        aTotalRadiance = FetchEnvironment (aDirect, 1.0, true).rgb;\n"
709   "      }\n"
710   "      else\n"
711   "      {\n"
712   "        aTotalRadiance = FetchEnvironment (theRay.Direct, 1.0, false).rgb;\n"
713   "      }\n"
714   "    #else\n"
715   "      aTotalRadiance = FetchEnvironment (theRay.Direct, 1.0, theDepth == 0).rgb;\n"
716   "    #endif\n"
717   "    }\n"
718   "  #ifdef THE_SHIFT_sRGB\n"
719   "    aTotalRadiance = pow (aTotalRadiance, vec3 (2.f));\n"
720   "  #endif\n"
721   "  }\n"
722   "  \n"
723   "  return aTotalRadiance;\n"
724   "}\n"
725   "\n"
726   "#define MIN_THROUGHPUT   vec3 (1.0e-3f)\n"
727   "#define MIN_CONTRIBUTION vec3 (1.0e-2f)\n"
728   "\n"
729   "#define MATERIAL_KC(index)           (19 * index + 11)\n"
730   "#define MATERIAL_KD(index)           (19 * index + 12)\n"
731   "#define MATERIAL_KS(index)           (19 * index + 13)\n"
732   "#define MATERIAL_KT(index)           (19 * index + 14)\n"
733   "#define MATERIAL_LE(index)           (19 * index + 15)\n"
734   "#define MATERIAL_FRESNEL_COAT(index) (19 * index + 16)\n"
735   "#define MATERIAL_FRESNEL_BASE(index) (19 * index + 17)\n"
736   "#define MATERIAL_ABSORPT_BASE(index) (19 * index + 18)\n"
737   "\n"
738   "//! Enables experimental Russian roulette sampling path termination.\n"
739   "//! In most cases, it provides faster image convergence with minimal\n"
740   "//! bias, so it is enabled by default.\n"
741   "#define RUSSIAN_ROULETTE\n"
742   "\n"
743   "//! Frame step to increase number of bounces. This mode is used\n"
744   "//! for interaction with the model, when path length is limited\n"
745   "//! for the first samples, and gradually increasing when camera\n"
746   "//! is stabilizing.\n"
747   "#ifdef ADAPTIVE_SAMPLING\n"
748   "  #define FRAME_STEP 4\n"
749   "#else\n"
750   "  #define FRAME_STEP 5\n"
751   "#endif\n"
752   "\n"
753   "//=======================================================================\n"
754   "// function : IsNotZero\n"
755   "// purpose  : Checks whether BSDF reflects direct light\n"
756   "//=======================================================================\n"
757   "bool IsNotZero (in SBSDF theBSDF, in vec3 theThroughput)\n"
758   "{\n"
759   "  vec3 aGlossy = theBSDF.Kc.rgb * step (FLT_EPSILON, theBSDF.Kc.w) +\n"
760   "                 theBSDF.Ks.rgb * step (FLT_EPSILON, theBSDF.Ks.w);\n"
761   "\n"
762   "  return convolve (theBSDF.Kd.rgb + aGlossy, theThroughput) > FLT_EPSILON;\n"
763   "}\n"
764   "\n"
765   "//=======================================================================\n"
766   "// function : PathTrace\n"
767   "// purpose  : Calculates radiance along the given ray\n"
768   "//=======================================================================\n"
769   "vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)\n"
770   "{\n"
771   "  float aRaytraceDepth = MAXFLOAT;\n"
772   "\n"
773   "  vec3 aRadiance   = ZERO;\n"
774   "  vec3 aThroughput = UNIT;\n"
775   "\n"
776   "  int  aTransfID = 0;     // ID of object transformation\n"
777   "  bool aInMedium = false; // is the ray inside an object\n"
778   "\n"
779   "  float aExpPDF = 1.f;\n"
780   "  float aImpPDF = 1.f;\n"
781   "\n"
782   "  for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)\n"
783   "  {\n"
784   "    SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n"
785   "\n"
786   "    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n"
787   "\n"
788   "    // check implicit path\n"
789   "    vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n"
790   "\n"
791   "    if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n"
792   "    {\n"
793   "      float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n"
794   "        aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
795   "\n"
796   "      aRadiance += aThroughput * aLe * aMIS; break; // terminate path\n"
797   "    }\n"
798   "\n"
799   "    vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTransfID + 0).xyz;\n"
800   "    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTransfID + 1).xyz;\n"
801   "    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTransfID + 2).xyz;\n"
802   "\n"
803   "    // compute geometrical normal\n"
804   "    aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),\n"
805   "                                   dot (aInvTransf1, aHit.Normal),\n"
806   "                                   dot (aInvTransf2, aHit.Normal)));\n"
807   "\n"
808   "    theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point\n"
809   "\n"
810   "    // evaluate depth on first hit\n"
811   "    if (aDepth == 0)\n"
812   "    {\n"
813   "      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n"
814   "\n"
815   "      float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n"
816   "      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n"
817   "    }\n"
818   "\n"
819   "    SBSDF aBSDF;\n"
820   "\n"
821   "    // fetch BxDF weights\n"
822   "    aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));\n"
823   "    aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));\n"
824   "    aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));\n"
825   "    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w));\n"
826   "\n"
827   "    // fetch Fresnel reflectance for both layers\n"
828   "    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;\n"
829   "    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;\n"
830   "\n"
831   "    vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w));\n"
832   "\n"
833   "    // compute smooth normal (in parallel with fetch)\n"
834   "    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"
835   "    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n"
836   "                               dot (aInvTransf1, aNormal),\n"
837   "                               dot (aInvTransf2, aNormal)));\n"
838   "\n"
839   "    SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
840   "\n"
841   "#ifdef USE_TEXTURES\n"
842   "    if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || anLE.w >= 0.0)\n"
843   "    {\n"
844   "      vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n"
845   "      vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n"
846   "      vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n"
847   "      aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n"
848   "                           dot (aTrsfRow2, aTexCoord));\n"
849   "\n"
850   "      if (anLE.w >= 0.0)\n"
851   "      {\n"
852   "        anLE.rgb *= textureLod (sampler2D (uTextureSamplers[int (anLE.w)]), aTexCoord.st, 0.0).rgb;\n"
853   "      }\n"
854   "      if (aBSDF.Kt.w >= 0.0)\n"
855   "      {\n"
856   "        vec2 aTexMetRough = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kt.w)]), aTexCoord.st, 0.0).bg;\n"
857   "        float aPbrMetal = aTexMetRough.x;\n"
858   "        float aPbrRough2 = aTexMetRough.y * aTexMetRough.y;\n"
859   "        aBSDF.Ks.a *= aPbrRough2;\n"
860   "        // when using metal-roughness texture, global metalness of material (encoded in FresnelBase) is expected to be 1.0 so that Kd will be 0.0\n"
861   "        aBSDF.Kd.rgb = aBSDF.FresnelBase * (1.0 - aPbrMetal);\n"
862   "        aBSDF.FresnelBase *= aPbrMetal;\n"
863   "      }\n"
864   "      if (aBSDF.Kd.w >= 0.0)\n"
865   "      {\n"
866   "        vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.0);\n"
867   "        vec3 aDiff = aTexColor.rgb * aTexColor.a;\n"
868   "        aBSDF.Kd.rgb *= aDiff;\n"
869   "        aBSDF.FresnelBase *= aDiff;\n"
870   "        if (aTexColor.a != 1.0)\n"
871   "        {\n"
872   "          // mix transparency BTDF with texture alpha-channel\n"
873   "          aBSDF.Ks.rgb *= aTexColor.a;\n"
874   "          aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb;\n"
875   "        }\n"
876   "      }\n"
877   "    }\n"
878   "#endif\n"
879   "\n"
880   "    if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n"
881   "    {\n"
882   "      aExpPDF = 1.f / uLightCount;\n"
883   "\n"
884   "      int aLightIdx = min (int (floor (RandFloat() * uLightCount)), uLightCount - 1);\n"
885   "\n"
886   "      vec4 aLight = texelFetch (\n"
887   "        uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n"
888   "      vec4 aParam = texelFetch (\n"
889   "        uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n"
890   "\n"
891   "      // 'w' component is 0 for infinite light and 1 for point light\n"
892   "      aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n"
893   "\n"
894   "      float aDistance = length (aLight.xyz);\n"
895   "\n"
896   "      aLight.xyz = SampleLight (aLight.xyz, aDistance,\n"
897   "        aLight.w == 0.f /* is infinite */, aParam.w /* max cos or radius */, aExpPDF);\n"
898   "\n"
899   "      aImpPDF = BsdfPdfLayered (aBSDF,\n"
900   "        toLocalSpace (-theRay.Direct, aSpace), toLocalSpace (aLight.xyz, aSpace), aThroughput);\n"
901   "\n"
902   "      // MIS weight including division by explicit PDF\n"
903   "      float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
904   "\n"
905   "      vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalBsdfLayered (\n"
906   "          aBSDF, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));\n"
907   "\n"
908   "      if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important\n"
909   "      {\n"
910   "        SRay aShadow = SRay (theRay.Origin + aLight.xyz * uSceneEpsilon, aLight.xyz);\n"
911   "\n"
912   "        aShadow.Origin += aHit.Normal * mix (\n"
913   "          -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));\n"
914   "\n"
915   "        float aVisibility = SceneAnyHit (aShadow,\n"
916   "          InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);\n"
917   "\n"
918   "        aRadiance += aVisibility * (aThroughput * aContrib);\n"
919   "      }\n"
920   "    }\n"
921   "\n"
922   "    // account for self-emission\n"
923   "    aRadiance += aThroughput * anLE.rgb;\n"
924   "\n"
925   "    if (aInMedium) // handle attenuation\n"
926   "    {\n"
927   "      vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w));\n"
928   "\n"
929   "      aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb));\n"
930   "    }\n"
931   "\n"
932   "    vec3 anInput = UNIT; // sampled input direction\n"
933   "\n"
934   "    aImpPDF = SampleBsdfLayered (aBSDF,\n"
935   "      toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aInMedium);\n"
936   "\n"
937   "    float aSurvive = float (any (greaterThan (aThroughput, MIN_THROUGHPUT)));\n"
938   "\n"
939   "#ifdef RUSSIAN_ROULETTE\n"
940   "    aSurvive = aDepth < 3 ? aSurvive : min (dot (LUMA, aThroughput), 0.95f);\n"
941   "#endif\n"
942   "\n"
943   "    // here, we additionally increase path length for non-diffuse bounces\n"
944   "    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
945   "    {\n"
946   "      aDepth = INVALID_BOUNCES; // terminate path\n"
947   "    }\n"
948   "\n"
949   "#ifdef RUSSIAN_ROULETTE\n"
950   "    aThroughput /= aSurvive;\n"
951   "#endif\n"
952   "\n"
953   "    anInput = normalize (fromLocalSpace (anInput, aSpace));\n"
954   "\n"
955   "    theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +\n"
956   "      aHit.Normal * mix (-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, anInput))), anInput);\n"
957   "\n"
958   "    theInverse = InverseDirection (anInput);\n"
959   "  }\n"
960   "\n"
961   "  gl_FragDepth = aRaytraceDepth;\n"
962   "\n"
963   "  return vec4 (aRadiance, aRaytraceDepth);\n"
964   "}\n"
965   "\n"
966   "#endif\n";