Principled v2 combined changes for 4.0 #112848

Closed
Brecht Van Lommel wants to merge 16 commits from brecht:principled into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
39 changed files with 774 additions and 396 deletions

View File

@ -537,12 +537,12 @@ static ShaderNode *add_node(Scene *scene,
case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
subsurface->set_method(CLOSURE_BSSRDF_BURLEY_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_FIXED_RADIUS:
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK:
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
break;
case BL::ShaderNodeSubsurfaceScattering::falloff_RANDOM_WALK_SKIN:
subsurface->set_method(CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
break;
}
node = subsurface;
@ -651,12 +651,12 @@ static ShaderNode *add_node(Scene *scene,
case BL::ShaderNodeBsdfPrincipled::subsurface_method_BURLEY:
principled->set_subsurface_method(CLOSURE_BSSRDF_BURLEY_ID);
break;
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_FIXED_RADIUS:
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
break;
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK:
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_ID);
break;
case BL::ShaderNodeBsdfPrincipled::subsurface_method_RANDOM_WALK_SKIN:
principled->set_subsurface_method(CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
break;
}
node = principled;
}

View File

@ -359,7 +359,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg,
case CLOSURE_BSDF_DIFFUSE_ID:
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSSRDF_RANDOM_WALK_ID:
case CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID:
case CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID:
label = LABEL_REFLECT | LABEL_DIFFUSE;
break;
#ifdef __SVM__

View File

@ -26,6 +26,7 @@ enum MicrofacetFresnel {
DIELECTRIC_TINT, /* used by the OSL MaterialX closures */
CONDUCTOR,
GENERALIZED_SCHLICK,
F82_TINT,
};
typedef struct FresnelDielectricTint {
@ -46,6 +47,13 @@ typedef struct FresnelGeneralizedSchlick {
float exponent;
} FresnelGeneralizedSchlick;
typedef struct FresnelF82Tint {
/* Perpendicular reflectivity. */
Spectrum f0;
/* Precomputed (1-cos)^6 factor for edge tint. */
Spectrum b;
} FresnelF82Tint;
typedef struct MicrofacetBsdf {
SHADER_CLOSURE_BASE;
@ -236,6 +244,17 @@ ccl_device_forceinline void microfacet_fresnel(ccl_private const MicrofacetBsdf
*r_reflectance = fresnel_conductor(cos_theta_i, fresnel->n, fresnel->k);
*r_transmittance = zero_spectrum();
}
else if (bsdf->fresnel_type == MicrofacetFresnel::F82_TINT) {
/* F82-Tint model, described in "Novel aspects of the Adobe Standard Material" by Kutz et al.
* Essentially, this is the usual Schlick Fresnel with an additional cosI*(1-cosI)^6
* term which modulates the reflectivity around acos(1/7) degrees (ca. 82°). */
ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)bsdf->fresnel;
const float mu = saturatef(1.0f - cos_theta_i);
const float mu5 = sqr(sqr(mu)) * mu;
const Spectrum F_schlick = mix(fresnel->f0, one_spectrum(), mu5);
*r_reflectance = saturate(F_schlick - fresnel->b * cos_theta_i * mu5 * mu);
*r_transmittance = zero_spectrum();
}
else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *)
bsdf->fresnel;
@ -379,6 +398,14 @@ ccl_device Spectrum bsdf_microfacet_estimate_albedo(KernelGlobals kg,
}
reflectance = mix(fresnel->f0, fresnel->f90, s) * fresnel->reflection_tint;
}
else if (bsdf->fresnel_type == MicrofacetFresnel::F82_TINT) {
ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)bsdf->fresnel;
float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y));
const float s = lookup_table_read_3D(
kg, rough, cos_NI, 0.5f, kernel_data.tables.ggx_gen_schlick_s, 16, 16, 16);
/* TODO: Precompute B factor term and account for it here. */
reflectance = mix(fresnel->f0, one_spectrum(), s);
}
return reflectance + transmittance;
}
@ -738,6 +765,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
ccl_private FresnelGeneralizedSchlick *fresnel,
const bool preserve_energy)
{
fresnel->f0 = saturate(fresnel->f0);
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
bsdf->fresnel = fresnel;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
@ -780,6 +808,40 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
}
}
ccl_device void bsdf_microfacet_setup_fresnel_f82_tint(KernelGlobals kg,
ccl_private MicrofacetBsdf *bsdf,
ccl_private const ShaderData *sd,
ccl_private FresnelF82Tint *fresnel,
const Spectrum f82_tint,
const bool preserve_energy)
{
if (isequal(f82_tint, one_spectrum())) {
fresnel->b = zero_spectrum();
}
else {
/* Precompute the F82 term factor for the Fresnel model.
* In the classic F82 model, the F82 input directly determines the value of the Fresnel
* model at ~82°, similar to F0 and F90.
* With F82-Tint, on the other hand, the value at 82° is the value of the classic Schlick
* model multiplied by the tint input.
* Therefore, the factor follows by setting F82Tint(cosI) = FSchlick(cosI) - b*cosI*(1-cosI)^6
* and F82Tint(acos(1/7)) = FSchlick(acos(1/7)) * f82_tint and solving for b. */
const float f = 6.0f / 7.0f;
const float f5 = sqr(sqr(f)) * f;
const Spectrum F_schlick = mix(fresnel->f0, one_spectrum(), f5);
fresnel->b = F_schlick * (7.0f / (f5 * f)) * (one_spectrum() - f82_tint);
}
bsdf->fresnel_type = MicrofacetFresnel::F82_TINT;
bsdf->fresnel = fresnel;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
if (preserve_energy) {
Spectrum Fss = mix(fresnel->f0, one_spectrum(), 1.0f / 21.0f) - fresnel->b * (1.0f / 126.0f);
microfacet_ggx_preserve_energy(kg, bsdf, sd, Fss);
}
}
ccl_device void bsdf_microfacet_setup_fresnel_constant(KernelGlobals kg,
ccl_private MicrofacetBsdf *bsdf,
ccl_private const ShaderData *sd,

View File

@ -59,7 +59,7 @@ ccl_device float bssrdf_dipole_compute_alpha_prime(float rd, float fourthirdA)
ccl_device void bssrdf_setup_radius(ccl_private Bssrdf *bssrdf, const ClosureType type)
{
if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) {
if (type == CLOSURE_BSSRDF_BURLEY_ID || type == CLOSURE_BSSRDF_RANDOM_WALK_ID) {
/* Scale mean free path length so it gives similar looking result to older
* Cubic, Gaussian and Burley models. */
bssrdf->radius *= 0.25f * M_1_PI_F;
@ -291,8 +291,8 @@ ccl_device int bssrdf_setup(ccl_private ShaderData *sd,
int flag = 0;
if (type == CLOSURE_BSSRDF_RANDOM_WALK_ID) {
/* CLOSURE_BSSRDF_RANDOM_WALK_ID uses a fixed roughness. */
if (type == CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID) {
/* CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID uses a fixed roughness. */
bssrdf->alpha = 1.0f;
}

View File

@ -31,8 +31,8 @@ ccl_device_inline bool subsurface_entry_bounce(KernelGlobals kg,
{
float2 rand_bsdf = path_state_rng_2D(kg, rng_state, PRNG_SUBSURFACE_BSDF);
if (bssrdf->type == CLOSURE_BSSRDF_RANDOM_WALK_ID) {
/* CLOSURE_BSSRDF_RANDOM_WALK_ID has a 50% chance to sample a diffuse entry bounce.
if (bssrdf->type == CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID) {
/* CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID has a 50% chance to sample a diffuse entry bounce.
* Also, for the refractive entry, it uses a fixed roughness of 1.0. */
if (rand_bsdf.x < 0.5f) {
rand_bsdf.x *= 2.0f;

View File

@ -474,6 +474,53 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg,
/* Special-purpose Microfacet closures */
ccl_device void osl_closure_microfacet_f82_tint_setup(
KernelGlobals kg,
ccl_private ShaderData *sd,
uint32_t path_flag,
float3 weight,
ccl_private const MicrofacetF82TintClosure *closure,
float3 *layer_albedo)
{
if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) {
return;
}
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight));
if (!bsdf) {
return;
}
ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)closure_alloc_extra(
sd, sizeof(FresnelF82Tint));
if (!fresnel) {
return;
}
bsdf->N = maybe_ensure_valid_specular_reflection(sd, closure->N);
bsdf->alpha_x = closure->alpha_x;
bsdf->alpha_y = closure->alpha_y;
bsdf->ior = 0.0f;
bsdf->T = closure->T;
bool preserve_energy = false;
/* Beckmann */
if (closure->distribution == make_string("beckmann", 14712237670914973463ull)) {
sd->flag |= bsdf_microfacet_beckmann_setup(bsdf);
}
/* GGX (either single- or multi-scattering) */
else {
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
preserve_energy = (closure->distribution == make_string("multi_ggx", 16842698693386468366ull));
}
fresnel->f0 = rgb_to_spectrum(closure->f0);
bsdf_microfacet_setup_fresnel_f82_tint(
kg, bsdf, sd, fresnel, rgb_to_spectrum(closure->f82), preserve_energy);
}
ccl_device void osl_closure_microfacet_multi_ggx_glass_setup(
KernelGlobals kg,
ccl_private ShaderData *sd,
@ -760,12 +807,12 @@ ccl_device void osl_closure_bssrdf_setup(KernelGlobals kg,
if (closure->method == make_string("burley", 186330084368958868ull)) {
type = CLOSURE_BSSRDF_BURLEY_ID;
}
else if (closure->method == make_string("random_walk_fixed_radius", 5695810351010063150ull)) {
type = CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID;
}
else if (closure->method == make_string("random_walk", 11360609267673527222ull)) {
else if (closure->method == make_string("random_walk", 5695810351010063150ull)) {
type = CLOSURE_BSSRDF_RANDOM_WALK_ID;
}
else if (closure->method == make_string("random_walk_skin", 11360609267673527222ull)) {
type = CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID;
}
else {
return;
}

View File

@ -84,6 +84,16 @@ OSL_CLOSURE_STRUCT_BEGIN(Microfacet, microfacet)
OSL_CLOSURE_STRUCT_MEMBER(Microfacet, INT, int, refract, NULL)
OSL_CLOSURE_STRUCT_END(Microfacet, microfacet)
OSL_CLOSURE_STRUCT_BEGIN(MicrofacetF82Tint, microfacet_f82_tint)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, STRING, DeviceString, distribution, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, VECTOR, packed_float3, T, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, FLOAT, float, alpha_x, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, FLOAT, float, alpha_y, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, VECTOR, packed_float3, f0, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetF82Tint, VECTOR, packed_float3, f82, NULL)
OSL_CLOSURE_STRUCT_END(MicrofacetF82Tint, microfacet)
OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXGlass, microfacet_multi_ggx_glass)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlass, VECTOR, packed_float3, N, NULL)
OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlass, FLOAT, float, alpha_x, NULL)

View File

@ -73,7 +73,7 @@ ccl_device void flatten_closure_tree(KernelGlobals kg,
int layer_stack_level = -1;
float3 layer_albedo = zero_float3();
while (closure) {
while (true) {
switch (closure->id) {
case OSL_CLOSURE_MUL_ID: {
ccl_private const OSLClosureMul *mul = static_cast<ccl_private const OSLClosureMul *>(
@ -134,7 +134,12 @@ ccl_device void flatten_closure_tree(KernelGlobals kg,
break;
}
if (stack_size > 0) {
/* Pop the next closure from the stack (or return if we're done). */
do {
if (stack_size == 0) {
return;
}
weight = weight_stack[--stack_size];
closure = closure_stack[stack_size];
if (stack_size == layer_stack_level) {
@ -142,22 +147,13 @@ ccl_device void flatten_closure_tree(KernelGlobals kg,
* account for the layering. */
weight *= saturatef(1.0f - reduce_max(safe_divide_color(layer_albedo, weight)));
layer_stack_level = -1;
/* If it's fully occluded, skip the base layer we just popped from the stack and grab
* the next entry instead. */
if (is_zero(weight)) {
/* If it's fully occluded, skip the base layer we just popped from the stack and grab
* the next entry instead. */
if (stack_size > 0) {
weight = weight_stack[--stack_size];
closure = closure_stack[stack_size];
}
else {
closure = nullptr;
}
continue;
}
}
}
else {
closure = nullptr;
}
} while (closure == nullptr);
}
}

View File

@ -42,3 +42,9 @@ float F0_from_ior(float eta)
float f0 = (eta - 1.0) / (eta + 1.0);
return f0 * f0;
}
float ior_from_F0(float f0)
{
float sqrt_f0 = sqrt(clamp(f0, 0.0, 0.99));
return (1.0 + sqrt_f0) / (1.0 - sqrt_f0);
}

View File

@ -8,27 +8,27 @@
shader node_principled_bsdf(string distribution = "multi_ggx",
string subsurface_method = "random_walk",
color BaseColor = color(0.8, 0.8, 0.8),
float Subsurface = 0.0,
float SubsurfaceWeight = 0.0,
float SubsurfaceScale = 0.1,
vector SubsurfaceRadius = vector(1.0, 1.0, 1.0),
float SubsurfaceIOR = 1.4,
float SubsurfaceAnisotropy = 0.0,
float Metallic = 0.0,
float Specular = 0.5,
float SpecularTint = 0.0,
float SpecularIORLevel = 0.5,
color SpecularTint = color(1.0),
float Roughness = 0.5,
float Anisotropic = 0.0,
float AnisotropicRotation = 0.0,
float Sheen = 0.0,
float SheenWeight = 0.0,
float SheenRoughness = 0.5,
color SheenTint = 0.5,
float Coat = 0.0,
float CoatWeight = 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,
color Emission = 1.0,
float TransmissionWeight = 0.0,
color EmissionColor = 1.0,
float EmissionStrength = 0.0,
float Alpha = 1.0,
normal Normal = N,
@ -36,7 +36,11 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
normal Tangent = normalize(dPdu),
output closure color BSDF = 0)
{
float r2 = Roughness * Roughness;
color specular_tint = max(SpecularTint, color(0.0));
float r2 = clamp(Roughness, 0.0, 1.0);
r2 = r2 * r2;
float alpha_x = r2, alpha_y = r2;
/* Handle anisotropy. */
@ -49,11 +53,22 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
}
if (Metallic < 1.0 && Transmission < 1.0) {
if (Metallic < 1.0 && TransmissionWeight < 1.0) {
float eta = IOR;
float f0 = F0_from_ior(eta);
if (SpecularIORLevel != 0.5) {
f0 *= 2.0 * max(SpecularIORLevel, 0.0);
eta = ior_from_F0(f0);
if (IOR < 1.0) {
eta = 1.0 / eta;
}
}
BSDF = BaseColor * diffuse(Normal);
if (Subsurface > 1e-5) {
if (SubsurfaceWeight > 1e-5) {
float subsurface_weight = min(SubsurfaceWeight, 1.0);
vector radius = SubsurfaceScale * SubsurfaceRadius;
float subsurface_ior = (subsurface_method == "random_walk") ? SubsurfaceIOR : IOR;
float subsurface_ior = (subsurface_method == "random_walk_skin") ? SubsurfaceIOR : eta;
closure color SubsurfBSDF = bssrdf(subsurface_method,
Normal,
SubsurfaceScale * SubsurfaceRadius,
@ -64,66 +79,64 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
subsurface_ior,
"anisotropy",
SubsurfaceAnisotropy);
BSDF = mix(BSDF, BaseColor * SubsurfBSDF, Subsurface);
BSDF = mix(BSDF, BaseColor * SubsurfBSDF, subsurface_weight);
}
color f0 = color(F0_from_ior(IOR));
color f90 = color(1.0);
/* Apply specular tint */
float m_cdlum = luminance(BaseColor);
color m_ctint = m_cdlum > 0.0 ? BaseColor / m_cdlum : color(1.0);
color specTint = mix(color(1.0), m_ctint, SpecularTint);
f0 *= (specTint * 2.0 * Specular);
color F0 = f0 * specular_tint;
color F90 = color(1.0);
BSDF = layer(
generalized_schlick_bsdf(
Normal, T, color(1.0), color(0.0), alpha_x, alpha_y, f0, f90, -IOR, distribution),
Normal, T, color(1.0), color(0.0), alpha_x, alpha_y, F0, F90, -eta, distribution),
BSDF);
}
closure color TransmissionBSDF = 0;
if (Metallic < 1.0 && Transmission > 0.0) {
color reflectTint = mix(color(1.0), BaseColor, SpecularTint);
if (Metallic < 1.0 && TransmissionWeight > 0.0) {
float eta = max(IOR, 1e-5);
eta = backfacing() ? 1.0 / eta : eta;
TransmissionBSDF = dielectric_bsdf(
Normal, vector(0.0), reflectTint, sqrt(BaseColor), r2, r2, eta, distribution);
BSDF = mix(BSDF, TransmissionBSDF, clamp(Transmission, 0.0, 1.0));
color F0 = F0_from_ior(eta) * specular_tint;
color F90 = color(1.0);
TransmissionBSDF = generalized_schlick_bsdf(
Normal, vector(0.0), color(1.0), sqrt(BaseColor), r2, r2, F0, F90, -eta, distribution),
BSDF = mix(BSDF, TransmissionBSDF, clamp(TransmissionWeight, 0.0, 1.0));
}
closure color MetallicBSDF = 0;
if (Metallic > 0.0) {
color f0 = BaseColor;
color f90 = color(1.0);
MetallicBSDF = generalized_schlick_bsdf(
Normal, T, color(1.0), color(0.0), alpha_x, alpha_y, f0, f90, 5.0, distribution);
color F0 = BaseColor;
color F82 = specular_tint;
MetallicBSDF = microfacet_f82_tint(distribution, Normal, T, alpha_x, alpha_y, F0, F82);
BSDF = mix(BSDF, MetallicBSDF, clamp(Metallic, 0.0, 1.0));
}
if (EmissionStrength > 0.0 && Emission != color(0.0)) {
BSDF += EmissionStrength * Emission * emission();
if (EmissionStrength > 0.0 && EmissionColor != color(0.0)) {
BSDF += EmissionStrength * EmissionColor * emission();
}
if (Coat > 1e-5) {
if (CoatWeight > 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);
BSDF *= pow(CoatTint, CoatWeight / cosNT);
}
float coat_r2 = CoatRoughness * CoatRoughness;
float coat_r2 = clamp(CoatRoughness, 0.0, 1.0);
coat_r2 = coat_r2 * coat_r2;
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);
BSDF = layer(clamp(CoatWeight, 0.0, 1.0) * CoatBSDF, BSDF);
}
if (Sheen > 1e-5) {
closure color SheenBSDF = sheen(Normal, SheenRoughness);
BSDF = layer(SheenTint * Sheen * SheenBSDF, BSDF);
if (SheenWeight > 1e-5) {
closure color SheenBSDF = sheen(Normal, clamp(SheenRoughness, 0.0, 1.0));
BSDF = layer(clamp(SheenWeight, 0.0, 1.0) * SheenTint * SheenBSDF, BSDF);
}
BSDF = mix(transparent(), BSDF, Alpha);
BSDF = mix(transparent(), BSDF, clamp(Alpha, 0.0, 1.0));
}

View File

@ -26,6 +26,9 @@ closure color ashikhmin_velvet(normal N, float sigma) BUILTIN;
closure color sheen(normal N, float roughness) BUILTIN;
closure color ambient_occlusion() BUILTIN;
closure color microfacet_f82_tint(
string distribution, vector N, vector T, float ax, float ay, color f0, color f82) BUILTIN;
/* Needed to pass along the color for multi-scattering saturation adjustment,
* otherwise could be replaced by microfacet() */
closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN;

View File

@ -74,46 +74,50 @@ 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, sheen_roughness_offset, coat_offset,
coat_roughness_offset, coat_ior_offset, eta_offset, transmission_offset,
uint specular_ior_level_offset, roughness_offset, specular_tint_offset, anisotropic_offset,
sheen_weight_offset, sheen_tint_offset, sheen_roughness_offset, coat_weight_offset,
coat_roughness_offset, coat_ior_offset, eta_offset, transmission_weight_offset,
anisotropic_rotation_offset, coat_tint_offset, coat_normal_offset, dummy, alpha_offset,
emission_strength_offset, emission_offset;
emission_strength_offset, emission_offset, unused;
uint4 data_node2 = read_node(kg, &offset);
float3 T = stack_load_float3(stack, data_node.y);
svm_unpack_node_uchar4(data_node.z,
&specular_offset,
&specular_ior_level_offset,
&roughness_offset,
&specular_tint_offset,
&anisotropic_offset);
svm_unpack_node_uchar4(
data_node.w, &sheen_offset, &sheen_tint_offset, &sheen_roughness_offset, &dummy);
data_node.w, &sheen_weight_offset, &sheen_tint_offset, &sheen_roughness_offset, &unused);
svm_unpack_node_uchar4(data_node2.x,
&eta_offset,
&transmission_offset,
&transmission_weight_offset,
&anisotropic_rotation_offset,
&coat_normal_offset);
svm_unpack_node_uchar4(
data_node2.w, &coat_offset, &coat_roughness_offset, &coat_ior_offset, &coat_tint_offset);
svm_unpack_node_uchar4(data_node2.w,
&coat_weight_offset,
&coat_roughness_offset,
&coat_ior_offset,
&coat_tint_offset);
// get Disney principled parameters
float metallic = saturatef(param1);
float subsurface = param2;
float specular = stack_load_float(stack, specular_offset);
float roughness = stack_load_float(stack, roughness_offset);
float specular_tint = stack_load_float(stack, specular_tint_offset);
float anisotropic = stack_load_float(stack, anisotropic_offset);
float sheen = stack_load_float(stack, sheen_offset);
float subsurface_weight = saturatef(param2);
brecht marked this conversation as resolved Outdated

Should be clamped to 0..1

Should be clamped to 0..1
float specular_ior_level = fmaxf(stack_load_float(stack, specular_ior_level_offset), 0.0f);
float roughness = saturatef(stack_load_float(stack, roughness_offset));
Spectrum specular_tint = rgb_to_spectrum(
max(stack_load_float3(stack, specular_tint_offset), zero_float3()));
brecht marked this conversation as resolved Outdated

Same as in EEVEE, I don't think we want to hard-clamp >1.0 anymore.

Same as in EEVEE, I don't think we want to hard-clamp >1.0 anymore.
float anisotropic = saturatef(stack_load_float(stack, anisotropic_offset));
float sheen_weight = saturatef(stack_load_float(stack, sheen_weight_offset));
float3 sheen_tint = stack_load_float3(stack, sheen_tint_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 sheen_roughness = saturatef(stack_load_float(stack, sheen_roughness_offset));
float coat_weight = saturatef(stack_load_float(stack, coat_weight_offset));
float coat_roughness = saturatef(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 transmission_weight = saturatef(stack_load_float(stack, transmission_weight_offset));
float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset);
float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
float ior = fmaxf(stack_load_float(stack, eta_offset), 1e-5f);
ClosureType distribution = (ClosureType)data_node2.y;
ClosureType subsurface_method = (ClosureType)data_node2.z;
@ -139,17 +143,18 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
&dummy);
float alpha = stack_valid(alpha_offset) ? stack_load_float(stack, alpha_offset) :
__uint_as_float(data_alpha_emission.y);
float3 emission = stack_load_float3(stack, emission_offset);
/* Emission strength */
emission *= stack_valid(emission_strength_offset) ?
stack_load_float(stack, emission_strength_offset) :
__uint_as_float(data_alpha_emission.z);
alpha = saturatef(alpha);
float emission_strength = stack_valid(emission_strength_offset) ?
stack_load_float(stack, emission_strength_offset) :
__uint_as_float(data_alpha_emission.z);
float3 emission = stack_load_float3(stack, emission_offset) * fmaxf(emission_strength, 0.0f);
Spectrum weight = closure_weight * mix_weight;
float alpha_x = sqr(roughness), alpha_y = sqr(roughness);
if (anisotropic > 0.0f) {
float aspect = sqrtf(1.0f - saturatef(anisotropic) * 0.9f);
float aspect = sqrtf(1.0f - anisotropic * 0.9f);
alpha_x /= aspect;
alpha_y *= aspect;
if (anisotropic_rotation != 0.0f)
@ -174,9 +179,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
/* First layer: Sheen */
if (sheen > CLOSURE_WEIGHT_CUTOFF) {
if (sheen_weight > CLOSURE_WEIGHT_CUTOFF) {
ccl_private SheenBsdf *bsdf = (ccl_private SheenBsdf *)bsdf_alloc(
sd, sizeof(SheenBsdf), sheen * rgb_to_spectrum(sheen_tint) * weight);
sd, sizeof(SheenBsdf), sheen_weight * rgb_to_spectrum(sheen_tint) * weight);
if (bsdf) {
bsdf->N = N;
@ -192,14 +197,14 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
/* Second layer: Coat */
if (coat > CLOSURE_WEIGHT_CUTOFF) {
if (coat_weight > CLOSURE_WEIGHT_CUTOFF) {
float3 coat_normal = stack_valid(coat_normal_offset) ?
stack_load_float3(stack, coat_normal_offset) :
sd->N;
coat_normal = maybe_ensure_valid_specular_reflection(sd, coat_normal);
if (reflective_caustics) {
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), coat * weight);
sd, sizeof(MicrofacetBsdf), coat_weight * weight);
if (bsdf) {
bsdf->N = coat_normal;
@ -242,7 +247,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
* 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);
weight *= power(rgb_to_spectrum(coat_tint), coat_weight * optical_depth);
}
}
@ -255,10 +260,10 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
if (reflective_caustics && metallic > CLOSURE_WEIGHT_CUTOFF) {
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), metallic * weight);
ccl_private FresnelGeneralizedSchlick *fresnel =
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
sd, sizeof(FresnelGeneralizedSchlick)) :
NULL;
ccl_private FresnelF82Tint *fresnel =
(bsdf != NULL) ?
(ccl_private FresnelF82Tint *)closure_alloc_extra(sd, sizeof(FresnelF82Tint)) :
NULL;
if (bsdf && fresnel) {
bsdf->N = valid_reflection_N;
@ -268,15 +273,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf->alpha_y = alpha_y;
fresnel->f0 = rgb_to_spectrum(base_color);
fresnel->f90 = one_spectrum();
fresnel->exponent = 5.0f;
fresnel->reflection_tint = one_spectrum();
fresnel->transmission_tint = zero_spectrum();
const Spectrum f82 = specular_tint;
/* setup bsdf */
sd->flag |= bsdf_microfacet_ggx_setup(bsdf);
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx);
bsdf_microfacet_setup_fresnel_f82_tint(kg, bsdf, sd, fresnel, f82, is_multiggx);
/* Attenuate other components */
weight *= (1.0f - metallic);
@ -284,12 +286,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
/* Transmission component */
if (glass_caustics && transmission > CLOSURE_WEIGHT_CUTOFF) {
if (glass_caustics && transmission_weight > CLOSURE_WEIGHT_CUTOFF) {
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), transmission * weight);
ccl_private FresnelDielectricTint *fresnel =
(bsdf != NULL) ? (ccl_private FresnelDielectricTint *)closure_alloc_extra(
sd, sizeof(FresnelDielectricTint)) :
sd, sizeof(MicrofacetBsdf), transmission_weight * weight);
ccl_private FresnelGeneralizedSchlick *fresnel =
(bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra(
sd, sizeof(FresnelGeneralizedSchlick)) :
NULL;
if (bsdf && fresnel) {
@ -297,19 +299,21 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bsdf->T = zero_float3();
bsdf->alpha_x = bsdf->alpha_y = sqr(roughness);
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta;
bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / ior : ior;
fresnel->reflection_tint = mix(
one_spectrum(), rgb_to_spectrum(base_color), specular_tint);
fresnel->f0 = make_float3(F0_from_ior(ior));
fresnel->f90 = one_spectrum();
fresnel->exponent = -ior;
fresnel->reflection_tint = one_spectrum();
fresnel->transmission_tint = sqrt(rgb_to_spectrum(base_color));
/* setup bsdf */
sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf);
const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
bsdf_microfacet_setup_fresnel_dielectric_tint(kg, bsdf, sd, fresnel, is_multiggx);
bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx);
/* Attenuate other components */
weight *= (1.0f - transmission);
weight *= (1.0f - transmission_weight);
}
}
@ -323,17 +327,24 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
NULL;
if (bsdf && fresnel) {
/* Apply IOR adjustment */
float eta = ior;
float f0 = F0_from_ior(eta);
if (specular_ior_level != 0.5f) {
f0 *= 2.0f * specular_ior_level;
eta = ior_from_F0(f0);
if (ior < 1.0f) {
eta = 1.0f / eta;
}
}
bsdf->N = valid_reflection_N;
bsdf->ior = eta;
bsdf->T = T;
bsdf->alpha_x = alpha_x;
bsdf->alpha_y = alpha_y;
float m_cdlum = linear_rgb_to_gray(kg, base_color);
float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : one_float3();
float3 specTint = mix(one_spectrum(), rgb_to_spectrum(m_ctint), specular_tint);
fresnel->f0 = F0_from_ior(eta) * 2.0f * specular * specTint;
fresnel->f0 = f0 * specular_tint;
fresnel->f90 = one_spectrum();
fresnel->exponent = -eta;
fresnel->reflection_tint = one_spectrum();
@ -352,8 +363,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
/* Diffuse/Subsurface component */
#ifdef __SUBSURFACE__
ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd,
rgb_to_spectrum(base_color) * subsurface * weight);
ccl_private Bssrdf *bssrdf = bssrdf_alloc(
sd, rgb_to_spectrum(base_color) * subsurface_weight * weight);
if (bssrdf) {
float3 subsurface_radius = stack_load_float3(stack, data_subsurf.y);
float subsurface_scale = stack_load_float(stack, data_subsurf.z);
@ -362,9 +373,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
bssrdf->albedo = rgb_to_spectrum(base_color);
bssrdf->N = N;
bssrdf->alpha = sqr(roughness);
bssrdf->ior = eta;
bssrdf->ior = ior;
bssrdf->anisotropy = stack_load_float(stack, data_subsurf.w);
if (subsurface_method == CLOSURE_BSSRDF_RANDOM_WALK_ID) {
if (subsurface_method == CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID) {
bssrdf->ior = stack_load_float(stack, data_subsurf.x);
}
@ -372,11 +383,13 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
sd->flag |= bssrdf_setup(sd, bssrdf, path_flag, subsurface_method);
}
#else
subsurface = 0.0f;
subsurface_weight = 0.0f;
#endif
ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc(
sd, sizeof(DiffuseBsdf), rgb_to_spectrum(base_color) * (1.0f - subsurface) * weight);
sd,
sizeof(DiffuseBsdf),
rgb_to_spectrum(base_color) * (1.0f - subsurface_weight) * weight);
if (bsdf) {
bsdf->N = N;
@ -804,7 +817,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
#ifdef __SUBSURFACE__
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSSRDF_RANDOM_WALK_ID:
case CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID: {
case CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID: {
Spectrum weight = closure_weight * mix_weight;
ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, weight);

View File

@ -453,7 +453,7 @@ typedef enum ClosureType {
/* BSSRDF */
CLOSURE_BSSRDF_BURLEY_ID,
CLOSURE_BSSRDF_RANDOM_WALK_ID,
CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID,
CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID,
/* Other */
CLOSURE_HOLDOUT_ID,
@ -490,9 +490,9 @@ typedef enum ClosureType {
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) \
(type != CLOSURE_NONE_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
(type != CLOSURE_NONE_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID)
#define CLOSURE_IS_BSSRDF(type) \
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID)
#define CLOSURE_IS_VOLUME(type) \
(type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_VOLUME_SCATTER(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)

View File

@ -138,7 +138,7 @@ static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant)
{
const bool is_principled = (node->type == PrincipledBsdfNode::get_node_type());
/* Emission and Background node. */
ShaderInput *color_in = node->input(is_principled ? "Emission" : "Color");
ShaderInput *color_in = node->input(is_principled ? "Emission Color" : "Color");
ShaderInput *strength_in = node->input(is_principled ? "Emission Strength" : "Strength");
if (is_principled) {

View File

@ -2690,9 +2690,8 @@ NODE_DEFINE(PrincipledBsdfNode)
static NodeEnum subsurface_method_enum;
subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
subsurface_method_enum.insert("random_walk_fixed_radius",
CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
subsurface_method_enum.insert("random_walk_skin", CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
SOCKET_ENUM(subsurface_method,
"Subsurface Method",
subsurface_method_enum,
@ -2700,31 +2699,38 @@ NODE_DEFINE(PrincipledBsdfNode)
SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f))
SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
SOCKET_IN_NORMAL(normal, "Normal", zero_float3(), SocketType::LINK_NORMAL);
SOCKET_IN_FLOAT(subsurface_weight, "Subsurface Weight", 0.0f);
SOCKET_IN_FLOAT(subsurface_scale, "Subsurface Scale", 0.1f);
SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
SOCKET_IN_FLOAT(subsurface_ior, "Subsurface IOR", 1.4f);
SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f);
SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
SOCKET_IN_FLOAT(specular_ior_level, "Specular IOR Level", 0.0f);
SOCKET_IN_COLOR(specular_tint, "Specular Tint", one_float3());
SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
SOCKET_IN_NORMAL(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT);
SOCKET_IN_FLOAT(transmission_weight, "Transmission Weight", 0.0f);
SOCKET_IN_FLOAT(sheen_weight, "Sheen Weight", 0.0f);
SOCKET_IN_FLOAT(sheen_roughness, "Sheen Roughness", 0.5f);
SOCKET_IN_COLOR(sheen_tint, "Sheen Tint", one_float3());
SOCKET_IN_FLOAT(coat, "Coat", 0.0f);
SOCKET_IN_FLOAT(coat_weight, "Coat Weight", 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);
SOCKET_IN_COLOR(emission, "Emission", one_float3());
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
SOCKET_IN_NORMAL(normal, "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_COLOR(emission_color, "Emission Color", one_float3());
SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
@ -2742,7 +2748,7 @@ void PrincipledBsdfNode::simplify_settings(Scene * /* scene */)
{
if (!has_surface_emission()) {
/* Emission will be zero, so optimize away any connected emission input. */
ShaderInput *emission_in = input("Emission");
ShaderInput *emission_in = input("Emission Color");
ShaderInput *strength_in = input("Emission Strength");
if (emission_in->link) {
emission_in->disconnect();
@ -2761,16 +2767,18 @@ bool PrincipledBsdfNode::has_surface_transparent()
bool PrincipledBsdfNode::has_surface_emission()
{
ShaderInput *emission_in = input("Emission");
ShaderInput *emission_color_in = input("Emission Color");
ShaderInput *emission_strength_in = input("Emission Strength");
return (emission_in->link != NULL || reduce_max(emission) > CLOSURE_WEIGHT_CUTOFF) &&
return (emission_color_in->link != NULL || reduce_max(emission_color) > CLOSURE_WEIGHT_CUTOFF) &&
(emission_strength_in->link != NULL || emission_strength > CLOSURE_WEIGHT_CUTOFF);
}
bool PrincipledBsdfNode::has_surface_bssrdf()
{
ShaderInput *subsurface_in = input("Subsurface");
return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF);
ShaderInput *subsurface_weight_in = input("Subsurface Weight");
ShaderInput *subsurface_scale_in = input("Subsurface Scale");
return (subsurface_weight_in->link != NULL || subsurface_weight > CLOSURE_WEIGHT_CUTOFF) &&
(subsurface_scale_in->link != NULL || subsurface_scale != 0.0f);
}
void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@ -2791,7 +2799,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
ShaderInput *base_color_in = input("Base Color");
ShaderInput *p_metallic = input("Metallic");
ShaderInput *p_subsurface = input("Subsurface");
ShaderInput *p_subsurface_weight = input("Subsurface Weight");
ShaderInput *emission_strength_in = input("Emission Strength");
ShaderInput *alpha_in = input("Alpha");
@ -2803,19 +2811,19 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
int normal_offset = compiler.stack_assign_if_linked(input("Normal"));
int coat_normal_offset = compiler.stack_assign_if_linked(input("Coat Normal"));
int tangent_offset = compiler.stack_assign_if_linked(input("Tangent"));
int specular_offset = compiler.stack_assign(input("Specular"));
int specular_ior_level_offset = compiler.stack_assign(input("Specular IOR Level"));
int roughness_offset = compiler.stack_assign(input("Roughness"));
int specular_tint_offset = compiler.stack_assign(input("Specular Tint"));
int anisotropic_offset = compiler.stack_assign(input("Anisotropic"));
int sheen_offset = compiler.stack_assign(input("Sheen"));
int sheen_weight_offset = compiler.stack_assign(input("Sheen Weight"));
int sheen_roughness_offset = compiler.stack_assign(input("Sheen Roughness"));
int sheen_tint_offset = compiler.stack_assign(input("Sheen Tint"));
int coat_offset = compiler.stack_assign(input("Coat"));
int coat_weight_offset = compiler.stack_assign(input("Coat Weight"));
int coat_roughness_offset = compiler.stack_assign(input("Coat Roughness"));
int coat_ior_offset = compiler.stack_assign(input("Coat IOR"));
int coat_tint_offset = compiler.stack_assign(input("Coat Tint"));
int ior_offset = compiler.stack_assign(input("IOR"));
int transmission_offset = compiler.stack_assign(input("Transmission"));
int transmission_weight_offset = compiler.stack_assign(input("Transmission Weight"));
int anisotropic_rotation_offset = compiler.stack_assign(input("Anisotropic Rotation"));
int subsurface_radius_offset = compiler.stack_assign(input("Subsurface Radius"));
int subsurface_scale_offset = compiler.stack_assign(input("Subsurface Scale"));
@ -2823,31 +2831,31 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
int subsurface_anisotropy_offset = compiler.stack_assign(input("Subsurface Anisotropy"));
int alpha_offset = compiler.stack_assign_if_linked(alpha_in);
int emission_strength_offset = compiler.stack_assign_if_linked(emission_strength_in);
int emission_offset = compiler.stack_assign(input("Emission"));
int emission_color_offset = compiler.stack_assign(input("Emission Color"));
compiler.add_node(NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
compiler.stack_assign(p_metallic),
compiler.stack_assign(p_subsurface),
compiler.closure_mix_weight_offset()),
__float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
__float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f));
compiler.add_node(
NODE_CLOSURE_BSDF,
compiler.encode_uchar4(closure,
compiler.stack_assign(p_metallic),
compiler.stack_assign(p_subsurface_weight),
compiler.closure_mix_weight_offset()),
__float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
__float_as_int((p_subsurface_weight) ? get_float(p_subsurface_weight->socket_type) : 0.0f));
compiler.add_node(
normal_offset,
tangent_offset,
compiler.encode_uchar4(
specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
compiler.encode_uchar4(
sheen_offset, sheen_tint_offset, sheen_roughness_offset, SVM_STACK_INVALID));
specular_ior_level_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
compiler.encode_uchar4(sheen_weight_offset, sheen_tint_offset, sheen_roughness_offset));
compiler.add_node(
compiler.encode_uchar4(
ior_offset, transmission_offset, anisotropic_rotation_offset, coat_normal_offset),
ior_offset, transmission_weight_offset, anisotropic_rotation_offset, coat_normal_offset),
distribution,
subsurface_method,
compiler.encode_uchar4(
coat_offset, coat_roughness_offset, coat_ior_offset, coat_tint_offset));
coat_weight_offset, coat_roughness_offset, coat_ior_offset, coat_tint_offset));
float3 bc_default = get_float3(base_color_in->socket_type);
@ -2864,7 +2872,7 @@ void PrincipledBsdfNode::compile(SVMCompiler &compiler)
compiler.add_node(
compiler.encode_uchar4(
alpha_offset, emission_strength_offset, emission_offset, SVM_STACK_INVALID),
alpha_offset, emission_strength_offset, emission_color_offset, SVM_STACK_INVALID),
__float_as_int(get_float(alpha_in->socket_type)),
__float_as_int(get_float(emission_strength_in->socket_type)),
SVM_STACK_INVALID);
@ -2953,8 +2961,8 @@ NODE_DEFINE(SubsurfaceScatteringNode)
static NodeEnum method_enum;
method_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
method_enum.insert("random_walk_fixed_radius", CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID);
method_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
method_enum.insert("random_walk_skin", CLOSURE_BSSRDF_RANDOM_WALK_SKIN_ID);
SOCKET_ENUM(method, "Method", method_enum, CLOSURE_BSSRDF_RANDOM_WALK_ID);
SOCKET_IN_FLOAT(scale, "Scale", 0.01f);

View File

@ -519,35 +519,35 @@ class PrincipledBsdfNode : public BsdfBaseNode {
void simplify_settings(Scene *scene);
NODE_SOCKET_API(float3, base_color)
NODE_SOCKET_API(float, metallic)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, ior)
NODE_SOCKET_API(float3, normal)
NODE_SOCKET_API(float, alpha)
NODE_SOCKET_API(ClosureType, subsurface_method)
NODE_SOCKET_API(float, subsurface_weight)
NODE_SOCKET_API(float3, subsurface_radius)
NODE_SOCKET_API(float, subsurface_scale)
NODE_SOCKET_API(float, subsurface_ior)
NODE_SOCKET_API(float, subsurface_anisotropy)
NODE_SOCKET_API(float, metallic)
NODE_SOCKET_API(float, subsurface)
NODE_SOCKET_API(float, specular)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, specular_tint)
NODE_SOCKET_API(ClosureType, distribution)
NODE_SOCKET_API(float, specular_ior_level)
NODE_SOCKET_API(float3, specular_tint)
NODE_SOCKET_API(float, anisotropic)
NODE_SOCKET_API(float, sheen)
NODE_SOCKET_API(float, anisotropic_rotation)
NODE_SOCKET_API(float3, tangent)
NODE_SOCKET_API(float, transmission_weight)
NODE_SOCKET_API(float, sheen_weight)
NODE_SOCKET_API(float, sheen_roughness)
NODE_SOCKET_API(float3, sheen_tint)
NODE_SOCKET_API(float, coat)
NODE_SOCKET_API(float, coat_weight)
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, coat_normal)
NODE_SOCKET_API(float3, tangent)
NODE_SOCKET_API(float, surface_mix_weight)
NODE_SOCKET_API(ClosureType, distribution)
NODE_SOCKET_API(ClosureType, subsurface_method)
NODE_SOCKET_API(float3, emission)
NODE_SOCKET_API(float3, emission_color)
NODE_SOCKET_API(float, emission_strength)
NODE_SOCKET_API(float, alpha)
NODE_SOCKET_API(float, surface_mix_weight)
public:
void attributes(Shader *shader, AttributeRequestSet *attributes);

View File

@ -281,27 +281,28 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def specular_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
return self.material.specular_intensity
return self.node_principled_bsdf.inputs["Specular"].default_value
return self.node_principled_bsdf.inputs["Specular IOR Level"].default_value
@_set_check
def specular_set(self, value):
value = values_clamp(value, 0.0, 1.0)
self.material.specular_intensity = value
if self.use_nodes and self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Specular"].default_value = value
self.node_principled_bsdf.inputs["Specular IOR Level"].default_value = value
specular = property(specular_get, specular_set)
def specular_tint_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
return 0.0
return self.node_principled_bsdf.inputs["Specular Tint"].default_value
return Color((0.0, 0.0, 0.0))
return rgba_to_rgb(self.node_principled_bsdf.inputs["Specular Tint"].default_value)
@_set_check
def specular_tint_set(self, value):
value = values_clamp(value, 0.0, 1.0)
def specular_tint_set(self, color):
color = values_clamp(color, 0.0, 1.0)
color = rgb_to_rgba(color)
if self.use_nodes and self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Specular Tint"].default_value = value
self.node_principled_bsdf.inputs["Specular Tint"].default_value = color
specular_tint = property(specular_tint_get, specular_tint_set)
@ -312,7 +313,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Specular"],
self.node_principled_bsdf.inputs["Specular IOR Level"],
grid_row_diff=0,
colorspace_name='Non-Color',
)
@ -411,13 +412,13 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def transmission_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
return 0.0
return self.node_principled_bsdf.inputs["Transmission"].default_value
return self.node_principled_bsdf.inputs["Transmission Weight"].default_value
@_set_check
def transmission_set(self, value):
value = values_clamp(value, 0.0, 1.0)
if self.use_nodes and self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Transmission"].default_value = value
self.node_principled_bsdf.inputs["Transmission Weight"].default_value = value
transmission = property(transmission_get, transmission_set)
@ -427,7 +428,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Transmission"],
self.node_principled_bsdf.inputs["Transmission Weight"],
grid_row_diff=-1,
colorspace_name='Non-Color',
)
@ -467,14 +468,14 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def emission_color_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
return Color((0.0, 0.0, 0.0))
return rgba_to_rgb(self.node_principled_bsdf.inputs["Emission"].default_value)
return rgba_to_rgb(self.node_principled_bsdf.inputs["Emission Color"].default_value)
@_set_check
def emission_color_set(self, color):
if self.use_nodes and self.node_principled_bsdf is not None:
color = values_clamp(color, 0.0, 1000000.0)
color = rgb_to_rgba(color)
self.node_principled_bsdf.inputs["Emission"].default_value = color
self.node_principled_bsdf.inputs["Emission Color"].default_value = color
emission_color = property(emission_color_get, emission_color_set)
@ -483,7 +484,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
self.node_principled_bsdf.inputs["Emission"],
self.node_principled_bsdf.inputs["Emission Color"],
grid_row_diff=1,
)

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 24
#define BLENDER_FILE_SUBVERSION 25
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -1070,7 +1070,7 @@ static void displacement_principled_nodes(bNode *node)
}
}
else if (node->type == SH_NODE_BSDF_PRINCIPLED) {
if (node->custom2 != SHD_SUBSURFACE_RANDOM_WALK) {
if (node->custom2 != SHD_SUBSURFACE_RANDOM_WALK_SKIN) {
node->custom2 = SHD_SUBSURFACE_BURLEY;
}
}

View File

@ -1548,13 +1548,13 @@ static bool seq_meta_channels_ensure(Sequence *seq, void * /*user_data*/)
static void do_version_subsurface_methods(bNode *node)
{
if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
if (!ELEM(node->custom1, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
if (!ELEM(node->custom1, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK_SKIN)) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
}
}
else if (node->type == SH_NODE_BSDF_PRINCIPLED) {
if (!ELEM(node->custom2, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK)) {
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS;
if (!ELEM(node->custom2, SHD_SUBSURFACE_BURLEY, SHD_SUBSURFACE_RANDOM_WALK_SKIN)) {
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
}
}
}

View File

@ -692,6 +692,19 @@ static void version_principled_bsdf_emission(bNodeTree *ntree)
}
}
/* Rename various Principled BSDF sockets. */
brecht marked this conversation as resolved Outdated

