0030686: Visualization, SelectMgr_ViewerSelector - sorting issues of transformation...
[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.\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.\n"
47   "  vec3 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 : Latlong\n"
588   "// purpose  : Converts world direction to environment texture coordinates\n"
589   "// =======================================================================\n"
590   "vec2 Latlong (in vec3 thePoint)\n"
591   "{\n"
592   "  float aPsi = acos (-thePoint.z);\n"
593   "\n"
594   "  float aPhi = atan (thePoint.y, thePoint.x) + M_PI;\n"
595   "\n"
596   "  return vec2 (aPhi * 0.1591549f,\n"
597   "               aPsi * 0.3183098f);\n"
598   "}\n"
599   "\n"
600   "//=======================================================================\n"
601   "// function : SampleLight\n"
602   "// purpose  : General sampling function for directional and point lights\n"
603   "//=======================================================================\n"
604   "vec3 SampleLight (in vec3 theToLight, inout float theDistance, in bool isInfinite, in float theSmoothness, inout float thePDF)\n"
605   "{\n"
606   "  SLocalSpace aSpace = buildLocalSpace (theToLight * (1.f / theDistance));\n"
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"
617   "  vec3 anInput = vec3 (cos (M_2_PI * aKsi1),\n"
618   "                       sin (M_2_PI * aKsi1),\n"
619   "                       aTmp);\n"
620   "\n"
621   "  anInput.xy *= sqrt (1.f - aTmp * aTmp);\n"
622   "\n"
623   "  thePDF = (aCosMax < 1.f) ? (thePDF / M_2_PI) / (1.f - aCosMax) : MAXFLOAT;\n"
624   "\n"
625   "  return normalize (fromLocalSpace (anInput, aSpace));\n"
626   "}\n"
627   "\n"
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"
633   "{\n"
634   "  float aCosMax = inversesqrt (1.f + theRadius * theRadius / (theDistance * theDistance));\n"
635   "\n"
636   "  float aVisibility = step (aCosMax, dot (theInput, theToLight));\n"
637   "\n"
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"
654   "}\n"
655   "\n"
656   "// =======================================================================\n"
657   "// function: IntersectLight\n"
658   "// purpose : Checks intersections with light sources\n"
659   "// =======================================================================\n"
660   "vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, out float thePDF)\n"
661   "{\n"
662   "  vec3 aTotalRadiance = ZERO;\n"
663   "\n"
664   "  thePDF = 0.f; // PDF of sampling light sources\n"
665   "\n"
666   "  for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)\n"
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"
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"
678   "    if (aLight.w != 0.f) // point light source\n"
679   "    {\n"
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"
695   "    }\n"
696   "    else if (theHitDistance == MAXFLOAT) // directional light source\n"
697   "    {\n"
698   "      aTotalRadiance += aParam.rgb * HandleDistantLight (\n"
699   "        theRay.Direct, aLight.xyz, aParam.w /* angle cosine */, aPDF);\n"
700   "\n"
701   "      thePDF += aPDF;\n"
702   "    }\n"
703   "  }\n"
704   "\n"
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"
709   "      aTotalRadiance = pow (BackgroundColor().rgb, vec3 (2.f));\n"
710   "    }\n"
711   "    else\n"
712   "    {\n"
713   "      aTotalRadiance = pow (FetchEnvironment (Latlong (theRay.Direct)).rgb, vec3 (2.f));\n"
714   "    }\n"
715   "  }\n"
716   "  \n"
717   "  return aTotalRadiance;\n"
718   "}\n"
719   "\n"
720   "#define MIN_THROUGHPUT   vec3 (1.0e-3f)\n"
721   "#define MIN_CONTRIBUTION vec3 (1.0e-2f)\n"
722   "\n"
723   "#define MATERIAL_KC(index)           (19 * index + 11)\n"
724   "#define MATERIAL_KD(index)           (19 * index + 12)\n"
725   "#define MATERIAL_KS(index)           (19 * index + 13)\n"
726   "#define MATERIAL_KT(index)           (19 * index + 14)\n"
727   "#define MATERIAL_LE(index)           (19 * index + 15)\n"
728   "#define MATERIAL_FRESNEL_COAT(index) (19 * index + 16)\n"
729   "#define MATERIAL_FRESNEL_BASE(index) (19 * index + 17)\n"
730   "#define MATERIAL_ABSORPT_BASE(index) (19 * index + 18)\n"
731   "\n"
732   "//! Enables experimental Russian roulette sampling path termination.\n"
733   "//! In most cases, it provides faster image convergence with minimal\n"
734   "//! bias, so it is enabled by default.\n"
735   "#define RUSSIAN_ROULETTE\n"
736   "\n"
737   "//! Frame step to increase number of bounces. This mode is used\n"
738   "//! for interaction with the model, when path length is limited\n"
739   "//! for the first samples, and gradually increasing when camera\n"
740   "//! is stabilizing.\n"
741   "#ifdef ADAPTIVE_SAMPLING\n"
742   "  #define FRAME_STEP 4\n"
743   "#else\n"
744   "  #define FRAME_STEP 5\n"
745   "#endif\n"
746   "\n"
747   "//=======================================================================\n"
748   "// function : IsNotZero\n"
749   "// purpose  : Checks whether BSDF reflects direct light\n"
750   "//=======================================================================\n"
751   "bool IsNotZero (in SBSDF theBSDF, in vec3 theThroughput)\n"
752   "{\n"
753   "  vec3 aGlossy = theBSDF.Kc.rgb * step (FLT_EPSILON, theBSDF.Kc.w) +\n"
754   "                 theBSDF.Ks.rgb * step (FLT_EPSILON, theBSDF.Ks.w);\n"
755   "\n"
756   "  return convolve (theBSDF.Kd.rgb + aGlossy, theThroughput) > FLT_EPSILON;\n"
757   "}\n"
758   "\n"
759   "//=======================================================================\n"
760   "// function : PathTrace\n"
761   "// purpose  : Calculates radiance along the given ray\n"
762   "//=======================================================================\n"
763   "vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples)\n"
764   "{\n"
765   "  float aRaytraceDepth = MAXFLOAT;\n"
766   "\n"
767   "  vec3 aRadiance   = ZERO;\n"
768   "  vec3 aThroughput = UNIT;\n"
769   "\n"
770   "  int  aTransfID = 0;     // ID of object transformation\n"
771   "  bool aInMedium = false; // is the ray inside an object\n"
772   "\n"
773   "  float aExpPDF = 1.f;\n"
774   "  float aImpPDF = 1.f;\n"
775   "\n"
776   "  for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)\n"
777   "  {\n"
778   "    SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n"
779   "\n"
780   "    ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n"
781   "\n"
782   "    // check implicit path\n"
783   "    vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n"
784   "\n"
785   "    if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n"
786   "    {\n"
787   "      float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n"
788   "        aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
789   "\n"
790   "      aRadiance += aThroughput * aLe * aMIS; break; // terminate path\n"
791   "    }\n"
792   "\n"
793   "    vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTransfID + 0).xyz;\n"
794   "    vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTransfID + 1).xyz;\n"
795   "    vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTransfID + 2).xyz;\n"
796   "\n"
797   "    // compute geometrical normal\n"
798   "    aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),\n"
799   "                                   dot (aInvTransf1, aHit.Normal),\n"
800   "                                   dot (aInvTransf2, aHit.Normal)));\n"
801   "\n"
802   "    theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point\n"
803   "\n"
804   "    // evaluate depth on first hit\n"
805   "    if (aDepth == 0)\n"
806   "    {\n"
807   "      vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n"
808   "\n"
809   "      float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n"
810   "      aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n"
811   "    }\n"
812   "\n"
813   "    SBSDF aBSDF;\n"
814   "\n"
815   "    // fetch BxDF weights\n"
816   "    aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));\n"
817   "    aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));\n"
818   "    aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));\n"
819   "    aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w)).rgb;\n"
820   "\n"
821   "    // compute smooth normal (in parallel with fetch)\n"
822   "    vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"
823   "\n"
824   "    aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n"
825   "                               dot (aInvTransf1, aNormal),\n"
826   "                               dot (aInvTransf2, aNormal)));\n"
827   "\n"
828   "    SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
829   "\n"
830   "#ifdef USE_TEXTURES\n"
831   "    if (aBSDF.Kd.w >= 0.f)\n"
832   "    {\n"
833   "      vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n"
834   "\n"
835   "      vec4 aTrsfRow1 = texelFetch (\n"
836   "        uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n"
837   "      vec4 aTrsfRow2 = texelFetch (\n"
838   "        uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n"
839   "\n"
840   "      aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n"
841   "                           dot (aTrsfRow2, aTexCoord));\n"
842   "\n"
843   "      vec4 aTexColor = textureLod (\n"
844   "        sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.f);\n"
845   "\n"
846   "      aBSDF.Kd.rgb *= (aTexColor.rgb * aTexColor.rgb) * aTexColor.w; // de-gamma correction (for gamma = 2)\n"
847   "\n"
848   "      if (aTexColor.w != 1.0f)\n"
849   "      {\n"
850   "        // mix transparency BTDF with texture alpha-channel\n"
851   "        aBSDF.Kt = (UNIT - aTexColor.www) + aTexColor.w * aBSDF.Kt;\n"
852   "      }\n"
853   "    }\n"
854   "#endif\n"
855   "\n"
856   "    // fetch Fresnel reflectance for both layers\n"
857   "    aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;\n"
858   "    aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;\n"
859   "\n"
860   "    if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n"
861   "    {\n"
862   "      aExpPDF = 1.f / uLightCount;\n"
863   "\n"
864   "      int aLightIdx = min (int (floor (RandFloat() * uLightCount)), uLightCount - 1);\n"
865   "\n"
866   "      vec4 aLight = texelFetch (\n"
867   "        uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n"
868   "      vec4 aParam = texelFetch (\n"
869   "        uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n"
870   "\n"
871   "      // 'w' component is 0 for infinite light and 1 for point light\n"
872   "      aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n"
873   "\n"
874   "      float aDistance = length (aLight.xyz);\n"
875   "\n"
876   "      aLight.xyz = SampleLight (aLight.xyz, aDistance,\n"
877   "        aLight.w == 0.f /* is infinite */, aParam.w /* max cos or radius */, aExpPDF);\n"
878   "\n"
879   "      aImpPDF = BsdfPdfLayered (aBSDF,\n"
880   "        toLocalSpace (-theRay.Direct, aSpace), toLocalSpace (aLight.xyz, aSpace), aThroughput);\n"
881   "\n"
882   "      // MIS weight including division by explicit PDF\n"
883   "      float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
884   "\n"
885   "      vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalBsdfLayered (\n"
886   "          aBSDF, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));\n"
887   "\n"
888   "      if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important\n"
889   "      {\n"
890   "        SRay aShadow = SRay (theRay.Origin + aLight.xyz * uSceneEpsilon, aLight.xyz);\n"
891   "\n"
892   "        aShadow.Origin += aHit.Normal * mix (\n"
893   "          -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));\n"
894   "\n"
895   "        float aVisibility = SceneAnyHit (aShadow,\n"
896   "          InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);\n"
897   "\n"
898   "        aRadiance += aVisibility * (aThroughput * aContrib);\n"
899   "      }\n"
900   "    }\n"
901   "\n"
902   "    // account for self-emission\n"
903   "    aRadiance += aThroughput * texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;\n"
904   "\n"
905   "    if (aInMedium) // handle attenuation\n"
906   "    {\n"
907   "      vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w));\n"
908   "\n"
909   "      aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb));\n"
910   "    }\n"
911   "\n"
912   "    vec3 anInput = UNIT; // sampled input direction\n"
913   "\n"
914   "    aImpPDF = SampleBsdfLayered (aBSDF,\n"
915   "      toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aInMedium);\n"
916   "\n"
917   "    float aSurvive = float (any (greaterThan (aThroughput, MIN_THROUGHPUT)));\n"
918   "\n"
919   "#ifdef RUSSIAN_ROULETTE\n"
920   "    aSurvive = aDepth < 3 ? aSurvive : min (dot (LUMA, aThroughput), 0.95f);\n"
921   "#endif\n"
922   "\n"
923   "    // here, we additionally increase path length for non-diffuse bounces\n"
924   "    if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= theNbSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
925   "    {\n"
926   "      aDepth = INVALID_BOUNCES; // terminate path\n"
927   "    }\n"
928   "\n"
929   "#ifdef RUSSIAN_ROULETTE\n"
930   "    aThroughput /= aSurvive;\n"
931   "#endif\n"
932   "\n"
933   "    anInput = normalize (fromLocalSpace (anInput, aSpace));\n"
934   "\n"
935   "    theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +\n"
936   "      aHit.Normal * mix (-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, anInput))), anInput);\n"
937   "\n"
938   "    theInverse = InverseDirection (anInput);\n"
939   "  }\n"
940   "\n"
941   "  gl_FragDepth = aRaytraceDepth;\n"
942   "\n"
943   "  return vec4 (aRadiance, aRaytraceDepth);\n"
944   "}\n"
945   "\n"
946   "#endif\n";