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-10 19:02:06 +0300
committerClément Foucault <foucault.clem@gmail.com>2021-02-10 19:02:06 +0300
commita9ac8d8871312cfa94d4721af82501ca520e44eb (patch)
treeaa5eb09cdc4550ec5e39e925a6d309fa1f02d08d
parent9c2f45981691ee2a2c2774e7f51fa32582a1eaec (diff)
EEVEE: Better fit of BTDF LUTeevee-ggx-lut-fix
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. Also touched the ior > 1.0 approximation to be smoother.
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl30
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl55
3 files changed, 55 insertions, 33 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index 1ac965d24ca..cb4d8931af0 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -24,6 +24,7 @@ float ior_from_f0(float f0)
return (-f - 1.0) / (f - 1.0);
}
+/* Simplified form of F_eta(eta, 1.0). */
float f0_from_ior(float eta)
{
float A = (eta - 1.0) / (eta + 1.0);
@@ -69,7 +70,7 @@ float F_eta(float eta, float cos_theta)
/* Fresnel color blend base on fresnel factor */
vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
{
- float f0 = F_eta(eta, 1.0);
+ float f0 = f0_from_ior(eta);
float fac = saturate((fresnel - f0) / (1.0 - f0));
return mix(f0_color, vec3(1.0), fac);
}
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 b504b78ee06..2ffe23a9197 100644
--- a/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/btdf_lut_frag.glsl
@@ -11,18 +11,17 @@ void main()
float x = floor(gl_FragCoord.x) / (LUT_SIZE - 1.0);
float y = floor(gl_FragCoord.y) / (LUT_SIZE - 1.0);
- float ior = sqrt(x);
- ior = clamp(sqrt(ior), 0.0, 0.99995);
+ float ior = clamp(sqrt(x), 0.05, 0.999);
/* ior is sin of critical angle. */
float critical_cos = sqrt(1.0 - saturate(ior * ior));
- /* Manual fit to range. */
- y = y * 1.45 + 0.05;
- /* Remap for better accuracy. */
- float NV = 1.0 - y * y;
- /* Center LUT around critical angle to always have a sharp cut if roughness is 0. */
- NV += critical_cos;
- NV = clamp(NV, 0.0, 0.9999);
+ 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);
float a = z * z;
float a2 = clamp(a * a, 1e-8, 0.9999);
@@ -56,7 +55,7 @@ void main()
vec3 L = refract(-V, H, eta);
float NL = -L.z;
- if ((NL > 0.0) && (fresnel < 1.0)) {
+ if ((NL > 0.0) && (fresnel < 0.999)) {
float LH = dot(L, H);
/* Balancing the adjustments made in G1_Smith. */
@@ -73,6 +72,17 @@ void main()
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;
+ }
+
/* 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);
diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
index 65338cf0dac..b0cd6ac8459 100644
--- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl
@@ -40,35 +40,51 @@ vec2 brdf_lut(float cos_theta, float roughness)
return textureLod(utilTex, vec3(lut_coords(cos_theta, roughness), BRDF_LUT_LAYER), 0.0).rg;
}
+/* Return texture coordinates to sample Surface LUT. */
+vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
+{
+ /* ior is sin of critical angle. */
+ float critical_cos = sqrt(1.0 - ior * ior);
+
+ vec3 coords;
+ coords.x = sqr(ior);
+ coords.y = cos_theta;
+ coords.y -= critical_cos;
+ coords.y /= (coords.y > 0.0) ? (1.0 - critical_cos) : critical_cos;
+ coords.y = coords.y * 0.5 + 0.5;
+ coords.z = roughness;
+
+ coords = saturate(coords);
+
+ /* scale and bias coordinates, for correct filtered lookup */
+ coords.xy = coords.xy * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
+
+ return coords;
+}
+
/* Returns GGX BTDF in first component and fresnel in second. */
vec2 btdf_lut(float cos_theta, float roughness, float ior)
{
+ if (ior <= 1e-5) {
+ return vec2(0.0);
+ }
+
if (ior >= 1.0) {
vec2 split_sum = brdf_lut(cos_theta, roughness);
float f0 = f0_from_ior(ior);
- float fresnel = F_brdf_single_scatter(vec3(f0), vec3(1.0), split_sum).r;
+ /* Baked IOR for GGX BRDF. */
+ const float specular = 1.0;
+ const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
+ /* Avoid harsh transition comming from ior == 1. */
+ float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25)));
+ float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r;
/* Setting the BTDF to one is not really important since it is only used for multiscatter
* and it's already quite close to ground truth. */
float btdf = 1.0;
return vec2(btdf, fresnel);
}
- /* ior is sin of critical angle. */
- float critical_cos = sqrt(1.0 - ior * ior);
-
- vec3 coords;
- coords.x = sqr(ior);
- coords.y = sqrt(1.0 + critical_cos - cos_theta);
- coords.y = (coords.y - 0.05) / 1.45;
- coords.z = roughness;
-
- coords = saturate(coords);
-
- coords.xy = coords.xy * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
- /* Bias the lookup in the NV direction to be able to do the clear cut
- * at the end of the function. */
- float clear_cut = saturate(roughness * lut_btdf_layer_count * 0.5);
- coords.y -= clear_cut * 0.5 / LUT_SIZE;
+ vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
float layer = coords.z * lut_btdf_layer_count;
float layer_floored = floor(layer);
@@ -82,11 +98,6 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
/* Manual trilinear interpolation. */
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
- /* Do a manual trim if roughness is low enough to avoid seeing the bilinear interpolation. */
- if (clear_cut < 1.0 && cos_theta < critical_cos) {
- btdf = mix(vec2(0.0, 1.0), btdf, clear_cut);
- }
-
return btdf;
}