… and specular to specular ior level

… and specular to specular ior level
static void version_principled_bsdf_rename_sockets(bNodeTree *ntree)
{
version_node_input_socket_name(ntree, SH_NODE_BSDF_PRINCIPLED, "Emission", "Emission Color");
version_node_input_socket_name(ntree, SH_NODE_BSDF_PRINCIPLED, "Specular", "Specular IOR Level");
version_node_input_socket_name(
ntree, SH_NODE_BSDF_PRINCIPLED, "Subsurface", "Subsurface Weight");
version_node_input_socket_name(
ntree, SH_NODE_BSDF_PRINCIPLED, "Transmission", "Transmission Weight");
version_node_input_socket_name(ntree, SH_NODE_BSDF_PRINCIPLED, "Coat", "Coat Weight");
version_node_input_socket_name(ntree, SH_NODE_BSDF_PRINCIPLED, "Sheen", "Sheen Weight");
}
/* Replace old Principled Hair BSDF as a variant in the new Principled Hair BSDF. */
static void version_replace_principled_hair_model(bNodeTree *ntree)
{
@ -796,6 +809,65 @@ static void version_principled_bsdf_coat(bNodeTree *ntree)
ntree, SH_NODE_BSDF_PRINCIPLED, "Clearcoat Normal", "Coat Normal");
}
/* Convert specular tint in Principled BSDF. */
static void version_principled_bsdf_specular_tint(bNodeTree *ntree)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type != SH_NODE_BSDF_PRINCIPLED) {
continue;
}
bNodeSocket *specular_tint_sock = nodeFindSocket(node, SOCK_IN, "Specular Tint");
if (specular_tint_sock->type == SOCK_RGBA) {
/* Node is already updated. */
continue;
}
bNodeSocket *base_color_sock = nodeFindSocket(node, SOCK_IN, "Base Color");
float specular_tint_old = *version_cycles_node_socket_float_value(specular_tint_sock);
float *base_color = version_cycles_node_socket_rgba_value(base_color_sock);
/* Change socket type to Color. */
nodeModifySocketTypeStatic(ntree, node, specular_tint_sock, SOCK_RGBA, 0);
static float one[] = {1.0f, 1.0f, 1.0f, 1.0f};
/* If any of the two inputs is dynamic, we add a Mix node. */
if (base_color_sock->link || specular_tint_sock->link) {
bNode *mix = nodeAddStaticNode(nullptr, ntree, SH_NODE_MIX);
static_cast<NodeShaderMix *>(mix->storage)->data_type = SOCK_RGBA;
mix->locx = node->locx - 170;
mix->locy = node->locy - 120;
bNodeSocket *a_in = nodeFindSocket(mix, SOCK_IN, "A_Color");
bNodeSocket *b_in = nodeFindSocket(mix, SOCK_IN, "B_Color");
bNodeSocket *fac_in = nodeFindSocket(mix, SOCK_IN, "Factor_Float");
bNodeSocket *result_out = nodeFindSocket(mix, SOCK_OUT, "Result_Color");
copy_v4_v4(version_cycles_node_socket_rgba_value(a_in), one);
copy_v4_v4(version_cycles_node_socket_rgba_value(b_in), base_color);
*version_cycles_node_socket_float_value(fac_in) = specular_tint_old;
if (base_color_sock->link) {
nodeAddLink(
ntree, base_color_sock->link->fromnode, base_color_sock->link->fromsock, mix, b_in);
}
if (specular_tint_sock->link) {
nodeAddLink(ntree,
specular_tint_sock->link->fromnode,
specular_tint_sock->link->fromsock,
mix,
fac_in);
nodeRemLink(ntree, specular_tint_sock->link);
}
nodeAddLink(ntree, mix, result_out, node, specular_tint_sock);
}
float *specular_tint = version_cycles_node_socket_rgba_value(specular_tint_sock);
/* Mix the fixed values. */
interp_v4_v4v4(specular_tint, one, base_color, specular_tint_old);
}
}
static void version_copy_socket(bNodeTreeInterfaceSocket &dst,
const bNodeTreeInterfaceSocket &src,
char *identifier)
@ -1359,6 +1431,18 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 25)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
if (ntree->type == NTREE_SHADER) {
/* Convert specular tint on the Principled BSDF. */
version_principled_bsdf_specular_tint(ntree);
/* Rename some sockets. */
version_principled_bsdf_rename_sockets(ntree);
}
}
FOREACH_NODETREE_END;
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -609,7 +609,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
if (node->type == SH_NODE_BSDF_PRINCIPLED) {
bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness");
*version_cycles_node_socket_float_value(roughness_socket) = 0.5f;
bNodeSocket *emission = nodeFindSocket(node, SOCK_IN, "Emission");
bNodeSocket *emission = nodeFindSocket(node, SOCK_IN, "Emission Color");
copy_v4_fl(version_cycles_node_socket_rgba_value(emission), 1.0f);
bNodeSocket *emission_strength = nodeFindSocket(node, SOCK_IN, "Emission Strength");
*version_cycles_node_socket_float_value(emission_strength) = 0.0f;

View File

@ -1138,7 +1138,7 @@ bNodeTree *EEVEE_shader_default_surface_nodetree(Material *ma)
e_data.surface.roughness_socket = static_cast<bNodeSocketValueFloat *>(
nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value);
e_data.surface.specular_socket = static_cast<bNodeSocketValueFloat *>(
nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value);
nodeFindSocket(bsdf, SOCK_IN, "Specular IOR Level")->default_value);
e_data.surface.ntree = ntree;
}
/* Update */

