From def9b762070131979905affb36e10efdb3cc42d2 Mon Sep 17 00:00:00 2001 From: Weizhen Huang Date: Fri, 22 Sep 2023 16:56:44 +0200 Subject: [PATCH] Shader: Change specular tint in Principled BSDF from float to color For more artistic control. Tints the reflection of dielectric materials at normal incidence. Ref #99447 Pull Request: https://projects.blender.org/blender/blender/pulls/112192 --- .../osl/shaders/node_principled_bsdf.osl | 19 +++-- intern/cycles/kernel/svm/closure.h | 22 +++--- intern/cycles/scene/shader_nodes.cpp | 2 +- intern/cycles/scene/shader_nodes.h | 2 +- .../modules/bpy_extras/node_shader_utils.py | 11 +-- .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_400.cc | 69 +++++++++++++++++++ .../eevee/shaders/closure_type_lib.glsl | 10 ++- .../eevee/shaders/common_utiltex_lib.glsl | 55 +++++++++++---- .../eevee/shaders/volumetric_vert.glsl | 15 ++++ .../shaders/eevee_nodetree_lib.glsl | 59 +++++++++++----- .../gpu_shader_material_principled.glsl | 36 +++++----- .../nodes/node_shader_bsdf_principled.cc | 9 ++- 13 files changed, 225 insertions(+), 86 deletions(-) diff --git a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl index bca1a709a7f..1e36b447b93 100644 --- a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl +++ b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl @@ -15,7 +15,7 @@ shader node_principled_bsdf(string distribution = "multi_ggx", float SubsurfaceAnisotropy = 0.0, float Metallic = 0.0, float Specular = 0.5, - float SpecularTint = 0.0, + color SpecularTint = color(1.0), color MetallicTint = 1.0, float Roughness = 0.5, float Anisotropic = 0.0, @@ -68,14 +68,9 @@ shader node_principled_bsdf(string distribution = "multi_ggx", BSDF = mix(BSDF, BaseColor * SubsurfBSDF, Subsurface); } - color f0 = color(F0_from_ior(IOR)); - color f90 = color(1.0); - /* Apply specular tint */ - float m_cdlum = luminance(BaseColor); - color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : color(1.0); - color specTint = mix(color(1.0), m_ctint, SpecularTint); - f0 *= (specTint * 2.0 * Specular); + color f0 = F0_from_ior(IOR) * SpecularTint * 2.0 * Specular; + color f90 = color(1.0); BSDF = layer( generalized_schlick_bsdf( @@ -85,12 +80,14 @@ shader node_principled_bsdf(string distribution = "multi_ggx", closure color TransmissionBSDF = 0; if (Metallic < 1.0 && Transmission > 0.0) { - color reflectTint = mix(color(1.0), BaseColor, SpecularTint); float eta = max(IOR, 1e-5); eta = backfacing() ? 1.0 / eta : eta; - TransmissionBSDF = dielectric_bsdf( - Normal, vector(0.0), reflectTint, sqrt(BaseColor), r2, r2, eta, distribution); + color f0 = F0_from_ior(eta) * SpecularTint; + color f90 = color(1.0); + + TransmissionBSDF = generalized_schlick_bsdf( + Normal, vector(0.0), color(1.0), sqrt(BaseColor), r2, r2, f0, f90, -eta, distribution), BSDF = mix(BSDF, TransmissionBSDF, clamp(Transmission, 0.0, 1.0)); } diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 574bb6191fe..50f1900a77c 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -105,7 +105,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float subsurface = param2; float specular = stack_load_float(stack, specular_offset); float roughness = stack_load_float(stack, roughness_offset); - float specular_tint = stack_load_float(stack, specular_tint_offset); + Spectrum specular_tint = rgb_to_spectrum(stack_load_float3(stack, specular_tint_offset)); float anisotropic = stack_load_float(stack, anisotropic_offset); float sheen = stack_load_float(stack, sheen_offset); float3 sheen_tint = stack_load_float3(stack, sheen_tint_offset); @@ -287,9 +287,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (glass_caustics && transmission > CLOSURE_WEIGHT_CUTOFF) { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), transmission * weight); - ccl_private FresnelDielectricTint *fresnel = - (bsdf != NULL) ? (ccl_private FresnelDielectricTint *)closure_alloc_extra( - sd, sizeof(FresnelDielectricTint)) : + ccl_private FresnelGeneralizedSchlick *fresnel = + (bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra( + sd, sizeof(FresnelGeneralizedSchlick)) : NULL; if (bsdf && fresnel) { @@ -299,14 +299,16 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; - fresnel->reflection_tint = mix( - one_spectrum(), rgb_to_spectrum(base_color), specular_tint); + fresnel->f0 = F0_from_ior(eta) * specular_tint; + fresnel->f90 = one_spectrum(); + fresnel->exponent = -eta; + fresnel->reflection_tint = one_spectrum(); fresnel->transmission_tint = sqrt(rgb_to_spectrum(base_color)); /* setup bsdf */ sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); - bsdf_microfacet_setup_fresnel_dielectric_tint(kg, bsdf, sd, fresnel, is_multiggx); + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx); /* Attenuate other components */ weight *= (1.0f - transmission); @@ -329,11 +331,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, bsdf->alpha_x = alpha_x; bsdf->alpha_y = alpha_y; - float m_cdlum = linear_rgb_to_gray(kg, base_color); - float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : one_float3(); - float3 specTint = mix(one_spectrum(), rgb_to_spectrum(m_ctint), specular_tint); - - fresnel->f0 = F0_from_ior(eta) * 2.0f * specular * specTint; + fresnel->f0 = F0_from_ior(eta) * 2.0f * specular * specular_tint; fresnel->f90 = one_spectrum(); fresnel->exponent = -eta; fresnel->reflection_tint = one_spectrum(); diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 12d2d4850da..a34b7188814 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -2707,7 +2707,7 @@ NODE_DEFINE(PrincipledBsdfNode) SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f); SOCKET_IN_FLOAT(specular, "Specular", 0.0f); SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f); - SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f); + SOCKET_IN_COLOR(specular_tint, "Specular Tint", one_float3()); SOCKET_IN_COLOR(metallic_tint, "Metallic Tint", one_float3()); SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index 097d7540250..2948dd52931 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -527,7 +527,7 @@ class PrincipledBsdfNode : public BsdfBaseNode { NODE_SOCKET_API(float, subsurface) NODE_SOCKET_API(float, specular) NODE_SOCKET_API(float, roughness) - NODE_SOCKET_API(float, specular_tint) + NODE_SOCKET_API(float3, specular_tint) NODE_SOCKET_API(float3, metallic_tint) NODE_SOCKET_API(float, anisotropic) NODE_SOCKET_API(float, sheen) diff --git a/scripts/modules/bpy_extras/node_shader_utils.py b/scripts/modules/bpy_extras/node_shader_utils.py index 97005d7d0e6..ce600999dea 100644 --- a/scripts/modules/bpy_extras/node_shader_utils.py +++ b/scripts/modules/bpy_extras/node_shader_utils.py @@ -294,14 +294,15 @@ class PrincipledBSDFWrapper(ShaderWrapper): def specular_tint_get(self): if not self.use_nodes or self.node_principled_bsdf is None: - return 0.0 - return self.node_principled_bsdf.inputs["Specular Tint"].default_value + return Color((0.0, 0.0, 0.0)) + return rgba_to_rgb(self.node_principled_bsdf.inputs["Specular Tint"].default_value) @_set_check - def specular_tint_set(self, value): - value = values_clamp(value, 0.0, 1.0) + def specular_tint_set(self, color): + color = values_clamp(color, 0.0, 1.0) + color = rgb_to_rgba(color) if self.use_nodes and self.node_principled_bsdf is not None: - self.node_principled_bsdf.inputs["Specular Tint"].default_value = value + self.node_principled_bsdf.inputs["Specular Tint"].default_value = color specular_tint = property(specular_tint_get, specular_tint_set) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index a6cfd3a8b13..a61367fc256 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 24 +#define BLENDER_FILE_SUBVERSION 25 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index 86d678fb9fa..7ec4879a59b 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -905,6 +905,65 @@ static void version_node_group_split_socket(bNodeTreeInterface &tree_interface, csocket->flag &= ~NODE_INTERFACE_SOCKET_OUTPUT; } +/* Convert specular tint in Principled BSDF. */ +static void version_principled_bsdf_specular_tint(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type != SH_NODE_BSDF_PRINCIPLED) { + continue; + } + bNodeSocket *specular_tint_sock = nodeFindSocket(node, SOCK_IN, "Specular Tint"); + if (specular_tint_sock->type == SOCK_RGBA) { + /* Node is already updated. */ + continue; + } + + bNodeSocket *base_color_sock = nodeFindSocket(node, SOCK_IN, "Base Color"); + float specular_tint_old = *version_cycles_node_socket_float_value(specular_tint_sock); + float *base_color = version_cycles_node_socket_rgba_value(base_color_sock); + + /* Change socket type to Color. */ + nodeModifySocketTypeStatic(ntree, node, specular_tint_sock, SOCK_RGBA, 0); + + static float one[] = {1.0f, 1.0f, 1.0f, 1.0f}; + + /* If any of the two inputs is dynamic, we add a Mix node. */ + if (base_color_sock->link || specular_tint_sock->link) { + bNode *mix = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX); + static_cast(mix->storage)->data_type = SOCK_RGBA; + mix->locx = node->locx - 170; + mix->locy = node->locy - 120; + + bNodeSocket *a_in = nodeFindSocket(mix, SOCK_IN, "A_Color"); + bNodeSocket *b_in = nodeFindSocket(mix, SOCK_IN, "B_Color"); + bNodeSocket *fac_in = nodeFindSocket(mix, SOCK_IN, "Factor_Float"); + bNodeSocket *result_out = nodeFindSocket(mix, SOCK_OUT, "Result_Color"); + + copy_v4_v4(version_cycles_node_socket_rgba_value(a_in), one); + copy_v4_v4(version_cycles_node_socket_rgba_value(b_in), base_color); + *version_cycles_node_socket_float_value(fac_in) = specular_tint_old; + + if (base_color_sock->link) { + nodeAddLink( + ntree, base_color_sock->link->fromnode, base_color_sock->link->fromsock, mix, b_in); + } + if (specular_tint_sock->link) { + nodeAddLink(ntree, + specular_tint_sock->link->fromnode, + specular_tint_sock->link->fromsock, + mix, + fac_in); + nodeRemLink(ntree, specular_tint_sock->link); + } + nodeAddLink(ntree, mix, result_out, node, specular_tint_sock); + } + + float *specular_tint = version_cycles_node_socket_rgba_value(specular_tint_sock); + /* Mix the fixed values. */ + interp_v4_v4v4(specular_tint, one, base_color, specular_tint_old); + } +} + void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) { @@ -1359,6 +1418,16 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 25)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + /* Convert specular tint on the Principled BSDF. */ + version_principled_bsdf_specular_tint(ntree); + } + } + FOREACH_NODETREE_END; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl index f30bf4715f6..039f20fbf73 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl @@ -93,7 +93,15 @@ float ambient_occlusion_eval(vec3 normal, vec3 safe_normalize(vec3 N); float fast_sqrt(float a); vec3 cameraVec(vec3 P); -vec2 bsdf_lut(float a, float b, float c, float d); +void bsdf_lut(vec3 F0, + vec3 F90, + vec3 transmission_tint, + float cos_theta, + float roughness, + float ior, + float do_multiscatter, + out vec3 reflectance, + out vec3 transmittance); 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); diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index d6b541bf403..6fe14a40059 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -101,24 +101,35 @@ vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior) return coords; } -/* Computes the reflectance and transmittance based on the BSDF LUT. */ -vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter) +/* Computes the reflectance and transmittance based on the tint (`f0`, `f90`, `transmission_tint`) + * and the BSDF LUT. */ +void bsdf_lut(vec3 F0, + vec3 F90, + vec3 transmission_tint, + float cos_theta, + float roughness, + float ior, + float do_multiscatter, + out vec3 reflectance, + out vec3 transmittance) { if (ior == 1.0) { - return vec2(0.0, 1.0); + reflectance = vec3(0.0); + transmittance = transmission_tint; + return; } vec2 split_sum; float transmission_factor; - float F0 = F0_from_ior(ior); - float F90 = 1.0; - if (ior >= 1.0) { + if (ior > 1.0) { split_sum = brdf_lut(cos_theta, roughness); transmission_factor = sample_3D_texture(utilTex, lut_coords_btdf(cos_theta, roughness, ior)).a; /* 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`. */ - F90 = saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0)); + if (all(equal(F90, vec3(1.0)))) { + F90 = vec3(saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0))); + } } else { vec3 bsdf = sample_3D_texture(utilTex, lut_coords_bsdf(cos_theta, roughness, ior)).rgb; @@ -126,20 +137,34 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter transmission_factor = bsdf.b; } - float reflectance = F_brdf_single_scatter(vec3(F0), vec3(F90), split_sum).r; - float transmittance = (1.0 - F0) * transmission_factor; + reflectance = F_brdf_single_scatter(F0, F90, split_sum); + transmittance = (vec3(1.0) - F0) * transmission_factor * transmission_tint; if (do_multiscatter != 0.0) { - float Ess = F0 * split_sum.x + split_sum.y + (1.0 - F0) * transmission_factor; - /* TODO: maybe add saturation for higher roughness similar as in `F_brdf_multi_scatter()`. - * However, it is not necessarily desirable that the users see a different color than they - * picked. */ - float scale = 1.0 / Ess; + float real_F0 = F0_from_ior(ior); + float Ess = real_F0 * split_sum.x + split_sum.y + (1.0 - real_F0) * transmission_factor; + float Ems = 1.0 - Ess; + /* Assume that the transmissive tint makes up most of the overall color if it's not zero. */ + vec3 Favg = all(equal(transmission_tint, vec3(0.0))) ? F0 + (F90 - F0) / 21.0 : + transmission_tint; + + vec3 scale = 1.0 / (1.0 - Ems * Favg); reflectance *= scale; transmittance *= scale; } - return vec2(reflectance, transmittance); + return; +} + +/* Computes the reflectance and transmittance based on the BSDF LUT. */ +vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter) +{ + float F0 = F0_from_ior(ior); + vec3 color = vec3(1.0); + vec3 reflectance, transmittance; + bsdf_lut( + F0, color, color, cos_theta, roughness, ior, do_multiscatter, reflectance, transmittance); + return vec2(reflectance.r, transmittance.r); } /** \} */ diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl index 973834f7008..7700641466d 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl @@ -43,6 +43,21 @@ vec2 bsdf_lut(float a, float b, float c, float d) return vec2(0.0); } +void bsdf_lut(vec3 F0, + vec3 F90, + vec3 transmission_tint, + float cos_theta, + float roughness, + float ior, + float do_multiscatter, + out vec3 reflectance, + out vec3 transmittance) +{ + reflectance = vec3(0.0); + transmittance = vec3(0.0); + return; +} + vec2 brdf_lut(float a, float b) { return vec2(0.0); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl index 20984d36e74..0fedbcd315f 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl @@ -323,26 +323,37 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior) return vec3(sqrt((ior - 1.0) / (ior + 1.0)), sqrt(1.0 - cos_theta), roughness); } -/* Computes the reflectance and transmittance based on the BSDF LUT. */ -vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter) +/* Computes the reflectance and transmittance based on the tint (`f0`, `f90`, `transmission_tint`) + * and the BSDF LUT. */ +void bsdf_lut(vec3 F0, + vec3 F90, + vec3 transmission_tint, + float cos_theta, + float roughness, + float ior, + float do_multiscatter, + out vec3 reflectance, + out vec3 transmittance) { #ifdef EEVEE_UTILITY_TX if (ior == 1.0) { - return vec2(0.0, 1.0); + reflectance = vec3(0.0); + transmittance = transmission_tint; + return; } vec2 split_sum; float transmission_factor; - float F0 = F0_from_ior(ior); - float F90 = 1.0; - if (ior >= 1.0) { + if (ior > 1.0) { split_sum = brdf_lut(cos_theta, roughness); vec3 coords = lut_coords_btdf(cos_theta, roughness, ior); transmission_factor = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z).a; /* 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`. */ - F90 = saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0)); + if (all(equal(F90, vec3(1.0)))) { + F90 = vec3(saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0))); + } } else { vec3 coords = lut_coords_bsdf(cos_theta, roughness, ior); @@ -351,23 +362,37 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter transmission_factor = bsdf.b; } - float reflectance = F_brdf_single_scatter(vec3(F0), vec3(F90), split_sum).r; - float transmittance = (1.0 - F0) * transmission_factor; + reflectance = F_brdf_single_scatter(F0, F90, split_sum); + transmittance = (vec3(1.0) - F0) * transmission_factor * transmission_tint; if (do_multiscatter != 0.0) { - float Ess = F0 * split_sum.x + split_sum.y + (1.0 - F0) * transmission_factor; - /* TODO: maybe add saturation for higher roughness similar as in `F_brdf_multi_scatter()`. - * However, it is not necessarily desirable that the users see a different color than they - * picked. */ - float scale = 1.0 / Ess; + float real_F0 = F0_from_ior(ior); + float Ess = real_F0 * split_sum.x + split_sum.y + (1.0 - real_F0) * transmission_factor; + float Ems = 1.0 - Ess; + /* Assume that the transmissive tint makes up most of the overall color if it's not zero. */ + vec3 Favg = all(equal(transmission_tint, vec3(0.0))) ? F0 + (F90 - F0) / 21.0 : + transmission_tint; + + vec3 scale = 1.0 / (1.0 - Ems * Favg); reflectance *= scale; transmittance *= scale; } - - return vec2(reflectance, transmittance); #else - return vec2(0.0); + reflectance = vec3(0.0); + transmittance = vec3(0.0); #endif + return; +} + +/* Computes the reflectance and transmittance based on the BSDF LUT. */ +vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter) +{ + float F0 = F0_from_ior(ior); + vec3 color = vec3(1.0); + vec3 reflectance, transmittance; + bsdf_lut( + F0, color, color, cos_theta, roughness, ior, do_multiscatter, reflectance, transmittance); + return vec2(reflectance.r, transmittance.r); } #ifdef EEVEE_MATERIAL_STUBS 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 a4836956743..75885cfc8d8 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -33,7 +33,7 @@ void node_bsdf_principled(vec4 base_color, float subsurface_anisotropy, vec4 metallic_tint, float specular, - float specular_tint, + vec4 specular_tint, float anisotropic, float anisotropic_rotation, vec3 T, @@ -110,10 +110,11 @@ void node_bsdf_principled(vec4 base_color, ClosureReflection reflection_data; reflection_data.N = N; reflection_data.roughness = roughness; - vec2 split_sum = brdf_lut(NV, roughness); + if (true) { vec3 f0 = base_color.rgb; vec3 f90 = vec3(1.0); + vec2 split_sum = brdf_lut(NV, roughness); vec3 metallic_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : F_brdf_single_scatter(f0, f90, split_sum); reflection_data.color = weight * metallic * metallic_brdf; @@ -123,15 +124,18 @@ void node_bsdf_principled(vec4 base_color, /* Transmission component */ ClosureRefraction refraction_data; - /* TODO: change `specular_tint` to rgb. */ - vec3 reflection_tint = mix(vec3(1.0), base_color.rgb, specular_tint); + vec3 reflection_tint = specular_tint.rgb; if (true) { - vec2 bsdf = bsdf_lut(NV, roughness, ior, do_multiscatter); + vec3 F0 = vec3(F0_from_ior(ior)) * reflection_tint; + vec3 F90 = vec3(1.0); + vec3 reflectance, transmittance; + bsdf_lut( + F0, F90, base_color.rgb, NV, roughness, ior, do_multiscatter, reflectance, transmittance); - reflection_data.color += weight * transmission * bsdf.x * reflection_tint; + reflection_data.color += weight * transmission * reflectance; - refraction_data.weight = weight * transmission * bsdf.y; - refraction_data.color = base_color.rgb * coat_tint.rgb; + refraction_data.weight = weight * transmission; + refraction_data.color = transmittance * coat_tint.rgb; refraction_data.N = N; refraction_data.roughness = roughness; refraction_data.ior = ior; @@ -141,17 +145,15 @@ void node_bsdf_principled(vec4 base_color, /* Specular component */ if (true) { - vec3 f0 = vec3(F0_from_ior(ior)); - /* 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`. */ - vec3 f90 = sqrt(saturate(f0 / 0.02)); - f0 *= 2.0 * specular * reflection_tint; + vec3 F0 = vec3(F0_from_ior(ior)) * 2.0 * specular * reflection_tint; + F0 = clamp(F0, vec3(0.0), vec3(1.0)); + vec3 F90 = vec3(1.0); + vec3 reflectance, unused; + bsdf_lut(F0, F90, vec3(0.0), NV, roughness, ior, do_multiscatter, reflectance, unused); - vec3 specular_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) : - F_brdf_single_scatter(f0, f90, split_sum); - reflection_data.color += weight * specular_brdf; + reflection_data.color += weight * reflectance; /* Attenuate lower layers */ - weight *= (1.0 - max_v3(specular_brdf)); + weight *= (1.0 - max_v3(reflectance)); } /* Diffuse component */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index f94efdcb10a..f6c75b387d5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -112,11 +112,10 @@ static void node_declare(NodeDeclarationBuilder &b) .max(1.0f) .subtype(PROP_FACTOR); #define SOCK_SPECULAR_ID 14 - spec.add_input("Specular Tint") - .default_value(0.0f) - .min(0.0f) - .max(1.0f) - .subtype(PROP_FACTOR); + spec.add_input("Specular Tint") + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .description( + "Tint of the specular reflection at normal incidence. Affects dielectric materials"); #define SOCK_SPECULAR_TINT_ID 15 spec.add_input("Anisotropic") .default_value(0.0f)