@@ -504,9 +504,9 @@ D_{GGX}(h,\alpha) = \frac{\aa}{\pi ( (\NoH)^2 (\aa - 1) + 1)^2}
\end{equation}$$
< / p > < p >
The GLSL implementation of the NDF, shown in < a href = "#listing_speculard" > listing 1< / a > , is simple and efficient.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-built_in " > float< / span > < span class = "hljs-title" > D_GGX< / span > ( < span class = "hljs-params" > < span class = "hljs-built_in " > float< / span > NoH, < span class = "hljs-built_in " > float< / span > roughness< / span > )< / span > {< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > a = NoH * roughness;< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > k = roughness / (< span class = "hljs-number" > 1.0< / span > - NoH * NoH + a * a);< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > D_GGX< / span > < span class = "hljs-params" > ( < span class = "hljs-type " > float< / span > NoH, < span class = "hljs-type " > float< / span > roughness)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > a = NoH * roughness;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > k = roughness / (< span class = "hljs-number" > 1.0< / span > - NoH * NoH + a * a);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > k * k * (< span class = "hljs-number" > 1.0< / span > / PI);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_speculard" > < / a > < b style = "font-style:normal;" > Listing 1:< / b > Implementation of the specular D term in GLSL< / div > < / center >
< p >
@@ -590,10 +590,10 @@ V(v,l,\alpha) = \frac{0.5}{\NoL \sqrt{(\NoV)^2 (1 - \aa) + \aa} + \NoV \sqrt{(\N
\end{equation}$$
< / p > < p >
The GLSL implementation of the visibility term, shown in < a href = "#listing_specularv" > listing 3< / a > , is a bit more expensive than we would like since it requires two < code > sqrt< / code > operations.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > V_SmithGGXCorrelated< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > NoV, < span class = "hljs-keyword " > float< / span > NoL, < span class = "hljs-keyword " > float< / span > roughness)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > a2 = roughness * roughness;< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > GGXV = NoL * < span class = "hljs-built_in" > sqrt< / span > (NoV * NoV * (< span class = "hljs-number" > 1.0< / span > - a2) + a2);< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > GGXL = NoV * < span class = "hljs-built_in" > sqrt< / span > (NoL * NoL * (< span class = "hljs-number" > 1.0< / span > - a2) + a2);< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > V_SmithGGXCorrelated< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > NoV, < span class = "hljs-type " > float< / span > NoL, < span class = "hljs-type " > float< / span > roughness)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > a2 = roughness * roughness;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > GGXV = NoL * < span class = "hljs-built_in" > sqrt< / span > (NoV * NoV * (< span class = "hljs-number" > 1.0< / span > - a2) + a2);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > GGXL = NoV * < span class = "hljs-built_in" > sqrt< / span > (NoL * NoL * (< span class = "hljs-number" > 1.0< / span > - a2) + a2);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 0.5< / span > / (GGXV + GGXL);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_specularv" > < / a > < b style = "font-style:normal;" > Listing 3:< / b > Implementation of the specular V term in GLSL< / div > < / center >
< p >
@@ -604,10 +604,10 @@ V(v,l,\alpha) = \frac{0.5}{\NoL (\NoV (1 - \alpha) + \alpha) + \NoV (\NoL (1 - \
\end{equation}$$
< / p > < p >
This approximation is mathematically wrong but saves two square root operations and is good enough for real-time mobile applications, as shown in < a href = "#listing_approximatedspecularv" > listing 4< / a > .
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-built_in " > float< / span > < span class = "hljs-title" > V_SmithGGXCorrelatedFast< / span > ( < span class = "hljs-params" > < span class = "hljs-built_in " > float< / span > NoV, < span class = "hljs-built_in " > float< / span > NoL, < span class = "hljs-built_in " > float< / span > roughness< / span > )< / span > {< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > a = roughness;< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > GGXV = NoL * (NoV * (< span class = "hljs-number" > 1.0< / span > - a) + a);< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > GGXL = NoV * (NoL * (< span class = "hljs-number" > 1.0< / span > - a) + a);< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > V_SmithGGXCorrelatedFast< / span > < span class = "hljs-params" > ( < span class = "hljs-type " > float< / span > NoV, < span class = "hljs-type " > float< / span > NoL, < span class = "hljs-type " > float< / span > roughness)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > a = roughness;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > GGXV = NoL * (NoV * (< span class = "hljs-number" > 1.0< / span > - a) + a);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > GGXL = NoV * (NoL * (< span class = "hljs-number" > 1.0< / span > - a) + a);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 0.5< / span > / (GGXV + GGXL);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_approximatedspecularv" > < / a > < b style = "font-style:normal;" > Listing 4:< / b > Implementation of the approximated specular V term in GLSL< / div > < / center >
< p >
@@ -659,7 +659,7 @@ $$\begin{equation}
\end{equation}$$
< / p > < p >
In practice, the diffuse reflectance \(\sigma\) is multiplied later, as shown in < a href = "#listing_diffusebrdf" > listing 8< / a > .
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-built_in" > float< / span > < span class = "hljs-title" > Fd_Lambert< / span > (< span class = "hljs-params" > < / span > )< / span > {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-built_in" > float< / span > < span class = "hljs-title" > Fd_Lambert< / span > ()< / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / PI;< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
@@ -680,14 +680,14 @@ Where:
$$\begin{equation}
\fGrazing=0.5 + 2 \cdot \alpha cos^2(\theta_d)
\end{equation}$$
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > F_Schlick< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > u, < span class = "hljs-keyword " > float< / span > f0, < span class = "hljs-keyword " > float< / span > f90)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > f0 + (f90 - f0) * < span class = "hljs-built_in" > pow< / span > (< span class = "hljs-number" > 1.0< / span > - u, < span class = "hljs-number" > 5.0< / span > );< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-title function_ " > F_Schlick< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > u, < span class = "hljs-type " > float< / span > f0, < span class = "hljs-type " > float< / span > f90)< / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > f0 + (f90 - f0) * pow (< span class = "hljs-number" > 1.0< / span > - u, < span class = "hljs-number" > 5.0< / span > );< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > Fd_Burley< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > NoV, < span class = "hljs-keyword " > float< / span > NoL, < span class = "hljs-keyword " > float< / span > LoH, < span class = "hljs-keyword " > float< / span > roughness)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > f90 = < span class = "hljs-number" > 0.5< / span > + < span class = "hljs-number" > 2.0< / span > * roughness * LoH * LoH;< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > lightScatter = F_Schlick(NoL, < span class = "hljs-number" > 1.0< / span > , f90);< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > viewScatter = F_Schlick(NoV, < span class = "hljs-number" > 1.0< / span > , f90);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-title function_ " > Fd_Burley< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > NoV, < span class = "hljs-type " > float< / span > NoL, < span class = "hljs-type " > float< / span > LoH, < span class = "hljs-type " > float< / span > roughness)< / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-variable" > f90< / span > < span class = "hljs-operator" > =< / span > < span class = "hljs-number" > 0.5< / span > + < span class = "hljs-number" > 2.0< / span > * roughness * LoH * LoH;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-variable" > lightScatter< / span > < span class = "hljs-operator" > =< / span > F_Schlick(NoL, < span class = "hljs-number" > 1.0< / span > , f90);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-variable" > viewScatter< / span > < span class = "hljs-operator" > =< / span > F_Schlick(NoV, < span class = "hljs-number" > 1.0< / span > , f90);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > lightScatter * viewScatter * (< span class = "hljs-number" > 1.0< / span > / PI);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_diffusebrdf" > < / a > < b style = "font-style:normal;" > Listing 8:< / b > Implementation of the diffuse Disney BRDF in GLSL< / div > < / center >
< p >
@@ -704,47 +704,47 @@ We could allow artists/developers to choose the Disney diffuse BRDF depending on
< strong class = "asterisk" > Diffuse term< / strong > : a Lambertian diffuse model.
< / p > < p >
The full GLSL implementation of the standard model is shown in < a href = "#listing_glslbrdf" > listing 9< / a > .
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type" > float< / span > D_GGX (< span class = "hljs-type" > float< / span > NoH, < span class = "hljs-type" > float< / span > a) {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > a2 = a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > f = (NoH * a2 - NoH) * NoH + < span class = "hljs-number" > 1.0< / span > ;< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-title function_" > D_GGX< / span > < span class = "hljs-params" > (< span class = "hljs-type" > float< / span > NoH, < span class = "hljs-type" > float< / span > a)< / span > {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > a2< / span > < span class = "hljs-operator" > =< / span > a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > f< / span > < span class = "hljs-operator" > =< / span > (NoH * a2 - NoH) * NoH + < span class = "hljs-number" > 1.0< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > a2 / (PI * f * f);< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > vec3 < / span > F_Schlick( < span class = "hljs-type " > float< / span > u, < span class = "hljs-type" > vec3 < / span > f0) {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > f0 + (< span class = "hljs-type" > vec3< / span > (< span class = "hljs-number" > 1.0< / span > ) - f0) * < span class = "hljs-built_in" > pow< / span > (< span class = "hljs-number" > 1.0< / span > - u, < span class = "hljs-number" > 5.0< / span > );< / span >
< span class = "line" > vec3 < span class = "hljs-title function_" > F_Schlick < / span > < span class = "hljs-params " > ( < span class = "hljs-type" > float< / span > u, vec3 f0) < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > f0 + (vec3 (< span class = "hljs-number" > 1.0< / span > ) - f0) * pow (< span class = "hljs-number" > 1.0< / span > - u, < span class = "hljs-number" > 5.0< / span > );< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > V_SmithGGXCorrelated (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > NoL, < span class = "hljs-type" > float< / span > a) {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > a2 = a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > GGXL = NoV * < span class = "hljs-built_in " > sqrt < / span > ((-NoL * a2 + NoL) * NoL + a2);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > GGXV = NoL * < span class = "hljs-built_in " > sqrt < / span > ((-NoV * a2 + NoV) * NoV + a2);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-title function_" > V_SmithGGXCorrelated< / span > < span class = "hljs-params" > (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > NoL, < span class = "hljs-type" > float< / span > a)< / span > {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > a2< / span > < span class = "hljs-operator" > =< / span > a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > GGXL< / span > < span class = "hljs-operator " > = < / span > NoV * sqrt ((-NoL * a2 + NoL) * NoL + a2);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > GGXV< / span > < span class = "hljs-operator " > = < / span > NoL * sqrt ((-NoV * a2 + NoV) * NoV + a2);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 0.5< / span > / (GGXV + GGXL);< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > Fd_Lambert() {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-title function_" > Fd_Lambert< / span > < span class = "hljs-params" > ()< / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / PI;< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type " > void< / span > BRDF(...) {< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > h = < span class = "hljs-built_in" > normalize < / span > (v + l);< / span >
< span class = "line" > < span class = "hljs-keyword " > void< / span > < span class = "hljs-title function_" > BRDF< / span > < span class = "hljs-params" > (...)< / span > {< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > < span class = "hljs-variable" > h< / span > < span class = "hljs-operator" > = < / span > normalize (v + l);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > NoV = < span class = "hljs-built_in " > abs < / span > ( < span class = "hljs-built_in " > dot < / span > (n, v)) + < span class = "hljs-number" > 1e-5< / span > ;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > NoL = < span class = "hljs-built_in " > clamp < / span > ( < span class = "hljs-built_in " > dot < / span > (n, l), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > NoH = < span class = "hljs-built_in " > clamp < / span > ( < span class = "hljs-built_in " > dot < / span > (n, h), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > LoH = < span class = "hljs-built_in " > clamp < / span > ( < span class = "hljs-built_in " > dot < / span > (l, h), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable " > NoV < / span > < span class = "hljs-operator " > = < / span > abs(dot (n, v)) + < span class = "hljs-number" > 1e-5< / span > ;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable " > NoL < / span > < span class = "hljs-operator " > = < / span > clamp(dot (n, l), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable " > NoH < / span > < span class = "hljs-operator " > = < / span > clamp(dot (n, h), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable " > LoH < / span > < span class = "hljs-operator " > = < / span > clamp(dot (l, h), < span class = "hljs-number" > 0.0< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // perceptually linear roughness to roughness (see parameterization)< / span > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > roughness = perceptualRoughness * perceptualRoughness;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > roughness< / span > < span class = "hljs-operator" > =< / span > perceptualRoughness * perceptualRoughness;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > D = D_GGX(NoH, roughness);< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > F = F_Schlick(LoH, f0);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > V = V_SmithGGXCorrelated(NoV, NoL, roughness);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > D< / span > < span class = "hljs-operator" > =< / span > D_GGX(NoH, roughness);< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > < span class = "hljs-variable" > F< / span > < span class = "hljs-operator" > =< / span > F_Schlick(LoH, f0);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > V< / span > < span class = "hljs-operator" > =< / span > V_SmithGGXCorrelated(NoV, NoL, roughness);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // specular BRDF< / span > < / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > Fr = (D * V) * F;< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > < span class = "hljs-variable" > Fr< / span > < span class = "hljs-operator" > =< / span > (D * V) * F;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // diffuse BRDF< / span > < / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > Fd = diffuseColor * Fd_Lambert();< / span >
< span class = "line" > < span class = "hljs-type" > vec3< / span > < span class = "hljs-variable" > Fd< / span > < span class = "hljs-operator" > =< / span > diffuseColor * Fd_Lambert();< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // apply lighting...< / span > < / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_glslbrdf" > < / a > < b style = "font-style:normal;" > Listing 9:< / b > Evaluation of the BRDF in GLSL< / div > < / center >
@@ -965,7 +965,7 @@ $$\begin{equation}
\end{equation}$$
< / p > < p >
< a href = "#listing_fnormal" > Listing 12< / a > shows how \(\fNormal\) is computed for both dielectric and metallic materials. It shows that the color of the specular reflectance is derived from the base color in the metallic case.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > vec3 f0 = 0.16 < span class = "hljs-emphasis" > * reflectance * < / span > reflectance < span class = "hljs-emphasis" > * (1.0 - metallic) + baseColor * < / span > metallic; < / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_fnormal" > < / a > < b style = "font-style:normal;" > Listing 12:< / b > Computing \(\fNormal\) for dielectric and metallic materials in GLSL< / div > < / center >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-symbol" > vec3< / span > < span class = "hljs-built_in" > f0< / span > = < span class = "hljs-number" > 0< / span > .< span class = "hljs-number" > 16< / span > * reflectance * reflectance * ( < span class = "hljs-number" > 1< / span > .< span class = "hljs-number" > 0< / span > - metallic) + baseColor * metallic< span class = "hljs-comment" > ; < / span > < / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_fnormal" > < / a > < b style = "font-style:normal;" > Listing 12:< / b > Computing \(\fNormal\) for dielectric and metallic materials in GLSL< / div > < / center >
< a class = "target" name = "roughnessremappingandclamping" > < / a > < a class = "target" name = "materialsystem/parameterization/remapping/roughnessremappingandclamping" > < / a > < a class = "target" name = "toc4.8.3.3" > < / a > < h4 id = "roughness-remapping-and-clamping" > < a class = "header" href = "#roughness-remapping-and-clamping" > Roughness remapping and clamping< / a > < / h4 >
< p >
< p > The roughness set by the user, called < code > perceptualRoughness< / code > here, is remapped to a perceptually linear range using the following formulation:< / p >
@@ -1054,7 +1054,7 @@ V(l,h) = \frac{1}{4(\LoH)^2}
This masking-shadowing function is not physically based, as shown in [< a href = "#citation-heitz14" > Heitz14< / a > ], but its simplicity makes it desirable for real-time rendering.
< / p > < p >
In summary, our clear coat BRDF is a Cook-Torrance specular microfacet model, with a GGX normal distribution function, a Kelemen visibility function, and a Schlick Fresnel function. < a href = "#listing_kelemen" > Listing 13< / a > shows how trivial the GLSL implementation is.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-built_in " > float< / span > < span class = "hljs-title" > V_Kelemen< / span > ( < span class = "hljs-params" > < span class = "hljs-built_in " > float< / span > LoH< / span > ) < / span > {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > V_Kelemen< / span > < span class = "hljs-params" > ( < span class = "hljs-type " > float< / span > LoH) < / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 0.25< / span > / (LoH * LoH);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_kelemen" > < / a > < b style = "font-style:normal;" > Listing 13:< / b > Implementation of the Kelemen visibility term in GLSL< / div > < / center >
< p >
@@ -1097,18 +1097,18 @@ The clear coat roughness parameter is remapped and clamped in a similar way to t
< center > < div class = "image" style = "" > < a href = "../images/material_clear_coat2.png" target = "_blank" > < img class = "markdeep" src = "../images/material_clear_coat2.png" / > < / a > < center > < span class = "imagecaption" > < a class = "target" name = "figure_clearcoatroughness" > < / a > < b style = "font-style:normal;" > Figure 26:< / b > Clear coat roughness varying from 0.0 (left) to 1.0 (right) with metallic set to 1.0, roughness to 0.8 and clear coat to 1.0< / span > < / center > < / div > < / center >
< / p > < p >
< a href = "#listing_clearcoatbrdf" > Listing 14< / a > shows the GLSL implementation of the clear coat material model after remapping, parameterization and integration in the standard surface response.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > void< / span > < span class = "hljs-title" > BRDF< / span > ( < span class = "hljs-params" > ...< / span > ) < / span > {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > void< / span > < span class = "hljs-title" > BRDF< / span > < span class = "hljs-params" > ( ...) < / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // compute Fd and Fr from standard model< / span > < / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // remapping and linearization of clear coat roughness< / span > < / span >
< span class = "line" > clearCoatPerceptualRoughness = clamp (clearCoatPerceptualRoughness, < span class = "hljs-number" > 0.089< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > clearCoatPerceptualRoughness = < span class = "hljs-built_in" > clamp< / span > (clearCoatPerceptualRoughness, < span class = "hljs-number" > 0.089< / span > , < span class = "hljs-number" > 1.0< / span > );< / span >
< span class = "line" > clearCoatRoughness = clearCoatPerceptualRoughness * clearCoatPerceptualRoughness;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // clear coat BRDF< / span > < / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > Dc = D_GGX (clearCoatRoughness, NoH);< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > Vc = V_Kelemen (clearCoatRoughness, LoH);< / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > Fc = F_Schlick (< span class = "hljs-number" > 0.04< / span > , LoH) * clearCoat; < span class = "hljs-comment" > // clear coat strength< / span > < / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > Frc = (Dc * Vc) * Fc;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > Dc = < span class = "hljs-built_in" > D_GGX< / span > (clearCoatRoughness, NoH);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > Vc = < span class = "hljs-built_in" > V_Kelemen< / span > (clearCoatRoughness, LoH);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > Fc = < span class = "hljs-built_in" > F_Schlick< / span > (< span class = "hljs-number" > 0.04< / span > , LoH) * clearCoat; < span class = "hljs-comment" > // clear coat strength< / span > < / span >
< span class = "line" > < span class = "hljs-type " > float< / span > Frc = (Dc * Vc) * Fc;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // account for energy loss in the base layer< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > color * ((Fd + Fr * (< span class = "hljs-number" > 1.0< / span > - Fc)) * (< span class = "hljs-number" > 1.0< / span > - Fc) + Frc);< / span >
@@ -1294,14 +1294,14 @@ f_{r}(v,h,\alpha) = \frac{D_{velvet}(v,h,\alpha)}{4(\NoL + \NoV - (\NoL)(\NoV))}
\end{equation}$$
< / p > < p >
The implementation of the velvet NDF is presented in < a href = "#listing_clothbrdf" > listing 17< / a > , optimized to properly fit in half float formats and to avoid computing a costly cotangent, relying instead on trigonometric identities. Note that we removed the Fresnel component from this BRDF.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > float D_Ashikhmin(float roughness, float NoH) {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type" > float< / span > < span class = "hljs-title" > D_Ashikhmin< / span > < span class = "hljs-params" > (< span class = "hljs-type" > float< / span > roughness, < span class = "hljs-type" > float< / span > NoH)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // Ashikhmin 2007, " Distribution-based BRDFs" < / span > < / span >
< span class = "line" > float a < span class = "hljs-number " > 2 < / span > = roughness * roughness;< / span >
< span class = "line" > float < span class = "hljs-keyword " > cos < / span > < span class = "hljs-number" > 2< / span > h = NoH * NoH;< / span >
< span class = "line" > float < span class = "hljs-keyword " > sin < / span > < span class = "hljs-number" > 2< / span > h = < span class = "hljs-keyword " > max< / span > (< span class = "hljs-number" > 1.0< / span > - < span class = "hljs-keyword" > cos< / span > < span class = "hljs-number" > 2< / span > h, < span class = "hljs-number" > 0.0078125< / span > ); < span class = "hljs-comment" > // 2^(-14/2), so sin2h^2 > 0 in fp16< / span > < / span >
< span class = "line" > float < span class = "hljs-keyword " > sin < / span > < span class = "hljs-number" > 4< / span > h = < span class = "hljs-keyword" > sin< / span > < span class = "hljs-number" > 2< / span > h * < span class = "hljs-keyword" > sin< / span > < span class = "hljs-number" > 2< / span > h;< / span >
< span class = "line" > float cot < span class = "hljs-number " > 2 < / span > = -< span class = "hljs-keyword" > cos< / span > < span class = "hljs-number" > 2< / span > h / (a< span class = "hljs-number" > 2< / span > * < span class = "hljs-keyword" > sin< / span > < span class = "hljs-number" > 2< / span > h);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / (PI * (< span class = "hljs-number" > 4.0< / span > * a< span class = "hljs-number" > 2< / span > + < span class = "hljs-number" > 1.0< / span > ) * < span class = "hljs-keyword" > sin< / span > < span class = "hljs-number" > 4< / span > h) * (< span class = "hljs-number" > 4.0< / span > * exp(cot < span class = "hljs-number " > 2 < / span > ) + < span class = "hljs-keyword" > sin< / span > < span class = "hljs-number" > 4< / span > h);< / span >
< span class = "line" > < span class = "hljs-type " > float < / span > a2 = roughness * roughness;< / span >
< span class = "line" > < span class = "hljs-type " > float < / span > cos2 h = NoH * NoH;< / span >
< span class = "line" > < span class = "hljs-type " > float < / span > sin2 h = < span class = "hljs-built_in " > max< / span > (< span class = "hljs-number" > 1.0< / span > - cos2 h, < span class = "hljs-number" > 0.0078125< / span > ); < span class = "hljs-comment" > // 2^(-14/2), so sin2h^2 > 0 in fp16< / span > < / span >
< span class = "line" > < span class = "hljs-type " > float < / span > sin4h = sin2h * sin2 h;< / span >
< span class = "line" > < span class = "hljs-type " > float < / span > cot2 = -cos2h / (a2 * sin2 h);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / (PI * (< span class = "hljs-number" > 4.0< / span > * a2 + < span class = "hljs-number" > 1.0< / span > ) * sin4 h) * (< span class = "hljs-number" > 4.0< / span > * < span class = "hljs-built_in " > exp < / span > (cot2) + sin4 h);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_clothbrdf" > < / a > < b style = "font-style:normal;" > Listing 17:< / b > Implementation of Ashikhmin's velvet NDF in GLSL< / div > < / center >
< p >
< p > In [< a href = "#citation-estevez17" > Estevez17< / a > ] Estevez and Kulla propose a different NDF (called the “Charlie” sheen) that is based on an exponentiated sinusoidal instead of an inverted Gaussian. This NDF is appealing for several reasons: its parameterization feels more natural and intuitive, it provides a softer appearance and, as shown in equation (\ref{charlieNDF}), its implementation is simpler:< / p >
@@ -1312,11 +1312,11 @@ D(m) = \frac{(2 + \frac{1}{\alpha}) sin(\theta)^{\frac{1}{\alpha}}}{2 \pi}
< / p > < p >
[< a href = "#citation-estevez17" > Estevez17< / a > ] also presents a new shadowing term that we omit here because of its cost. We instead rely on the visibility term from [< a href = "#citation-neubelt13" > Neubelt13< / a > ] (shown in equation \(\ref{clothSpecularBRDF}\) above).
The implementation of this NDF is presented in < a href = "#listing_clothcharliebrdf" > listing 18< / a > , optimized to properly fit in half float formats.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > D_Charlie< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > roughness, < span class = "hljs-keyword " > float< / span > NoH)< / span > < / span > {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > D_Charlie< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > roughness, < span class = "hljs-type " > float< / span > NoH)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // Estevez and Kulla 2017, " Production Friendly Microfacet Sheen BRDF" < / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > invAlpha = < span class = "hljs-number" > 1.0< / span > / roughness;< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > cos2h = NoH * NoH;< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > sin2h = max (< span class = "hljs-number" > 1.0< / span > - cos2h, < span class = "hljs-number" > 0.0078125< / span > ); < span class = "hljs-comment" > // 2^(-14/2), so sin2h^2 > 0 in fp16< / span > < / span >
< span class = "line" > < span class = "hljs-type " > float< / span > invAlpha = < span class = "hljs-number" > 1.0< / span > / roughness;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > cos2h = NoH * NoH;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > sin2h = < span class = "hljs-built_in" > max< / span > (< span class = "hljs-number" > 1.0< / span > - cos2h, < span class = "hljs-number" > 0.0078125< / span > ); < span class = "hljs-comment" > // 2^(-14/2), so sin2h^2 > 0 in fp16< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > (< span class = "hljs-number" > 2.0< / span > + invAlpha) * < span class = "hljs-built_in" > pow< / span > (sin2h, invAlpha * < span class = "hljs-number" > 0.5< / span > ) / (< span class = "hljs-number" > 2.0< / span > * PI);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_clothcharliebrdf" > < / a > < b style = "font-style:normal;" > Listing 18:< / b > Implementation of the “ Charlie” NDF in GLSL< / div > < / center >
< a class = "target" name = "sheencolor" > < / a > < a class = "target" name = "materialsystem/clothmodel/clothspecularbrdf/sheencolor" > < / a > < a class = "target" name = "toc4.12.1.1" > < / a > < h4 id = "sheen-color" > < a class = "header" href = "#sheen-color" > Sheen color< / a > < / h4 >
@@ -1745,21 +1745,21 @@ The photometric attenuation function can be easily implemented in GLSL by adding
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_glslphotometricpunctuallight" > < / a > < b style = "font-style:normal;" > Listing 22:< / b > Implementation of attenuation from photometric profiles in GLSL< / div > < / center >
< p >
< p > The light intensity is computed CPU-side (< a href = "#listing_photometriclightintensity" > listing 23< / a > ) and depends on whether the photometric profile is used as a mask.< / p >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-keyword " > float< / span > multiplier;< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type " > float< / span > multiplier;< / span >
< span class = "line" > < span class = "hljs-comment" > // Photometric profile used as a mask< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (photometricLight.isMasked ()) {< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (photometricLight.< span class = "hljs-built_in" > isMasked< / span > ()) {< / span >
< span class = "line" > < span class = "hljs-comment" > // The desired intensity is set by the artist< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // The integrated intensity comes from a Monte-Carlo< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // integration over the unit sphere around the luminaire< / span > < / span >
< span class = "line" > multiplier = photometricLight.getDesiredIntensity() /< / span >
< span class = "line" > photometricLight.getIntegratedIntensity();< / span >
< span class = "line" > multiplier = photometricLight.< span class = "hljs-built_in" > getDesiredIntensity< / span > () /< / span >
< span class = "line" > photometricLight.< span class = "hljs-built_in" > getIntegratedIntensity< / span > ();< / span >
< span class = "line" > } < span class = "hljs-keyword" > else< / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // Multiplier provided for convenience, set to 1.0 by default< / span > < / span >
< span class = "line" > multiplier = photometricLight.getMultiplier ();< / span >
< span class = "line" > multiplier = photometricLight.< span class = "hljs-built_in" > getMultiplier< / span > ();< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // The max intensity in cd comes from the IES profile< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > lightIntensity = photometricLight.getMaxIntensity () * multiplier;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_photometriclightintensity" > < / a > < b style = "font-style:normal;" > Listing 23:< / b > Computing the intensity of a photometric light on the CPU< / div > < / center >
< span class = "line" > < span class = "hljs-type " > float< / span > lightIntensity = photometricLight.< span class = "hljs-built_in" > getMaxIntensity< / span > () * multiplier;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_photometriclightintensity" > < / a > < b style = "font-style:normal;" > Listing 23:< / b > Computing the intensity of a photometric light on the CPU< / div > < / center >
< p >
< div class = "endnote" > < a class = "target" name = "endnote-xarrowintensity" > < / a > < sup > 4< / sup > The XArrow profile declares a luminous intensity of 1,750 lm but a Monte-Carlo integration shows an intensity of only 350 lm.
< / div >
@@ -2058,19 +2058,19 @@ In practice only 4 or 9 coefficients (i.e.: 2 or 3 bands) are enough for \(\cosT
< center > < div class = "image" style = "" > < a href = "../images/ibl/ibl_irradiance_sh2.png" target = "_blank" > < img class = "markdeep" src = "../images/ibl/ibl_irradiance_sh2.png" style = "max-width:100%;" / > < / a > < center > < span class = "imagecaption" > < a class = "target" name = "figure_iblsh2" > < / a > < b style = "font-style:normal;" > Figure 52:< / b > 2 bands (4 coefficients)< / span > < / center > < / div > < / center >
< / p > < p >
In practice we pre-convolve \(\Lt\) with \(\cosTheta\) and pre-scale these coefficients by the basis scaling factors \(K_l^m\) so that the reconstruction code is as simple as possible in the shader:
< / p > < pre class = "listing tilde" > < code > < span class = "line" > vec3 < span class = "hljs-function" > < span class = "hljs-title" > irradianceSH< / span > (< span class = "hljs-params" > vec3 n< / span > )< / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // uniform vec3 sphericalHarmonics [9]< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // We can use only the first 2 bands for better performance< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < / span >
< span class = "line" > sphericalHarmonics[ < span class = "hljs-numbe r" > 0 < / span > ] < / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 1 < / span > ] * (n.y )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 2 < / span > ] * (n.z )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 3 < / span > ] * (n.x )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 4 < / span > ] * (n.y * n.x )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 5 < / span > ] * (n.y * n.z )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 6 < / span > ] * (< span class = "hljs-number" > 3.0< / span > * n.z * n.z - < span class = "hljs-number" > 1.0< / span > )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 7 < / span > ] * (n.z * n.x )< / span >
< span class = "line" > + sphericalHarmonics[ < span class = "hljs-numbe r" > 8 < / span > ] * (n.x * n.x - n.y * n.y );< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > vec3 irradianceSH(vec3 n) {< / span >
< span class = "line" > // uniform vec3 sphericalHarmonics< span class = "hljs-selector-attr" > [9]< / span > < / span >
< span class = "line" > // We can < span class = "hljs-selector-tag" > use< / span > only the first < span class = "hljs-number" > 2< / span > bands for better performance< / span >
< span class = "line" > return < / span >
< span class = "line" > sphericalHarmonics< span class = "hljs-selector-att r" > [0] < / span > < / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [1] < / span > * (n< span class = "hljs-selector-class" > .y< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [2] < / span > * (n< span class = "hljs-selector-class" > .z< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [3] < / span > * (n< span class = "hljs-selector-class" > .x< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [4] < / span > * (n< span class = "hljs-selector-class" > .y< / span > * n< span class = "hljs-selector-class" > .x< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [5] < / span > * (n< span class = "hljs-selector-class" > .y< / span > * n< span class = "hljs-selector-class" > .z< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [6] < / span > * (< span class = "hljs-number" > 3.0< / span > * n< span class = "hljs-selector-class" > .z< / span > * n< span class = "hljs-selector-class" > .z< / span > - < span class = "hljs-number" > 1.0< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [7] < / span > * (n< span class = "hljs-selector-class" > .z< / span > * n< span class = "hljs-selector-class" > .x< / span > )< / span >
< span class = "line" > + sphericalHarmonics< span class = "hljs-selector-att r" > [8] < / span > * (n< span class = "hljs-selector-class" > .x< / span > * n< span class = "hljs-selector-class" > .x< / span > - n< span class = "hljs-selector-class" > .y< / span > * n< span class = "hljs-selector-class" > .y< / span > );< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_irradiancesh" > < / a > < b style = "font-style:normal;" > Listing 26:< / b > GLSL code to reconstruct the irradiance from the pre-scaled SH< / div > < / center >
< p >
< p > Note that with 2 bands, the computation above becomes a single (4 \times 4) matrix-by-vector multiply.< / p >
@@ -2443,7 +2443,7 @@ LD(n, \alpha) &= \frac{\sum_i^N V(l_i, n,
$$
< / p > < p >
These two new \(DFG\) terms simply need to replace the ones used in the implementation shown in section < a href = "#toc9.5" > 9.5< / a > :
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-keyword " > float< / span > Fc = < span class = "hljs-built_in" > pow< / span > (< span class = "hljs-number" > 1< / span > - VoH, < span class = "hljs-number" > 5.0f< / span > );< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type " > float< / span > Fc = < span class = "hljs-built_in" > pow< / span > (< span class = "hljs-number" > 1< / span > - VoH, < span class = "hljs-number" > 5.0f< / span > );< / span >
< span class = "line" > r.x += Gv * Fc;< / span >
< span class = "line" > r.y += Gv;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_multiscatteriblpreintegration" > < / a > < b style = "font-style:normal;" > Listing 29:< / b > C++ implementation of the \(L_{DFG}\) term for multiscattering< / div > < / center >
< p >
@@ -2507,11 +2507,11 @@ using an environment made of colored vertical stripes (skybox hidden).</span></c
< p >
< p > When sampling the IBL, the clear coat layer is calculated as a second specular lobe. This specular lobe is oriented along the view direction since we cannot reasonably integrate over the hemisphere. < a href = "#listing_clearcoatibl" > Listing 31< / a > demonstrates this approximation in practice. It also shows the energy conservation step. It is important to note that this second specular lobe is computed exactly the same way as the main specular lobe, using the same DFG approximation.< / p >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-comment" > // clearCoat_NoV == shading_NoV if the clear coat layer doesn' t have its own normal map< / span > < / span >
< span class = "line" > < span class = "hljs-built_in " > float< / span > Fc = F_Schlick (< span class = "hljs-number" > 0.04< / span > , < span class = "hljs-number" > 1.0< / span > , clearCoat_NoV) * clearCoat;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > Fc = < span class = "hljs-built_in" > F_Schlick< / span > (< span class = "hljs-number" > 0.04< / span > , < span class = "hljs-number" > 1.0< / span > , clearCoat_NoV) * clearCoat;< / span >
< span class = "line" > < span class = "hljs-comment" > // base layer attenuation for energy compensation< / span > < / span >
< span class = "line" > iblDiffuse *= < span class = "hljs-number" > 1.0< / span > - Fc;< / span >
< span class = "line" > iblSpecular *= sq (< span class = "hljs-number" > 1.0< / span > - Fc);< / span >
< span class = "line" > iblSpecular += specularIBL (r, clearCoatPerceptualRoughness) * Fc;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_clearcoatibl" > < / a > < b style = "font-style:normal;" > Listing 31:< / b > GLSL implementation of the clear coat specular lobe for image-based lighting< / div > < / center >
< span class = "line" > iblSpecular *= < span class = "hljs-built_in" > sq< / span > (< span class = "hljs-number" > 1.0< / span > - Fc);< / span >
< span class = "line" > iblSpecular += < span class = "hljs-built_in" > specularIBL< / span > (r, clearCoatPerceptualRoughness) * Fc;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_clearcoatibl" > < / a > < b style = "font-style:normal;" > Listing 31:< / b > GLSL implementation of the clear coat specular lobe for image-based lighting< / div > < / center >
< a class = "target" name = "anisotropy" > < / a > < a class = "target" name = "lighting/imagebasedlights/anisotropy" > < / a > < a class = "target" name = "toc5.3.6" > < / a > < h3 id = "anisotropy" > < a class = "header" href = "#anisotropy" > Anisotropy < / a > < / h3 >
< p >
< p > [< a href = "#citation-mcauley15" > McAuley15< / a > ] describes a technique called “bent reflection vector”, based [< a href = "#citation-revie12" > Revie12< / a > ]. The bent reflection vector is a rough approximation of anisotropic lighting but the alternative is to use importance sampling. This approximation is sufficiently cheap to compute and provides good results, as shown in < a href = "#figure_anisotropicibl1" > figure 59< / a > and < a href = "#figure_anisotropicibl2" > figure 60< / a > .< / p >
@@ -2550,17 +2550,17 @@ The DG term is generated using uniform sampling as recommended in [<a href="#cit
< center > < div class = "image" style = "" > < a href = "../images/ibl/dfg_cloth.png" target = "_blank" > < img class = "markdeep" src = "../images/ibl/dfg_cloth.png" / > < / a > < center > < span class = "imagecaption" > < a class = "target" name = "figure_dfgclothlut" > < / a > < b style = "font-style:normal;" > Figure 62:< / b > DFG LUT with a 3rd channel encoding the DG term of the cloth BRDF< / span > < / center > < / div > < / center >
< / p > < p >
The remainder of the image-based lighting implementation follows the same steps as the implementation of regular lights, including the optional subsurface scattering term and its wrap diffuse component. Just as with the clear coat IBL implementation, we cannot integrate over the hemisphere and use the view direction as the dominant light direction to compute the wrap diffuse component.
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-built_in " > float< / span > diffuse = Fd_Lambert () * ambientOcclusion;< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > if< / span > defined(SHADING_MODEL_CLOTH)< / span > < / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > if< / span > defined(MATERIAL_HAS_SUBSURFACE_COLOR)< / span > < / span >
< span class = "line" > diffuse *= saturate ((NoV + < span class = "hljs-number" > 0.5< / span > ) / < span class = "hljs-number" > 2.25< / span > );< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > endif< / span > < / span > < / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > endif< / span > < / span > < / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type " > float< / span > diffuse = < span class = "hljs-built_in" > Fd_Lambert< / span > () * ambientOcclusion;< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > if< / span > defined(SHADING_MODEL_CLOTH)< / span > < / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > if< / span > defined(MATERIAL_HAS_SUBSURFACE_COLOR)< / span > < / span >
< span class = "line" > diffuse *= < span class = "hljs-built_in" > saturate< / span > ((NoV + < span class = "hljs-number" > 0.5< / span > ) / < span class = "hljs-number" > 2.25< / span > );< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > endif< / span > < / span > < / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > endif< / span > < / span > < / span >
< span class = "line" > < / span >
< span class = "line" > vec3 indirectDiffuse = irradianceIBL (n) * diffuse;< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > if< / span > defined(SHADING_MODEL_CLOTH) & & defined(MATERIAL_HAS_SUBSURFACE_COLOR)< / span > < / span >
< span class = "line" > indirectDiffuse *= saturate (subsurfaceColor + NoV);< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-meta- keyword" > endif< / span > < / span > < / span >
< span class = "line" > vec3 indirectDiffuse = < span class = "hljs-built_in" > irradianceIBL< / span > (n) * diffuse;< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > if< / span > defined(SHADING_MODEL_CLOTH) & & defined(MATERIAL_HAS_SUBSURFACE_COLOR)< / span > < / span >
< span class = "line" > indirectDiffuse *= < span class = "hljs-built_in" > saturate< / span > (subsurfaceColor + NoV);< / span >
< span class = "line" > < span class = "hljs-meta" > #< span class = "hljs-keyword" > endif< / span > < / span > < / span >
< span class = "line" > < / span >
< span class = "line" > vec3 ibl = diffuseColor * indirectDiffuse + indirectSpecular * specularColor;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_clothapprox" > < / a > < b style = "font-style:normal;" > Listing 34:< / b > GLSL implementation of the DFG approximation for the cloth NDF< / div > < / center >
< p >
@@ -2982,20 +2982,20 @@ L_{max} &= 2^{EV_{100}} \times 1.2
< span class = "line" > < span class = "hljs-comment" > // aperture in f-stops< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // shutterSpeed in seconds< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // sensitivity in ISO< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > exposureSettings< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > aperture, < span class = "hljs-keyword " > float< / span > shutterSpeed, < span class = "hljs-keyword " > float< / span > sensitivity)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-title function_ " > exposureSettings< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > aperture, < span class = "hljs-type " > float< / span > shutterSpeed, < span class = "hljs-type " > float< / span > sensitivity)< / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > log2((aperture * aperture) / shutterSpeed * < span class = "hljs-number" > 100.0< / span > / sensitivity);< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // Computes the exposure normalization factor from< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // the camera' s EV100< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > exposure< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > ev100)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / (< span class = "hljs-built_in" > pow< / span > (< span class = "hljs-number" > 2.0< / span > , ev100) * < span class = "hljs-number" > 1.2< / span > );< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-title function_ " > exposure< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > ev100)< / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 1.0< / span > / (pow (< span class = "hljs-number" > 2.0< / span > , ev100) * < span class = "hljs-number" > 1.2< / span > );< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > ev100 = exposureSettings(aperture, shutterSpeed, sensitivity);< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > exposure = exposure(ev100);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-variable" > ev100< / span > < span class = "hljs-operator" > =< / span > exposureSettings(aperture, shutterSpeed, sensitivity);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > < span class = "hljs-variable" > exposure< / span > < span class = "hljs-operator" > =< / span > exposure(ev100);< / span >
< span class = "line" > < / span >
< span class = "line" > vec4 color = evaluateLighting();< / span >
< span class = "line" > < span class = "hljs-type" > vec4< / span > < span class = "hljs-variable" > color< / span > < span class = "hljs-operator" > =< / span > evaluateLighting();< / span >
< span class = "line" > color.rgb *= exposure;< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_fragmentexposure" > < / a > < b style = "font-style:normal;" > Listing 42:< / b > Implementation of exposure in GLSL< / div > < / center >
< p >
< p > In practice the exposure factor can be pre-computed on the CPU to save shader instructions.< / p >
@@ -3466,9 +3466,9 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
< span class = "line" > < span class = "hljs-comment" > // Data source:< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // http://cvrl.ioo.ucl.ac.uk/cmfs.htm< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // http://cvrl.ioo.ucl.ac.uk/database/text/cmfs/ciexyz31.htm< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_XYZ_START = < span class = "hljs-number" > 360< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_XYZ_COUNT = < span class = "hljs-number" > 471< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > float3 CIE_XYZ[CIE_XYZ_COUNT] = { ... };< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_XYZ_START = < span class = "hljs-number" > 360< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_XYZ_COUNT = < span class = "hljs-number" > 471< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > float3 CIE_XYZ[CIE_XYZ_COUNT] = { ... };< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // CIE Standard Illuminant D65 relative spectral power distribution,< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // from 300nm to 830, at 5nm intervals< / span > < / span >
@@ -3476,51 +3476,51 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
< span class = "line" > < span class = "hljs-comment" > // Data source:< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // https://en.wikipedia.org/wiki/Illuminant_D65< / span > < / span >
< span class = "line" > < span class = "hljs-comment" > // https://cielab.xyz/pdf/CIE_sel_colorimetric_tables.xls< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_D65_INTERVAL = < span class = "hljs-number" > 5< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_D65_START = < span class = "hljs-number" > 300< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_D65_END = < span class = "hljs-number" > 830< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > CIE_D65_COUNT = < span class = "hljs-number" > 107< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > float< / span > CIE_D65[CIE_D65_COUNT] = { ... };< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_D65_INTERVAL = < span class = "hljs-number" > 5< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_D65_START = < span class = "hljs-number" > 300< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_D65_END = < span class = "hljs-number" > 830< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > CIE_D65_COUNT = < span class = "hljs-number" > 107< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > float< / span > CIE_D65[CIE_D65_COUNT] = { ... };< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-class" > < span class = "hljs- keyword" > struct< / span > < span class = "hljs-title" > Sample< / span > {< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > w = < span class = "hljs-number" > 0.0f< / span > ; < span class = "hljs-comment" > // wavelength< / span > < / span >
< span class = "line" > < span class = "hljs-built_in" > std< / span > ::< span class = "hljs-built_in" > complex< / span > < < span class = "hljs-keyword " > float< / span > > ior; < span class = "hljs-comment" > // complex IOR, n + ik< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > struct< / span > < span class = "hljs-title class_ " > Sample< / span > {< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > w = < span class = "hljs-number" > 0.0f< / span > ; < span class = "hljs-comment" > // wavelength< / span > < / span >
< span class = "line" > std::complex < < span class = "hljs-type " > float< / span > > ior; < span class = "hljs-comment" > // complex IOR, n + ik< / span > < / span >
< span class = "line" > };< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > illuminantD65< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > float< / span > w)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > i0 = < span class = "hljs-keyword " > size_t< / span > ((w - CIE_D65_START) / CIE_D65_INTERVAL);< / span >
< span class = "line" > uint2 indexBounds{i0, < span class = "hljs-built_in" > std < / span > ::min (i0 + < span class = "hljs-number" > 1< / span > , CIE_D65_END)};< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > illuminantD65< / span > < span class = "hljs-params" > (< span class = "hljs-type " > float< / span > w)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > i0 = < span class = "hljs-built_in " > size_t< / span > ((w - CIE_D65_START) / CIE_D65_INTERVAL);< / span >
< span class = "line" > uint2 indexBounds{i0, std:: < span class = "hljs-built_in" > min < / span > (i0 + < span class = "hljs-number" > 1< / span > , CIE_D65_END)};< / span >
< span class = "line" > < / span >
< span class = "line" > float2 wavelengthBounds = CIE_D65_START + float2{indexBounds} * CIE_D65_INTERVAL;< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > t = (w - wavelengthBounds.x) / (wavelengthBounds.y - wavelengthBounds.x);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > lerp (CIE_D65[indexBounds.x], CIE_D65[indexBounds.y], t);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > t = (w - wavelengthBounds.x) / (wavelengthBounds.y - wavelengthBounds.x);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-built_in" > lerp< / span > (CIE_D65[indexBounds.x], CIE_D65[indexBounds.y], t);< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // For std::lower_bound< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > bool< / span > < span class = "hljs-keyword" > operator< / span > < (< span class = "hljs-keyword " > const< / span > Sample& lhs, < span class = "hljs-keyword " > const< / span > Sample& rhs) {< / span >
< span class = "line" > < span class = "hljs-type " > bool< / span > < span class = "hljs-keyword" > operator< / span > < (< span class = "hljs-type " > const< / span > Sample& lhs, < span class = "hljs-type " > const< / span > Sample& rhs) {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > lhs.w < rhs.w;< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // The wavelength w must be between 360nm and 830nm< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > < span class = "hljs-built_in" > std< / span > ::< span class = "hljs-built_in" > complex< / span > < < span class = "hljs-keyword " > float< / span > > < span class = "hljs-title" > findSample< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > const< / span > < span class = "hljs-built_in" > std< / span > ::< span class = "hljs-built_in" > vector< / span > < sample> & samples, < span class = "hljs-keyword " > float< / span > w)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > i1 = < span class = "hljs-built_in" > st d< / span > ::lower_bound (< / span >
< span class = "line" > samples.begin(), samples.end (), Sample{w, < span class = "hljs-number" > 0.0f< / span > + < span class = "hljs-number" > 0.0< / span > < span class = "hljs-keyword" > if< / span > });< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > std::complex < < span class = "hljs-type " > float< / span > > < span class = "hljs-title" > findSample< / span > < span class = "hljs-params" > (< span class = "hljs-type " > const< / span > std::vector < sample> & samples, < span class = "hljs-type " > float< / span > w)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > i1 = std:: < span class = "hljs-built_in" > lower_boun d< / span > (< / span >
< span class = "line" > samples.< span class = "hljs-built_in" > begin< / span > (), samples.< span class = "hljs-built_in" > end< / span > (), Sample{w, < span class = "hljs-number" > 0.0f< / span > + < span class = "hljs-number" > 0.0< / span > < span class = "hljs-keyword" > if< / span > });< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > i0 = i1 - < span class = "hljs-number" > 1< / span > ;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // Interpolate the complex IORs< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > t = (w - i0-> w) / (i1-> w - i0-> w);< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > n = lerp(i0-> ior.real(), i1-> ior.real (), t);< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > k = lerp(i0-> ior.imag(), i1-> ior.imag (), t);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > t = (w - i0-> w) / (i1-> w - i0-> w);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > n = < span class = "hljs-built_in" > lerp< / span > (i0-> ior.< span class = "hljs-built_in" > real< / span > (), i1-> ior.< span class = "hljs-built_in" > real< / span > (), t);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > k = < span class = "hljs-built_in" > lerp< / span > (i0-> ior.< span class = "hljs-built_in" > imag< / span > (), i1-> ior.< span class = "hljs-built_in" > imag< / span > (), t);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > { n, k };< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > < span class = "hljs-keyword " > float< / span > < span class = "hljs-title" > fresnel< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > const< / span > < span class = "hljs-built_in" > std< / span > ::< span class = "hljs-built_in" > complex< / span > < < span class = "hljs-keyword " > float< / span > > & sample)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > (((sample - (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )) * (< span class = "hljs-built_in" > std < / span > ::conj (sample) - (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > ))) /< / span >
< span class = "line" > ((sample + (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )) * (< span class = "hljs-built_in" > std < / span > ::conj (sample) + (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )))).real ();< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > < span class = "hljs-type " > float< / span > < span class = "hljs-title" > fresnel< / span > < span class = "hljs-params" > (< span class = "hljs-type " > const< / span > std::complex < < span class = "hljs-type " > float< / span > > & sample)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > (((sample - (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )) * (std:: < span class = "hljs-built_in" > conj < / span > (sample) - (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > ))) /< / span >
< span class = "line" > ((sample + (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )) * (std:: < span class = "hljs-built_in" > conj < / span > (sample) + (< span class = "hljs-number" > 1.0f< / span > + < span class = "hljs-number" > 0< / span > < span class = "hljs-keyword" > if< / span > )))).< span class = "hljs-built_in" > real< / span > ();< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > float3 < span class = "hljs-title" > XYZ_to_sRGB< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > const< / span > float3& v)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > mat3f XYZ_sRGB{< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > float3 < span class = "hljs-title" > XYZ_to_sRGB< / span > < span class = "hljs-params" > (< span class = "hljs-type " > const< / span > float3& v)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > mat3f XYZ_sRGB{< / span >
< span class = "line" > < span class = "hljs-number" > 3.2404542f< / span > , < span class = "hljs-number" > -0.9692660f< / span > , < span class = "hljs-number" > 0.0556434f< / span > ,< / span >
< span class = "line" > < span class = "hljs-number" > -1.5371385f< / span > , < span class = "hljs-number" > 1.8760108f< / span > , < span class = "hljs-number" > -0.2040259f< / span > ,< / span >
< span class = "line" > < span class = "hljs-number" > -0.4985314f< / span > , < span class = "hljs-number" > 0.0415560f< / span > , < span class = "hljs-number" > 1.0572252f< / span > < / span >
@@ -3529,21 +3529,21 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // Outputs a linear sRGB color< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > float3 < span class = "hljs-title" > computeColor< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > const< / span > < span class = "hljs-built_in" > std< / span > ::< span class = "hljs-built_in" > vector< / span > < sample> & samples)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > float3 < span class = "hljs-title" > computeColor< / span > < span class = "hljs-params" > (< span class = "hljs-type " > const< / span > std::vector < sample> & samples)< / span > < / span > {< / span >
< span class = "line" > float3 xyz{< span class = "hljs-number" > 0.0f< / span > };< / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > y = < span class = "hljs-number" > 0.0f< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > y = < span class = "hljs-number" > 0.0f< / span > ;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > size_t< / span > i = < span class = "hljs-number" > 0< / span > ; i < CIE_XYZ_COUNT; i++) {< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > size_t< / span > i = < span class = "hljs-number" > 0< / span > ; i < CIE_XYZ_COUNT; i++) {< / span >
< span class = "line" > < span class = "hljs-comment" > // Current wavelength< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > w = CIE_XYZ_START + i;< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > w = CIE_XYZ_START + i;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // Find most appropriate CIE XYZ sample for the wavelength< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > sample = findSample (samples, w);< / span >
< span class = "line" > < span class = "hljs-keyword" > auto< / span > sample = < span class = "hljs-built_in" > findSample< / span > (samples, w);< / span >
< span class = "line" > < span class = "hljs-comment" > // Compute Fresnel reflectance at normal incidence< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > f0 = fresnel (sample);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > f0 = < span class = "hljs-built_in" > fresnel< / span > (sample);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // We need to multiply by the spectral power distribution of the illuminant< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > float< / span > d65 = illuminantD65 (w);< / span >
< span class = "line" > < span class = "hljs-type " > float< / span > d65 = < span class = "hljs-built_in" > illuminantD65< / span > (w);< / span >
< span class = "line" > < / span >
< span class = "line" > xyz += f0 * CIE_XYZ[i] * d65;< / span >
< span class = "line" > y += CIE_XYZ[i].y * d65;< / span >
@@ -3552,10 +3552,10 @@ Our implementation is presented in <a href="#listing_specularcolorimpl">listing&
< span class = "line" > < span class = "hljs-comment" > // Normalize so that 100% reflectance at every wavelength yields Y=1< / span > < / span >
< span class = "line" > xyz /= y;< / span >
< span class = "line" > < / span >
< span class = "line" > float3 linear = XYZ_to_sRGB (xyz);< / span >
< span class = "line" > float3 linear = < span class = "hljs-built_in" > XYZ_to_sRGB< / span > (xyz);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // Normalize out-of-gamut values< / span > < / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (any(greaterThan (linear, float3{< span class = "hljs-number" > 1.0f< / span > }))) linear *= < span class = "hljs-number" > 1.0f< / span > / max (linear);< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (< span class = "hljs-built_in" > any< / span > (< span class = "hljs-built_in" > greaterThan< / span > (linear, float3{< span class = "hljs-number" > 1.0f< / span > }))) linear *= < span class = "hljs-number" > 1.0f< / span > / < span class = "hljs-built_in" > max< / span > (linear);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > linear;< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > < a class = "target" name = "listing_specularcolorimpl" > < / a > < b style = "font-style:normal;" > Listing 46:< / b > C++ implementation to compute the base color of a metallic surface from spectral data< / div > < / center >
@@ -3735,47 +3735,47 @@ l &= \{ cos\phi sin\theta,sin\phi sin\theta,cos\theta \}
< pre class = "listing tilde" > < code > < span class = "line" > vec2f hammersley(uint i, < span class = "hljs-built_in" > float< / span > numSamples) {< / span >
< span class = "line" > uint bits = i;< / span >
< span class = "line" > bits = (bits < < < span class = "hljs-string" > 16) | (bits > > 16< / span > );< / span >
< span class = "line" > bits = ((bits & 0 x55555555) < < < span class = "hljs-string " > 1) | ((bits & 0xAAAAAAAA) > > 1< / span > );< / span >
< span class = "line" > bits = ((bits & 0 x33333333) < < < span class = "hljs-string " > 2) | ((bits & 0xCCCCCCCC) > > 2< / span > );< / span >
< span class = "line" > bits = ((bits & 0 x0F0F0F0F) < < < span class = "hljs-string " > 4) | ((bits & 0xF0F0F0F0) > > 4< / span > );< / span >
< span class = "line" > bits = ((bits & 0 x00FF00FF) < < < span class = "hljs-string " > 8) | ((bits & 0xFF00FF00) > > 8< / span > );< / span >
< span class = "line" > < span class = "hljs-built_in " > return < / span > vec2f(i / numSamples, bits / exp2(32 ));< / span >
< span class = "line" > bits = ((bits & < span class = "hljs-number" > 0< / span > x55555555) < < < span class = "hljs-number " > 1< / span > ) | ((bits & < span class = "hljs-number" > 0< / span > xAAAAAAAA) > > < span class = "hljs-number" > 1< / span > );< / span >
< span class = "line" > bits = ((bits & < span class = "hljs-number" > 0< / span > x33333333) < < < span class = "hljs-number " > 2< / span > ) | ((bits & < span class = "hljs-number" > 0< / span > xCCCCCCCC) > > < span class = "hljs-number" > 2< / span > );< / span >
< span class = "line" > bits = ((bits & < span class = "hljs-number" > 0< / span > x0F0F0F0F) < < < span class = "hljs-number " > 4< / span > ) | ((bits & < span class = "hljs-number" > 0< / span > xF0F0F0F0) > > < span class = "hljs-number" > 4< / span > );< / span >
< span class = "line" > bits = ((bits & < span class = "hljs-number" > 0< / span > x00FF00FF) < < < span class = "hljs-number " > 8< / span > ) | ((bits & < span class = "hljs-number" > 0< / span > xFF00FF00) > > < span class = "hljs-number" > 8< / span > );< / span >
< span class = "line" > return vec2f(i / numSamples, bits / exp2( < span class = "hljs-number " > 32 < / span > ));< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > C++ implementation of a Hammersley sequence generator< / div > < / center >
< a class = "target" name = "precomputinglforimage-basedlighting" > < / a > < a class = "target" name = "annex/precomputinglforimage-basedlighting" > < / a > < a class = "target" name = "toc9.5" > < / a > < h2 id = "precomputing-l-for-image-based-lighting" > < a class = "header" href = "#precomputing-l-for-image-based-lighting" > Precomputing L for image-based lighting< / a > < / h2 >
< p >
< p > The term ( L_{DFG} ) is only dependent on ( \NoV ). Below, the normal is arbitrarily set to ( n=\left[0, 0, 1\right] ) and (v) is chosen to satisfy ( \NoV ). The vector ( h_i ) is the ( D_{GGX}(\alpha) ) important direction sample (i).< / p >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type" > float< / span > GDFG (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > NoL, < span class = "hljs-type" > float< / span > a) {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > a2 = a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > GGXL = NoV * < span class = "hljs-built_in " > sqrt < / span > ((-NoL * a2 + NoL) * NoL + a2);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > GGXV = NoL * < span class = "hljs-built_in " > sqrt < / span > ((-NoV * a2 + NoV) * NoV + a2);< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-title function_" > GDFG< / span > < span class = "hljs-params" > (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > NoL, < span class = "hljs-type" > float< / span > a)< / span > {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > a2< / span > < span class = "hljs-operator" > =< / span > a * a;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > GGXL< / span > < span class = "hljs-operator " > = < / span > NoV * sqrt ((-NoL * a2 + NoL) * NoL + a2);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > GGXV< / span > < span class = "hljs-operator " > = < / span > NoL * sqrt ((-NoV * a2 + NoV) * NoV + a2);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > (< span class = "hljs-number" > 2< / span > * NoL) / (GGXV + GGXL);< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > float2 DFG (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > a) {< / span >
< span class = "line" > float2 < span class = "hljs-title function_" > DFG< / span > < span class = "hljs-params" > (< span class = "hljs-type" > float< / span > NoV, < span class = "hljs-type" > float< / span > a)< / span > {< / span >
< span class = "line" > float3 V;< / span >
< span class = "line" > V.x = < span class = "hljs-built_in" > sqrt< / span > (< span class = "hljs-number" > 1.0< / span > f - NoV*NoV);< / span >
< span class = "line" > V.y = < span class = "hljs-number" > 0.0< / span > f ;< / span >
< span class = "line" > V.x = sqrt (< span class = "hljs-number" > 1.0f < / span > - NoV*NoV);< / span >
< span class = "line" > V.y = < span class = "hljs-number" > 0.0f < / span > ;< / span >
< span class = "line" > V.z = NoV;< / span >
< span class = "line" > < / span >
< span class = "line" > float2 r = < span class = "hljs-number" > 0.0< / span > f ;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type" > uint< / span > i = < span class = "hljs-number" > 0< / span > ; i < sampleCount; i++) {< / span >
< span class = "line" > float2 Xi = hammersley(i, sampleCount);< / span >
< span class = "line" > float3 H = importanceSampleGGX(Xi, a, N);< / span >
< span class = "line" > float3 L = < span class = "hljs-numbe r" > 2.0 < / span > f * < span class = "hljs-built_in " > dot < / span > (V, H) * H - V;< / span >
< span class = "line" > < span class = "hljs-type" > float2< / span > < span class = "hljs-variable" > r< / span > < span class = "hljs-operator" > =< / span > < span class = "hljs-number" > 0.0f < / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type" > uint< / span > < span class = "hljs-variable" > i< / span > < span class = "hljs-operator" > =< / span > < span class = "hljs-number" > 0< / span > ; i < sampleCount; i++) {< / span >
< span class = "line" > < span class = "hljs-type" > float2< / span > < span class = "hljs-variable" > Xi< / span > < span class = "hljs-operator" > =< / span > hammersley(i, sampleCount);< / span >
< span class = "line" > < span class = "hljs-type" > float3< / span > < span class = "hljs-variable" > H< / span > < span class = "hljs-operator" > =< / span > importanceSampleGGX(Xi, a, N);< / span >
< span class = "line" > < span class = "hljs-type" > float3< / span > < span class = "hljs-variable" > L< / span > < span class = "hljs-operato r" > = < / span > < span class = "hljs-number " > 2.0f < / span > * dot (V, H) * H - V;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-type" > float< / span > VoH = saturate( < span class = "hljs-built_in " > dot < / span > (V, H));< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > NoL = saturate(L.z);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > NoH = saturate(H.z);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > VoH< / span > < span class = "hljs-operator " > = < / span > saturate(dot (V, H));< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > NoL< / span > < span class = "hljs-operator" > =< / span > saturate(L.z);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > NoH< / span > < span class = "hljs-operator" > =< / span > saturate(H.z);< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (NoL > < span class = "hljs-number" > 0.0< / span > f ) {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > G = GDFG(NoV, NoL, a);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > Gv = G * VoH / NoH;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > Fc = < span class = "hljs-built_in " > pow < / span > (< span class = "hljs-number" > 1< / span > - VoH, < span class = "hljs-number" > 5.0< / span > f );< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (NoL > < span class = "hljs-number" > 0.0f < / span > ) {< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > G< / span > < span class = "hljs-operator" > =< / span > GDFG(NoV, NoL, a);< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > Gv< / span > < span class = "hljs-operator" > =< / span > G * VoH / NoH;< / span >
< span class = "line" > < span class = "hljs-type" > float< / span > < span class = "hljs-variable" > Fc< / span > < span class = "hljs-operator " > = < / span > pow (< span class = "hljs-number" > 1< / span > - VoH, < span class = "hljs-number" > 5.0f < / span > );< / span >
< span class = "line" > r.x += Gv * (< span class = "hljs-number" > 1< / span > - Fc);< / span >
< span class = "line" > r.y += Gv * Fc;< / span >
< span class = "line" > }< / span >
< span class = "line" > }< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > r * (< span class = "hljs-number" > 1.0< / span > f / sampleCount);< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > r * (< span class = "hljs-number" > 1.0f < / span > / sampleCount);< / span >
< span class = "line" > }< / span > < / code > < / pre > < center > < div class = "listingcaption tilde" > C++ implementation of the \( L_{DFG} \) term< / div > < / center >
< a class = "target" name = "sphericalharmonics" > < / a > < a class = "target" name = "annex/sphericalharmonics" > < / a > < a class = "target" name = "toc9.6" > < / a > < h2 id = "spherical-harmonics" > < a class = "header" href = "#spherical-harmonics" > Spherical Harmonics< / a > < / h2 >
< p >
@@ -3851,56 +3851,56 @@ sin(m \phi + \phi) &= sin(m \phi) cos(\phi) + cos(m \phi) sin(\phi) \Leftrightar
\end{align*}$$
< / p > < p >
< a href = "#listing_nonnormalizedshbasis" > Listing 47< / a > shows the C++ code to compute the non-normalized SH basis \(\frac{y^m_l(s)}{\sqrt{2} K^m_l}\):
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > < span class = "hljs-keyword" > inline< / span > < span class = "hljs-keyword " > size_t< / span > < span class = "hljs-title" > SHindex< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > ssize_t< / span > m, < span class = "hljs-keyword " > size_t< / span > l)< / span > < / span > {< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > < span class = "hljs-keyword" > inline< / span > < span class = "hljs-type " > size_t< / span > < span class = "hljs-title" > SHindex< / span > < span class = "hljs-params" > (< span class = "hljs-type " > ssize_t< / span > m, < span class = "hljs-type " > size_t< / span > l)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > l * (l + < span class = "hljs-number" > 1< / span > ) + m;< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > void< / span > < span class = "hljs-title" > computeShBasis< / span > < span class = "hljs-params" > (< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > * < span class = "hljs-keyword " > const< / span > SHb,< / span >
< span class = "line" > < span class = "hljs-keyword " > size_t< / span > numBands,< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > vec3& s)< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > void< / span > < span class = "hljs-title" > computeShBasis< / span > < span class = "hljs-params" > (< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > * < span class = "hljs-type " > const< / span > SHb,< / span >
< span class = "line" > < span class = "hljs-type " > size_t< / span > numBands,< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > vec3& s)< / span > < / span >
< span class = "line" > < / span > {< / span >
< span class = "line" > < span class = "hljs-comment" > // handle m=0 separately, since it produces only one coefficient< / span > < / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml_2 = < span class = "hljs-number" > 0< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml_1 = < span class = "hljs-number" > 1< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml_2 = < span class = "hljs-number" > 0< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml_1 = < span class = "hljs-number" > 1< / span > ;< / span >
< span class = "line" > SHb[< span class = "hljs-number" > 0< / span > ] = Pml_1;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > ssize_t< / span > l = < span class = "hljs-number" > 1< / span > ; l < numBands; l++) {< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml = ((< span class = "hljs-number" > 2< / span > * l - < span class = "hljs-number" > 1< / span > ) * Pml_1 * s.z - (l - < span class = "hljs-number" > 1< / span > ) * Pml_2) / l;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > ssize_t< / span > l = < span class = "hljs-number" > 1< / span > ; l < numBands; l++) {< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml = ((< span class = "hljs-number" > 2< / span > * l - < span class = "hljs-number" > 1< / span > ) * Pml_1 * s.z - (l - < span class = "hljs-number" > 1< / span > ) * Pml_2) / l;< / span >
< span class = "line" > Pml_2 = Pml_1;< / span >
< span class = "line" > Pml_1 = Pml;< / span >
< span class = "line" > SHb[SHindex (< span class = "hljs-number" > 0< / span > , l)] = Pml;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > (< span class = "hljs-number" > 0< / span > , l)] = Pml;< / span >
< span class = "line" > }< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pmm = < span class = "hljs-number" > 1< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > ssize_t< / span > m = < span class = "hljs-number" > 1< / span > ; m < numBands ; m++) {< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pmm = < span class = "hljs-number" > 1< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > ssize_t< / span > m = < span class = "hljs-number" > 1< / span > ; m < numBands ; m++) {< / span >
< span class = "line" > Pmm = (< span class = "hljs-number" > 1< / span > - < span class = "hljs-number" > 2< / span > * m) * Pmm;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml_2 = Pmm;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml_1 = (< span class = "hljs-number" > 2< / span > * m + < span class = "hljs-number" > 1< / span > )*Pmm*s.z;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml_2 = Pmm;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml_1 = (< span class = "hljs-number" > 2< / span > * m + < span class = "hljs-number" > 1< / span > )*Pmm*s.z;< / span >
< span class = "line" > < span class = "hljs-comment" > // l == m< / span > < / span >
< span class = "line" > SHb[SHindex (-m, m)] = Pml_2;< / span >
< span class = "line" > SHb[SHindex ( m, m)] = Pml_2;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > (-m, m)] = Pml_2;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > ( m, m)] = Pml_2;< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (m + < span class = "hljs-number" > 1< / span > < numBands) {< / span >
< span class = "line" > < span class = "hljs-comment" > // l == m+1< / span > < / span >
< span class = "line" > SHb[SHindex (-m, m + < span class = "hljs-number" > 1< / span > )] = Pml_1;< / span >
< span class = "line" > SHb[SHindex ( m, m + < span class = "hljs-number" > 1< / span > )] = Pml_1;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > ssize_t< / span > l = m + < span class = "hljs-number" > 2< / span > ; l < numBands; l++) {< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Pml = ((< span class = "hljs-number" > 2< / span > * l - < span class = "hljs-number" > 1< / span > ) * Pml_1 * s.z - (l + m - < span class = "hljs-number" > 1< / span > ) * Pml_2)< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > (-m, m + < span class = "hljs-number" > 1< / span > )] = Pml_1;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > ( m, m + < span class = "hljs-number" > 1< / span > )] = Pml_1;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > ssize_t< / span > l = m + < span class = "hljs-number" > 2< / span > ; l < numBands; l++) {< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Pml = ((< span class = "hljs-number" > 2< / span > * l - < span class = "hljs-number" > 1< / span > ) * Pml_1 * s.z - (l + m - < span class = "hljs-number" > 1< / span > ) * Pml_2)< / span >
< span class = "line" > / (l - m);< / span >
< span class = "line" > Pml_2 = Pml_1;< / span >
< span class = "line" > Pml_1 = Pml;< / span >
< span class = "line" > SHb[SHindex (-m, l)] = Pml;< / span >
< span class = "line" > SHb[SHindex ( m, l)] = Pml;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > (-m, l)] = Pml;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > ( m, l)] = Pml;< / span >
< span class = "line" > }< / span >
< span class = "line" > }< / span >
< span class = "line" > }< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Cm = s.x;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Sm = s.y;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > ssize_t< / span > m = < span class = "hljs-number" > 1< / span > ; m < = numBands ; m++) {< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-keyword " > ssize_t< / span > l = m; l < numBands ; l++) {< / span >
< span class = "line" > SHb[SHindex (-m, l)] *= Sm;< / span >
< span class = "line" > SHb[SHindex ( m, l)] *= Cm;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Cm = s.x;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Sm = s.y;< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > ssize_t< / span > m = < span class = "hljs-number" > 1< / span > ; m < = numBands ; m++) {< / span >
< span class = "line" > < span class = "hljs-keyword" > for< / span > (< span class = "hljs-type " > ssize_t< / span > l = m; l < numBands ; l++) {< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > (-m, l)] *= Sm;< / span >
< span class = "line" > SHb[< span class = "hljs-built_in" > SHindex< / span > ( m, l)] *= Cm;< / span >
< span class = "line" > }< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Cm1 = Cm * s.x - Sm * s.y;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > Sm1 = Sm * s.x + Cm * s.y;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Cm1 = Cm * s.x - Sm * s.y;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > Sm1 = Sm * s.x + Cm * s.y;< / span >
< span class = "line" > Cm = Cm1;< / span >
< span class = "line" > Sm = Sm1;< / span >
< span class = "line" > }< / span >
@@ -3979,10 +3979,10 @@ $$\begin{equation}
\end{equation}$$
< / p > < p >
Here is the C++ code to compute \(\hat{C}_l\):
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > static< / span > < span class = "hljs-keyword " > double< / span > < span class = "hljs-title" > factorial< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > size_t< / span > n, < span class = "hljs-keyword " > size_t< / span > d = < span class = "hljs-number" > 1< / span > )< / span > < / span > ;< / span >
< / p > < pre class = "listing tilde" > < code > < span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > static< / span > < span class = "hljs-type " > double< / span > < span class = "hljs-title" > factorial< / span > < span class = "hljs-params" > (< span class = "hljs-type " > size_t< / span > n, < span class = "hljs-type " > size_t< / span > d = < span class = "hljs-number" > 1< / span > )< / span > < / span > ;< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // < cos(theta) > SH coefficients pre-multiplied by 1 / K(0,l)< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > double< / span > < span class = "hljs-title" > computeTruncatedCosSh< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > size_t< / span > l)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > double< / span > < span class = "hljs-title" > computeTruncatedCosSh< / span > < span class = "hljs-params" > (< span class = "hljs-type " > size_t< / span > l)< / span > < / span > {< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (l == < span class = "hljs-number" > 0< / span > ) {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > M_PI;< / span >
< span class = "line" > } < span class = "hljs-keyword" > else< / span > < span class = "hljs-keyword" > if< / span > (l == < span class = "hljs-number" > 1< / span > ) {< / span >
@@ -3990,17 +3990,17 @@ Here is the C++ code to compute \(\hat{C}_l\):
< span class = "line" > } < span class = "hljs-keyword" > else< / span > < span class = "hljs-keyword" > if< / span > (l & < span class = "hljs-number" > 1< / span > ) {< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 0< / span > ;< / span >
< span class = "line" > }< / span >
< span class = "line" > < span class = "hljs-keyword " > const< / span > < span class = "hljs-keyword " > size_t< / span > l_2 = l / < span class = "hljs-number" > 2< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > A0 = ((l_2 & < span class = "hljs-number" > 1< / span > ) ? < span class = "hljs-number" > 1.0< / span > : < span class = "hljs-number" > -1.0< / span > ) / ((l + < span class = "hljs-number" > 2< / span > ) * (l - < span class = "hljs-number" > 1< / span > ));< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > A1 = factorial(l, l_2) / (factorial (l_2) * (< span class = "hljs-number" > 1< / span > < < l));< / span >
< span class = "line" > < span class = "hljs-type " > const< / span > < span class = "hljs-type " > size_t< / span > l_2 = l / < span class = "hljs-number" > 2< / span > ;< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > A0 = ((l_2 & < span class = "hljs-number" > 1< / span > ) ? < span class = "hljs-number" > 1.0< / span > : < span class = "hljs-number" > -1.0< / span > ) / ((l + < span class = "hljs-number" > 2< / span > ) * (l - < span class = "hljs-number" > 1< / span > ));< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > A1 = < span class = "hljs-built_in" > factorial< / span > (l, l_2) / (< span class = "hljs-built_in" > factorial< / span > (l_2) * (< span class = "hljs-number" > 1< / span > < < l));< / span >
< span class = "line" > < span class = "hljs-keyword" > return< / span > < span class = "hljs-number" > 2< / span > * M_PI * A0 * A1;< / span >
< span class = "line" > }< / span >
< span class = "line" > < / span >
< span class = "line" > < span class = "hljs-comment" > // returns n! / d!< / span > < / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-keyword " > double< / span > < span class = "hljs-title" > factorial< / span > < span class = "hljs-params" > (< span class = "hljs-keyword " > size_t< / span > n, < span class = "hljs-keyword " > size_t< / span > d )< / span > < / span > {< / span >
< span class = "line" > d = < span class = "hljs-built_in" > std < / span > ::max (< span class = "hljs-keyword " > size_t< / span > (< span class = "hljs-number" > 1< / span > ), d);< / span >
< span class = "line" > n = < span class = "hljs-built_in" > std < / span > ::max (< span class = "hljs-keyword " > size_t< / span > (< span class = "hljs-number" > 1< / span > ), n);< / span >
< span class = "line" > < span class = "hljs-keyword " > double< / span > r = < span class = "hljs-number" > 1.0< / span > ;< / span >
< span class = "line" > < span class = "hljs-function" > < span class = "hljs-type " > double< / span > < span class = "hljs-title" > factorial< / span > < span class = "hljs-params" > (< span class = "hljs-type " > size_t< / span > n, < span class = "hljs-type " > size_t< / span > d )< / span > < / span > {< / span >
< span class = "line" > d = std:: < span class = "hljs-built_in" > max < / span > (< span class = "hljs-built_in " > size_t< / span > (< span class = "hljs-number" > 1< / span > ), d);< / span >
< span class = "line" > n = std:: < span class = "hljs-built_in" > max < / span > (< span class = "hljs-built_in " > size_t< / span > (< span class = "hljs-number" > 1< / span > ), n);< / span >
< span class = "line" > < span class = "hljs-type " > double< / span > r = < span class = "hljs-number" > 1.0< / span > ;< / span >
< span class = "line" > < span class = "hljs-keyword" > if< / span > (n == d) {< / span >
< span class = "line" > < span class = "hljs-comment" > // intentionally left blank< / span > < / span >
< span class = "line" > } < span class = "hljs-keyword" > else< / span > < span class = "hljs-keyword" > if< / span > (n > d) {< / span >