From ec774fdb481808368e4ada01241fce907ce673ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 18 May 2017 18:35:25 +0200 Subject: [PATCH] Eevee: Fix fresnel factor to match Unreal Engine specular input. --- .../eevee/shaders/bsdf_common_lib.glsl | 29 ++++++++++++++++--- .../eevee/shaders/bsdf_direct_lib.glsl | 8 ++--- .../eevee/shaders/lit_surface_frag.glsl | 2 +- 3 files changed, 28 insertions(+), 11 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 1954a2ad85d..feaddd3c0e3 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -89,9 +89,9 @@ vec3 mul(mat3 m, vec3 v) { return m * v; } mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; } float saturate(float a) { return clamp(a, 0.0, 1.0); } -vec2 saturate(vec2 a) { return vec2(saturate(a.x), saturate(a.y)); } -vec3 saturate(vec3 a) { return vec3(saturate(a.x), saturate(a.y), saturate(a.z)); } -vec4 saturate(vec4 a) { return vec4(saturate(a.x), saturate(a.y), saturate(a.z), saturate(a.w)); } +vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); } +vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); } +vec4 saturate(vec4 a) { return clamp(a, 0.0, 1.0); } float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); } float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); } @@ -285,7 +285,28 @@ vec3 mrp_area(LightData ld, ShadingData sd, vec3 dir, inout float roughness, out vec3 F_schlick(vec3 f0, float cos_theta) { float fac = pow(1.0 - cos_theta, 5); - return f0 + (1.0 - f0) * fac; + + /* Unreal specular matching : if specular color is below 2% intensity, + * (using green channel for intensity) treat as shadowning */ + return saturate(50.0 * f0.g) * fac + (1.0 - fac) * f0; +} + +/* Fresnel approximation for LTC area lights (not MRP) */ +vec3 F_area(vec3 f0, vec2 lut) +{ + vec2 fac = normalize(lut.xy); + + /* Unreal specular matching : if specular color is below 2% intensity, + * (using green channel for intensity) treat as shadowning */ + return saturate(50.0 * f0.g) * fac.y + fac.x * f0; +} + +/* Fresnel approximation for LTC area lights (not MRP) */ +vec3 F_ibl(vec3 f0, vec2 lut) +{ + /* Unreal specular matching : if specular color is below 2% intensity, + * (using green channel for intensity) treat as shadowning */ + return saturate(50.0 * f0.g) * lut.y + lut.x * f0; } /* GGX */ diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl index a949f85b426..9097f4aca5a 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl @@ -135,9 +135,7 @@ vec3 direct_ggx_sphere(LightData ld, ShadingData sd, float roughness, vec3 f0) bsdf *= lut.b; /* Bsdf intensity */ bsdf *= M_1_2PI * M_1_PI; - /* Rough fresnel approximation using the LUT */ - lut.xy = normalize(lut.xy); - vec3 spec = bsdf * lut.y + f0 * bsdf * lut.x; + vec3 spec = F_area(f0, lut.xy) * bsdf; #else float energy_conservation; vec3 L = mrp_sphere(ld, sd, sd.spec_dominant_dir, roughness, energy_conservation); @@ -165,9 +163,7 @@ vec3 direct_ggx_rectangle(LightData ld, ShadingData sd, float roughness, vec3 f0 bsdf *= lut.b; /* Bsdf intensity */ bsdf *= M_1_2PI; - /* Rough fresnel approximation using the LUT */ - lut.xy = normalize(lut.xy); - vec3 spec = bsdf * lut.y + f0 * bsdf * lut.x; + vec3 spec = F_area(f0, lut.xy) * bsdf; #else float energy_conservation; vec3 L = mrp_area(ld, sd, sd.spec_dominant_dir, roughness, energy_conservation); diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index fe460e73477..1e29aed739d 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -273,7 +273,7 @@ vec3 eevee_surface_lit(vec3 world_normal, vec3 albedo, vec3 f0, float roughness, vec2 uv = lut_coords(dot(sd.N, sd.V), sqrt(roughness)); vec2 brdf_lut = texture(brdfLut, uv).rg; vec3 Li = textureLod(probeFiltered, sd.spec_dominant_dir, roughness * lodMax).rgb; - indirect_radiance += Li * brdf_lut.y + f0 * Li * brdf_lut.x; + indirect_radiance += Li * F_ibl(f0, brdf_lut); indirect_radiance += spherical_harmonics(sd.N, shCoefs) * albedo;