EEVEE-Next: Add back fresnel functions
This commit is contained in:
@@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user