Cycles/EEVEE: Change Specular input on Principled BSDF to affect IOR #112552

Manually merged
Brecht Van Lommel merged 1 commits from LukasStockner/blender:principled-specular-ior-adjust into main 2023-09-25 19:53:31 +02:00
5 changed files with 32 additions and 13 deletions

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

@ -50,10 +50,15 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
}
if (Metallic < 1.0 && Transmission < 1.0) {
float eta = ior_from_F0(2.0 * Specular * F0_from_ior(IOR));
if (IOR < 1.0) {
eta = 1.0 / eta;
}
BSDF = BaseColor * diffuse(Normal);
if (Subsurface > 1e-5) {
vector radius = SubsurfaceScale * SubsurfaceRadius;
float subsurface_ior = (subsurface_method == "random_walk") ? SubsurfaceIOR : IOR;
float subsurface_ior = (subsurface_method == "random_walk") ? SubsurfaceIOR : eta;
closure color SubsurfBSDF = bssrdf(subsurface_method,
Normal,
SubsurfaceScale * SubsurfaceRadius,
@ -67,18 +72,17 @@ shader node_principled_bsdf(string distribution = "multi_ggx",
BSDF = mix(BSDF, BaseColor * SubsurfBSDF, Subsurface);
}
color f0 = color(F0_from_ior(IOR));
color f0 = color(F0_from_ior(eta));
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);
f0 *= mix(color(1.0), m_ctint, SpecularTint);
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);
}

View File

@ -76,7 +76,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
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,
coat_roughness_offset, coat_ior_offset, ior_offset, transmission_offset,
anisotropic_rotation_offset, coat_tint_offset, coat_normal_offset, dummy, alpha_offset,
emission_strength_offset, emission_offset;
uint4 data_node2 = read_node(kg, &offset);
@ -90,7 +90,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
svm_unpack_node_uchar4(
data_node.w, &sheen_offset, &sheen_tint_offset, &sheen_roughness_offset, &dummy);
svm_unpack_node_uchar4(data_node2.x,
&eta_offset,
&ior_offset,
&transmission_offset,
&anisotropic_rotation_offset,
&coat_normal_offset);
@ -113,7 +113,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
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);
float ior = fmaxf(stack_load_float(stack, ior_offset), 1e-5f);
ClosureType distribution = (ClosureType)data_node2.y;
ClosureType subsurface_method = (ClosureType)data_node2.z;
@ -297,7 +297,7 @@ 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);
@ -313,6 +313,12 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
}
/* Apply IOR adjustment for specular and subsurface components. */
float eta = ior_from_F0(2.0f * specular * F0_from_ior(ior));
if (ior < 1.0f) {
eta = 1.0f / eta;
}
/* Specular component */
if (reflective_caustics) {
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
@ -333,7 +339,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : one_float3();
float3 specTint = mix(one_spectrum(), rgb_to_spectrum(m_ctint), specular_tint);
fresnel->f0 = F0_from_ior(eta) * 2.0f * specular * specTint;
fresnel->f0 = F0_from_ior(eta) * specTint;
fresnel->f90 = one_spectrum();
fresnel->exponent = -eta;
fresnel->reflection_tint = one_spectrum();

View File

@ -140,11 +140,11 @@ void node_bsdf_principled(vec4 base_color,
/* Specular component */
if (true) {
vec3 f0 = vec3(F0_from_ior(ior));
vec3 f0 = vec3(2.0 * specular * 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;
f0 *= reflection_tint;
vec3 specular_brdf = (do_multiscatter != 0.0) ? F_brdf_multi_scatter(f0, f90, split_sum) :
F_brdf_single_scatter(f0, f90, split_sum);

View File

@ -108,7 +108,10 @@ static void node_declare(NodeDeclarationBuilder &b)
.default_value(0.5f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
.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)");
#define SOCK_SPECULAR_ID 13
spec.add_input<decl::Float>("Specular Tint")
.default_value(0.0f)