EEVEE: change Principled BSDF to match Cycles #111754
|
@ -95,7 +95,7 @@ float ambient_occlusion_eval(vec3 normal,
|
|||
vec3 safe_normalize(vec3 N);
|
||||
float fast_sqrt(float a);
|
||||
vec3 cameraVec(vec3 P);
|
||||
vec2 btdf_lut(float a, float b, float c);
|
||||
vec2 btdf_lut(float a, float b, float c, float d);
|
||||
vec2 brdf_lut(float a, float b);
|
||||
vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c);
|
||||
vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c);
|
||||
|
|
|
@ -74,7 +74,7 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
|
|||
}
|
||||
|
||||
/* Returns GGX BTDF in first component and fresnel in second. */
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
|
||||
{
|
||||
if (ior <= 1e-5) {
|
||||
return vec2(0.0);
|
||||
|
@ -83,16 +83,16 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
|||
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 multi-scatter
|
||||
* and it's already quite close to ground truth. */
|
||||
float btdf = 1.0;
|
||||
return vec2(btdf, fresnel);
|
||||
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
|
||||
* transition at `IOR == 1`. */
|
||||
float f90 = fast_sqrt(saturate(f0 / 0.02));
|
||||
|
||||
float brdf = F_brdf_multi_scatter(vec3(f0), vec3(f90), split_sum).r;
|
||||
/* Energy conservation. */
|
||||
float btdf = 1.0 - brdf;
|
||||
/* Assuming the energy loss caused by single-scattering is distributed proportionally in the
|
||||
* reflection and refraction lobes. */
|
||||
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
|
||||
}
|
||||
|
||||
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
|
||||
|
@ -101,15 +101,21 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
|||
float layer_floored = floor(layer);
|
||||
|
||||
coords.z = lut_btdf_layer_first + layer_floored;
|
||||
vec2 btdf_low = textureLod(utilTex, coords, 0.0).rg;
|
||||
vec2 btdf_brdf_low = textureLod(utilTex, coords, 0.0).rg;
|
||||
|
||||
coords.z += 1.0;
|
||||
vec2 btdf_high = textureLod(utilTex, coords, 0.0).rg;
|
||||
vec2 btdf_brdf_high = textureLod(utilTex, coords, 0.0).rg;
|
||||
|
||||
/* Manual trilinear interpolation. */
|
||||
vec2 btdf = mix(btdf_low, btdf_high, layer - layer_floored);
|
||||
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
|
||||
|
||||
return btdf;
|
||||
if (do_multiscatter != 0.0) {
|
||||
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming
|
||||
* the energy loss of single-scattering is distributed proportionally in the two lobes. */
|
||||
btdf_brdf /= (btdf_brdf.x + btdf_brdf.y);
|
||||
}
|
||||
|
||||
return btdf_brdf;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -38,7 +38,7 @@ void main()
|
|||
}
|
||||
|
||||
/* Stubs */
|
||||
vec2 btdf_lut(float a, float b, float c)
|
||||
vec2 btdf_lut(float a, float b, float c, float d)
|
||||
{
|
||||
return vec2(0.0);
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ vec2 brdf_lut(float cos_theta, float roughness)
|
|||
#endif
|
||||
}
|
||||
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
||||
vec2 btdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
|
||||
{
|
||||
if (ior <= 1e-5) {
|
||||
return vec2(0.0);
|
||||
|
@ -325,16 +325,16 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
|||
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 multi-scatter
|
||||
* and it's already quite close to ground truth. */
|
||||
float btdf = 1.0;
|
||||
return vec2(btdf, fresnel);
|
||||
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
|
||||
* transition at `IOR == 1`. */
|
||||
float f90 = fast_sqrt(saturate(f0 / 0.02));
|
||||
|
||||
float brdf = F_brdf_multi_scatter(vec3(f0), vec3(f90), split_sum).r;
|
||||
/* Energy conservation. */
|
||||
float btdf = 1.0 - brdf;
|
||||
/* Assuming the energy loss caused by single-scattering is distributed proportionally in the
|
||||
* reflection and refraction lobes. */
|
||||
return vec2(btdf, brdf) * ((do_multiscatter == 0.0) ? sum(split_sum) : 1.0);
|
||||
}
|
||||
|
||||
/* IOR is sin of critical angle. */
|
||||
|
@ -355,11 +355,18 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior)
|
|||
|
||||
#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;
|
||||
vec2 btdf_brdf_low = utility_tx_sample_lut(utility_tx, coords.xy, coords.z).rg;
|
||||
vec2 btdf_brdf_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;
|
||||
vec2 btdf_brdf = mix(btdf_brdf_low, btdf_brdf_high, layer - layer_floored);
|
||||
|
||||
if (do_multiscatter != 0.0) {
|
||||
/* For energy-conserving BSDF the reflection and refraction lobes should sum to one. Assuming
|
||||
* the energy loss of single-scattering is distributed proportionally in the two lobes. */
|
||||
btdf_brdf /= (btdf_brdf.x + btdf_brdf.y);
|
||||
}
|
||||
|
||||
return btdf_brdf;
|
||||
#else
|
||||
return vec2(0.0);
|
||||
#endif
|
||||
|
|
|
@ -14,20 +14,17 @@ void node_bsdf_glass(vec4 color,
|
|||
vec3 V = cameraVec(g_data.P);
|
||||
float NV = dot(N, V);
|
||||
|
||||
vec2 split_sum = btdf_lut(NV, roughness, ior);
|
||||
|
||||
float fresnel = (do_multiscatter != 0.0) ? split_sum.y : F_eta(ior, NV);
|
||||
float btdf = (do_multiscatter != 0.0) ? 1.0 : split_sum.x;
|
||||
vec2 bsdf = btdf_lut(NV, roughness, ior, do_multiscatter);
|
||||
|
||||
ClosureReflection reflection_data;
|
||||
reflection_data.weight = fresnel * weight;
|
||||
reflection_data.weight = bsdf.y * weight;
|
||||
reflection_data.color = color.rgb;
|
||||
reflection_data.N = N;
|
||||
reflection_data.roughness = roughness;
|
||||
|
||||
ClosureRefraction refraction_data;
|
||||
refraction_data.weight = (1.0 - fresnel) * weight;
|
||||
refraction_data.color = color.rgb * btdf;
|
||||
refraction_data.weight = bsdf.x * weight;
|
||||
refraction_data.color = color.rgb;
|
||||
refraction_data.N = N;
|
||||
refraction_data.roughness = roughness;
|
||||
refraction_data.ior = ior;
|
||||
|
|
|
@ -64,9 +64,9 @@ void node_bsdf_principled(vec4 base_color,
|
|||
vec3 V = cameraVec(g_data.P);
|
||||
float NV = dot(N, V);
|
||||
|
||||
float fresnel = (do_multiscatter != 0.0) ? btdf_lut(NV, roughness, ior).y : F_eta(ior, NV);
|
||||
float glass_reflection_weight = fresnel * transmission;
|
||||
float glass_transmission_weight = (1.0 - fresnel) * transmission;
|
||||
vec2 glass_bsdf = btdf_lut(NV, roughness, ior, do_multiscatter);
|
||||
float glass_reflection_weight = glass_bsdf.y * transmission;
|
||||
float glass_transmission_weight = glass_bsdf.x * transmission;
|
||||
|
||||
vec3 base_color_tint = tint_from_color(base_color.rgb);
|
||||
|
||||
|
@ -144,9 +144,7 @@ void node_bsdf_principled(vec4 base_color,
|
|||
/* Refraction. */
|
||||
ClosureRefraction refraction_data;
|
||||
refraction_data.weight = glass_transmission_weight * weight;
|
||||
float btdf = (do_multiscatter != 0.0) ? 1.0 : btdf_lut(NV, roughness, ior).x;
|
||||
|
||||
refraction_data.color = base_color.rgb * btdf;
|
||||
refraction_data.color = base_color.rgb;
|
||||
refraction_data.N = N;
|
||||
refraction_data.roughness = roughness;
|
||||
refraction_data.ior = ior;
|
||||
|
|
Loading…
Reference in New Issue