View File

@ -17,12 +17,6 @@ vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
return normalize(mix(N, R, fac));
}
float ior_from_f0(float f0)
{
float f = sqrt(f0);
return (-f - 1.0) / (f - 1.0);
}
/* Simplified form of F_eta(eta, 1.0). */
float F0_from_ior(float eta)
{
@ -67,29 +61,29 @@ float F_eta(float eta, float cos_theta)
}
/* Fresnel color blend base on fresnel factor */
vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
vec3 F_color_blend(float eta, float fresnel, vec3 F0_color)
{
float f0 = F0_from_ior(eta);
float fac = saturate((fresnel - f0) / (1.0 - f0));
return mix(f0_color, vec3(1.0), fac);
float F0 = F0_from_ior(eta);
float fac = saturate((fresnel - F0) / (1.0 - F0));
return mix(F0_color, vec3(1.0), fac);
}
/* Fresnel split-sum approximation. */
vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
vec3 F_brdf_single_scatter(vec3 F0, vec3 F90, vec2 lut)
{
return f0 * lut.x + f90 * lut.y;
return F0 * lut.x + F90 * lut.y;
}
/* Multi-scattering brdf approximation from
* "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
* https://jcgt.org/published/0008/01/03/paper.pdf by Carmelo J. Fdez-Agüera. */
vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
vec3 F_brdf_multi_scatter(vec3 F0, vec3 F90, vec2 lut)
{
vec3 FssEss = F_brdf_single_scatter(f0, f90, lut);
vec3 FssEss = F_brdf_single_scatter(F0, F90, lut);
float Ess = lut.x + lut.y;
float Ems = 1.0 - Ess;
vec3 Favg = f0 + (f90 - f0) / 21.0;
vec3 Favg = F0 + (F90 - F0) / 21.0;
/* The original paper uses `FssEss * radiance + Fms*Ems * irradiance`, but
* "A Journey Through Implementing Multiscattering BRDFs and Area Lights" by Steve McAuley

View File

@ -94,6 +94,15 @@ vec3 safe_normalize(vec3 N);
float fast_sqrt(float a);
vec3 cameraVec(vec3 P);
vec2 bsdf_lut(float a, float b, float c, float d);
void bsdf_lut(vec3 F0,
vec3 F90,
vec3 transmission_tint,
float cos_theta,
float roughness,
float ior,
float do_multiscatter,
out vec3 reflectance,
out vec3 transmittance);
vec2 brdf_lut(float a, float b);
vec3 F_brdf_multi_scatter(vec3 a, vec3 b, vec2 c);
vec3 F_brdf_single_scatter(vec3 a, vec3 b, vec2 c);

View File

@ -101,24 +101,35 @@ vec3 lut_coords_bsdf(float cos_theta, float roughness, float ior)
return coords;
}
/* Computes the reflectance and transmittance based on the BSDF LUT. */
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
/* Computes the reflectance and transmittance based on the tint (`f0`, `f90`, `transmission_tint`)
* and the BSDF LUT. */
void bsdf_lut(vec3 F0,
vec3 F90,
vec3 transmission_tint,
float cos_theta,
float roughness,
float ior,
float do_multiscatter,
out vec3 reflectance,
out vec3 transmittance)
{
if (ior == 1.0) {
return vec2(0.0, 1.0);
reflectance = vec3(0.0);
transmittance = transmission_tint;
return;
}
vec2 split_sum;
float transmission_factor;
float F0 = F0_from_ior(ior);
float F90 = 1.0;
if (ior >= 1.0) {
if (ior > 1.0) {
split_sum = brdf_lut(cos_theta, roughness);
transmission_factor = sample_3D_texture(utilTex, lut_coords_btdf(cos_theta, roughness, ior)).a;
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
* transition at `IOR == 1`. */
F90 = saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0));
if (all(equal(F90, vec3(1.0)))) {
F90 = vec3(saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0)));
}
}
else {
vec3 bsdf = sample_3D_texture(utilTex, lut_coords_bsdf(cos_theta, roughness, ior)).rgb;
@ -126,20 +137,41 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
transmission_factor = bsdf.b;
}
float reflectance = F_brdf_single_scatter(vec3(F0), vec3(F90), split_sum).r;
float transmittance = (1.0 - F0) * transmission_factor;
reflectance = F_brdf_single_scatter(F0, F90, split_sum);
transmittance = (vec3(1.0) - F0) * transmission_factor * transmission_tint;
if (do_multiscatter != 0.0) {
float Ess = F0 * split_sum.x + split_sum.y + (1.0 - F0) * transmission_factor;
/* TODO: maybe add saturation for higher roughness similar as in `F_brdf_multi_scatter()`.
* However, it is not necessarily desirable that the users see a different color than they
* picked. */
float scale = 1.0 / Ess;
float real_F0 = F0_from_ior(ior);
float Ess = real_F0 * split_sum.x + split_sum.y + (1.0 - real_F0) * transmission_factor;
float Ems = 1.0 - Ess;
/* Assume that the transmissive tint makes up most of the overall color if it's not zero. */
vec3 Favg = all(equal(transmission_tint, vec3(0.0))) ? F0 + (F90 - F0) / 21.0 :
transmission_tint;
vec3 scale = 1.0 / (1.0 - Ems * Favg);
reflectance *= scale;
transmittance *= scale;
}
return vec2(reflectance, transmittance);
return;
}
/* Computes the reflectance and transmittance based on the BSDF LUT. */
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
float F0 = F0_from_ior(ior);
vec3 color = vec3(1.0);
vec3 reflectance, transmittance;
bsdf_lut(vec3(F0),
color,
color,
cos_theta,
roughness,
ior,
do_multiscatter,
reflectance,
transmittance);
return vec2(reflectance.r, transmittance.r);
}
/** \} */

