Adjust clamping of inputs in the Principled BSDF to avoid errors and inconsistencies between render engines, while trying to leave as many inputs as possible unclamped for artisitc purposes. Pull Request: https://projects.blender.org/blender/blender/pulls/112895
164 lines
6.5 KiB
Plaintext
164 lines
6.5 KiB
Plaintext
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#include "node_fresnel.h"
|
|
#include "stdcycles.h"
|
|
|
|
shader node_principled_bsdf(string distribution = "multi_ggx",
|
|
string subsurface_method = "random_walk",
|
|
color BaseColor = color(0.8, 0.8, 0.8),
|
|
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 SpecularIORLevel = 0.5,
|
|
color SpecularTint = color(1.0),
|
|
float Roughness = 0.5,
|
|
float Anisotropic = 0.0,
|
|
float AnisotropicRotation = 0.0,
|
|
float SheenWeight = 0.0,
|
|
float SheenRoughness = 0.5,
|
|
color SheenTint = 0.5,
|
|
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 TransmissionWeight = 0.0,
|
|
color EmissionColor = 1.0,
|
|
float EmissionStrength = 0.0,
|
|
float Alpha = 1.0,
|
|
normal Normal = N,
|
|
normal CoatNormal = N,
|
|
normal Tangent = normalize(dPdu),
|
|
output closure color BSDF = 0)
|
|
{
|
|
float CLOSURE_WEIGHT_CUTOFF = 1e-5;
|
|
|
|
/* Clamping to match SVM */
|
|
float metallic = clamp(Metallic, 0.0, 1.0);
|
|
float transmission = clamp(TransmissionWeight, 0.0, 1.0);
|
|
float subsurface_weight = clamp(SubsurfaceWeight, 0.0, 1.0);
|
|
color specular_tint = max(SpecularTint, color(0.0));
|
|
float coat_weight = max(CoatWeight, 0.0);
|
|
color coat_tint = max(CoatTint, color(0.0));
|
|
float sheen_weight = max(SheenWeight, 0.0);
|
|
color base_color = max(BaseColor, color(0.0));
|
|
color clamped_base_color = min(base_color, color(1.0));
|
|
|
|
float r2 = clamp(Roughness, 0.0, 1.0);
|
|
r2 = r2 * r2;
|
|
|
|
float alpha_x = r2, alpha_y = r2;
|
|
|
|
/* Handle anisotropy. */
|
|
vector T = Tangent;
|
|
if (Anisotropic > 0.0) {
|
|
float aspect = sqrt(1.0 - clamp(Anisotropic, 0.0, 1.0) * 0.9);
|
|
alpha_x /= aspect;
|
|
alpha_y *= aspect;
|
|
if (AnisotropicRotation != 0.0)
|
|
T = rotate(T, AnisotropicRotation * M_2PI, point(0.0, 0.0, 0.0), Normal);
|
|
}
|
|
|
|
if (metallic < 1.0 && TransmissionWeight < 1.0) {
|
|
float eta = max(IOR, 1e-5);
|
|
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 = base_color * diffuse(Normal);
|
|
if (subsurface_weight > CLOSURE_WEIGHT_CUTOFF) {
|
|
vector radius = max(SubsurfaceScale * SubsurfaceRadius, vector(0.0));
|
|
float subsurface_ior = (subsurface_method == "random_walk_skin") ? SubsurfaceIOR : eta;
|
|
closure color SubsurfBSDF = bssrdf(subsurface_method,
|
|
Normal,
|
|
radius,
|
|
clamped_base_color,
|
|
"roughness",
|
|
r2,
|
|
"ior",
|
|
subsurface_ior,
|
|
"anisotropy",
|
|
SubsurfaceAnisotropy);
|
|
BSDF = mix(BSDF, clamped_base_color * SubsurfBSDF, subsurface_weight);
|
|
}
|
|
|
|
if (eta != 1.0) {
|
|
/* Apply specular tint */
|
|
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, -eta, distribution),
|
|
BSDF);
|
|
}
|
|
}
|
|
|
|
closure color TransmissionBSDF = 0;
|
|
if (metallic < 1.0 && TransmissionWeight > CLOSURE_WEIGHT_CUTOFF) {
|
|
float eta = max(IOR, 1e-5);
|
|
eta = backfacing() ? 1.0 / eta : eta;
|
|
|
|
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(clamped_base_color),
|
|
r2,
|
|
r2,
|
|
F0,
|
|
F90,
|
|
-eta,
|
|
distribution),
|
|
BSDF = mix(BSDF, TransmissionBSDF, transmission);
|
|
}
|
|
|
|
closure color MetallicBSDF = 0;
|
|
if (metallic > CLOSURE_WEIGHT_CUTOFF) {
|
|
color F0 = clamped_base_color;
|
|
color F82 = min(specular_tint, color(1.0));
|
|
MetallicBSDF = microfacet_f82_tint(distribution, Normal, T, alpha_x, alpha_y, F0, F82);
|
|
BSDF = mix(BSDF, MetallicBSDF, metallic);
|
|
}
|
|
|
|
if (EmissionStrength != 0.0 && EmissionColor != color(0.0)) {
|
|
BSDF += EmissionStrength * EmissionColor * emission();
|
|
}
|
|
|
|
if (coat_weight > CLOSURE_WEIGHT_CUTOFF) {
|
|
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 *= mix(color(1.0), pow(CoatTint, 1.0 / cosNT), clamp(coat_weight, 0.0, 1.0));
|
|
}
|
|
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_weight * CoatBSDF, BSDF);
|
|
}
|
|
|
|
if (SheenWeight > CLOSURE_WEIGHT_CUTOFF) {
|
|
normal sheen_normal = normalize(mix(Normal, CoatNormal, clamp(coat_weight, 0.0, 1.0)));
|
|
closure color SheenBSDF = sheen(sheen_normal, clamp(SheenRoughness, 0.0, 1.0));
|
|
BSDF = layer(sheen_weight * max(SheenTint, color(0.0)) * SheenBSDF, BSDF);
|
|
}
|
|
|
|
BSDF = mix(transparent(), BSDF, clamp(Alpha, 0.0, 1.0));
|
|
}
|