EEVEE-Next: Add back fresnel functions

This commit is contained in:
Clément Foucault
2023-07-14 19:03:00 +02:00
parent 1a24b5f81f
commit d8e4fe3207
3 changed files with 105 additions and 11 deletions

View File

@@ -1095,6 +1095,14 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer)
{
return textureLod(util_tx, float3(uv, layer), 0.0);
}
/* Sample at uv position but with scale and bias so that uv space bounds lie on texel centers. */
float4 utility_tx_sample_lut(sampler2DArray util_tx, float2 uv, float layer)
{
/* Scale and bias coordinates, for correct filtered lookup. */
uv = uv * ((UTIL_TEX_SIZE - 1.0) / UTIL_TEX_SIZE) + (0.5 / UTIL_TEX_SIZE);
return textureLod(util_tx, float3(uv, layer), 0.0);
}
#endif
/** \} */

View File

@@ -235,26 +235,111 @@ float nodetree_thickness();
vec4 closure_to_rgba(Closure cl);
#endif
/* Stubs. */
vec2 btdf_lut(float a, float b, float c)
/* Fresnel monochromatic, perfect mirror */
float F_eta(float eta, float cos_theta)
{
return vec2(1, 0);
/* Compute fresnel reflectance without explicitly computing
* the refracted direction. */
float c = abs(cos_theta);
float g = eta * eta - 1.0 + c * c;
if (g > 0.0) {
g = sqrt(g);
float A = (g - c) / (g + c);
float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
return 0.5 * A * A * (1.0 + B * B);
}
/* Total internal reflections. */
return 1.0;
}
vec2 brdf_lut(float a, float b)
/* Simplified form of F_eta(eta, 1.0). */
float F0_from_ior(float eta)
{
return vec2(1, 0);
float A = (eta - 1.0) / (eta + 1.0);
return A * A;
}
vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c)
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
{
return a;
return lut.y * f90 + lut.x * f0;
}
vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c)
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
{
return a;
/**
* From "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
* by Carmelo J. Fdez-Aguera
* https://jcgt.org/published/0008/01/03/paper.pdf
*/
vec3 FssEss = lut.y * f90 + lut.x * f0;
float Ess = lut.x + lut.y;
float Ems = 1.0 - Ess;
vec3 Favg = f0 + (1.0 - f0) / 21.0;
vec3 Fms = FssEss * Favg / (1.0 - (1.0 - Ess) * Favg);
/* We don't do anything special for diffuse surfaces because the principle bsdf
* does not care about energy conservation of the specular layer for dielectrics. */
return FssEss + Fms * Ems;
}
float F_eta(float a, float b)
vec2 brdf_lut(float cos_theta, float roughness)
{
return a;
#ifdef EEVEE_UTILITY_TX
return utility_tx_sample_lut(utility_tx, vec2(cos_theta, roughness), UTIL_BSDF_LAYER).rg;
#else
return vec2(1.0, 0.0);
#endif
}
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);
/* 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 coming 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 = 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);
float layer = coords.z * UTIL_BTDF_LAYER_COUNT;
float layer_floored = floor(layer);
#ifdef EEVEE_UTILITY_TX
coords.z = UTIL_BTDF_LAYER + layer_floored;
vec2 btdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
vec2 btdf_high = utility_tx_sample_lut(utility_tx, coords.xy, coords.z + 1.0).rg;
/* Manual trilinear interpolation. */
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
return btdf;
#else
return vec2(0.0);
#endif
}
void output_renderpass_color(int id, vec4 color)

View File

@@ -20,6 +20,7 @@ GPU_SHADER_CREATE_INFO(eevee_sampling_data)
.storage_buf(SAMPLING_BUF_SLOT, Qualifier::READ, "SamplingData", "sampling_buf");
GPU_SHADER_CREATE_INFO(eevee_utility_texture)
.define("EEVEE_UTILITY_TX")
.sampler(RBUFS_UTILITY_TEX_SLOT, ImageType::FLOAT_2D_ARRAY, "utility_tx");
GPU_SHADER_CREATE_INFO(eevee_camera).uniform_buf(CAMERA_BUF_SLOT, "CameraData", "camera_buf");