This implements three improvements to the energy preservation and albedo scaling logic, which help the Principled BSDF pass the white-furnace test when using the coat layers at high roughness. Specifically, at roughness 0.3, the albedo scaling brings it from 60% at the edge to 95%, and with the energy preservation it's 99.8%. Pull Request: https://projects.blender.org/blender/blender/pulls/134620
190 lines
7.8 KiB
Plaintext
190 lines
7.8 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 DiffuseRoughness = 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,
|
|
float ThinFilmThickness = 0.0,
|
|
float ThinFilmIOR = 1.33,
|
|
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 diffuse_roughness = clamp(DiffuseRoughness, 0.0, 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;
|
|
}
|
|
}
|
|
|
|
if (diffuse_roughness > CLOSURE_WEIGHT_CUTOFF) {
|
|
BSDF = oren_nayar_diffuse_bsdf(Normal, base_color, diffuse_roughness);
|
|
}
|
|
else {
|
|
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 || ThinFilmThickness > 0.1) {
|
|
/* 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,
|
|
"thinfilm_thickness",
|
|
ThinFilmThickness,
|
|
"thinfilm_ior",
|
|
ThinFilmIOR),
|
|
BSDF);
|
|
}
|
|
}
|
|
|
|
closure color TransmissionBSDF = 0;
|
|
if (metallic < 1.0 && TransmissionWeight > CLOSURE_WEIGHT_CUTOFF) {
|
|
float eta = max(IOR, 1e-5);
|
|
float thinfilm_ior = backfacing() ? ThinFilmIOR / eta : ThinFilmIOR;
|
|
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,
|
|
"thinfilm_thickness",
|
|
ThinFilmThickness,
|
|
"thinfilm_ior",
|
|
thinfilm_ior),
|
|
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, "multi_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));
|
|
}
|