Cleanup: simplify terms in EEVEE multiscatter GGX #111634

Merged
Weizhen Huang merged 2 commits from weizhen/blender:simplify-eevee-multiggx into main 2023-08-29 12:51:00 +02:00
2 changed files with 28 additions and 23 deletions

View File

@ -77,25 +77,28 @@ vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
/* Fresnel split-sum approximation. */
vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
{
/* Unreal specular matching : if specular color is below 2% intensity,
* treat as shadowing. */
return lut.y * f90 + lut.x * f0;
return f0 * lut.x + f90 * lut.y;
}
/* Multi-scattering brdf approximation from :
/* Multi-scattering brdf approximation from
* "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
* by Carmelo J. Fdez-Agüera. */
* https://jcgt.org/published/0008/01/03/paper.pdf by Carmelo J. Fdez-Agüera. */
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
{
vec3 FssEss = lut.y * f90 + lut.x * f0;
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
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;
/* The original paper uses `FssEss * radiance + Fms*Ems * irradiance`, but
* "A Journey Through Implementing Multiscattering BRDFs and Area Lights" by Steve McAuley
* suggests to use `FssEss * radiance + Fms*Ems * radiance` which results in comparible quality.
* We handle `radiance` outside of this function, so the result simplifies to:
* `FssEss + Fms*Ems = FssEss * (1 + Ems*Favg / (1 - Ems*Favg)) = FssEss / (1 - Ems*Favg)`.
* This is a simple albedo scaling very similar to the approach used by Cycles:
* "Practical multiple scattering compensation for microfacet model". */
return FssEss / (1.0 - Ems * Favg);
}
/* GGX */

View File

@ -280,29 +280,31 @@ float F0_from_ior(float eta)
return A * A;
}
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
/* Return the fresnel color from a precomputed LUT value (from brdf_lut). */
vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
{
return lut.y * f90 + lut.x * f0;
return f0 * lut.x + f90 * lut.y;
}
/* Return the fresnel color from a precomputed LUT value (from brdf_lutb). */
/* Multi-scattering brdf approximation from
* "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
* https://jcgt.org/published/0008/01/03/paper.pdf by Carmelo J. Fdez-Agüera. */
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
{
/**
* 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;
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
float Ess = lut.x + lut.y;
float Ems = 1.0 - Ess;
weizhen marked this conversation as resolved Outdated

Maybe keep this one for clarity.

Maybe keep this one for clarity.
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;
/* The original paper uses `FssEss * radiance + Fms*Ems * irradiance`, but
* "A Journey Through Implementing Multiscattering BRDFs and Area Lights" by Steve McAuley
* suggests to use `FssEss * radiance + Fms*Ems * radiance` which results in comparible quality.
weizhen marked this conversation as resolved Outdated

I would still include the derivation (or part of it if it is too long) to avoid confusion to the future reader to why it is different than the reference materials.

I would still include the derivation (or part of it if it is too long) to avoid confusion to the future reader to why it is different than the reference materials.
* We handle `radiance` outside of this function, so the result simplifies to:
* `FssEss + Fms*Ems = FssEss * (1 + Ems*Favg / (1 - Ems*Favg)) = FssEss / (1 - Ems*Favg)`.
* This is a simple albedo scaling very similar to the approach used by Cycles:
* "Practical multiple scattering compensation for microfacet model". */
return FssEss / (1.0 - Ems * Favg);
}
vec2 brdf_lut(float cos_theta, float roughness)