diff --git a/intern/cycles/hydra/material.cpp b/intern/cycles/hydra/material.cpp index 2768a420b5a..0c4fd1fd787 100644 --- a/intern/cycles/hydra/material.cpp +++ b/intern/cycles/hydra/material.cpp @@ -139,7 +139,7 @@ class UsdToCycles { {TfToken("diffuseColor"), ustring("base_color")}, {TfToken("emissiveColor"), ustring("emission")}, {TfToken("specularColor"), ustring("specular")}, - {TfToken("clearcoatRoughness"), ustring("clearcoat_roughness")}, + {TfToken("clearcoatRoughness"), ustring("coat_roughness")}, {TfToken("opacity"), ustring("alpha")}, // opacityThreshold // occlusion diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index be3b4db81ec..ff94e3dce24 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -153,7 +153,6 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, *eta = 1.0f; break; case CLOSURE_BSDF_MICROFACET_GGX_ID: - case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: label = bsdf_microfacet_ggx_sample( @@ -284,7 +283,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, *eta = 1.0f; break; case CLOSURE_BSDF_MICROFACET_GGX_ID: - case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: @@ -385,7 +383,6 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg, label = LABEL_TRANSMIT | LABEL_TRANSPARENT; break; case CLOSURE_BSDF_MICROFACET_GGX_ID: - case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -484,7 +481,6 @@ ccl_device_inline eval = bsdf_transparent_eval(sc, sd->wi, wo, pdf); break; case CLOSURE_BSDF_MICROFACET_GGX_ID: - case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: eval = bsdf_microfacet_ggx_eval(sc, Ng, sd->wi, wo, pdf); @@ -555,7 +551,6 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float #if defined(__SVM__) || defined(__OSL__) switch (sc->type) { case CLOSURE_BSDF_MICROFACET_GGX_ID: - case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 78547ff7257..22d4803c7f5 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -377,17 +377,6 @@ ccl_device Spectrum bsdf_microfacet_estimate_albedo(KernelGlobals kg, return albedo; } -/* Generalized Trowbridge-Reitz for clearcoat. */ -ccl_device_forceinline float bsdf_clearcoat_D(float alpha2, float cos_NH) -{ - if (alpha2 >= 1.0f) { - return M_1_PI_F; - } - - const float t = 1.0f + (alpha2 - 1.0f) * cos_NH * cos_NH; - return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); -} - /* Smith shadowing-masking term, here in the non-separable form. * For details, see: * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. @@ -529,18 +518,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc, * harder to compute. */ if (alpha_x == alpha_y || is_transmission) { /* Isotropic. */ float alpha2 = alpha_x * alpha_y; - - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - D = bsdf_clearcoat_D(alpha2, cos_NH); - - /* The masking-shadowing term for clearcoat has a fixed alpha of 0.25 - * => alpha2 = 0.25 * 0.25 */ - alpha2 = 0.0625f; - } - else { - D = bsdf_D(alpha2, cos_NH); - } - + D = bsdf_D(alpha2, cos_NH); lambdaI = bsdf_lambda(alpha2, cos_NI); lambdaO = bsdf_lambda(alpha2, cos_NO); } @@ -687,17 +665,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, const float cos_NH = dot(N, H); const float cos_NO = dot(N, *wo); - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - D = bsdf_clearcoat_D(alpha2, cos_NH); - - /* The masking-shadowing term for clearcoat has a fixed alpha of 0.25 - * => alpha2 = 0.25 * 0.25 */ - alpha2 = 0.0625f; - } - else { - D = bsdf_D(alpha2, cos_NH); - } - + D = bsdf_D(alpha2, cos_NH); lambdaO = bsdf_lambda(alpha2, cos_NO); lambdaI = bsdf_lambda(alpha2, cos_NI); } @@ -831,6 +799,14 @@ ccl_device void bsdf_microfacet_setup_fresnel_constant(KernelGlobals kg, microfacet_ggx_preserve_energy(kg, bsdf, sd, color); } +ccl_device void bsdf_microfacet_setup_fresnel_dielectric(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd) +{ + bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC; + bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true)); +} + /* GGX microfacet with Smith shadow-masking from: * * Microfacet Models for Refraction through Rough Surfaces @@ -856,21 +832,6 @@ ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf) return SD_BSDF | bsdf_microfacet_eval_flag(bsdf); } -ccl_device int bsdf_microfacet_ggx_clearcoat_setup(KernelGlobals kg, - ccl_private MicrofacetBsdf *bsdf, - ccl_private const ShaderData *sd) -{ - bsdf->alpha_x = saturatef(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; - - bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC; - bsdf->energy_scale = 1.0f; - bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID; - bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true)); - - return SD_BSDF | bsdf_microfacet_eval_flag(bsdf); -} - ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf) { bsdf->alpha_x = saturatef(bsdf->alpha_x); diff --git a/intern/cycles/kernel/osl/closures_setup.h b/intern/cycles/kernel/osl/closures_setup.h index 96514855d49..05894d7d814 100644 --- a/intern/cycles/kernel/osl/closures_setup.h +++ b/intern/cycles/kernel/osl/closures_setup.h @@ -420,10 +420,6 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg, else if (closure->distribution == make_string("ashikhmin_shirley", 11318482998918370922ull)) { sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); } - /* Clearcoat */ - else if (closure->distribution == make_string("clearcoat", 3490136178980547276ull)) { - sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(kg, bsdf, sd); - } /* GGX (either single- or multi-scattering) */ else { if (closure->refract == 1) { diff --git a/intern/cycles/kernel/osl/osl.h b/intern/cycles/kernel/osl/osl.h index 945cbce8fbe..acd6475f8e6 100644 --- a/intern/cycles/kernel/osl/osl.h +++ b/intern/cycles/kernel/osl/osl.h @@ -140,7 +140,7 @@ ccl_device void flatten_closure_tree(KernelGlobals kg, if (stack_size == layer_stack_level) { /* We just finished processing the top layers of a Layer closure, so adjust the weight to * account for the layering. */ - weight *= saturatef(1.0f - reduce_max(layer_albedo / weight)); + weight *= saturatef(1.0f - reduce_max(safe_divide_color(layer_albedo, weight))); layer_stack_level = -1; if (is_zero(weight)) { /* If it's fully occluded, skip the base layer we just popped from the stack and grab diff --git a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl index ae8e485d6fd..24a3192127d 100644 --- a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl +++ b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl @@ -22,12 +22,14 @@ shader node_principled_bsdf(string distribution = "multi_ggx", float Sheen = 0.0, float SheenRoughness = 0.5, color SheenTint = 0.5, - float Clearcoat = 0.0, - float ClearcoatRoughness = 0.03, + float Coat = 0.0, + float CoatRoughness = 0.03, + float CoatIOR = 1.5, + color CoatTint = color(1.0, 1.0, 1.0), float IOR = 1.45, float Transmission = 0.0, normal Normal = N, - normal ClearcoatNormal = N, + normal CoatNormal = N, normal Tangent = normalize(dPdu), output closure color BSDF = 0) { @@ -97,10 +99,18 @@ shader node_principled_bsdf(string distribution = "multi_ggx", BSDF = mix(BSDF, MetallicBSDF, clamp(Metallic, 0.0, 1.0)); } - if (Clearcoat > 1e-5) { - float clearcoat_r2 = ClearcoatRoughness * ClearcoatRoughness; - closure color ClearcoatBSDF = microfacet("clearcoat", ClearcoatNormal, clearcoat_r2, 1.5, 0); - BSDF = layer(0.25 * Clearcoat * ClearcoatBSDF, BSDF); + if (Coat > 1e-5) { + float coat_ior = max(CoatIOR, 1.0); + if (CoatTint != color(1.0)) { + float coat_neta = 1.0 / coat_ior; + float cosNI = dot(I, CoatNormal); + float cosNT = sqrt(1.0 - coat_neta * coat_neta * (1 - cosNI * cosNI)); + BSDF *= pow(CoatTint, Coat / cosNT); + } + float coat_r2 = CoatRoughness * CoatRoughness; + closure color CoatBSDF = dielectric_bsdf( + CoatNormal, vector(0.0), color(1.0), color(0.0), coat_r2, coat_r2, coat_ior, "ggx"); + BSDF = layer(Coat * CoatBSDF, BSDF); } if (Sheen > 1e-5) { diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 6ba19575ea8..df590226411 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -69,8 +69,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, switch (type) { case CLOSURE_BSDF_PRINCIPLED_ID: { uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset, - sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset, - eta_offset, transmission_offset, anisotropic_rotation_offset, pad1; + sheen_offset, sheen_tint_offset, sheen_roughness_offset, coat_offset, + coat_roughness_offset, coat_ior_offset, eta_offset, transmission_offset, + anisotropic_rotation_offset, coat_tint_offset, dummy; uint4 data_node2 = read_node(kg, &offset); float3 T = stack_load_float3(stack, data_node.y); @@ -79,13 +80,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, &roughness_offset, &specular_tint_offset, &anisotropic_offset); - svm_unpack_node_uchar4(data_node.w, - &sheen_offset, - &sheen_tint_offset, - &clearcoat_offset, - &clearcoat_roughness_offset); svm_unpack_node_uchar4( - data_node2.x, &eta_offset, &transmission_offset, &anisotropic_rotation_offset, &pad1); + data_node.w, &sheen_offset, &sheen_tint_offset, &sheen_roughness_offset, &dummy); + svm_unpack_node_uchar4( + data_node2.x, &eta_offset, &transmission_offset, &anisotropic_rotation_offset, &dummy); + svm_unpack_node_uchar4( + data_node2.w, &coat_offset, &coat_roughness_offset, &coat_ior_offset, &coat_tint_offset); // get Disney principled parameters float metallic = saturatef(param1); @@ -96,9 +96,11 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, 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); - float sheen_roughness = stack_load_float(stack, data_node2.w); - float clearcoat = stack_load_float(stack, clearcoat_offset); - float clearcoat_roughness = stack_load_float(stack, clearcoat_roughness_offset); + float sheen_roughness = stack_load_float(stack, sheen_roughness_offset); + float coat = stack_load_float(stack, coat_offset); + float coat_roughness = stack_load_float(stack, coat_roughness_offset); + float coat_ior = fmaxf(stack_load_float(stack, coat_ior_offset), 1.0f); + float3 coat_tint = stack_load_float3(stack, coat_tint_offset); float transmission = saturatef(stack_load_float(stack, transmission_offset)); float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset); float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); @@ -116,12 +118,11 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, __uint_as_float(data_base_color.z), __uint_as_float(data_base_color.w)); - // get the additional clearcoat normal and subsurface scattering radius + // get the additional coat normal and subsurface scattering radius uint4 data_cn_ssr = read_node(kg, &offset); - float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? - stack_load_float3(stack, data_cn_ssr.x) : - sd->N; - clearcoat_normal = maybe_ensure_valid_specular_reflection(sd, clearcoat_normal); + float3 coat_normal = stack_valid(data_cn_ssr.x) ? stack_load_float3(stack, data_cn_ssr.x) : + sd->N; + coat_normal = maybe_ensure_valid_specular_reflection(sd, coat_normal); float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? stack_load_float3(stack, data_cn_ssr.y) : one_float3(); @@ -175,31 +176,58 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, /* Attenuate lower layers */ Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false); - weight *= 1.0f - reduce_max(albedo / weight); + weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight)); } } - /* Second layer: Clearcoat */ - if (reflective_caustics && clearcoat > CLOSURE_WEIGHT_CUTOFF) { + /* Second layer: Coat */ + if (reflective_caustics && coat > CLOSURE_WEIGHT_CUTOFF) { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), 0.25f * clearcoat * weight); + sd, sizeof(MicrofacetBsdf), coat * weight); if (bsdf) { - bsdf->N = clearcoat_normal; + bsdf->N = coat_normal; bsdf->T = zero_float3(); - bsdf->ior = 1.5f; + bsdf->ior = coat_ior; - bsdf->alpha_x = bsdf->alpha_y = sqr(clearcoat_roughness); + bsdf->alpha_x = bsdf->alpha_y = sqr(coat_roughness); /* setup bsdf */ - sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(kg, bsdf, sd); + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + bsdf_microfacet_setup_fresnel_dielectric(kg, bsdf, sd); /* Attenuate lower layers */ Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false); - weight *= 1.0f - reduce_max(albedo / weight); + weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight)); } } + if (coat > CLOSURE_WEIGHT_CUTOFF && !isequal(coat_tint, one_float3())) { + /* Tint is normalized to perpendicular incidence. + * Therefore, if we define the coat thickness as length 1, the length along the ray is + * t = sqrt(1+tan^2(angle(N, I))) = sqrt(1+tan^2(acos(dotNI))) = 1 / dotNI. + * From Beer's law, we have T = exp(-sigma_e * t). + * Therefore, tint = exp(-sigma_e * 1) (per def.), so -sigma_e = log(tint). + * From this, T = exp(log(tint) * t) = exp(log(tint)) ^ t = tint ^ t; + * + * Note that this is only an approximation - it assumes that the outgoing ray + * follows the same angle, and that there aren't multiple internal bounces. + * In particular, things that could be improved: + * - For transmissive materials, there should not be an outgoing path at all if the path + * is transmitted. + * - For rough materials, we could blend towards a view-independent average path length + * (e.g. 2 for diffuse reflection) for the outgoing direction. + * However, there's also an argument to be made for keeping parameters independent of each + * other for more intuitive control, in particular main roughness not affecting the coat. + */ + float cosNI = dot(sd->wi, coat_normal); + /* Refract incoming direction into coat material. + * TIR is no concern here since we're always coming from the outside. */ + float cosNT = sqrtf(1.0f - sqr(1.0f / coat_ior) * (1 - sqr(cosNI))); + float optical_depth = 1.0f / cosNT; + weight *= power(rgb_to_spectrum(coat_tint), coat * optical_depth); + } + /* Metallic component */ if (reflective_caustics && metallic > CLOSURE_WEIGHT_CUTOFF) { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( @@ -295,7 +323,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, /* Attenuate lower layers */ Spectrum albedo = bsdf_albedo(kg, sd, (ccl_private ShaderClosure *)bsdf, true, false); - weight *= 1.0f - reduce_max(albedo / weight); + weight *= 1.0f - reduce_max(safe_divide_color(albedo, weight)); } } diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index 9def5a19fcb..9f119d88293 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -427,7 +427,6 @@ typedef enum ClosureType { /* Glossy */ CLOSURE_BSDF_MICROFACET_GGX_ID, - CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */ CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 6856f9bfec5..a5999a73402 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -2674,8 +2674,10 @@ NODE_DEFINE(PrincipledBsdfNode) SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); SOCKET_IN_FLOAT(sheen_roughness, "Sheen Roughness", 0.5f); SOCKET_IN_COLOR(sheen_tint, "Sheen Tint", one_float3()); - SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); - SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f); + SOCKET_IN_FLOAT(coat, "Coat", 0.0f); + SOCKET_IN_FLOAT(coat_roughness, "Coat Roughness", 0.03f); + SOCKET_IN_FLOAT(coat_ior, "Coat IOR", 1.5f); + SOCKET_IN_COLOR(coat_tint, "Coat Tint", one_float3()); SOCKET_IN_FLOAT(ior, "IOR", 0.0f); SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f); SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f); @@ -2683,7 +2685,7 @@ NODE_DEFINE(PrincipledBsdfNode) SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 1.0f); SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f); SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL); - SOCKET_IN_NORMAL(clearcoat_normal, "Clearcoat Normal", zero_float3(), SocketType::LINK_NORMAL); + SOCKET_IN_NORMAL(coat_normal, "Coat Normal", zero_float3(), SocketType::LINK_NORMAL); SOCKET_IN_NORMAL(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT); SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); @@ -2785,8 +2787,10 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, ShaderInput *p_sheen, ShaderInput *p_sheen_roughness, ShaderInput *p_sheen_tint, - ShaderInput *p_clearcoat, - ShaderInput *p_clearcoat_roughness, + ShaderInput *p_coat, + ShaderInput *p_coat_roughness, + ShaderInput *p_coat_ior, + ShaderInput *p_coat_tint, ShaderInput *p_ior, ShaderInput *p_transmission, ShaderInput *p_anisotropic_rotation) @@ -2794,7 +2798,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, ShaderInput *base_color_in = input("Base Color"); ShaderInput *subsurface_color_in = input("Subsurface Color"); ShaderInput *normal_in = input("Normal"); - ShaderInput *clearcoat_normal_in = input("Clearcoat Normal"); + ShaderInput *coat_normal_in = input("Coat Normal"); ShaderInput *tangent_in = input("Tangent"); float3 weight = one_float3(); @@ -2802,7 +2806,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight); int normal_offset = compiler.stack_assign_if_linked(normal_in); - int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in); + int coat_normal_offset = compiler.stack_assign_if_linked(coat_normal_in); int tangent_offset = compiler.stack_assign_if_linked(tangent_in); int specular_offset = compiler.stack_assign(p_specular); int roughness_offset = compiler.stack_assign(p_roughness); @@ -2811,8 +2815,10 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, int sheen_offset = compiler.stack_assign(p_sheen); int sheen_roughness_offset = compiler.stack_assign(p_sheen_roughness); int sheen_tint_offset = compiler.stack_assign(p_sheen_tint); - int clearcoat_offset = compiler.stack_assign(p_clearcoat); - int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness); + int coat_offset = compiler.stack_assign(p_coat); + int coat_roughness_offset = compiler.stack_assign(p_coat_roughness); + int coat_ior_offset = compiler.stack_assign(p_coat_ior); + int coat_tint_offset = compiler.stack_assign(p_coat_tint); int ior_offset = compiler.stack_assign(p_ior); int transmission_offset = compiler.stack_assign(p_transmission); int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation); @@ -2834,14 +2840,15 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, compiler.encode_uchar4( specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset), compiler.encode_uchar4( - sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset)); + sheen_offset, sheen_tint_offset, sheen_roughness_offset, SVM_STACK_INVALID)); compiler.add_node( compiler.encode_uchar4( ior_offset, transmission_offset, anisotropic_rotation_offset, SVM_STACK_INVALID), distribution, subsurface_method, - sheen_roughness_offset); + compiler.encode_uchar4( + coat_offset, coat_roughness_offset, coat_ior_offset, coat_tint_offset)); float3 bc_default = get_float3(base_color_in->socket_type); @@ -2851,7 +2858,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler, __float_as_int(bc_default.y), __float_as_int(bc_default.z)); - compiler.add_node(clearcoat_normal_offset, + compiler.add_node(coat_normal_offset, subsurface_radius_offset, subsurface_ior_offset, subsurface_anisotropy_offset); @@ -2880,8 +2887,10 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler) input("Sheen"), input("Sheen Roughness"), input("Sheen Tint"), - input("Clearcoat"), - input("Clearcoat Roughness"), + input("Coat"), + input("Coat Roughness"), + input("Coat IOR"), + input("Coat Tint"), input("IOR"), input("Transmission"), input("Anisotropic Rotation")); diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index 61e4f7d5df3..a3fec15249e 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -530,8 +530,10 @@ class PrincipledBsdfNode : public BsdfBaseNode { ShaderInput *sheen, ShaderInput *sheen_roughness, ShaderInput *sheen_tint, - ShaderInput *clearcoat, - ShaderInput *clearcoat_roughness, + ShaderInput *coat, + ShaderInput *coat_roughness, + ShaderInput *coat_ior, + ShaderInput *coat_tint, ShaderInput *ior, ShaderInput *transmission, ShaderInput *anisotropic_rotation); @@ -550,13 +552,15 @@ class PrincipledBsdfNode : public BsdfBaseNode { NODE_SOCKET_API(float, sheen) NODE_SOCKET_API(float, sheen_roughness) NODE_SOCKET_API(float3, sheen_tint) - NODE_SOCKET_API(float, clearcoat) - NODE_SOCKET_API(float, clearcoat_roughness) + NODE_SOCKET_API(float, coat) + NODE_SOCKET_API(float, coat_roughness) + NODE_SOCKET_API(float, coat_ior) + NODE_SOCKET_API(float3, coat_tint) NODE_SOCKET_API(float, ior) NODE_SOCKET_API(float, transmission) NODE_SOCKET_API(float, anisotropic_rotation) NODE_SOCKET_API(float3, normal) - NODE_SOCKET_API(float3, clearcoat_normal) + NODE_SOCKET_API(float3, coat_normal) NODE_SOCKET_API(float3, tangent) NODE_SOCKET_API(float, surface_mix_weight) NODE_SOCKET_API(ClosureType, distribution) diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index 5a300dcd0ec..ecd70c0c162 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -655,6 +655,35 @@ static void versioning_convert_node_tree_socket_lists_to_interface(bNodeTree *nt } } +/* Convert coat inputs on the Principled BSDF. */ +static void version_principled_bsdf_coat(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type != SH_NODE_BSDF_PRINCIPLED) { + continue; + } + if (nodeFindSocket(node, SOCK_IN, "Coat IOR") != nullptr) { + continue; + } + bNodeSocket *coat_ior_input = nodeAddStaticSocket( + ntree, node, SOCK_IN, SOCK_FLOAT, PROP_NONE, "Coat IOR", "Coat IOR"); + + /* Adjust for 4x change in intensity. */ + bNodeSocket *coat_input = nodeFindSocket(node, SOCK_IN, "Clearcoat"); + *version_cycles_node_socket_float_value(coat_input) *= 0.25f; + /* When the coat input is dynamic, instead of inserting a *0.25 math node, set the Coat IOR + * to 1.2 instead - this also roughly quarters reflectivity compared to the 1.5 default. */ + *version_cycles_node_socket_float_value(coat_ior_input) = (coat_input->link) ? 1.2f : 1.5f; + } + + /* Rename sockets. */ + version_node_input_socket_name(ntree, SH_NODE_BSDF_PRINCIPLED, "Clearcoat", "Coat"); + version_node_input_socket_name( + ntree, SH_NODE_BSDF_PRINCIPLED, "Clearcoat Roughness", "Coat Roughness"); + version_node_input_socket_name( + ntree, SH_NODE_BSDF_PRINCIPLED, "Clearcoat Normal", "Coat Normal"); +} + void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) { @@ -1062,5 +1091,13 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) */ { /* Keep this block, even when empty. */ + + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + /* Convert coat inputs on the Principled BSDF. */ + version_principled_bsdf_coat(ntree); + } + } + FOREACH_NODETREE_END; } } diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl index 84b1a751af9..e02759f6c82 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl @@ -230,15 +230,13 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) /* Specular BSDF */ CLOSURE_EVAL_FUNCTION_DECLARE_3(SpecularBSDF, Diffuse, Glossy, Glossy) -Closure closure_eval(ClosureDiffuse diffuse, - ClosureReflection reflection, - ClosureReflection clearcoat) +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, ClosureReflection coat) { #if defined(DO_SPLIT_CLOSURE_EVAL) Closure closure = closure_eval(diffuse); Closure closure_reflection = closure_eval(reflection); - Closure closure_clearcoat = closure_eval(clearcoat, false); - closure.radiance += closure_reflection.radiance + closure_clearcoat.radiance; + Closure closure_coat = closure_eval(coat, false); + closure.radiance += closure_reflection.radiance + closure_coat.radiance; return closure; #else /* Glue with the old system. */ @@ -250,8 +248,8 @@ Closure closure_eval(ClosureDiffuse diffuse, in_Diffuse_0.albedo = diffuse.color; in_Glossy_1.N = reflection.N; in_Glossy_1.roughness = reflection.roughness; - in_Glossy_2.N = clearcoat.N; - in_Glossy_2.roughness = clearcoat.roughness; + in_Glossy_2.N = coat.N; + in_Glossy_2.roughness = coat.roughness; CLOSURE_EVAL_FUNCTION_3(SpecularBSDF, Diffuse, Glossy, Glossy); @@ -259,7 +257,7 @@ Closure closure_eval(ClosureDiffuse diffuse, if (!output_sss(diffuse, out_Diffuse_0)) { closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; } - closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight; + closure.radiance += out_Glossy_2.radiance * coat.color * coat.weight; if (!output_ssr(reflection)) { closure.radiance += out_Glossy_1.radiance * reflection.color * reflection.weight; } @@ -271,15 +269,15 @@ Closure closure_eval(ClosureDiffuse diffuse, CLOSURE_EVAL_FUNCTION_DECLARE_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction) Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, - ClosureReflection clearcoat, + ClosureReflection coat, ClosureRefraction refraction) { #if defined(DO_SPLIT_CLOSURE_EVAL) Closure closure = closure_eval(diffuse); Closure closure_reflection = closure_eval(reflection); - Closure closure_clearcoat = closure_eval(clearcoat, false); + Closure closure_coat = closure_eval(coat, false); Closure closure_refraction = closure_eval(refraction); - closure.radiance += closure_reflection.radiance + closure_clearcoat.radiance + + closure.radiance += closure_reflection.radiance + closure_coat.radiance + closure_refraction.radiance; return closure; #else @@ -290,8 +288,8 @@ Closure closure_eval(ClosureDiffuse diffuse, in_Diffuse_0.albedo = diffuse.color; in_Glossy_1.N = reflection.N; in_Glossy_1.roughness = reflection.roughness; - in_Glossy_2.N = clearcoat.N; - in_Glossy_2.roughness = clearcoat.roughness; + in_Glossy_2.N = coat.N; + in_Glossy_2.roughness = coat.roughness; in_Refraction_3.N = refraction.N; in_Refraction_3.roughness = refraction.roughness; in_Refraction_3.ior = refraction.ior; @@ -299,7 +297,7 @@ Closure closure_eval(ClosureDiffuse diffuse, CLOSURE_EVAL_FUNCTION_4(PrincipledBSDF, Diffuse, Glossy, Glossy, Refraction); Closure closure = CLOSURE_DEFAULT; - closure.radiance += out_Glossy_2.radiance * clearcoat.color * clearcoat.weight; + closure.radiance += out_Glossy_2.radiance * coat.color * coat.weight; closure.radiance += out_Refraction_3.radiance * refraction.color * refraction.weight; if (!output_sss(diffuse, out_Diffuse_0)) { closure.radiance += out_Diffuse_0.radiance * diffuse.color * diffuse.weight; @@ -312,10 +310,10 @@ Closure closure_eval(ClosureDiffuse diffuse, } CLOSURE_EVAL_FUNCTION_DECLARE_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy) -Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +Closure closure_eval(ClosureReflection reflection, ClosureReflection coat) { #if defined(DO_SPLIT_CLOSURE_EVAL) - Closure closure = closure_eval(clearcoat); + Closure closure = closure_eval(coat); Closure closure_reflection = closure_eval(reflection); closure.radiance += closure_reflection.radiance; return closure; @@ -325,13 +323,13 @@ Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) in_Glossy_0.N = reflection.N; in_Glossy_0.roughness = reflection.roughness; - in_Glossy_1.N = clearcoat.N; - in_Glossy_1.roughness = clearcoat.roughness; + in_Glossy_1.N = coat.N; + in_Glossy_1.roughness = coat.roughness; CLOSURE_EVAL_FUNCTION_2(PrincipledBSDFMetalClearCoat, Glossy, Glossy); Closure closure = CLOSURE_DEFAULT; - closure.radiance += out_Glossy_1.radiance * clearcoat.color * clearcoat.weight; + closure.radiance += out_Glossy_1.radiance * coat.color * coat.weight; if (!output_ssr(reflection)) { closure.radiance += out_Glossy_0.radiance * reflection.color * reflection.weight; } diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl index bb73f909675..4c18d3e16bc 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_volume_lib.glsl @@ -42,20 +42,18 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) { return CLOSURE_DEFAULT; } -Closure closure_eval(ClosureDiffuse diffuse, - ClosureReflection reflection, - ClosureReflection clearcoat) +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, ClosureReflection coat) { return CLOSURE_DEFAULT; } Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, - ClosureReflection clearcoat, + ClosureReflection coat, ClosureRefraction refraction) { return CLOSURE_DEFAULT; } -Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +Closure closure_eval(ClosureReflection reflection, ClosureReflection coat) { return CLOSURE_DEFAULT; } 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 3fff9f02d88..f59c76dd4ea 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl @@ -67,20 +67,18 @@ Closure closure_eval(ClosureHair hair); Closure closure_eval(ClosureReflection reflection, ClosureRefraction refraction); /* Dielectric BSDF. */ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection); -/* ClearCoat BSDF. */ -Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat); +/* Coat BSDF. */ +Closure closure_eval(ClosureReflection reflection, ClosureReflection coat); /* Volume BSDF. */ Closure closure_eval(ClosureVolumeScatter volume_scatter, ClosureVolumeAbsorption volume_absorption, ClosureEmission emission); /* Specular BSDF. */ -Closure closure_eval(ClosureDiffuse diffuse, - ClosureReflection reflection, - ClosureReflection clearcoat); +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, ClosureReflection coat); /* Principled BSDF. */ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, - ClosureReflection clearcoat, + ClosureReflection coat, ClosureRefraction refraction); Closure closure_add(inout Closure cl1, inout Closure cl2); 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 543874dc19f..aee4505c85f 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 @@ -166,11 +166,11 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection) return Closure(0); } -/* ClearCoat BSDF. */ -Closure closure_eval(ClosureReflection reflection, ClosureReflection clearcoat) +/* Coat BSDF. */ +Closure closure_eval(ClosureReflection reflection, ClosureReflection coat) { SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection); - SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat); + SELECT_CLOSURE(g_reflection_data, g_reflection_rand, coat); return Closure(0); } @@ -186,25 +186,23 @@ Closure closure_eval(ClosureVolumeScatter volume_scatter, } /* Specular BSDF. */ -Closure closure_eval(ClosureDiffuse diffuse, - ClosureReflection reflection, - ClosureReflection clearcoat) +Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, ClosureReflection coat) { SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse); SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection); - SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat); + SELECT_CLOSURE(g_reflection_data, g_reflection_rand, coat); return Closure(0); } /* Principled BSDF. */ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection, - ClosureReflection clearcoat, + ClosureReflection coat, ClosureRefraction refraction) { SELECT_CLOSURE(g_diffuse_data, g_diffuse_rand, diffuse); SELECT_CLOSURE(g_reflection_data, g_reflection_rand, reflection); - SELECT_CLOSURE(g_reflection_data, g_reflection_rand, clearcoat); + SELECT_CLOSURE(g_reflection_data, g_reflection_rand, coat); SELECT_CLOSURE(g_refraction_data, g_refraction_rand, refraction); return Closure(0); } diff --git a/source/blender/editors/io/io_obj.cc b/source/blender/editors/io/io_obj.cc index 87d28c61c35..504f54dcfcb 100644 --- a/source/blender/editors/io/io_obj.cc +++ b/source/blender/editors/io/io_obj.cc @@ -334,7 +334,7 @@ void WM_OT_obj_export(wmOperatorType *ot) false, "Export Materials with PBR Extensions", "Export MTL library using PBR extensions (roughness, metallic, sheen, " - "clearcoat, anisotropy, transmission)"); + "coat, anisotropy, transmission)"); RNA_def_enum(ot->srna, "path_mode", io_obj_path_mode, diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 04a32d99012..403eb048fcc 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -78,7 +78,7 @@ typedef enum eGPUMaterialFlag { GPU_MATFLAG_HOLDOUT = (1 << 6), GPU_MATFLAG_SHADER_TO_RGBA = (1 << 7), GPU_MATFLAG_AO = (1 << 8), - GPU_MATFLAG_CLEARCOAT = (1 << 9), + GPU_MATFLAG_COAT = (1 << 9), GPU_MATFLAG_OBJECT_INFO = (1 << 10), GPU_MATFLAG_AOV = (1 << 11), @@ -86,7 +86,7 @@ typedef enum eGPUMaterialFlag { GPU_MATFLAG_BARYCENTRIC = (1 << 20), /* Optimization to only add the branches of the principled shader that are necessary. */ - GPU_MATFLAG_PRINCIPLED_CLEARCOAT = (1 << 21), + GPU_MATFLAG_PRINCIPLED_COAT = (1 << 21), GPU_MATFLAG_PRINCIPLED_METALLIC = (1 << 22), GPU_MATFLAG_PRINCIPLED_DIELECTRIC = (1 << 23), GPU_MATFLAG_PRINCIPLED_GLASS = (1 << 24), diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 930c3a9a06e..04cac214b41 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -404,8 +404,8 @@ void GPUCodegen::generate_resources() /* Ref. #98190: Defines are optimizations for old compilers. * Might become unnecessary with EEVEE-Next. */ - if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_CLEARCOAT)) { - info.define("PRINCIPLED_CLEARCOAT"); + if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_COAT)) { + info.define("PRINCIPLED_COAT"); } if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_METALLIC)) { info.define("PRINCIPLED_METALLIC"); 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 d4a66702e08..949148a4a38 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -33,8 +33,10 @@ void node_bsdf_principled(vec4 base_color, float sheen, float sheen_roughness, vec4 sheen_tint, - float clearcoat, - float clearcoat_roughness, + float coat, + float coat_roughness, + float coat_ior, + vec4 coat_tint, float ior, float transmission, vec4 emission, @@ -45,7 +47,7 @@ void node_bsdf_principled(vec4 base_color, vec3 T, float weight, const float do_diffuse, - const float do_clearcoat, + const float do_coat, const float do_refraction, const float do_multiscatter, float do_sss, @@ -54,7 +56,8 @@ void node_bsdf_principled(vec4 base_color, /* Match cycles. */ metallic = clamp(metallic, 0.0, 1.0); transmission = clamp(transmission, 0.0, 1.0); - clearcoat = max(clearcoat, 0.0) * 0.25; + coat = max(coat, 0.0); + coat_ior = max(coat_ior, 1.0); N = safe_normalize(N); CN = safe_normalize(CN); @@ -76,22 +79,31 @@ void node_bsdf_principled(vec4 base_color, /* Attenuate lower layers */ weight *= (1.0 - max_v3(sheen_color)); - /* Second layer: Clearcoat */ - ClosureReflection clearcoat_data; - clearcoat_data.N = CN; - clearcoat_data.roughness = clearcoat_roughness; - float coat_ior = 1.5; - float coat_NV = dot(clearcoat_data.N, V); - float reflectance = btdf_lut(coat_NV, clearcoat_data.roughness, coat_ior, 0.0).y; - clearcoat_data.weight = weight * clearcoat * reflectance; - clearcoat_data.color = vec3(1.0); + /* Second layer: Coat */ + ClosureReflection coat_data; + coat_data.N = CN; + coat_data.roughness = coat_roughness; + float coat_NV = dot(coat_data.N, V); + float reflectance = btdf_lut(coat_NV, coat_data.roughness, coat_ior, 0.0).y; + coat_data.weight = weight * coat * reflectance; + coat_data.color = vec3(1.0); /* Attenuate lower layers */ - weight *= (1.0 - reflectance * clearcoat); + weight *= (1.0 - reflectance * coat); - /* Attenuated by sheen and clearcoat. */ + if (coat == 0) { + coat_tint.rgb = vec3(1.0); + } + else if (!all(equal(coat_tint.rgb, vec3(1.0)))) { + float coat_neta = 1.0 / coat_ior; + float NT = fast_sqrt(1.0 - coat_neta * coat_neta * (1 - NV * NV)); + /* Tint lower layers. */ + coat_tint.rgb = pow(coat_tint.rgb, vec3(coat / NT)); + } + + /* Attenuated by sheen and coat. */ ClosureEmission emission_data; emission_data.weight = weight; - emission_data.emission = emission.rgb * emission_strength; + emission_data.emission = coat_tint.rgb * emission.rgb * emission_strength; /* Metallic component */ ClosureReflection reflection_data; @@ -118,7 +130,7 @@ void node_bsdf_principled(vec4 base_color, reflection_data.color += weight * transmission * bsdf.y * reflection_tint; refraction_data.weight = weight * transmission * bsdf.x; - refraction_data.color = base_color.rgb; + refraction_data.color = base_color.rgb * coat_tint.rgb; refraction_data.N = N; refraction_data.roughness = roughness; refraction_data.ior = ior; @@ -146,36 +158,38 @@ void node_bsdf_principled(vec4 base_color, vec3 diffuse_color = mix(base_color.rgb, subsurface_color.rgb, subsurface); diffuse_data.sss_radius = subsurface_radius * subsurface; diffuse_data.sss_id = uint(do_sss); - diffuse_data.color += weight * diffuse_color; + diffuse_data.color += weight * diffuse_color * coat_tint.rgb; } /* Adjust the weight of picking the closure. */ + reflection_data.color *= coat_tint.rgb; reflection_data.weight = avg(reflection_data.color); reflection_data.color *= safe_rcp(reflection_data.weight); + diffuse_data.weight = avg(diffuse_data.color); diffuse_data.color *= safe_rcp(diffuse_data.weight); /* Ref. #98190: Defines are optimizations for old compilers. * Might become unnecessary with EEVEE-Next. */ - if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat != 0.0) { -#ifdef PRINCIPLED_CLEARCOAT - /* Metallic & Clearcoat case. */ - result = closure_eval(reflection_data, clearcoat_data); + if (do_diffuse == 0.0 && do_refraction == 0.0 && do_coat != 0.0) { +#ifdef PRINCIPLED_COAT + /* Metallic & Coat case. */ + result = closure_eval(reflection_data, coat_data); #endif } - else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) { + else if (do_diffuse == 0.0 && do_refraction == 0.0 && do_coat == 0.0) { #ifdef PRINCIPLED_METALLIC /* Metallic case. */ result = closure_eval(reflection_data); #endif } - else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_clearcoat == 0.0) { + else if (do_diffuse != 0.0 && do_refraction == 0.0 && do_coat == 0.0) { #ifdef PRINCIPLED_DIELECTRIC /* Dielectric case. */ result = closure_eval(diffuse_data, reflection_data); #endif } - else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_clearcoat == 0.0) { + else if (do_diffuse == 0.0 && do_refraction != 0.0 && do_coat == 0.0) { #ifdef PRINCIPLED_GLASS /* Glass case. */ result = closure_eval(reflection_data, refraction_data); @@ -184,7 +198,7 @@ void node_bsdf_principled(vec4 base_color, else { #ifdef PRINCIPLED_ANY /* Un-optimized case. */ - result = closure_eval(diffuse_data, reflection_data, clearcoat_data, refraction_data); + result = closure_eval(diffuse_data, reflection_data, coat_data, refraction_data); #endif } Closure emission_cl = closure_eval(emission_data); diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index a77d2d245d2..1a586d92b97 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -481,15 +481,12 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled, set_node_input(roughness_input, principled, "Roughness", ntree, column, &context); } - if (pxr::UsdShadeInput clearcoat_input = usd_shader.GetInput(usdtokens::clearcoat)) { - set_node_input(clearcoat_input, principled, "Clearcoat", ntree, column, &context); + if (pxr::UsdShadeInput coat_input = usd_shader.GetInput(usdtokens::clearcoat)) { + set_node_input(coat_input, principled, "Coat", ntree, column, &context); } - if (pxr::UsdShadeInput clearcoat_roughness_input = usd_shader.GetInput( - usdtokens::clearcoatRoughness)) - { - set_node_input( - clearcoat_roughness_input, principled, "Clearcoat Roughness", ntree, column, &context); + if (pxr::UsdShadeInput coat_roughness_input = usd_shader.GetInput(usdtokens::clearcoatRoughness)) { + set_node_input(coat_roughness_input, principled, "Coat Roughness", ntree, column, &context); } if (pxr::UsdShadeInput opacity_input = usd_shader.GetInput(usdtokens::opacity)) { diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc index 3db290aff9d..38b08eb9e3d 100644 --- a/source/blender/io/usd/intern/usd_writer_material.cc +++ b/source/blender/io/usd/intern/usd_writer_material.cc @@ -298,9 +298,8 @@ static InputSpecMap &preview_surface_input_map() {"IOR", {usdtokens::ior, pxr::SdfValueTypeNames->Float, true}}, /* Note that for the Normal input set_default_value is false. */ {"Normal", {usdtokens::normal, pxr::SdfValueTypeNames->Float3, false}}, - {"Clearcoat", {usdtokens::clearcoat, pxr::SdfValueTypeNames->Float, true}}, - {"Clearcoat Roughness", - {usdtokens::clearcoatRoughness, pxr::SdfValueTypeNames->Float, true}}, + {"Coat", {usdtokens::clearcoat, pxr::SdfValueTypeNames->Float, true}}, + {"Coat Roughness", {usdtokens::clearcoatRoughness, pxr::SdfValueTypeNames->Float, true}}, }; return input_map; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc index 48bd4be570e..01c4ab26834 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -237,19 +237,21 @@ static void store_bsdf_properties(const bNode *bsdf_node, mul_v3_fl(emission_col, emission_strength); float sheen = -1.0f; - float clearcoat = -1.0f; - float clearcoat_roughness = -1.0f; + float coat = -1.0f; + float coat_roughness = -1.0f; float aniso = -1.0f; float aniso_rot = -1.0f; float transmission = -1.0f; if (bsdf_node) { copy_property_from_node(SOCK_FLOAT, bsdf_node, "Sheen", {&sheen, 1}); - copy_property_from_node(SOCK_FLOAT, bsdf_node, "Clearcoat", {&clearcoat, 1}); - copy_property_from_node( - SOCK_FLOAT, bsdf_node, "Clearcoat Roughness", {&clearcoat_roughness, 1}); + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Coat", {&coat, 1}); + copy_property_from_node(SOCK_FLOAT, bsdf_node, "Coat Roughness", {&coat_roughness, 1}); copy_property_from_node(SOCK_FLOAT, bsdf_node, "Anisotropic", {&aniso, 1}); copy_property_from_node(SOCK_FLOAT, bsdf_node, "Anisotropic Rotation", {&aniso_rot, 1}); copy_property_from_node(SOCK_FLOAT, bsdf_node, "Transmission", {&transmission, 1}); + + /* Clearcoat used to include an implicit 0.25 factor, so stay compatible to old versions. */ + coat *= 4.0f; } /* See https://wikipedia.org/wiki/Wavefront_.obj_file for all possible values of `illum`. */ @@ -290,8 +292,8 @@ static void store_bsdf_properties(const bNode *bsdf_node, r_mtl_mat.roughness = roughness; r_mtl_mat.metallic = metallic; r_mtl_mat.sheen = sheen; - r_mtl_mat.cc_thickness = clearcoat; - r_mtl_mat.cc_roughness = clearcoat_roughness; + r_mtl_mat.cc_thickness = coat; + r_mtl_mat.cc_roughness = coat_roughness; r_mtl_mat.aniso = aniso; r_mtl_mat.aniso_rot = aniso_rot; r_mtl_mat.transmit_color = {transmission, transmission, transmission}; diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 15d79fd577e..ce7020c6792 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -327,10 +327,11 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial set_property_of_socket(SOCK_FLOAT, "Sheen", {mtl_mat.sheen}, bsdf); } if (mtl_mat.cc_thickness >= 0) { - set_property_of_socket(SOCK_FLOAT, "Clearcoat", {mtl_mat.cc_thickness}, bsdf); + /* Clearcoat used to include an implicit 0.25 factor, so stay compatible to old versions. */ + set_property_of_socket(SOCK_FLOAT, "Coat", {0.25f * mtl_mat.cc_thickness}, bsdf); } if (mtl_mat.cc_roughness >= 0) { - set_property_of_socket(SOCK_FLOAT, "Clearcoat Roughness", {mtl_mat.cc_roughness}, bsdf); + set_property_of_socket(SOCK_FLOAT, "Coat Roughness", {mtl_mat.cc_roughness}, bsdf); } if (mtl_mat.aniso >= 0) { set_property_of_socket(SOCK_FLOAT, "Anisotropic", {mtl_mat.aniso}, bsdf); 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 d9028ef974d..b079dc3ce42 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -93,42 +93,62 @@ static void node_declare(NodeDeclarationBuilder &b) #define SOCK_SHEEN_ROUGHNESS_ID 13 b.add_input("Sheen Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f}); #define SOCK_SHEEN_TINT_ID 14 - b.add_input("Clearcoat") + b.add_input("Coat") .default_value(0.0f) .min(0.0f) .max(1.0f) - .subtype(PROP_FACTOR); -#define SOCK_CLEARCOAT_ID 15 - b.add_input("Clearcoat Roughness") + .subtype(PROP_FACTOR) + .description( + "Controls the intensity of the coat layer, both the reflection and the tinting. " + "Typically should be zero or one for physically-based materials"); +#define SOCK_COAT_ID 15 + b.add_input("Coat Roughness") .default_value(0.03f) .min(0.0f) .max(1.0f) - .subtype(PROP_FACTOR); -#define SOCK_CLEARCOAT_ROUGHNESS_ID 16 + .subtype(PROP_FACTOR) + .description("The roughness of the coat layer"); +#define SOCK_COAT_ROUGHNESS_ID 16 + b.add_input("Coat IOR") + .default_value(1.5f) + .min(1.0f) + .max(4.0f) + .description( + "The index of refraction of the coat layer (affects its reflectivity as well " + "as the falloff of coat tinting)"); +#define SOCK_COAT_IOR_ID 17 + b.add_input("Coat Tint") + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .description( + "Adds a colored tint to the coat layer by modeling absorption in the layer. " + "Saturation increases at shallower angles, as the light travels farther through the " + "medium " + "(depending on the Coat IOR)"); +#define SOCK_COAT_TINT_ID 18 b.add_input("IOR").default_value(1.45f).min(1.0f).max(1000.0f); -#define SOCK_IOR_ID 17 +#define SOCK_IOR_ID 19 b.add_input("Transmission") .default_value(0.0f) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); -#define SOCK_TRANSMISSION_ID 18 +#define SOCK_TRANSMISSION_ID 20 b.add_input("Emission").default_value({0.0f, 0.0f, 0.0f, 1.0f}); -#define SOCK_EMISSION_ID 19 +#define SOCK_EMISSION_ID 21 b.add_input("Emission Strength").default_value(1.0).min(0.0f).max(1000000.0f); -#define SOCK_EMISSION_STRENGTH_ID 20 +#define SOCK_EMISSION_STRENGTH_ID 22 b.add_input("Alpha").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); -#define SOCK_ALPHA_ID 21 +#define SOCK_ALPHA_ID 23 b.add_input("Normal").hide_value(); -#define SOCK_NORMAL_ID 22 - b.add_input("Clearcoat Normal").hide_value(); -#define SOCK_CLEARCOAT_NORMAL_ID 23 +#define SOCK_NORMAL_ID 24 + b.add_input("Coat Normal").hide_value(); +#define SOCK_COAT_NORMAL_ID 25 b.add_input("Tangent").hide_value(); -#define SOCK_TANGENT_ID 24 +#define SOCK_TANGENT_ID 26 b.add_input("Weight").unavailable(); -#define SOCK_WEIGHT_ID 25 +#define SOCK_WEIGHT_ID 27 b.add_output("BSDF"); -#define SOCK_BSDF_ID 26 +#define SOCK_BSDF_ID 28 } static void node_shader_buts_principled(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) @@ -158,9 +178,9 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[SOCK_NORMAL_ID].link); } - /* Clearcoat Normals */ - if (!in[SOCK_CLEARCOAT_NORMAL_ID].link) { - GPU_link(mat, "world_normals_get", &in[SOCK_CLEARCOAT_NORMAL_ID].link); + /* Coat Normals */ + if (!in[SOCK_COAT_NORMAL_ID].link) { + GPU_link(mat, "world_normals_get", &in[SOCK_COAT_NORMAL_ID].link); } #if 0 /* Not used at the moment. */ @@ -177,7 +197,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bool use_subsurf = socket_not_zero(SOCK_SUBSURFACE_ID) && use_diffuse; bool use_refract = socket_not_one(SOCK_METALLIC_ID) && socket_not_zero(SOCK_TRANSMISSION_ID); bool use_transparency = socket_not_one(SOCK_ALPHA_ID); - bool use_clear = socket_not_zero(SOCK_CLEARCOAT_ID); + bool use_coat = socket_not_zero(SOCK_COAT_ID); eGPUMaterialFlag flag = GPU_MATFLAG_GLOSSY; if (use_diffuse) { @@ -192,22 +212,22 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, if (use_transparency) { flag |= GPU_MATFLAG_TRANSPARENT; } - if (use_clear) { - flag |= GPU_MATFLAG_CLEARCOAT; + if (use_coat) { + flag |= GPU_MATFLAG_COAT; } /* Ref. #98190: Defines are optimizations for old compilers. * Might become unnecessary with EEVEE-Next. */ - if (use_diffuse == false && use_refract == false && use_clear == true) { - flag |= GPU_MATFLAG_PRINCIPLED_CLEARCOAT; + if (use_diffuse == false && use_refract == false && use_coat == true) { + flag |= GPU_MATFLAG_PRINCIPLED_COAT; } - else if (use_diffuse == false && use_refract == false && use_clear == false) { + else if (use_diffuse == false && use_refract == false && use_coat == false) { flag |= GPU_MATFLAG_PRINCIPLED_METALLIC; } - else if (use_diffuse == true && use_refract == false && use_clear == false) { + else if (use_diffuse == true && use_refract == false && use_coat == false) { flag |= GPU_MATFLAG_PRINCIPLED_DIELECTRIC; } - else if (use_diffuse == false && use_refract == true && use_clear == false) { + else if (use_diffuse == false && use_refract == true && use_coat == false) { flag |= GPU_MATFLAG_PRINCIPLED_GLASS; } else { @@ -225,7 +245,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; float use_sss = (use_subsurf) ? 1.0f : 0.0f; float use_diffuse_f = (use_diffuse) ? 1.0f : 0.0f; - float use_clear_f = (use_clear) ? 1.0f : 0.0f; + float use_coat_f = (use_coat) ? 1.0f : 0.0f; float use_refract_f = (use_refract) ? 1.0f : 0.0f; GPU_material_flag_set(mat, flag); @@ -236,7 +256,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, in, out, GPU_constant(&use_diffuse_f), - GPU_constant(&use_clear_f), + GPU_constant(&use_coat_f), GPU_constant(&use_refract_f), GPU_constant(&use_multi_scatter), GPU_uniform(&use_sss)); diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc index 58828325a87..9a4c00e0760 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc @@ -53,7 +53,7 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, GPU_link(mat, "world_normals_get", &in[5].link); } - /* Clearcoat Normals */ + /* Coat Normals */ if (!in[8].link) { GPU_link(mat, "world_normals_get", &in[8].link); }