View File

@ -43,6 +43,21 @@ vec2 bsdf_lut(float a, float b, float c, float d)
return vec2(0.0);
}
void bsdf_lut(vec3 F0,
vec3 F90,
vec3 transmission_tint,
float cos_theta,
float roughness,
float ior,
float do_multiscatter,
out vec3 reflectance,
out vec3 transmittance)
{
reflectance = vec3(0.0);
transmittance = vec3(0.0);
return;
}
vec2 brdf_lut(float a, float b)
{
return vec2(0.0);

View File

@ -41,7 +41,7 @@ DefaultSurfaceNodeTree::DefaultSurfaceNodeTree()
roughness_socket_ =
(bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Roughness")->default_value;
specular_socket_ =
(bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Specular")->default_value;
(bNodeSocketValueFloat *)nodeFindSocket(bsdf, SOCK_IN, "Specular IOR Level")->default_value;
ntree_ = ntree;
}

View File

@ -320,26 +320,37 @@ vec3 lut_coords_btdf(float cos_theta, float roughness, float ior)
return vec3(sqrt((ior - 1.0) / (ior + 1.0)), sqrt(1.0 - cos_theta), roughness);
}
/* Computes the reflectance and transmittance based on the BSDF LUT. */
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
/* Computes the reflectance and transmittance based on the tint (`f0`, `f90`, `transmission_tint`)
* and the BSDF LUT. */
void bsdf_lut(vec3 F0,
vec3 F90,
vec3 transmission_tint,
float cos_theta,
float roughness,
float ior,
float do_multiscatter,
out vec3 reflectance,
out vec3 transmittance)
{
#ifdef EEVEE_UTILITY_TX
if (ior == 1.0) {
return vec2(0.0, 1.0);
reflectance = vec3(0.0);
transmittance = transmission_tint;
return;
}
vec2 split_sum;
float transmission_factor;
float F0 = F0_from_ior(ior);
float F90 = 1.0;
if (ior >= 1.0) {
if (ior > 1.0) {
split_sum = brdf_lut(cos_theta, roughness);
vec3 coords = lut_coords_btdf(cos_theta, roughness, ior);
transmission_factor = utility_tx_sample_bsdf_lut(utility_tx, coords.xy, coords.z).a;
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
* transition at `IOR == 1`. */
F90 = saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0));
if (all(equal(F90, vec3(1.0)))) {
F90 = vec3(saturate(2.33 / 0.33 * (ior - 1.0) / (ior + 1.0)));
}
}
else {
vec3 coords = lut_coords_bsdf(cos_theta, roughness, ior);
@ -348,23 +359,37 @@ vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter
transmission_factor = bsdf.b;
}
float reflectance = F_brdf_single_scatter(vec3(F0), vec3(F90), split_sum).r;
float transmittance = (1.0 - F0) * transmission_factor;
reflectance = F_brdf_single_scatter(F0, F90, split_sum);
transmittance = (vec3(1.0) - F0) * transmission_factor * transmission_tint;
if (do_multiscatter != 0.0) {
float Ess = F0 * split_sum.x + split_sum.y + (1.0 - F0) * transmission_factor;
/* TODO: maybe add saturation for higher roughness similar as in `F_brdf_multi_scatter()`.
* However, it is not necessarily desirable that the users see a different color than they
* picked. */
float scale = 1.0 / Ess;
float real_F0 = F0_from_ior(ior);
float Ess = real_F0 * split_sum.x + split_sum.y + (1.0 - real_F0) * transmission_factor;
float Ems = 1.0 - Ess;
/* Assume that the transmissive tint makes up most of the overall color if it's not zero. */
vec3 Favg = all(equal(transmission_tint, vec3(0.0))) ? F0 + (F90 - F0) / 21.0 :
transmission_tint;
vec3 scale = 1.0 / (1.0 - Ems * Favg);
reflectance *= scale;
transmittance *= scale;
}
return vec2(reflectance, transmittance);
#else
return vec2(0.0);
reflectance = vec3(0.0);
transmittance = vec3(0.0);
#endif
return;
}
/* Computes the reflectance and transmittance based on the BSDF LUT. */
vec2 bsdf_lut(float cos_theta, float roughness, float ior, float do_multiscatter)
{
float F0 = F0_from_ior(ior);
vec3 color = vec3(1.0);
vec3 reflectance, transmittance;
bsdf_lut(
F0, color, color, cos_theta, roughness, ior, do_multiscatter, reflectance, transmittance);
return vec2(reflectance.r, transmittance.r);
}
#ifdef EEVEE_MATERIAL_STUBS

