diff options
8 files changed, 102 insertions, 45 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index deedde64194..3560ae62a84 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -74,34 +74,36 @@ vec3 F_color_blend(float eta, float fresnel, vec3 f0_color) return mix(f0_color, vec3(1.0), fac); } -/* Fresnel */ -vec3 F_schlick(vec3 f0, float cos_theta) -{ - float fac = 1.0 - cos_theta; - float fac2 = fac * fac; - fac = fac2 * fac2 * fac; - - /* Unreal specular matching : if specular color is below 2% intensity, - * (using green channel for intensity) treat as shadowning */ - return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac + (1.0 - fac) * f0; -} - -/* Fresnel approximation for LTC area lights (not MRP) */ -vec3 F_area(vec3 f0, vec3 f90, vec2 lut) +/* 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 shadowning */ - return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * f90 + lut.x * f0; + return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * abs(f90) + lut.x * f0; } -/* Fresnel approximation for IBL */ -vec3 F_ibl(vec3 f0, vec3 f90, vec2 lut) +/* Multi-scattering brdf approximation from : + * "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting" + * by Carmelo J. Fdez-Agüera. */ +vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut) { - /* Unreal specular matching : if specular color is below 2% intensity, - * treat as shadowning */ - return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y * f90 + lut.x * f0; + vec3 FssEss = F_brdf_single_scatter(f0, f90, lut); + /* Hack to avoid many more shader variations. */ + if (f90.g < 0.0) { + return FssEss; + } + + 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; } +#define F_brdf(f0, f90, lut) F_brdf_multi_scatter(f0, f90, lut) + /* GGX */ float D_ggx_opti(float NH, float a2) { diff --git a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl index bf33caf9854..613b48ff9b8 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_lit_lib.glsl @@ -250,12 +250,12 @@ void CLOSURE_NAME(vec3 N # ifdef CLOSURE_GLOSSY vec2 brdf_lut_lights = texture(utilTex, vec3(lut_uv, 1.0)).ba; - out_spec *= F_area(f0, f90, brdf_lut_lights.xy); + out_spec *= F_brdf(f0, f90, brdf_lut_lights.xy); # endif # ifdef CLOSURE_CLEARCOAT vec2 brdf_lut_lights_clear = texture(utilTex, vec3(lut_uv_clear, 1.0)).ba; - out_spec_clear *= F_area(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy); + out_spec_clear *= F_brdf(vec3(0.04), vec3(1.0), brdf_lut_lights_clear.xy); out_spec += out_spec_clear * C_intensity; # endif @@ -449,7 +449,7 @@ void CLOSURE_NAME(vec3 N /* This factor is outputted to be used by SSR in order * to match the intensity of the regular reflections. */ - ssr_spec = F_ibl(f0, f90, brdf_lut); + ssr_spec = F_brdf(f0, f90, brdf_lut); float spec_occlu = specular_occlusion(NV, final_ao, roughness); /* The SSR pass recompute the occlusion to not apply it to the SSR */ @@ -470,7 +470,7 @@ void CLOSURE_NAME(vec3 N NV = dot(C_N, V); vec2 C_uv = lut_coords(NV, C_roughness); vec2 C_brdf_lut = texture(utilTex, vec3(C_uv, 1.0)).rg; - vec3 C_fresnel = F_ibl(vec3(0.04), vec3(1.0), C_brdf_lut) * + vec3 C_fresnel = F_brdf(vec3(0.04), vec3(1.0), C_brdf_lut) * specular_occlusion(NV, final_ao, C_roughness); out_spec += C_spec_accum.rgb * C_fresnel * C_intensity; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl index e1137d9d0e7..8131958313b 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl @@ -5,11 +5,12 @@ void node_bsdf_anisotropic(vec4 color, float rotation, vec3 N, vec3 T, + float use_multiscatter, out Closure result) { - node_bsdf_glossy(color, roughness, N, -1, result); + node_bsdf_glossy(color, roughness, N, -1, use_multiscatter, result); } #else /* Stub anisotropic because it is not compatible with volumetrics. */ -# define node_bsdf_anisotropic(a, b, c, d, e, f, g) (g = CLOSURE_DEFAULT) +# define node_bsdf_anisotropic(a, b, c, d, e, f, g, result) (result = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl index 5ea22f3e0b4..36675cf720d 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_glossy.glsl @@ -1,10 +1,18 @@ #ifndef VOLUMETRICS -void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result) +void node_bsdf_glossy( + vec4 color, float roughness, vec3 N, float use_multiscatter, float ssr_id, out Closure result) { N = normalize(N); vec3 out_spec, ssr_spec; - eevee_closure_glossy( - N, vec3(1.0), vec3(1.0), int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec); + eevee_closure_glossy(N, + vec3(1.0), + use_multiscatter != 0.0 ? vec3(1.0) : vec3(-1.0), /* HACK */ + int(ssr_id), + roughness, + 1.0, + true, + out_spec, + ssr_spec); vec3 vN = mat3(ViewMatrix) * N; result = CLOSURE_DEFAULT; result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec) * color.rgb; @@ -12,5 +20,5 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Clo } #else /* Stub glossy because it is not compatible with volumetrics. */ -# define node_bsdf_glossy(a, b, c, d, e) (e = CLOSURE_DEFAULT) +# define node_bsdf_glossy(a, b, c, d, e, result) (result = CLOSURE_DEFAULT) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index f7803155934..3fc40fd88e5 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -60,6 +60,7 @@ void node_bsdf_principled(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -107,7 +108,9 @@ void node_bsdf_principled(vec4 base_color, eevee_closure_principled(N, mixed_ss_base_color, f0, - f90, + /* HACK: Pass the multiscatter flag as the sign to not add closure + * variations or increase register usage. */ + (use_multiscatter != 0.0) ? f90 : -f90, int(ssr_id), roughness, CN, @@ -168,6 +171,7 @@ void node_bsdf_principled_dielectric(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -188,8 +192,19 @@ void node_bsdf_principled_dielectric(vec4 base_color, float NV = dot(N, cameraVec); principled_sheen(NV, ctint, sheen, sheen_tint, out_sheen, sheen_color); - eevee_closure_default( - N, diffuse, f0, f90, int(ssr_id), roughness, 1.0, true, out_diff, out_spec, ssr_spec); + eevee_closure_default(N, + diffuse, + f0, + /* HACK: Pass the multiscatter flag as the sign to not add closure + * variations or increase register usage. */ + (use_multiscatter != 0.0) ? f90 : -f90, + int(ssr_id), + roughness, + 1.0, + true, + out_diff, + out_spec, + ssr_spec); result = CLOSURE_DEFAULT; result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); @@ -226,6 +241,7 @@ void node_bsdf_principled_metallic(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -236,8 +252,17 @@ void node_bsdf_principled_metallic(vec4 base_color, vec3 f90 = mix(vec3(1.0), base_color.rgb, (1.0 - specular) * metallic); - eevee_closure_glossy( - N, base_color.rgb, f90, int(ssr_id), roughness, 1.0, true, out_spec, ssr_spec); + eevee_closure_glossy(N, + base_color.rgb, + /* HACK: Pass the multiscatter flag as the sign to not add closure + * variations or increase register usage. */ + (use_multiscatter != 0.0) ? f90 : -f90, + int(ssr_id), + roughness, + 1.0, + true, + out_spec, + ssr_spec); result = CLOSURE_DEFAULT; result.radiance = render_pass_glossy_mask(vec3(1.0), out_spec); @@ -272,6 +297,7 @@ void node_bsdf_principled_clearcoat(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -284,7 +310,9 @@ void node_bsdf_principled_clearcoat(vec4 base_color, eevee_closure_clearcoat(N, base_color.rgb, - f90, + /* HACK: Pass the multiscatter flag as the sign to not add closure + * variations or increase register usage. */ + (use_multiscatter != 0.0) ? f90 : -f90, int(ssr_id), roughness, CN, @@ -331,6 +359,7 @@ void node_bsdf_principled_subsurface(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -357,7 +386,9 @@ void node_bsdf_principled_subsurface(vec4 base_color, eevee_closure_skin(N, mixed_ss_base_color, f0, - f90, + /* HACK: Pass the multiscatter flag as the sign to not add closure variations + or increase register usage. */ + (use_multiscatter != 0.0) ? f90 : -f90, int(ssr_id), roughness, 1.0, @@ -405,6 +436,7 @@ void node_bsdf_principled_glass(vec4 base_color, vec3 CN, vec3 T, vec3 I, + float use_multiscatter, float ssr_id, float sss_id, vec3 sss_scale, @@ -450,11 +482,11 @@ void node_bsdf_principled_glass(vec4 base_color, #else /* clang-format off */ /* Stub principled because it is not compatible with volumetrics. */ -# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) -# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_dielectric(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_metallic(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_clearcoat(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_subsurface(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_principled_glass(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, aa, bb, result) (result = CLOSURE_DEFAULT) /* clang-format on */ #endif diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c index b0e17ed7716..7ce085d2c82 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c @@ -53,7 +53,10 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY); - return GPU_stack_link(mat, node, "node_bsdf_anisotropic", in, out); + float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; + + return GPU_stack_link( + mat, node, "node_bsdf_anisotropic", in, out, GPU_constant(&use_multi_scatter)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c index 2bbd260fe0e..13b1b21c7fc 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c @@ -54,7 +54,15 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY); - return GPU_stack_link(mat, node, "node_bsdf_glossy", in, out, GPU_constant(&node->ssr_id)); + float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; + + return GPU_stack_link(mat, + node, + "node_bsdf_glossy", + in, + out, + GPU_constant(&use_multi_scatter), + GPU_constant(&node->ssr_id)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index ccc5198832a..b9f0e793a61 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -172,6 +172,8 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, flag |= GPU_MATFLAG_SSS; } + float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; + GPU_material_flag_set(mat, flag); return GPU_stack_link(mat, @@ -180,6 +182,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, in, out, GPU_builtin(GPU_VIEW_POSITION), + GPU_constant(&use_multi_scatter), GPU_constant(&node->ssr_id), GPU_constant(&node->sss_id), sss_scale); |