Cycles: Support Thin Film iridescence in the Glass BSDF

Supporting this on the Metallic BSDF will require some extra work,
and on the Glossy BSDF it doesn't make much sense conceptually
(for that kind of shader setup, we'll want to support layering in SVM),
but Glass BSDF just needs to be hooked up so might as well do that.

Pull Request: https://projects.blender.org/blender/blender/pulls/140832
This commit is contained in:
Lukas Stockner
2025-07-09 22:07:24 +02:00
parent cd567f15af
commit cf92af3ac4
5 changed files with 67 additions and 14 deletions

View File

@@ -9,6 +9,8 @@ shader node_glass_bsdf(color Color = 0.8,
string distribution = "ggx",
float Roughness = 0.2,
float IOR = 1.45,
float ThinFilmThickness = 0.0,
float ThinFilmIOR = 1.33,
normal Normal = N,
output closure color BSDF = 0)
{
@@ -17,9 +19,22 @@ shader node_glass_bsdf(color Color = 0.8,
r2 = r2 * r2;
float eta = max(IOR, 1e-5);
eta = backfacing() ? 1.0 / eta : eta;
float thinfilm_ior = backfacing() ? ThinFilmIOR / eta : ThinFilmIOR;
color F0 = F0_from_ior(eta);
color F90 = color(1.0);
BSDF = generalized_schlick_bsdf(
Normal, vector(0.0), base_color, base_color, r2, r2, F0, F90, -eta, distribution);
BSDF = generalized_schlick_bsdf(Normal,
vector(0.0),
base_color,
base_color,
r2,
r2,
F0,
F90,
-eta,
distribution,
"thinfilm_thickness",
ThinFilmThickness,
"thinfilm_ior",
thinfilm_ior);
}

View File

@@ -715,6 +715,10 @@ ccl_device
const bool reflective_caustics = true;
const bool refractive_caustics = true;
#endif
const float thinfilm_thickness = fmaxf(stack_load_float(stack, data_node.z), 1e-5f);
const float thinfilm_ior = fmaxf(stack_load_float(stack, data_node.w), 1e-5f);
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), make_spectrum(mix_weight));
ccl_private FresnelGeneralizedSchlick *fresnel =
@@ -737,9 +741,8 @@ ccl_device
fresnel->reflection_tint = reflective_caustics ? rgb_to_spectrum(color) : zero_spectrum();
fresnel->transmission_tint = refractive_caustics ? rgb_to_spectrum(color) :
zero_spectrum();
fresnel->thin_film.thickness = 0.0f;
fresnel->thin_film.ior = 0.0f;
fresnel->thin_film.thickness = thinfilm_thickness;
fresnel->thin_film.ior = (sd->flag & SD_BACKFACING) ? thinfilm_ior / ior : thinfilm_ior;
/* setup bsdf */
if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) {
sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf);

View File

@@ -2334,6 +2334,9 @@ NODE_DEFINE(GlassBsdfNode)
SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
SOCKET_IN_FLOAT(IOR, "IOR", 1.5f);
SOCKET_IN_FLOAT(thin_film_thickness, "Thin Film Thickness", 0.0f);
SOCKET_IN_FLOAT(thin_film_ior, "Thin Film IOR", 1.3f);
SOCKET_OUT_CLOSURE(BSDF, "BSDF");
return type;
@@ -2347,7 +2350,12 @@ GlassBsdfNode::GlassBsdfNode() : BsdfNode(get_node_type())
void GlassBsdfNode::compile(SVMCompiler &compiler)
{
closure = distribution;
BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
BsdfNode::compile(compiler,
input("Roughness"),
input("IOR"),
input("Color"),
input("Thin Film Thickness"),
input("Thin Film IOR"));
}
void GlassBsdfNode::compile(OSLCompiler &compiler)

View File

@@ -658,6 +658,8 @@ class GlassBsdfNode : public BsdfNode {
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, IOR)
NODE_SOCKET_API(float, thin_film_thickness)
NODE_SOCKET_API(float, thin_film_ior)
NODE_SOCKET_API(ClosureType, distribution)
};

View File

@@ -8,6 +8,10 @@ namespace blender::nodes::node_shader_bsdf_glass_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.use_custom_socket_order();
b.add_output<decl::Shader>("BSDF");
b.add_input<decl::Color>("Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
b.add_input<decl::Float>("Roughness")
.default_value(0.0f)
@@ -17,7 +21,19 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Float>("IOR").default_value(1.5f).min(0.0f).max(1000.0f);
b.add_input<decl::Vector>("Normal").hide_value();
b.add_input<decl::Float>("Weight").available(false);
b.add_output<decl::Shader>("BSDF");
PanelDeclarationBuilder &film = b.add_panel("Thin Film").default_closed(true);
film.add_input<decl::Float>("Thin Film Thickness")
.default_value(0.0)
.min(0.0f)
.max(100000.0f)
.subtype(PROP_WAVELENGTH)
.description("Thickness of the film in nanometers");
film.add_input<decl::Float>("Thin Film IOR")
.default_value(1.33f)
.min(1.0f)
.max(1000.0f)
.description("Index of refraction (IOR) of the thin film");
}
static void node_shader_init_glass(bNodeTree * /*ntree*/, bNode *node)
@@ -53,14 +69,23 @@ NODE_SHADER_MATERIALX_BEGIN
NodeItem roughness = get_input_value("Roughness", NodeItem::Type::Vector2);
NodeItem ior = get_input_value("IOR", NodeItem::Type::Float);
NodeItem normal = get_input_link("Normal", NodeItem::Type::Vector3);
NodeItem thin_film_thickness = get_input_value("Thin Film Thickness", NodeItem::Type::Float);
NodeItem thin_film_ior = get_input_value("Thin Film IOR", NodeItem::Type::Float);
return create_node("dielectric_bsdf",
NodeItem::Type::BSDF,
{{"normal", normal},
{"tint", color},
{"roughness", roughness},
{"ior", ior},
{"scatter_mode", val(std::string("RT"))}});
NodeItem n_base_bsdf = create_node("dielectric_bsdf",
NodeItem::Type::BSDF,
{{"normal", normal},
{"tint", color},
{"roughness", roughness},
{"ior", ior},
{"scatter_mode", val(std::string("RT"))}});
NodeItem n_thin_film_bsdf = create_node(
"thin_film_bsdf",
NodeItem::Type::BSDF,
{{"thickness", thin_film_thickness}, {"ior", thin_film_ior}});
return create_node(
"layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_base_bsdf}});
}
#endif
NODE_SHADER_MATERIALX_END