View File

@ -10,7 +10,7 @@ vec3 tint_from_color(vec3 color)
float principled_sheen(float NV, float rough)
{
/* Empirical approximation (manual curve fitting) to the sheen albedo. Can be refined. */
/* Empirical approximation (manual curve fitting) to the sheen_weight albedo. Can be refined. */
float den = 35.6694f * rough * rough - 24.4269f * rough * NV - 0.1405f * NV * NV +
6.1211f * rough + 0.28105f * NV - 0.1405f;
float num = 58.5299f * rough * rough - 85.0941f * rough * NV + 9.8955f * NV * NV +
@ -18,30 +18,36 @@ float principled_sheen(float NV, float rough)
return saturate(den / num);
}
float ior_from_F0(float F0)
{
float f = sqrt(clamp(F0, 0.0, 0.99));
return (-f - 1.0) / (f - 1.0);
}
void node_bsdf_principled(vec4 base_color,
float metallic,
float roughness,
float ior,
float transmission,
float alpha,
vec3 N,
float weight,
float subsurface,
float subsurface_scale,
float subsurface_weight,
vec3 subsurface_radius,
float subsurface_scale,
float subsurface_ior,
float subsurface_anisotropy,
float specular,
float specular_tint,
float specular_ior_level,
vec4 specular_tint,
float anisotropic,
float anisotropic_rotation,
vec3 T,
float coat,
float transmission_weight,
float coat_weight,
float coat_roughness,
float coat_ior,
vec4 coat_tint,
vec3 CN,
float sheen,
float sheen_weight,
float sheen_roughness,
vec4 sheen_tint,
vec4 emission,
@ -55,9 +61,21 @@ void node_bsdf_principled(vec4 base_color,
{
brecht marked this conversation as resolved Outdated

This should also be clamped between 0.0 and 1.0, a mix factor >1 makes no sense.

This should also be clamped between 0.0 and 1.0, a mix factor >1 makes no sense.

Sorry, the line number got messed up here. I meant subsurface_weight.

Sorry, the line number got messed up here. I meant `subsurface_weight`.
/* Match cycles. */
metallic = clamp(metallic, 0.0, 1.0);
brecht marked this conversation as resolved Outdated

I think this is still left over from before the "Tint is now a color" change? I don't think we want a hard limit on 1.0 now.

I think this is still left over from before the "Tint is now a color" change? I don't think we want a hard limit on 1.0 now.

Sorry, the line number got messed up here. I meant the specular_tint.

Sorry, the line number got messed up here. I meant the `specular_tint`.

The F0 is clamped instead, following glTF (706ba4aa38)
Not sure about the metallic tint.

The F0 is clamped instead, following glTF (706ba4aa38) Not sure about the metallic tint.
transmission = clamp(transmission, 0.0, 1.0);
coat = max(coat, 0.0);
roughness = clamp(roughness, 0.0, 1.0);
ior = max(ior, 1e-5);
transmission_weight = clamp(transmission_weight, 0.0, 1.0);
subsurface_weight = clamp(subsurface_weight, 0.0, 1.0);
specular_ior_level = max(specular_ior_level, 0.0);
specular_tint = max(specular_tint, vec4(0.0));
/* Not used by EEVEE */
/* anisotropic = clamp(anisotropic, 0.0, 1.0) */
coat_weight = clamp(coat_weight, 0.0, 1.0);
coat_roughness = clamp(coat_roughness, 0.0, 1.0);
coat_ior = max(coat_ior, 1.0);
sheen_weight = clamp(sheen_weight, 0.0, 1.0);
sheen_roughness = clamp(sheen_roughness, 0.0, 1.0);
emission_strength = max(emission_strength, 0.0);
alpha = clamp(alpha, 0.0, 1.0);
N = safe_normalize(N);
CN = safe_normalize(CN);
@ -71,33 +89,43 @@ void node_bsdf_principled(vec4 base_color,
weight *= alpha;
/* First layer: Sheen */
/* TODO: Maybe sheen should be specular. */
vec3 sheen_color = sheen * sheen_tint.rgb * principled_sheen(NV, sheen_roughness);
ClosureDiffuse diffuse_data;
diffuse_data.color = weight * sheen_color;
diffuse_data.N = N;
/* Attenuate lower layers */
weight *= (1.0 - max_v3(sheen_color));
if (sheen_weight > 0.0) {
/* TODO: Maybe sheen_weight should be specular. */
vec3 sheen_color = sheen_weight * sheen_tint.rgb * principled_sheen(NV, sheen_roughness);
diffuse_data.color = weight * sheen_color;
/* Attenuate lower layers */
weight *= (1.0 - max_v3(sheen_color));
}
else {
diffuse_data.color = vec3(0.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 = bsdf_lut(coat_NV, coat_data.roughness, coat_ior, 0.0).x;
coat_data.weight = weight * coat * reflectance;
coat_data.color = vec3(1.0);
/* Attenuate lower layers */
weight *= (1.0 - reflectance * coat);
if (coat == 0) {
coat_tint.rgb = vec3(1.0);
if (coat_weight > 0.0) {
float coat_NV = dot(coat_data.N, V);
float reflectance = bsdf_lut(coat_NV, coat_data.roughness, coat_ior, 0.0).x;
coat_data.weight = weight * coat_weight * reflectance;
/* Attenuate lower layers */
weight *= (1.0 - reflectance * coat_weight);
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_weight / NT));
}
}
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));
else {
coat_tint.rgb = vec3(1.0);
coat_data.weight = 0.0;
}
/* Attenuated by sheen and coat. */
@ -109,48 +137,67 @@ void node_bsdf_principled(vec4 base_color,
ClosureReflection reflection_data;
reflection_data.N = N;
reflection_data.roughness = roughness;
vec2 split_sum = brdf_lut(NV, roughness);
if (true) {
vec3 f0 = base_color.rgb;
vec3 f90 = vec3(1.0);
vec3 metallic_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
F_brdf_single_scatter(f0, f90, split_sum);
if (metallic > 0.0) {
vec3 F0 = base_color.rgb;
vec3 F90 = vec3(1.0);
vec2 split_sum = brdf_lut(NV, roughness);
vec3 metallic_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(F0, F90, split_sum) :
F_brdf_single_scatter(F0, F90, split_sum);
reflection_data.color = weight * metallic * metallic_brdf;
/* Attenuate lower layers */
weight *= (1.0 - metallic);
}
else {
reflection_data.color = vec3(0.0);
}
/* Transmission component */
ClosureRefraction refraction_data;
/* TODO: change `specular_tint` to rgb. */
vec3 reflection_tint = mix(vec3(1.0), base_color.rgb, specular_tint);
if (true) {
vec2 bsdf = bsdf_lut(NV, roughness, ior, do_multiscatter);
refraction_data.N = N;
refraction_data.roughness = roughness;
refraction_data.ior = ior;
vec3 reflection_tint = specular_tint.rgb;
if (transmission_weight > 0.0) {
vec3 F0 = vec3(F0_from_ior(ior)) * reflection_tint;
vec3 F90 = vec3(1.0);
vec3 reflectance, transmittance;
bsdf_lut(
F0, F90, base_color.rgb, NV, roughness, ior, do_multiscatter, reflectance, transmittance);
reflection_data.color += weight * transmission * bsdf.x * reflection_tint;
reflection_data.color += weight * transmission_weight * reflectance;
refraction_data.weight = weight * transmission * bsdf.y;
refraction_data.color = base_color.rgb * coat_tint.rgb;
refraction_data.N = N;
refraction_data.roughness = roughness;
refraction_data.ior = ior;
refraction_data.weight = weight * transmission_weight;
refraction_data.color = transmittance * coat_tint.rgb;
/* Attenuate lower layers */
weight *= (1.0 - transmission);
weight *= (1.0 - transmission_weight);
}
else {
refraction_data.weight = 0.0;
refraction_data.color = vec3(0.0);
}
/* Specular component */
if (true) {
vec3 f0 = vec3(F0_from_ior(ior));
/* Gradually increase `f90` from 0 to 1 when IOR is in the range of [1.0, 1.33], to avoid harsh
* transition at `IOR == 1`. */
vec3 f90 = sqrt(saturate(f0 / 0.02));
f0 *= 2.0 * specular * reflection_tint;
float eta = ior;
float f0 = F0_from_ior(eta);
if (specular_ior_level != 0.5) {
f0 *= 2.0 * specular_ior_level;
eta = ior_from_F0(f0);
if (ior < 1.0) {
eta = 1.0 / eta;
}
}
vec3 specular_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
F_brdf_single_scatter(f0, f90, split_sum);
reflection_data.color += weight * specular_brdf;
vec3 F0 = vec3(f0) * reflection_tint;
F0 = clamp(F0, vec3(0.0), vec3(1.0));
vec3 F90 = vec3(1.0);
vec3 reflectance, unused;
bsdf_lut(F0, F90, vec3(0.0), NV, roughness, eta, do_multiscatter, reflectance, unused);
reflection_data.color += weight * reflectance;
/* Attenuate lower layers */
weight *= (1.0 - max_v3(specular_brdf));
weight *= (1.0 - max_v3(reflectance));
}
/* Diffuse component */

View File

@ -330,7 +330,7 @@ void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
int locy = -300 * (node_map.size() - 2);
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission");
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Emission Color");
float *fcol = (float *)socket->default_value;
fcol[0] = col.getRed();
@ -340,9 +340,9 @@ void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
}
// texture
else if (cot.isTexture()) {
bNode *texture_node = add_texture_node(cot, -300, locy, "Emission");
bNode *texture_node = add_texture_node(cot, -300, locy, "Emission Color");
if (texture_node != nullptr) {
add_link(texture_node, "Color", shader_node, "Emission");
add_link(texture_node, "Color", shader_node, "Emission Color");
}
}
@ -388,13 +388,13 @@ void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
has_specularity = false;
}
else {
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular");
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular IOR Level");
set_color(node, col);
/* TODO: Connect node */
}
}
else if (cot.isTexture()) {
add_texture_node(cot, -300, locy, "Specular");
add_texture_node(cot, -300, locy, "Specular IOR Level");
/* TODO: Connect node */
}
else {
@ -407,7 +407,7 @@ void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
* TODO: This is a solution only for a corner case. We must find a better
* way to handle specularity in general. Also note that currently we
* do not export specularity values, see EffectExporter::operator() */
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Specular");
bNodeSocket *socket = nodeFindSocket(shader_node, SOCK_IN, "Specular IOR Level");
((bNodeSocketValueFloat *)socket->default_value)->value = 0.0f;
}
}

View File

@ -1188,7 +1188,7 @@ COLLADASW::ColorOrTexture bc_get_emission(Material *ma)
return bc_get_cot(default_color);
}
COLLADASW::ColorOrTexture cot = bc_get_cot_from_shader(shader, "Emission", default_color);
COLLADASW::ColorOrTexture cot = bc_get_cot_from_shader(shader, "Emission Color", default_color);
/* If using texture, emission strength is not supported. */
COLLADASW::Color col = cot.getColor();

