1 // This file has been automatically generated from resource file src/Shaders/PathtraceBase.fs
3 static const char Shaders_PathtraceBase_fs[] =
5 " #define PATH_TRACING // just for editing in MS VS\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"
16 "#ifdef PATH_TRACING\n"
18 "//! Number of previously rendered frames.\n"
19 "uniform int uAccumSamples;\n"
21 "///////////////////////////////////////////////////////////////////////////////////////\n"
22 "// Specific data types\n"
24 "//! Describes local space at the hit point (visualization space).\n"
25 "struct SLocalSpace\n"
27 " //! Local X axis.\n"
30 " //! Local Y axis.\n"
33 " //! Local Z axis.\n"
37 "//! Describes material properties (BSDF).\n"
40 " //! Weight of the Lambertian BRDF.\n"
43 " //! Weight of the reflection BRDF.\n"
46 " //! Weight of the transmission BTDF.\n"
49 " //! Weight of the Blinn BRDF (and roughness).\n"
52 " //! Fresnel coefficients.\n"
55 " //! Absorption color and intensity of the media.\n"
59 "///////////////////////////////////////////////////////////////////////////////////////\n"
60 "// Support subroutines\n"
62 "//=======================================================================\n"
63 "// function : buildLocalSpace\n"
64 "// purpose : Generates local space for the given normal\n"
65 "//=======================================================================\n"
66 "SLocalSpace buildLocalSpace (in vec3 theNormal)\n"
68 " vec3 anAxisX = vec3 (theNormal.z, 0.f, -theNormal.x);\n"
69 " vec3 anAxisY = vec3 (0.f, -theNormal.z, theNormal.y);\n"
71 " float aSqrLenX = dot (anAxisX, anAxisX);\n"
72 " float aSqrLenY = dot (anAxisY, anAxisY);\n"
74 " if (aSqrLenX > aSqrLenY)\n"
76 " anAxisX *= inversesqrt (aSqrLenX);\n"
77 " anAxisY = cross (anAxisX, theNormal);\n"
81 " anAxisY *= inversesqrt (aSqrLenY);\n"
82 " anAxisX = cross (anAxisY, theNormal);\n"
85 " return SLocalSpace (anAxisX, anAxisY, theNormal);\n"
88 "//=======================================================================\n"
89 "// function : toLocalSpace\n"
90 "// purpose : Transforms the vector to local space from world space\n"
91 "//=======================================================================\n"
92 "vec3 toLocalSpace (in vec3 theVector, in SLocalSpace theSpace)\n"
94 " return vec3 (dot (theVector, theSpace.AxisX),\n"
95 " dot (theVector, theSpace.AxisY),\n"
96 " dot (theVector, theSpace.AxisZ));\n"
99 "//=======================================================================\n"
100 "// function : fromLocalSpace\n"
101 "// purpose : Transforms the vector from local space to world space\n"
102 "//=======================================================================\n"
103 "vec3 fromLocalSpace (in vec3 theVector, in SLocalSpace theSpace)\n"
105 " return theVector.x * theSpace.AxisX +\n"
106 " theVector.y * theSpace.AxisY +\n"
107 " theVector.z * theSpace.AxisZ;\n"
110 "//=======================================================================\n"
111 "// function : convolve\n"
112 "// purpose : Performs a linear convolution of the vector components\n"
113 "//=======================================================================\n"
114 "float convolve (in vec3 theVector, in vec3 theFactor)\n"
116 " return dot (theVector, theFactor) * (1.f / max (theFactor.x + theFactor.y + theFactor.z, 1e-15f));\n"
119 "//=======================================================================\n"
120 "// function : fresnelSchlick\n"
121 "// purpose : Computes the Fresnel reflection formula using\n"
122 "// Schlick's approximation.\n"
123 "//=======================================================================\n"
124 "vec3 fresnelSchlick (in float theCosI, in vec3 theSpecularColor)\n"
126 " return theSpecularColor + (UNIT - theSpecularColor) * pow (1.f - theCosI, 5.f);\n"
129 "//=======================================================================\n"
130 "// function : fresnelDielectric\n"
131 "// purpose : Computes the Fresnel reflection formula for dielectric in\n"
132 "// case of circularly polarized light (Based on PBRT code).\n"
133 "//=======================================================================\n"
134 "float fresnelDielectric (in float theCosI,\n"
135 " in float theCosT,\n"
136 " in float theEtaI,\n"
137 " in float theEtaT)\n"
139 " float aParl = (theEtaT * theCosI - theEtaI * theCosT) /\n"
140 " (theEtaT * theCosI + theEtaI * theCosT);\n"
142 " float aPerp = (theEtaI * theCosI - theEtaT * theCosT) /\n"
143 " (theEtaI * theCosI + theEtaT * theCosT);\n"
145 " return (aParl * aParl + aPerp * aPerp) * 0.5f;\n"
148 "#define ENVIRONMENT_IOR 1.f\n"
150 "//=======================================================================\n"
151 "// function : fresnelDielectric\n"
152 "// purpose : Computes the Fresnel reflection formula for dielectric in\n"
153 "// case of circularly polarized light (based on PBRT code)\n"
154 "//=======================================================================\n"
155 "float fresnelDielectric (in float theCosI, in float theIndex)\n"
157 " float anEtaI = theCosI > 0.f ? 1.f : theIndex;\n"
158 " float anEtaT = theCosI > 0.f ? theIndex : 1.f;\n"
160 " float aSinT = (anEtaI / anEtaT) * sqrt (1.f - theCosI * theCosI);\n"
162 " if (aSinT >= 1.f)\n"
167 " float aCosT = sqrt (1.f - aSinT * aSinT);\n"
169 " return fresnelDielectric (abs (theCosI), aCosT, anEtaI, anEtaT);\n"
172 "//=======================================================================\n"
173 "// function : fresnelConductor\n"
174 "// purpose : Computes the Fresnel reflection formula for conductor in case\n"
175 "// of circularly polarized light (based on PBRT source code)\n"
176 "//=======================================================================\n"
177 "float fresnelConductor (in float theCosI, in float theEta, in float theK)\n"
179 " float aTmp = 2.f * theEta * theCosI;\n"
181 " float aTmp1 = theEta * theEta + theK * theK;\n"
183 " float aSPerp = (aTmp1 - aTmp + theCosI * theCosI) /\n"
184 " (aTmp1 + aTmp + theCosI * theCosI);\n"
186 " float aTmp2 = aTmp1 * theCosI * theCosI;\n"
188 " float aSParl = (aTmp2 - aTmp + 1.f) /\n"
189 " (aTmp2 + aTmp + 1.f);\n"
191 " return (aSPerp + aSParl) * 0.5f;\n"
194 "#define FRESNEL_SCHLICK -0.5f\n"
195 "#define FRESNEL_CONSTANT -1.5f\n"
196 "#define FRESNEL_CONDUCTOR -2.5f\n"
197 "#define FRESNEL_DIELECTRIC -3.5f\n"
199 "//=======================================================================\n"
200 "// function : fresnelMedia\n"
201 "// purpose : Computes the Fresnel reflection formula for general medium\n"
202 "// in case of circularly polarized light.\n"
203 "//=======================================================================\n"
204 "vec3 fresnelMedia (in float theCosI, in vec3 theFresnel)\n"
206 " if (theFresnel.x > FRESNEL_SCHLICK)\n"
208 " return fresnelSchlick (abs (theCosI), theFresnel);\n"
211 " if (theFresnel.x > FRESNEL_CONSTANT)\n"
213 " return vec3 (theFresnel.z);\n"
216 " if (theFresnel.x > FRESNEL_CONDUCTOR)\n"
218 " return vec3 (fresnelConductor (abs (theCosI), theFresnel.y, theFresnel.z));\n"
221 " return vec3 (fresnelDielectric (theCosI, theFresnel.y));\n"
224 "//=======================================================================\n"
225 "// function : transmitted\n"
226 "// purpose : Computes transmitted direction in tangent space\n"
227 "// (in case of TIR returned result is undefined!)\n"
228 "//=======================================================================\n"
229 "void transmitted (in float theIndex, in vec3 theIncident, out vec3 theTransmit)\n"
231 " // Compute relative index of refraction\n"
232 " float anEta = (theIncident.z > 0.f) ? 1.f / theIndex : theIndex;\n"
234 " // Handle total internal reflection (TIR)\n"
235 " float aSinT2 = anEta * anEta * (1.f - theIncident.z * theIncident.z);\n"
237 " // Compute direction of transmitted ray\n"
238 " float aCosT = sqrt (1.f - min (aSinT2, 1.f)) * sign (-theIncident.z);\n"
240 " theTransmit = normalize (vec3 (-anEta * theIncident.x,\n"
241 " -anEta * theIncident.y,\n"
245 "//////////////////////////////////////////////////////////////////////////////////////////////\n"
246 "// Handlers and samplers for materials\n"
247 "//////////////////////////////////////////////////////////////////////////////////////////////\n"
249 "//=======================================================================\n"
250 "// function : EvalLambertianReflection\n"
251 "// purpose : Evaluates Lambertian BRDF, with cos(N, PSI)\n"
252 "//=======================================================================\n"
253 "float EvalLambertianReflection (in vec3 theWi, in vec3 theWo)\n"
255 " return (theWi.z <= 0.f || theWo.z <= 0.f) ? 0.f : theWi.z * (1.f / M_PI);\n"
258 "//=======================================================================\n"
259 "// function : SmithG1\n"
261 "//=======================================================================\n"
262 "float SmithG1 (in vec3 theDirection, in vec3 theM, in float theRoughness)\n"
264 " if (dot (theDirection, theM) * theDirection.z <= 0.f)\n"
269 " float aTanThetaM = sqrt (1.f - theDirection.z * theDirection.z) / theDirection.z;\n"
271 " if (aTanThetaM == 0.0f)\n"
276 " float aVal = 1.f / (theRoughness * aTanThetaM);\n"
278 " if (aVal >= 1.6f)\n"
283 " // Use fast and accurate rational approximation to the\n"
284 " // shadowing-masking function (from Mitsuba renderer)\n"
285 " float aSqr = aVal * aVal;\n"
287 " return (3.535f * aVal + 2.181f * aSqr) / (1.f + 2.276f * aVal + 2.577f * aSqr);\n"
290 "//=======================================================================\n"
291 "// function : EvalBlinnReflection\n"
292 "// purpose : Evaluates Blinn glossy BRDF, with cos(N, PSI)\n"
293 "//=======================================================================\n"
294 "vec3 EvalBlinnReflection (in vec3 theWi, in vec3 theWo, in vec3 theFresnel, in float theRoughness)\n"
296 " // calculate the reflection half-vec\n"
297 " vec3 aH = normalize (theWi + theWo);\n"
299 " // roughness value -> Blinn exponent\n"
300 " float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n"
302 " // calculate microfacet distribution\n"
303 " float aD = (aPower + 2.f) * (1.f / M_2_PI) * pow (aH.z, aPower);\n"
305 " // calculate shadow-masking function\n"
306 " float aG = SmithG1 (theWo, aH, theRoughness) *\n"
307 " SmithG1 (theWi, aH, theRoughness);\n"
309 " // return total amount of reflection\n"
310 " return (theWi.z <= 0.f || theWo.z <= 0.f) ? ZERO :\n"
311 " aD * aG / (4.f * theWo.z) * fresnelMedia (dot (theWo, aH), theFresnel);\n"
314 "//=======================================================================\n"
315 "// function : EvalMaterial\n"
316 "// purpose : Evaluates BSDF for specified material, with cos(N, PSI)\n"
317 "//=======================================================================\n"
318 "vec3 EvalMaterial (in SMaterial theBSDF, in vec3 theWi, in vec3 theWo)\n"
320 "#ifdef TWO_SIDED_BXDF\n"
321 " theWi.z *= sign (theWi.z);\n"
322 " theWo.z *= sign (theWo.z);\n"
325 " return theBSDF.Kd.rgb * EvalLambertianReflection (theWi, theWo) +\n"
326 " theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.Fresnel, theBSDF.Ks.w);\n"
329 "//=======================================================================\n"
330 "// function : SampleLambertianReflection\n"
331 "// purpose : Samples Lambertian BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
332 "//=======================================================================\n"
333 "vec3 SampleLambertianReflection (in vec3 theWo, out vec3 theWi, inout float thePDF)\n"
335 " float aKsi1 = RandFloat();\n"
336 " float aKsi2 = RandFloat();\n"
338 " theWi = vec3 (cos (M_2_PI * aKsi1),\n"
339 " sin (M_2_PI * aKsi1),\n"
340 " sqrt (1.f - aKsi2));\n"
342 " theWi.xy *= sqrt (aKsi2);\n"
344 "#ifdef TWO_SIDED_BXDF\n"
345 " theWi.z *= sign (theWo.z);\n"
348 " thePDF *= theWi.z * (1.f / M_PI);\n"
350 "#ifdef TWO_SIDED_BXDF\n"
353 " return mix (UNIT, ZERO, theWo.z <= 0.f);\n"
357 "//=======================================================================\n"
358 "// function : SampleBlinnReflection\n"
359 "// purpose : Samples Blinn BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
360 "// The BRDF is a product of three main terms, D, G, and F,\n"
361 "// which is then divided by two cosine terms. Here we perform\n"
362 "// importance sample the D part of the Blinn model; trying to\n"
363 "// develop a sampling procedure that accounted for all of the\n"
364 "// terms would be complex, and it is the D term that accounts\n"
365 "// for most of the variation.\n"
366 "//=======================================================================\n"
367 "vec3 SampleBlinnReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel, in float theRoughness, inout float thePDF)\n"
369 " float aKsi1 = RandFloat();\n"
370 " float aKsi2 = RandFloat();\n"
372 " // roughness value --> Blinn exponent\n"
373 " float aPower = max (2.f / (theRoughness * theRoughness) - 2.f, 0.f);\n"
375 " // normal from microface distribution\n"
376 " float aCosThetaM = pow (aKsi1, 1.f / (aPower + 2.f));\n"
378 " vec3 aM = vec3 (cos (M_2_PI * aKsi2),\n"
379 " sin (M_2_PI * aKsi2),\n"
382 " aM.xy *= sqrt (1.f - aCosThetaM * aCosThetaM);\n"
384 " // calculate PDF of sampled direction\n"
385 " thePDF *= (aPower + 2.f) * (1.f / M_2_PI) * pow (aCosThetaM, aPower + 1.f);\n"
387 "#ifdef TWO_SIDED_BXDF\n"
388 " bool toFlip = theWo.z < 0.f;\n"
391 " theWo.z = -theWo.z;\n"
394 " float aCosDelta = dot (theWo, aM);\n"
396 " // pick input based on half direction\n"
397 " theWi = -theWo + 2.f * aCosDelta * aM;\n"
399 " if (theWi.z <= 0.f || theWo.z <= 0.f)\n"
404 " // Jacobian of half-direction mapping\n"
405 " thePDF /= 4.f * dot (theWi, aM);\n"
407 " // compute shadow-masking coefficient\n"
408 " float aG = SmithG1 (theWo, aM, theRoughness) *\n"
409 " SmithG1 (theWi, aM, theRoughness);\n"
411 "#ifdef TWO_SIDED_BXDF\n"
413 " theWi.z = -theWi.z;\n"
416 " return (aG * aCosDelta) / (theWo.z * aM.z) * fresnelMedia (aCosDelta, theFresnel);\n"
419 "//=======================================================================\n"
420 "// function : SampleSpecularReflection\n"
421 "// purpose : Samples specular BRDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
422 "//=======================================================================\n"
423 "vec3 SampleSpecularReflection (in vec3 theWo, out vec3 theWi, in vec3 theFresnel)\n"
425 " // Sample input direction\n"
426 " theWi = vec3 (-theWo.x,\n"
430 "#ifdef TWO_SIDED_BXDF\n"
431 " return fresnelMedia (theWo.z, theFresnel);\n"
433 " return fresnelMedia (theWo.z, theFresnel) * step (0.f, theWo.z);\n"
437 "//=======================================================================\n"
438 "// function : SampleSpecularTransmission\n"
439 "// purpose : Samples specular BTDF, W = BRDF * cos(N, PSI) / PDF(PSI)\n"
440 "//=======================================================================\n"
441 "vec3 SampleSpecularTransmission (in vec3 theWo, out vec3 theWi, in vec3 theWeight, in vec3 theFresnel, inout bool theInside)\n"
443 " vec3 aFactor = fresnelMedia (theWo.z, theFresnel);\n"
445 " float aReflection = convolve (aFactor, theWeight);\n"
447 " // sample specular BRDF/BTDF\n"
448 " if (RandFloat() <= aReflection)\n"
450 " theWi = vec3 (-theWo.x,\n"
454 " theWeight = aFactor * (1.f / aReflection);\n"
458 " theInside = !theInside;\n"
460 " transmitted (theFresnel.y, theWo, theWi);\n"
462 " theWeight = (UNIT - aFactor) * (1.f / (1.f - aReflection));\n"
465 " return theWeight;\n"
468 "#define FLT_EPSILON 1.0e-5F\n"
470 "//=======================================================================\n"
471 "// function : BsdfPdf\n"
472 "// purpose : Calculates BSDF of sampling input knowing output\n"
473 "//=======================================================================\n"
474 "float BsdfPdf (in SMaterial theBSDF, in vec3 theWo, in vec3 theWi, in vec3 theWeight)\n"
476 " float aPd = convolve (theBSDF.Kd.rgb, theWeight);\n"
477 " float aPs = convolve (theBSDF.Ks.rgb, theWeight);\n"
478 " float aPr = convolve (theBSDF.Kr.rgb, theWeight);\n"
479 " float aPt = convolve (theBSDF.Kt.rgb, theWeight);\n"
481 " float aReflection = aPd + aPs + aPr + aPt;\n"
483 " float aPDF = 0.f; // PDF of sampling input direction\n"
485 " if (theWi.z * theWo.z > 0.f)\n"
487 " vec3 aH = normalize (theWi + theWo);\n"
489 " // roughness value --> Blinn exponent\n"
490 " float aPower = max (2.f / (theBSDF.Ks.w * theBSDF.Ks.w) - 2.f, 0.f);\n"
492 " aPDF = aPd * abs (theWi.z / M_PI) +\n"
493 " aPs * (aPower + 2.f) * (1.f / M_2_PI) * pow (abs (aH.z), aPower + 1.f) / (4.f * dot (theWi, aH));\n"
496 " return aPDF / aReflection;\n"
499 "//! Tool macro to handle sampling of particular BxDF\n"
500 "#define PICK_BXDF(p, k) aPDF = p / aReflection; theWeight *= k / aPDF;\n"
502 "//=======================================================================\n"
503 "// function : SampleBsdf\n"
504 "// purpose : Samples specified composite material (BSDF)\n"
505 "//=======================================================================\n"
506 "float SampleBsdf (in SMaterial theBSDF, in vec3 theWo, out vec3 theWi, inout vec3 theWeight, inout bool theInside)\n"
508 " // compute probability of each reflection type (BxDF)\n"
509 " float aPd = convolve (theBSDF.Kd.rgb, theWeight);\n"
510 " float aPs = convolve (theBSDF.Ks.rgb, theWeight);\n"
511 " float aPr = convolve (theBSDF.Kr.rgb, theWeight);\n"
512 " float aPt = convolve (theBSDF.Kt.rgb, theWeight);\n"
514 " float aReflection = aPd + aPs + aPr + aPt;\n"
516 " // choose BxDF component to sample\n"
517 " float aKsi = aReflection * RandFloat();\n"
519 " // BxDF's PDF of sampled direction\n"
520 " float aPDF = 0.f;\n"
522 " if (aKsi < aPd) // diffuse reflection\n"
524 " PICK_BXDF (aPd, theBSDF.Kd.rgb);\n"
526 " theWeight *= SampleLambertianReflection (theWo, theWi, aPDF);\n"
528 " else if (aKsi < aPd + aPs) // glossy reflection\n"
530 " PICK_BXDF (aPs, theBSDF.Ks.rgb);\n"
532 " theWeight *= SampleBlinnReflection (theWo, theWi, theBSDF.Fresnel, theBSDF.Ks.w, aPDF);\n"
534 " else if (aKsi < aPd + aPs + aPr) // specular reflection\n"
536 " PICK_BXDF (aPr, theBSDF.Kr.rgb);\n"
538 " aPDF = MAXFLOAT;\n"
540 " theWeight *= SampleSpecularReflection (theWo, theWi, theBSDF.Fresnel);\n"
542 " else if (aKsi < aReflection) // specular transmission\n"
544 " PICK_BXDF (aPt, theBSDF.Kt.rgb);\n"
546 " aPDF = MAXFLOAT;\n"
548 " theWeight *= SampleSpecularTransmission (theWo, theWi, theWeight, theBSDF.Fresnel, theInside);\n"
551 " // path termination for extra small weights\n"
552 " theWeight = mix (ZERO, theWeight, step (FLT_EPSILON, aReflection));\n"
557 "//////////////////////////////////////////////////////////////////////////////////////////////\n"
558 "// Handlers and samplers for light sources\n"
559 "//////////////////////////////////////////////////////////////////////////////////////////////\n"
561 "// =======================================================================\n"
562 "// function : Latlong\n"
563 "// purpose : Converts world direction to environment texture coordinates\n"
564 "// =======================================================================\n"
565 "vec2 Latlong (in vec3 thePoint)\n"
567 " float aPsi = acos (-thePoint.z);\n"
569 " float aPhi = atan (thePoint.y, thePoint.x) + M_PI;\n"
571 " return vec2 (aPhi * 0.1591549f,\n"
572 " aPsi * 0.3183098f);\n"
575 "//=======================================================================\n"
576 "// function : SampleLight\n"
577 "// purpose : General sampling function for directional and point lights\n"
578 "//=======================================================================\n"
579 "vec3 SampleLight (in vec3 theToLight, inout float theDistance, in bool isInfinite, in float theSmoothness, inout float thePDF)\n"
581 " SLocalSpace aSpace = buildLocalSpace (theToLight * (1.f / theDistance));\n"
583 " // for point lights smoothness defines radius\n"
584 " float aCosMax = isInfinite ? theSmoothness :\n"
585 " inversesqrt (1.f + theSmoothness * theSmoothness / (theDistance * theDistance));\n"
587 " float aKsi1 = RandFloat();\n"
588 " float aKsi2 = RandFloat();\n"
590 " float aTmp = 1.f - aKsi2 * (1.f - aCosMax);\n"
592 " vec3 anInput = vec3 (cos (M_2_PI * aKsi1),\n"
593 " sin (M_2_PI * aKsi1),\n"
596 " anInput.xy *= sqrt (1.f - aTmp * aTmp);\n"
598 " thePDF = (aCosMax < 1.f) ? (thePDF / M_2_PI) / (1.f - aCosMax) : MAXFLOAT;\n"
600 " return normalize (fromLocalSpace (anInput, aSpace));\n"
603 "//=======================================================================\n"
604 "// function : HandlePointLight\n"
606 "//=======================================================================\n"
607 "float HandlePointLight (in vec3 theInput, in vec3 theToLight, in float theRadius, in float theDistance, inout float thePDF)\n"
609 " float aCosMax = inversesqrt (1.f + theRadius * theRadius / (theDistance * theDistance));\n"
611 " float aVisibility = step (aCosMax, dot (theInput, theToLight));\n"
613 " thePDF *= step (-1.f, -aCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - aCosMax);\n"
615 " return aVisibility;\n"
618 "//=======================================================================\n"
619 "// function : HandleDistantLight\n"
621 "//=======================================================================\n"
622 "float HandleDistantLight (in vec3 theInput, in vec3 theToLight, in float theCosMax, inout float thePDF)\n"
624 " float aVisibility = step (theCosMax, dot (theInput, theToLight));\n"
626 " thePDF *= step (-1.f, -theCosMax) * aVisibility * (1.f / M_2_PI) / (1.f - theCosMax);\n"
628 " return aVisibility;\n"
631 "// =======================================================================\n"
632 "// function: IntersectLight\n"
633 "// purpose : Checks intersections with light sources\n"
634 "// =======================================================================\n"
635 "vec3 IntersectLight (in SRay theRay, in int theDepth, in float theHitDistance, out float thePDF)\n"
637 " vec3 aTotalRadiance = ZERO;\n"
639 " thePDF = 0.f; // PDF of sampling light sources\n"
641 " for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx)\n"
643 " vec4 aLight = texelFetch (\n"
644 " uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n"
645 " vec4 aParam = texelFetch (\n"
646 " uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n"
648 " // W component: 0 for infinite light and 1 for point light\n"
649 " aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n"
651 " float aPDF = 1.f / uLightCount;\n"
653 " if (aLight.w != 0.f) // point light source\n"
655 " float aCenterDst = length (aLight.xyz);\n"
657 " if (aCenterDst < theHitDistance)\n"
659 " float aVisibility = HandlePointLight (\n"
660 " theRay.Direct, normalize (aLight.xyz), aParam.w /* radius */, aCenterDst, aPDF);\n"
662 " if (aVisibility > 0.f)\n"
664 " theHitDistance = aCenterDst;\n"
665 " aTotalRadiance = aParam.rgb;\n"
671 " else if (theHitDistance == MAXFLOAT) // directional light source\n"
673 " aTotalRadiance += aParam.rgb * HandleDistantLight (\n"
674 " theRay.Direct, aLight.xyz, aParam.w /* angle cosine */, aPDF);\n"
680 " if (thePDF == 0.f && theHitDistance == MAXFLOAT) // light source not found\n"
682 " if (theDepth + uSphereMapForBack == 0) // view ray and map is hidden\n"
684 " aTotalRadiance = pow (BackgroundColor().rgb, vec3 (2.f));\n"
688 " aTotalRadiance = pow (FetchEnvironment (Latlong (theRay.Direct)).rgb, vec3 (2.f));\n"
692 " return aTotalRadiance;\n"
695 "#define MIN_THROUGHPUT vec3 (1.0e-3f)\n"
696 "#define MIN_CONTRIBUTION vec3 (1.0e-2f)\n"
698 "#define MATERIAL_KD(index) (18 * index + 11)\n"
699 "#define MATERIAL_KR(index) (18 * index + 12)\n"
700 "#define MATERIAL_KT(index) (18 * index + 13)\n"
701 "#define MATERIAL_KS(index) (18 * index + 14)\n"
702 "#define MATERIAL_LE(index) (18 * index + 15)\n"
703 "#define MATERIAL_FRESNEL(index) (18 * index + 16)\n"
704 "#define MATERIAL_ABSORPT(index) (18 * index + 17)\n"
706 "// Enables expiremental russian roulette sampling\n"
707 "#define RUSSIAN_ROULETTE\n"
709 "//! Frame step to increase number of bounces\n"
710 "#define FRAME_STEP 5\n"
712 "//=======================================================================\n"
713 "// function : PathTrace\n"
714 "// purpose : Calculates radiance along the given ray\n"
715 "//=======================================================================\n"
716 "vec4 PathTrace (in SRay theRay, in vec3 theInverse)\n"
718 " float aRaytraceDepth = MAXFLOAT;\n"
720 " vec3 aRadiance = ZERO;\n"
721 " vec3 aThroughput = UNIT;\n"
723 " int aTransfID = 0; // ID of object transformation\n"
724 " bool aInMedium = false; // is the ray inside an object\n"
726 " float aExpPDF = 1.f;\n"
727 " float aImpPDF = 1.f;\n"
729 " for (int aDepth = 0; aDepth < NB_BOUNCES; ++aDepth)\n"
731 " SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n"
733 " ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n"
735 " // check implicit path\n"
736 " vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n"
738 " if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n"
740 " float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n"
741 " aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
743 " aRadiance += aThroughput * aLe * aMIS; break; // terminate path\n"
746 " vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, aTransfID + 0).xyz;\n"
747 " vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, aTransfID + 1).xyz;\n"
748 " vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, aTransfID + 2).xyz;\n"
750 " // compute geometrical normal\n"
751 " aHit.Normal = normalize (vec3 (dot (aInvTransf0, aHit.Normal),\n"
752 " dot (aInvTransf1, aHit.Normal),\n"
753 " dot (aInvTransf2, aHit.Normal)));\n"
755 " theRay.Origin += theRay.Direct * aHit.Time; // get new intersection point\n"
757 " // evaluate depth on first hit\n"
758 " if (aDepth == 0)\n"
760 " vec4 aNDCPoint = uViewMat * vec4 (theRay.Origin, 1.f);\n"
762 " float aPolygonOffset = PolygonOffset (aHit.Normal, theRay.Origin);\n"
763 " aRaytraceDepth = (aNDCPoint.z / aNDCPoint.w + aPolygonOffset * POLYGON_OFFSET_SCALE) * 0.5f + 0.5f;\n"
766 " // fetch material (BSDF)\n"
767 " SMaterial aMaterial = SMaterial (\n"
768 " vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w))),\n"
769 " vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KR (aTriIndex.w))),\n"
770 " vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w))),\n"
771 " vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w))),\n"
772 " vec3 (texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL (aTriIndex.w))),\n"
773 " vec4 (texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT (aTriIndex.w))));\n"
775 "#ifdef USE_TEXTURES\n"
776 " if (aMaterial.Kd.w >= 0.f)\n"
778 " vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n"
780 " vec4 aTrsfRow1 = texelFetch (\n"
781 " uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n"
782 " vec4 aTrsfRow2 = texelFetch (\n"
783 " uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n"
785 " aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n"
786 " dot (aTrsfRow2, aTexCoord));\n"
788 " vec4 aTexColor = textureLod (\n"
789 " sampler2D (uTextureSamplers[int (aMaterial.Kd.w)]), aTexCoord.st, 0.f);\n"
791 " aMaterial.Kd.rgb *= (aTexColor.rgb, aTexColor.rgb) * aTexColor.w; // de-gamma correction (for gamma = 2)\n"
793 " if (aTexColor.w != 1.0f)\n"
795 " // mix transparency BTDF with texture alpha-channel\n"
796 " aMaterial.Kt = (UNIT - aTexColor.www) + aTexColor.w * aMaterial.Kt;\n"
801 " // compute smooth normal\n"
802 " vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n"
804 " aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n"
805 " dot (aInvTransf1, aNormal),\n"
806 " dot (aInvTransf2, aNormal)));\n"
808 " SLocalSpace aSpace = buildLocalSpace (aNormal);\n"
810 " // account for self-emission (not stored in the material)\n"
811 " aRadiance += aThroughput * texelFetch (\n"
812 " uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)).rgb;\n"
814 " if (uLightCount > 0 && convolve (aMaterial.Kd.rgb + aMaterial.Ks.rgb, aThroughput) > 0.f)\n"
816 " aExpPDF = 1.f / uLightCount;\n"
818 " int aLightIdx = min (int (floor (RandFloat() * uLightCount)), uLightCount - 1);\n"
820 " vec4 aLight = texelFetch (\n"
821 " uRaytraceLightSrcTexture, LIGHT_POS (aLightIdx));\n"
822 " vec4 aParam = texelFetch (\n"
823 " uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx));\n"
825 " // 'w' component is 0 for infinite light and 1 for point light\n"
826 " aLight.xyz -= mix (ZERO, theRay.Origin, aLight.w);\n"
828 " float aDistance = length (aLight.xyz);\n"
830 " aLight.xyz = SampleLight (aLight.xyz, aDistance,\n"
831 " aLight.w == 0.f /* is infinite */, aParam.w /* max cos or radius */, aExpPDF);\n"
833 " aImpPDF = BsdfPdf (aMaterial,\n"
834 " toLocalSpace (-theRay.Direct, aSpace), toLocalSpace (aLight.xyz, aSpace), aThroughput);\n"
836 " // MIS weight including division by explicit PDF\n"
837 " float aMIS = (aExpPDF == MAXFLOAT) ? 1.f : aExpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n"
839 " vec3 aContrib = aMIS * aParam.rgb /* Le */ * EvalMaterial (\n"
840 " aMaterial, toLocalSpace (aLight.xyz, aSpace), toLocalSpace (-theRay.Direct, aSpace));\n"
842 " if (any (greaterThan (aContrib, MIN_CONTRIBUTION))) // check if light source is important\n"
844 " SRay aShadow = SRay (theRay.Origin + aLight.xyz * uSceneEpsilon, aLight.xyz);\n"
846 " aShadow.Origin += aHit.Normal * mix (\n"
847 " -uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, aLight.xyz)));\n"
849 " float aVisibility = SceneAnyHit (aShadow,\n"
850 " InverseDirection (aLight.xyz), aLight.w == 0.f ? MAXFLOAT : aDistance);\n"
852 " aRadiance += aVisibility * aThroughput * aContrib;\n"
856 " if (aInMedium) // handle attenuation\n"
858 " aThroughput *= exp (-aHit.Time *\n"
859 " aMaterial.Absorption.w * (UNIT - aMaterial.Absorption.rgb));\n"
862 " vec3 anInput = UNIT; // sampled input direction\n"
864 " aImpPDF = SampleBsdf (aMaterial,\n"
865 " toLocalSpace (-theRay.Direct, aSpace), anInput, aThroughput, aInMedium);\n"
867 " float aSurvive = 1.f;\n"
869 "#ifdef RUSSIAN_ROULETTE\n"
870 " aSurvive = aDepth < 3 ? 1.f : min (dot (LUMA, aThroughput), 0.95f);\n"
873 " if (RandFloat() > aSurvive || all (lessThan (aThroughput, MIN_THROUGHPUT)) || aDepth >= uAccumSamples / FRAME_STEP + step (1.f / M_PI, aImpPDF))\n"
875 " aDepth = INVALID_BOUNCES; // terminate path\n"
878 "#ifdef RUSSIAN_ROULETTE\n"
879 " aThroughput /= aSurvive;\n"
882 " anInput = normalize (fromLocalSpace (anInput, aSpace));\n"
884 " theRay = SRay (theRay.Origin + anInput * uSceneEpsilon +\n"
885 " aHit.Normal * mix (-uSceneEpsilon, uSceneEpsilon, step (0.f, dot (aHit.Normal, anInput))), anInput);\n"
887 " theInverse = InverseDirection (anInput);\n"
890 " gl_FragDepth = aRaytraceDepth;\n"
892 " return vec4 (aRadiance, aRaytraceDepth);\n"