Cycles: Rework Principled BSDF Clearcoat #110993

Merged
Lukas Stockner merged 21 commits from LukasStockner/blender:clearcoat-principled into main 2023-09-13 00:03:19 +02:00
25 changed files with 297 additions and 233 deletions

View File

@ -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

View File

@ -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:

View File

@ -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<m_type>(alpha2, cos_NH);
}
D = bsdf_D<m_type>(alpha2, cos_NH);
lambdaI = bsdf_lambda<m_type>(alpha2, cos_NI);
lambdaO = bsdf_lambda<m_type>(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<m_type>(alpha2, cos_NH);
}
D = bsdf_D<m_type>(alpha2, cos_NH);
lambdaO = bsdf_lambda<m_type>(alpha2, cos_NO);
lambdaI = bsdf_lambda<m_type>(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);

View File

@ -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) {

View File

@ -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

View File

@ -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");
LukasStockner marked this conversation as resolved Outdated

The CoatIOR in closure color CoatBSDF = dielectric_bsdf(CoatNormal, vector(0.0), color(1.0), color(0.0), coat_r2, coat_r2, CoatIOR, "ggx"); also needs to be set to max(CoatIOR, 1.0) to avoid inconsistencies when compared to Cycles SVM when the CoatIOR is below 1.0.

The `CoatIOR` in `closure color CoatBSDF = dielectric_bsdf(CoatNormal, vector(0.0), color(1.0), color(0.0), coat_r2, coat_r2, CoatIOR, "ggx");` also needs to be set to `max(CoatIOR, 1.0)` to avoid inconsistencies when compared to Cycles SVM when the `CoatIOR` is below 1.0.
BSDF = layer(Coat * CoatBSDF, BSDF);
}
if (Sheen > 1e-5) {

View File

@ -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));
}
}
Alaska marked this conversation as resolved Outdated

Replacing if (coat_tint != one_float3()) with if (!isequal(coat_tint, one_float3())) fixes compilation issues with the Metal backend.

For reference, the compilation issue is this:

error: value of type 'bool __attribute__((ext_vector_type(3)))' (vector of 3 'bool' values) is not contextually convertible to 'bool'
      if (coat_tint != one_float3()) {
          ^~~~~~~~~~~~~~~~~~~~~~~~~
Replacing `if (coat_tint != one_float3())` with `if (!isequal(coat_tint, one_float3()))` fixes compilation issues with the Metal backend. For reference, the compilation issue is this: ``` error: value of type 'bool __attribute__((ext_vector_type(3)))' (vector of 3 'bool' values) is not contextually convertible to 'bool' if (coat_tint != one_float3()) { ^~~~~~~~~~~~~~~~~~~~~~~~~ ```
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));
}
}

View File

@ -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,

View File

@ -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"));

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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,

View File

@ -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),

View File

@ -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");

View File

@ -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);

View File

@ -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)) {

I'm getting build errors here. Seems to be because you updated the names earlier in 96b362cac7 but didn't update them here.

/blender/source/blender/io/usd/intern/usd_reader_material.cc:484:70: error: no member named 'coat' in namespace 'usdtokens'
  if (pxr::UsdShadeInput coat_input = usd_shader.GetInput(usdtokens::coat)) {
                                                          ~~~~~~~~~~~^

/blender/source/blender/io/usd/intern/usd_reader_material.cc:488:80: error: no member named 'coatRoughness' in namespace 'usdtokens'
  if (pxr::UsdShadeInput coat_roughness_input = usd_shader.GetInput(usdtokens::coatRoughness)) {
                                                                    ~~~~~~~~~~~^~~~~~~~~~~~~
I'm getting build errors here. Seems to be because you updated the names earlier in https://projects.blender.org/blender/blender/commit/96b362cac7fb039f5717d5eb28a556d5dc75f0fb but didn't update them here. ``` /blender/source/blender/io/usd/intern/usd_reader_material.cc:484:70: error: no member named 'coat' in namespace 'usdtokens' if (pxr::UsdShadeInput coat_input = usd_shader.GetInput(usdtokens::coat)) { ~~~~~~~~~~~^ /blender/source/blender/io/usd/intern/usd_reader_material.cc:488:80: error: no member named 'coatRoughness' in namespace 'usdtokens' if (pxr::UsdShadeInput coat_roughness_input = usd_shader.GetInput(usdtokens::coatRoughness)) { ~~~~~~~~~~~^~~~~~~~~~~~~ ```

Ah, I was building with USD disabled. I'll fix it, thanks.

Ah, I was building with USD disabled. I'll fix it, thanks.
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)) {

View File

@ -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;

View File

@ -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};

View File

@ -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);

View File

@ -93,42 +93,62 @@ static void node_declare(NodeDeclarationBuilder &b)
#define SOCK_SHEEN_ROUGHNESS_ID 13
b.add_input<decl::Color>("Sheen Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_SHEEN_TINT_ID 14
b.add_input<decl::Float>("Clearcoat")
b.add_input<decl::Float>("Coat")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_CLEARCOAT_ID 15
b.add_input<decl::Float>("Clearcoat Roughness")
.subtype(PROP_FACTOR)
.description(
Alaska marked this conversation as resolved Outdated

Remove the full stop from the end of "Typically should be zero or one for physically-based materials.". The Blender UI automatically adds a full stop to the end.

Remove the full stop from the end of `"Typically should be zero or one for physically-based materials."`. The Blender UI automatically adds a full stop to the end.
"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<decl::Float>("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<decl::Float>("Coat IOR")
LukasStockner marked this conversation as resolved
Review

If CoatIORs below 1.0 aren't supported at this time, then I would personally like see to min IOR set to 1.0.

If CoatIORs below 1.0 aren't supported at this time, then I would personally like see to min IOR set to 1.0.
.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<decl::Color>("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<decl::Float>("IOR").default_value(1.45f).min(1.0f).max(1000.0f);
#define SOCK_IOR_ID 17
#define SOCK_IOR_ID 19
b.add_input<decl::Float>("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<decl::Color>("Emission").default_value({0.0f, 0.0f, 0.0f, 1.0f});
#define SOCK_EMISSION_ID 19
#define SOCK_EMISSION_ID 21
b.add_input<decl::Float>("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<decl::Float>("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<decl::Vector>("Normal").hide_value();
#define SOCK_NORMAL_ID 22
b.add_input<decl::Vector>("Clearcoat Normal").hide_value();
#define SOCK_CLEARCOAT_NORMAL_ID 23
#define SOCK_NORMAL_ID 24
b.add_input<decl::Vector>("Coat Normal").hide_value();
#define SOCK_COAT_NORMAL_ID 25
b.add_input<decl::Vector>("Tangent").hide_value();
#define SOCK_TANGENT_ID 24
#define SOCK_TANGENT_ID 26
b.add_input<decl::Float>("Weight").unavailable();
#define SOCK_WEIGHT_ID 25
#define SOCK_WEIGHT_ID 27
b.add_output<decl::Shader>("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));

View File

@ -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);
}