diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-08-09 16:03:15 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-08-09 17:46:03 +0300 |
commit | ddc2796e4d872fe3c063570ae735421f52bb56b9 (patch) | |
tree | 385f8684354dca46d8ecf0eab1e2c08445be416f | |
parent | 2b41b208c7e5e74a0a5fe043f4bfab2a122a9ed1 (diff) |
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.
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_material.glsl | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index c9564a21d15..56fa6291c65 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -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( |