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 /source/blender/gpu/shaders | |
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.
Diffstat (limited to 'source/blender/gpu/shaders')
-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( |