View File

@ -465,11 +465,11 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
}
if (pxr::UsdShadeInput emissive_input = usd_shader.GetInput(usdtokens::emissiveColor)) {
set_node_input(emissive_input, principled, "Emission", ntree, column, &context);
set_node_input(emissive_input, principled, "Emission Color", ntree, column, &context);
}
if (pxr::UsdShadeInput specular_input = usd_shader.GetInput(usdtokens::specularColor)) {
set_node_input(specular_input, principled, "Specular", ntree, column, &context);
set_node_input(specular_input, principled, "Specular Tint", ntree, column, &context);
}
if (pxr::UsdShadeInput metallic_input = usd_shader.GetInput(usdtokens::metallic)) {
@ -482,7 +482,7 @@ void USDMaterialReader::set_principled_node_inputs(bNode *principled,
}
if (pxr::UsdShadeInput coat_input = usd_shader.GetInput(usdtokens::clearcoat)) {
set_node_input(coat_input, principled, "Coat", ntree, column, &context);
set_node_input(coat_input, principled, "Coat Weight", ntree, column, &context);
}
if (pxr::UsdShadeInput coat_roughness_input = usd_shader.GetInput(usdtokens::clearcoatRoughness))

View File

@ -292,16 +292,16 @@ static InputSpecMap &preview_surface_input_map()
{
static InputSpecMap input_map = {
{"Base Color", {usdtokens::diffuse_color, pxr::SdfValueTypeNames->Float3, true}},
{"Emission", {usdtokens::emissive_color, pxr::SdfValueTypeNames->Float3, true}},
{"Emission Color", {usdtokens::emissive_color, pxr::SdfValueTypeNames->Float3, true}},
{"Color", {usdtokens::diffuse_color, pxr::SdfValueTypeNames->Float3, true}},
{"Roughness", {usdtokens::roughness, pxr::SdfValueTypeNames->Float, true}},
{"Metallic", {usdtokens::metallic, pxr::SdfValueTypeNames->Float, true}},
{"Specular", {usdtokens::specular, pxr::SdfValueTypeNames->Float, true}},
{"Specular IOR Level", {usdtokens::specular, pxr::SdfValueTypeNames->Float, true}},
{"Alpha", {usdtokens::opacity, pxr::SdfValueTypeNames->Float, true}},
{"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}},
{"Coat", {usdtokens::clearcoat, pxr::SdfValueTypeNames->Float, true}},
{"Coat Weight", {usdtokens::clearcoat, pxr::SdfValueTypeNames->Float, true}},
{"Coat Roughness", {usdtokens::clearcoatRoughness, pxr::SdfValueTypeNames->Float, true}},
};

View File

@ -27,12 +27,12 @@ namespace blender::io::obj {
const char *tex_map_type_to_socket_id[] = {
"Base Color",
"Metallic",
"Specular",
"Specular IOR Level",
"Roughness", /* Map specular exponent to roughness. */
"Roughness",
"Sheen",
"Sheen Weight",
"Metallic", /* Map reflection to metallic. */
"Emission",
"Emission Color",
"Alpha",
"Normal",
};
@ -204,7 +204,7 @@ static void store_bsdf_properties(const bNode *bsdf_node,
float specular = material->spec;
if (bsdf_node) {
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular", {&specular, 1});
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Specular IOR Level", {&specular, 1});
}
float metallic = material->metallic;
@ -232,7 +232,7 @@ static void store_bsdf_properties(const bNode *bsdf_node,
float emission_strength = 0.0f;
if (bsdf_node) {
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Emission Strength", {&emission_strength, 1});
copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission", {emission_col, 3});
copy_property_from_node(SOCK_RGBA, bsdf_node, "Emission Color", {emission_col, 3});
}
mul_v3_fl(emission_col, emission_strength);
@ -243,12 +243,12 @@ static void store_bsdf_properties(const bNode *bsdf_node,
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, "Coat", {&coat, 1});
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Sheen Weight", {&sheen, 1});
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Coat Weight", {&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});
copy_property_from_node(SOCK_FLOAT, bsdf_node, "Transmission Weight", {&transmission, 1});
/* Clearcoat used to include an implicit 0.25 factor, so stay compatible to old versions. */
coat *= 4.0f;

View File

@ -302,12 +302,12 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial
float3 emission_color = mtl_mat.emission_color;
if (emission_color.x >= 0 && emission_color.y >= 0 && emission_color.z >= 0) {
set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf);
set_property_of_socket(SOCK_RGBA, "Emission Color", {emission_color, 3}, bsdf);
}
if (mtl_mat.tex_map_of_type(MTLTexMapType::Emission).is_valid()) {
set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf);
}
set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf);
set_property_of_socket(SOCK_FLOAT, "Specular IOR Level", {specular}, bsdf);
set_property_of_socket(SOCK_FLOAT, "Roughness", {roughness}, bsdf);
mat->roughness = roughness;
set_property_of_socket(SOCK_FLOAT, "Metallic", {metallic}, bsdf);
@ -324,11 +324,11 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial
}
if (mtl_mat.sheen >= 0) {
set_property_of_socket(SOCK_FLOAT, "Sheen", {mtl_mat.sheen}, bsdf);
set_property_of_socket(SOCK_FLOAT, "Sheen Weight", {mtl_mat.sheen}, bsdf);
}
if (mtl_mat.cc_thickness >= 0) {
/* 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);
set_property_of_socket(SOCK_FLOAT, "Coat Weight", {0.25f * mtl_mat.cc_thickness}, bsdf);
}
if (mtl_mat.cc_roughness >= 0) {
set_property_of_socket(SOCK_FLOAT, "Coat Roughness", {mtl_mat.cc_roughness}, bsdf);
@ -345,7 +345,7 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial
mtl_mat.transmit_color[2]) /
3;
if (transmission >= 0) {
set_property_of_socket(SOCK_FLOAT, "Transmission", {transmission}, bsdf);
set_property_of_socket(SOCK_FLOAT, "Transmission Weight", {transmission}, bsdf);
}
}

View File

@ -2294,8 +2294,8 @@ enum {
SHD_SUBSURFACE_GAUSSIAN = 2,
#endif
SHD_SUBSURFACE_BURLEY = 3,
SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS = 4,
SHD_SUBSURFACE_RANDOM_WALK = 5,
SHD_SUBSURFACE_RANDOM_WALK = 4,
SHD_SUBSURFACE_RANDOM_WALK_SKIN = 5,
};
/* blur node */

View File

@ -4085,18 +4085,18 @@ static const EnumPropertyItem node_subsurface_method_items[] = {
0,
"Christensen-Burley",
"Approximation to physically based volume scattering"},
{SHD_SUBSURFACE_RANDOM_WALK_FIXED_RADIUS,
"RANDOM_WALK_FIXED_RADIUS",
0,
"Random Walk (Fixed Radius)",
"Volumetric approximation to physically based volume scattering, using the scattering radius "
"as specified"},
{SHD_SUBSURFACE_RANDOM_WALK,
"RANDOM_WALK",
0,
"Random Walk",
"Volumetric approximation to physically based volume scattering, using the scattering radius "
"as specified"},
{SHD_SUBSURFACE_RANDOM_WALK_SKIN,
"RANDOM_WALK_SKIN",
0,
"Random Walk (Skin)",
"Volumetric approximation to physically based volume scattering, with scattering radius "
"automatically adjusted to match color textures"},
"automatically adjusted to match color textures. Designed for skin shading"},
{0, nullptr, 0, nullptr, nullptr}};
static const EnumPropertyItem prop_image_extension[] = {

View File

@ -40,18 +40,12 @@ static void node_declare(NodeDeclarationBuilder &b)
#define SOCK_ROUGHNESS_ID 2
b.add_input<decl::Float>("IOR").default_value(1.45f).min(1.0f).max(1000.0f);
#define SOCK_IOR_ID 3
b.add_input<decl::Float>("Transmission")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_TRANSMISSION_ID 4
b.add_input<decl::Float>("Alpha").default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
#define SOCK_ALPHA_ID 5
#define SOCK_ALPHA_ID 4
b.add_input<decl::Vector>("Normal").hide_value();
#define SOCK_NORMAL_ID 6
#define SOCK_NORMAL_ID 5
b.add_input<decl::Float>("Weight").unavailable();
#define SOCK_WEIGHT_ID 7
#define SOCK_WEIGHT_ID 6
/* Panel for Subsurface scattering settings. */
PanelDeclarationBuilder &sss =
@ -60,7 +54,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.draw_buttons([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
uiItemR(layout, ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
});
sss.add_input<decl::Float>("Subsurface")
sss.add_input<decl::Float>("Subsurface Weight")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
@ -68,7 +62,14 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(
"Blend between diffuse surface and subsurface scattering. "
"Typically should be zero or one (either fully diffuse or subsurface)");
#define SOCK_SUBSURFACE_ID 8
#define SOCK_SUBSURFACE_WEIGHT_ID 7
sss.add_input<decl::Vector>("Subsurface Radius")
.default_value({1.0f, 0.2f, 0.1f})
.min(0.0f)
.max(100.0f)
.compact()
.description("Scattering radius to use for subsurface component (multiplied with Scale)");
#define SOCK_SUBSURFACE_RADIUS_ID 8
sss.add_input<decl::Float>("Subsurface Scale")
.default_value(0.05f)
.min(0.0f)
@ -76,26 +77,19 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_DISTANCE)
.description("Scale of the subsurface scattering (multiplied with Radius)");
#define SOCK_SUBSURFACE_SCALE_ID 9
sss.add_input<decl::Vector>("Subsurface Radius")
.default_value({1.0f, 0.2f, 0.1f})
.min(0.0f)
.max(100.0f)
.compact()
.description("Scattering radius to use for subsurface component (multiplied with Scale)");
#define SOCK_SUBSURFACE_RADIUS_ID 10
sss.add_input<decl::Float>("Subsurface IOR")
.default_value(1.4f)
.min(1.01f)
.max(3.8f)
.subtype(PROP_FACTOR)
.description("Index of refraction used for rays that enter the subsurface component");
#define SOCK_SUBSURFACE_IOR_ID 11
#define SOCK_SUBSURFACE_IOR_ID 10
sss.add_input<decl::Float>("Subsurface Anisotropy")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_SUBSURFACE_ANISOTROPY_ID 12
#define SOCK_SUBSURFACE_ANISOTROPY_ID 11
/* Panel for Specular settings. */
PanelDeclarationBuilder &spec =
@ -104,36 +98,50 @@ static void node_declare(NodeDeclarationBuilder &b)
.draw_buttons([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
uiItemR(layout, ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
});
spec.add_input<decl::Float>("Specular")
spec.add_input<decl::Float>("Specular IOR Level")
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_SPECULAR_ID 13
spec.add_input<decl::Float>("Specular Tint")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_SPECULAR_TINT_ID 14
.subtype(PROP_FACTOR)
.description(
"Adjustment to the IOR to increase or decrease specular intensity "
"(0.5 means no adjustment, 0 removes all reflections, 1 doubles them at normal "
"incidence)");
#define SOCK_SPECULAR_ID 12
spec.add_input<decl::Color>("Specular Tint")
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.description(
"Tint dielectric reflection at normal incidence for artistic control, and metallic "
brecht marked this conversation as resolved Outdated

Should clarify that 1 doubles the reflectivity at normal incidence, as suggested in the pull request

Should clarify that 1 doubles the reflectivity at normal incidence, as suggested in the pull request
"reflection at near-grazing incidence to simulate complex index of refraction");
#define SOCK_SPECULAR_TINT_ID 13
spec.add_input<decl::Float>("Anisotropic")
.default_value(0.0f)
.min(0.0f)
brecht marked this conversation as resolved Outdated

Should be something like “Tint of dielectric reflection at normal incidence or metallic reflection at near-grazing incidence”.

Should be something like “Tint of dielectric reflection at normal incidence or metallic reflection at near-grazing incidence”.
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_ANISOTROPIC_ID 15
#define SOCK_ANISOTROPIC_ID 14
spec.add_input<decl::Float>("Anisotropic Rotation")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_ANISOTROPIC_ROTATION_ID 16
#define SOCK_ANISOTROPIC_ROTATION_ID 15
spec.add_input<decl::Vector>("Tangent").hide_value();
#define SOCK_TANGENT_ID 17
#define SOCK_TANGENT_ID 16
/* Panel for Transmission settings. */
PanelDeclarationBuilder &transmission = b.add_panel("Transmission").default_closed(true);
transmission.add_input<decl::Float>("Transmission Weight")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
.description("Blend between transmission and other base layer components");
#define SOCK_TRANSMISSION_WEIGHT_ID 17
/* Panel for Coat settings. */
PanelDeclarationBuilder &coat = b.add_panel("Coat").default_closed(true);
coat.add_input<decl::Float>("Coat")
coat.add_input<decl::Float>("Coat Weight")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
@ -141,7 +149,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.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 18
#define SOCK_COAT_WEIGHT_ID 18
coat.add_input<decl::Float>("Coat Roughness")
.default_value(0.03f)
.min(0.0f)
@ -169,9 +177,12 @@ static void node_declare(NodeDeclarationBuilder &b)
/* Panel for Sheen settings. */
PanelDeclarationBuilder &sheen = b.add_panel("Sheen").default_closed(true);
sheen.add_input<decl::Float>("Sheen").default_value(0.0f).min(0.0f).max(1.0f).subtype(
PROP_FACTOR);
#define SOCK_SHEEN_ID 23
sheen.add_input<decl::Float>("Sheen Weight")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_SHEEN_WEIGHT_ID 23
sheen.add_input<decl::Float>("Sheen Roughness")
.default_value(0.5f)
.min(0.0f)
@ -183,7 +194,7 @@ static void node_declare(NodeDeclarationBuilder &b)
/* Panel for Emission settings. */
PanelDeclarationBuilder &emis = b.add_panel("Emission").default_closed(true);
emis.add_input<decl::Color>("Emission").default_value({1.0f, 1.0f, 1.0f, 1.0f});
emis.add_input<decl::Color>("Emission Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_EMISSION_ID 26
emis.add_input<decl::Float>("Emission Strength").default_value(0.0).min(0.0f).max(1000000.0f);
#define SOCK_EMISSION_STRENGTH_ID 27
@ -224,12 +235,14 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
}
#endif
bool use_diffuse = socket_not_zero(SOCK_SHEEN_ID) ||
(socket_not_one(SOCK_METALLIC_ID) && socket_not_one(SOCK_TRANSMISSION_ID));
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_diffuse = socket_not_zero(SOCK_SHEEN_WEIGHT_ID) ||
(socket_not_one(SOCK_METALLIC_ID) &&
socket_not_one(SOCK_TRANSMISSION_WEIGHT_ID));
bool use_subsurf = socket_not_zero(SOCK_SUBSURFACE_WEIGHT_ID) && use_diffuse;
bool use_refract = socket_not_one(SOCK_METALLIC_ID) &&
socket_not_zero(SOCK_TRANSMISSION_WEIGHT_ID);
bool use_transparency = socket_not_one(SOCK_ALPHA_ID);
bool use_coat = socket_not_zero(SOCK_COAT_ID);
bool use_coat = socket_not_zero(SOCK_COAT_WEIGHT_ID);
eGPUMaterialFlag flag = GPU_MATFLAG_GLOSSY;
if (use_diffuse) {
@ -300,7 +313,7 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
bke::nodeSetSocketAvailability(ntree,
nodeFindSocket(node, SOCK_IN, "Subsurface IOR"),
sss_method == SHD_SUBSURFACE_RANDOM_WALK);
sss_method == SHD_SUBSURFACE_RANDOM_WALK_SKIN);
bke::nodeSetSocketAvailability(ntree,
nodeFindSocket(node, SOCK_IN, "Subsurface Anisotropy"),
sss_method != SHD_SUBSURFACE_BURLEY);