Eevee: Principled BSDF: Add support for the sheen parameter

This is a rough (but fast) approximation that still match cycles reference
in common case.

In practice, it's just adding more of the diffuse light computed for the
diffuse contribution.
This commit is contained in:
Clément Foucault 2018-08-09 15:03:15 +02:00
parent 2b41b208c7
commit ddc2796e4d
1 changed files with 36 additions and 9 deletions

View File

@ -1065,17 +1065,29 @@ float floorfrac(float x, out int i)
/* bsdfs */
vec3 tint_from_color(vec3 color)
{
float lum = dot(color, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
return (lum > 0) ? color / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
}
void convert_metallic_to_specular_tinted(
vec3 basecol, float metallic, float specular_fac, float specular_tint,
vec3 basecol, vec3 basecol_tint, float metallic, float specular_fac, float specular_tint,
out vec3 diffuse, out vec3 f0)
{
float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
vec3 tmp_col = mix(vec3(1.0), tint, specular_tint);
vec3 tmp_col = mix(vec3(1.0), basecol_tint, specular_tint);
f0 = mix((0.08 * specular_fac) * tmp_col, basecol, metallic);
diffuse = basecol * (1.0 - metallic);
}
vec3 principled_sheen(float NV, vec3 basecol_tint, float sheen_tint)
{
float f = 1.0 - NV;
/* Empirical approximation (manual curve fitting). Can be refined. */
float sheen = f*f*f*0.077 + f*0.01 + 0.00026;
return sheen * mix(vec3(1.0), basecol_tint, sheen_tint);
}
#ifndef VOLUMETRICS
void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
{
@ -1137,16 +1149,21 @@ void node_bsdf_principled(
transmission = saturate(transmission);
float dielectric = 1.0 - metallic;
transmission *= dielectric;
sheen *= dielectric;
subsurface_color *= dielectric;
vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
vec3 ctint = tint_from_color(base_color.rgb);
convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
float NV = dot(N, cameraVec);
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
/* Far from being accurate, but 2 glossy evaluation is too expensive.
* Most noticeable difference is at grazing angles since the bsdf lut
* f0 color interpolation is done on top of this interpolation. */
vec3 f0_glass = mix(vec3(1.0), base_color.rgb, specular_tint);
float fresnel = F_eta(ior, dot(N, cameraVec));
float fresnel = F_eta(ior, NV);
vec3 spec_col = F_color_blend(ior, fresnel, f0_glass) * fresnel;
f0 = mix(f0, spec_col, transmission);
@ -1164,6 +1181,7 @@ void node_bsdf_principled(
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_refr;
result.radiance += out_diff * out_sheen; /* Coarse approx. */
#ifndef USE_SSS
result.radiance += (out_diff + out_trans) * mixed_ss_base_color * (1.0 - transmission);
#endif
@ -1192,13 +1210,17 @@ void node_bsdf_principled_dielectric(
float dielectric = 1.0 - metallic;
vec3 diffuse, f0, out_diff, out_spec, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
vec3 ctint = tint_from_color(base_color.rgb);
convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
float NV = dot(N, cameraVec);
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
eevee_closure_default(N, diffuse, f0, int(ssr_id), roughness, 1.0, out_diff, out_spec, ssr_spec);
vec3 vN = normalize(mat3(ViewMatrix) * N);
result = CLOSURE_DEFAULT;
result.radiance = out_spec + out_diff * diffuse;
result.radiance = out_spec + out_diff * (diffuse + out_sheen);
result.ssr_data = vec4(ssr_spec, roughness);
result.ssr_normal = normal_encode(vN, viewCameraVec);
result.ssr_id = int(ssr_id);
@ -1250,12 +1272,16 @@ void node_bsdf_principled_subsurface(
metallic = saturate(metallic);
vec3 diffuse, f0, out_diff, out_spec, out_trans, ssr_spec;
convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
vec3 ctint = tint_from_color(base_color.rgb);
convert_metallic_to_specular_tinted(base_color.rgb, ctint, metallic, specular, specular_tint, diffuse, f0);
subsurface_color = subsurface_color * (1.0 - metallic);
vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface);
float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface;
float NV = dot(N, cameraVec);
vec3 out_sheen = sheen * principled_sheen(NV, ctint, sheen_tint);
eevee_closure_skin(N, mixed_ss_base_color, f0, int(ssr_id), roughness, 1.0, sss_scalef,
out_diff, out_trans, out_spec, ssr_spec);
@ -1276,6 +1302,7 @@ void node_bsdf_principled_subsurface(
#else
result.radiance += (out_diff + out_trans) * mixed_ss_base_color;
#endif
result.radiance += out_diff * out_sheen;
}
void node_bsdf_principled_glass(