Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2021-02-13 20:50:09 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-13 20:52:19 +0300
commit83ac8628c490eda4fa5237b7a4256bc670dc0682 (patch)
tree89563a6d46dcea4ea51b70d23b3a73e7637161a6 /source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
parent06492fd61984c1a92fb1f93d30028de97ead451f (diff)
EEVEE: Update LUT GGX generation shader
This modifies the principled BSDF and the Glass BSDF which now have better fit to multiscatter GGX. Code to generate the LUT have been updated and can run at runtime. The refraction LUT has been changed to have the critical angle always centered around one pixel so that interpolation can be mitigated. Offline LUT data will be updated in another commit This simplify the BTDF retreival removing the manual clean cut at low roughness. This maximize the precision of the LUT by scalling the sides by the critical angle. I also touched the ior > 1.0 approximation to be smoother. Also incluse some cleanup of bsdf_sampling.glsl
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl')
-rw-r--r--source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl101
1 files changed, 64 insertions, 37 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
index d815d9d4e6b..2ffe23a9197 100644
--- a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
@@ -1,62 +1,89 @@
+#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl)
-uniform float a2;
+uniform float sampleCount;
+uniform float z;
out vec4 FragColor;
void main()
{
- vec3 N, T, B, V;
+ float x = floor(gl_FragCoord.x) / (LUT_SIZE - 1.0);
+ float y = floor(gl_FragCoord.y) / (LUT_SIZE - 1.0);
- float x = gl_FragCoord.x / LUT_SIZE;
- float y = gl_FragCoord.y / LUT_SIZE;
- /* There is little variation if ior > 1.0 so we
- * maximize LUT precision for ior < 1.0 */
- x = x * 1.1;
- float ior = (x > 1.0) ? ior_from_f0((x - 1.0) * 10.0) : sqrt(x);
- float NV = (1.0 - (clamp(y, 1e-4, 0.9999)));
+ float ior = clamp(sqrt(x), 0.05, 0.999);
+ /* ior is sin of critical angle. */
+ float critical_cos = sqrt(1.0 - saturate(ior * ior));
- N = vec3(0.0, 0.0, 1.0);
- T = vec3(1.0, 0.0, 0.0);
- B = vec3(0.0, 1.0, 0.0);
- V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
+ y = y * 2.0 - 1.0;
+ /* Maximize texture usage on both sides of the critical angle. */
+ y *= (y > 0.0) ? (1.0 - critical_cos) : critical_cos;
+ /* Center LUT around critical angle to avoid strange interpolation issues when the critical
+ * angle is changing. */
+ y += critical_cos;
+ float NV = clamp(y, 1e-4, 0.9999);
- setup_noise();
+ float a = z * z;
+ float a2 = clamp(a * a, 1e-8, 0.9999);
+
+ vec3 V = vec3(sqrt(1.0 - NV * NV), 0.0, NV);
/* Integrating BTDF */
float btdf_accum = 0.0;
- for (float i = 0.0; i < sampleCount; i++) {
- vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */
+ float fresnel_accum = 0.0;
+ for (float j = 0.0; j < sampleCount; j++) {
+ for (float i = 0.0; i < sampleCount; i++) {
+ vec3 Xi = (vec3(i, j, 0.0) + 0.5) / sampleCount;
+ Xi.yz = vec2(cos(Xi.y * M_2PI), sin(Xi.y * M_2PI));
- float VH = dot(V, H);
+ /* Microfacet normal. */
+ vec3 H = sample_ggx(Xi, a2);
- /* Check if there is total internal reflections. */
- float c = abs(VH);
- float g = ior * ior - 1.0 + c * c;
+ float VH = dot(V, H);
- float eta = 1.0 / ior;
- if (dot(H, V) < 0.0) {
- H = -H;
- eta = ior;
- }
+ /* Check if there is total internal reflections. */
+ float fresnel = F_eta(ior, VH);
+
+ fresnel_accum += fresnel;
+
+ float eta = 1.0 / ior;
+ if (dot(H, V) < 0.0) {
+ H = -H;
+ eta = ior;
+ }
- vec3 L = refract(-V, H, eta);
- float NL = -dot(N, L);
+ vec3 L = refract(-V, H, eta);
+ float NL = -L.z;
- if ((NL > 0.0) && (g > 0.0)) {
- float LH = dot(L, H);
+ if ((NL > 0.0) && (fresnel < 0.999)) {
+ float LH = dot(L, H);
- float G1_l = NL * 2.0 /
- G1_Smith_GGX(NL, a2); /* Balancing the adjustments made in G1_Smith */
+ /* Balancing the adjustments made in G1_Smith. */
+ float G1_l = NL * 2.0 / G1_Smith_GGX(NL, a2);
- /* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
- * pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
- float btdf = G1_l * abs(VH * LH) / (VH * abs(LH));
+ /* btdf = abs(VH*LH) * (ior*ior) * D * G(V) * G(L) / (Ht2 * NV)
+ * pdf = (VH * abs(LH)) * (ior*ior) * D * G(V) / (Ht2 * NV) */
+ float btdf = G1_l * abs(VH * LH) / (VH * abs(LH));
- btdf_accum += btdf;
+ btdf_accum += btdf;
+ }
}
}
- btdf_accum /= sampleCount;
+ btdf_accum /= sampleCount * sampleCount;
+ fresnel_accum /= sampleCount * sampleCount;
+
+ if (z == 0.0) {
+ /* Perfect mirror. Increased precision because the roughness is clamped. */
+ fresnel_accum = F_eta(ior, NV);
+ }
+
+ if (x == 0.0) {
+ /* Special case. */
+ fresnel_accum = 1.0;
+ btdf_accum = 0.0;
+ }
- FragColor = vec4(btdf_accum, 0.0, 0.0, 1.0);
+ /* There is place to put multiscater result (which is a little bit different still)
+ * and / or lobe fitting for better sampling of */
+ FragColor = vec4(btdf_accum, fresnel_accum, 0.0, 1.0);
}