Blender V5.0
node_shader_bsdf_principled.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <map>
6
7#include "node_shader_util.hh"
8
9#include "BLI_math_base.h"
10
12#include "UI_resources.hh"
13
14#include "BKE_node_runtime.hh"
15
17
19{
24
25 b.use_custom_socket_order();
26
27 b.add_output<decl::Shader>("BSDF");
28
29 b.add_input<decl::Color>("Base Color")
30 .default_value({0.8f, 0.8f, 0.8f, 1.0f})
31 .description(
32 "Color of the material used for diffuse, subsurface, metallic and transmission");
33#define SOCK_BASE_COLOR_ID 0
34 b.add_input<decl::Float>("Metallic")
35 .default_value(0.0f)
36 .min(0.0f)
37 .max(1.0f)
39 .description(
40 "Blends between a dielectric and metallic material model. "
41 "At 0.0 the material consists of a diffuse or transmissive base layer, "
42 "with a specular reflection layer on top. A value of 1.0 gives a fully specular "
43 "reflection tinted with the base color, without diffuse reflection or transmission");
44#define SOCK_METALLIC_ID 1
45 b.add_input<decl::Float>("Roughness")
46 .default_value(0.5f)
47 .min(0.0f)
48 .max(1.0f)
50 .description(
51 "Specifies microfacet roughness of the surface for specular reflection and transmission"
52 " (0.0 is a perfect mirror reflection, 1.0 is completely rough)");
53#define SOCK_ROUGHNESS_ID 2
54 b.add_input<decl::Float>("IOR").default_value(1.5f).min(1.0f).max(1000.0f).description(
55 "Index of Refraction (IOR) for specular reflection and transmission. "
56 "For most materials, the IOR is between 1.0 (vacuum and air) and 4.0 (germanium). "
57 "The default value of 1.5 is a good approximation for glass");
58#define SOCK_IOR_ID 3
59 b.add_input<decl::Float>("Alpha")
60 .default_value(1.0f)
61 .min(0.0f)
62 .max(1.0f)
64 .description("Controls the transparency of the surface, with 1.0 fully opaque");
65#define SOCK_ALPHA_ID 4
66 b.add_input<decl::Vector>("Normal").hide_value();
67#define SOCK_NORMAL_ID 5
68 b.add_input<decl::Float>("Weight").available(false);
69#define SOCK_WEIGHT_ID 6
70
71 /* Panel for Diffuse settings. */
72 PanelDeclarationBuilder &diffuse = b.add_panel("Diffuse").default_closed(true);
73 diffuse.add_input<decl::Float>("Diffuse Roughness")
74 .default_value(0.0f)
75 .min(0.0f)
76 .max(1.0f)
78 .description(
79 "Specifies microfacet roughness of the diffuse base"
80 " (0.0 is perfect lambertian reflection, 1.0 is completely rough)");
81#define SOCK_DIFFUSE_ROUGHNESS_ID 7
82
83 /* Panel for Subsurface scattering settings. */
84 PanelDeclarationBuilder &sss = b.add_panel("Subsurface").default_closed(true);
85 sss.add_layout([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
86 layout->prop(ptr, "subsurface_method", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
87 });
88 sss.add_input<decl::Float>("Subsurface Weight")
89 .default_value(0.0f)
90 .min(0.0f)
91 .max(1.0f)
93 .short_label("Weight")
94 .description(
95 "Blend between diffuse surface and subsurface scattering. "
96 "Typically should be zero or one (either fully diffuse or subsurface)");
97#define SOCK_SUBSURFACE_WEIGHT_ID 8
98 sss.add_input<decl::Vector>("Subsurface Radius")
99 .default_value({1.0f, 0.2f, 0.1f})
100 .min(0.0f)
101 .max(100.0f)
102 .short_label("Radius")
103 .description("Scattering radius per color channel (RGB), multiplied with Scale");
104#define SOCK_SUBSURFACE_RADIUS_ID 9
105 sss.add_input<decl::Float>("Subsurface Scale")
106 .default_value(0.05f)
107 .min(0.0f)
108 .max(10.0f)
110 .short_label("Scale")
111 .description("Scale factor of the subsurface scattering radius");
112#define SOCK_SUBSURFACE_SCALE_ID 10
113 sss.add_input<decl::Float>("Subsurface IOR")
114 .default_value(1.4f)
115 .min(1.01f)
116 .max(3.8f)
118 .short_label("IOR")
119 .description("Index of Refraction (IOR) used for rays that enter the subsurface component");
120#define SOCK_SUBSURFACE_IOR_ID 11
121 sss.add_input<decl::Float>("Subsurface Anisotropy")
122 .default_value(0.0f)
123 .min(0.0f)
124 .max(1.0f)
126 .short_label("Anisotropy")
127 .description(
128 "Directionality of volume scattering within the subsurface medium. "
129 "Zero scatters uniformly in all directions, with higher values "
130 "scattering more strongly forward. For example, skin has been measured "
131 "to have an anisotropy of 0.8");
132#define SOCK_SUBSURFACE_ANISOTROPY_ID 12
133
134 /* Panel for Specular settings. */
135 PanelDeclarationBuilder &spec = b.add_panel("Specular").default_closed(true);
136 spec.add_layout([](uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) {
137 layout->prop(ptr, "distribution", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
138 });
139 spec.add_input<decl::Float>("Specular IOR Level")
140 .default_value(0.5f)
141 .min(0.0f)
142 .max(1.0f)
144 .short_label("IOR Level")
145 .description(
146 "Adjustment to the Index of Refraction (IOR) to increase or decrease specular intensity "
147 "(0.5 means no adjustment, 0 removes all reflections, 1 doubles them at normal "
148 "incidence)");
149#define SOCK_SPECULAR_ID 13
150 spec.add_input<decl::Color>("Specular Tint")
151 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
152 .short_label("Tint")
154 "Tint dielectric reflection at normal incidence for artistic control, and metallic "
155 "reflection at near-grazing incidence to simulate complex index of refraction")
156 .translation_context(BLT_I18NCONTEXT_ID_NODETREE);
157#define SOCK_SPECULAR_TINT_ID 14
158 spec.add_input<decl::Float>("Anisotropic")
159 .default_value(0.0f)
160 .min(0.0f)
161 .max(1.0f)
163 .description(
164 "Amount of anisotropy for specular reflection. "
165 "Higher values give elongated highlights along the tangent direction");
166#define SOCK_ANISOTROPIC_ID 15
167 spec.add_input<decl::Float>("Anisotropic Rotation")
168 .default_value(0.0f)
169 .min(0.0f)
170 .max(1.0f)
172 .description("Rotates the direction of anisotropy, with 1.0 going full circle");
173#define SOCK_ANISOTROPIC_ROTATION_ID 16
174 spec.add_input<decl::Vector>("Tangent").hide_value().description(
175 "Controls the tangent direction for anisotropy");
176#define SOCK_TANGENT_ID 17
177
178 /* Panel for Transmission settings. */
179 PanelDeclarationBuilder &transmission = b.add_panel("Transmission").default_closed(true);
180 transmission.add_input<decl::Float>("Transmission Weight")
181 .default_value(0.0f)
182 .min(0.0f)
183 .max(1.0f)
185 .short_label("Weight")
186 .description("Blend between transmission and other base layer components");
187#define SOCK_TRANSMISSION_WEIGHT_ID 18
188
189 /* Panel for Coat settings. */
190 PanelDeclarationBuilder &coat = b.add_panel("Coat").default_closed(true);
191 coat.add_input<decl::Float>("Coat Weight")
192 .default_value(0.0f)
193 .min(0.0f)
194 .max(1.0f)
196 .short_label("Weight")
197 .description(
198 "Controls the intensity of the coat layer, both the reflection and the tinting. "
199 "Typically should be zero or one for physically-based materials");
200#define SOCK_COAT_WEIGHT_ID 19
201 coat.add_input<decl::Float>("Coat Roughness")
202 .default_value(0.03f)
203 .min(0.0f)
204 .max(1.0f)
206 .short_label("Roughness")
207 .description("The roughness of the coat layer");
208#define SOCK_COAT_ROUGHNESS_ID 20
209 coat.add_input<decl::Float>("Coat IOR")
210 .default_value(1.5f)
211 .min(1.0f)
212 .max(4.0f)
213 .short_label("IOR")
214 .description(
215 "The Index of Refraction (IOR) of the coat layer "
216 "(affects its reflectivity as well as the falloff of coat tinting)");
217#define SOCK_COAT_IOR_ID 21
218 coat.add_input<decl::Color>("Coat Tint")
219 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
220 .short_label("Tint")
222 "Adds a colored tint to the coat layer by modeling absorption in the layer. "
223 "Saturation increases at shallower angles, as the light travels farther "
224 "through the medium (depending on the Coat IOR)")
225 .translation_context(BLT_I18NCONTEXT_ID_NODETREE);
226#define SOCK_COAT_TINT_ID 22
227 coat.add_input<decl::Vector>("Coat Normal").short_label("Normal").hide_value();
228#define SOCK_COAT_NORMAL_ID 23
229
230 /* Panel for Sheen settings. */
231 PanelDeclarationBuilder &sheen = b.add_panel("Sheen").default_closed(true);
232 sheen.add_input<decl::Float>("Sheen Weight")
233 .default_value(0.0f)
234 .min(0.0f)
235 .max(1.0f)
237 .short_label("Weight")
238 .description(
239 "Intensity of the sheen layer, which simulates very small fibers on the surface");
240#define SOCK_SHEEN_WEIGHT_ID 24
241 sheen.add_input<decl::Float>("Sheen Roughness")
242 .default_value(0.5f)
243 .min(0.0f)
244 .max(1.0f)
246 .short_label("Roughness")
247 .description(
248 "Roughness of the sheen layer. Low and high roughness values produce fuzzy or dusty "
249 "appearance, respectively");
250#define SOCK_SHEEN_ROUGHNESS_ID 25
251 sheen.add_input<decl::Color>("Sheen Tint")
252 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
253 .translation_context(BLT_I18NCONTEXT_ID_NODETREE)
254 .short_label("Tint")
255 .description("Color of the sheen reflection");
256#define SOCK_SHEEN_TINT_ID 26
257
258 /* Panel for Emission settings. */
259 PanelDeclarationBuilder &emis = b.add_panel("Emission").default_closed(true);
260 emis.add_input<decl::Color>("Emission Color")
261 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
262 .short_label("Color")
263 .description("Color of light emission from the surface");
264#define SOCK_EMISSION_ID 27
265 emis.add_input<decl::Float>("Emission Strength")
266 .default_value(0.0)
267 .min(0.0f)
268 .max(1000000.0f)
269 .short_label("Strength")
270 .description(
271 "Strength of the emitted light. A value of 1.0 ensures "
272 "that the object in the image has the exact same color as the Emission Color")
273 .translation_context(BLT_I18NCONTEXT_AMOUNT);
274#define SOCK_EMISSION_STRENGTH_ID 28
275
276 /* Panel for Thin Film settings. */
277 PanelDeclarationBuilder &film = b.add_panel("Thin Film").default_closed(true);
278 film.add_input<decl::Float>("Thin Film Thickness")
279 .default_value(0.0)
280 .min(0.0f)
281 .max(100000.0f)
283 .description("Thickness of the film in nanometers");
284#define SOCK_THIN_FILM_THICKNESS_ID 29
285 film.add_input<decl::Float>("Thin Film IOR")
286 .default_value(1.33f)
287 .min(1.0f)
288 .max(1000.0f)
289 .description("Index of refraction (IOR) of the thin film");
290#define SOCK_THIN_FILM_IOR_ID 30
291}
292
293static void node_shader_init_principled(bNodeTree * /*ntree*/, bNode *node)
294{
297}
298
299static bool might_have_tinted_specular(const GPUNodeStack &base_color,
300 const GPUNodeStack &metallic,
301 const GPUNodeStack &specular_tint)
302{
303 if (metallic.socket_not_zero()) {
304 /* Metals might have colored specular. */
305 return base_color.might_be_tinted() || specular_tint.might_be_tinted();
306 }
307 /* Dielectrics get colored if tint is used. */
308 return specular_tint.might_be_tinted();
309}
310
312 bNode *node,
313 bNodeExecData * /*execdata*/,
316{
317 /* Normals */
318 if (!in[SOCK_NORMAL_ID].link) {
319 GPU_link(mat, "world_normals_get", &in[SOCK_NORMAL_ID].link);
320 }
321
322 /* Coat Normals */
323 if (!in[SOCK_COAT_NORMAL_ID].link) {
324 GPU_link(mat, "world_normals_get", &in[SOCK_COAT_NORMAL_ID].link);
325 }
326
327#if 0 /* Not used at the moment. */
328 /* Tangents */
329 if (!in[SOCK_TANGENT_ID].link) {
330 GPUNodeLink *orco = GPU_attribute(CD_ORCO, "");
331 GPU_link(mat, "tangent_orco_z", orco, &in[SOCK_TANGENT_ID].link);
332 GPU_link(mat, "node_tangent", in[SOCK_TANGENT_ID].link, &in[SOCK_TANGENT_ID].link);
333 }
334#endif
335
336 bool use_diffuse = in[SOCK_SHEEN_WEIGHT_ID].socket_not_zero() ||
337 (in[SOCK_METALLIC_ID].socket_not_one() &&
338 in[SOCK_TRANSMISSION_WEIGHT_ID].socket_not_one());
339 bool use_subsurf = in[SOCK_SUBSURFACE_WEIGHT_ID].socket_not_zero() && use_diffuse;
340 bool use_refract = in[SOCK_METALLIC_ID].socket_not_one() &&
341 in[SOCK_TRANSMISSION_WEIGHT_ID].socket_not_zero();
342 bool use_transparency = in[SOCK_ALPHA_ID].socket_not_one();
343 bool use_coat = in[SOCK_COAT_WEIGHT_ID].socket_not_zero();
344
346 if (use_diffuse) {
348 }
349 if (use_refract) {
351 }
352 if (use_subsurf) {
354 }
355 if (use_transparency) {
357 }
358 if (use_coat) {
360 }
361
364 {
366 }
367 if (use_refract && in[SOCK_BASE_COLOR_ID].might_be_tinted()) {
369 }
370 if (use_coat && in[SOCK_COAT_TINT_ID].might_be_tinted()) {
372 }
373
375
376 /* Make constant link for the cases we optimize. This allows the driver to constant fold.
377 * Note that doing so specialize the final tree topology, and thus the shader becomes less
378 * reusable. So to be used with care.
379 * Also note that we do note override existing links. This is because it would leak the current
380 * nodes otherwise. */
381 const float zero = 0.0f;
382 if (!use_coat && in[SOCK_COAT_WEIGHT_ID].link == nullptr) {
383 in[SOCK_COAT_WEIGHT_ID].link = GPU_constant(&zero);
384 }
385 if (!use_subsurf && in[SOCK_SUBSURFACE_WEIGHT_ID].link == nullptr) {
387 }
388 if (!use_refract && in[SOCK_TRANSMISSION_WEIGHT_ID].link == nullptr) {
390 }
391
392 float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
393
394 return GPU_stack_link(
395 mat, node, "node_bsdf_principled", in, out, GPU_constant(&use_multi_scatter));
396}
397
399{
400 const int sss_method = node->custom2;
401
403 *bke::node_find_socket(*node, SOCK_IN, "Subsurface IOR"),
404 sss_method == SHD_SUBSURFACE_RANDOM_WALK_SKIN);
406 *ntree,
407 *bke::node_find_socket(*node, SOCK_IN, "Subsurface Anisotropy"),
408 sss_method != SHD_SUBSURFACE_BURLEY);
409}
410
412#ifdef WITH_MATERIALX
413{
414 using InputsType = std::map<std::string, NodeItem>;
415
416 /* NOTE: commented inputs aren't used for node creation. */
417 auto bsdf_inputs = [&]() -> InputsType {
418 return {
419 {"base_color", get_input_value("Base Color", NodeItem::Type::Color3)},
420 {"diffuse_roughness", get_input_value("Diffuse Roughness", NodeItem::Type::Float)},
421 {"subsurface", get_input_value("Subsurface Weight", NodeItem::Type::Float)},
422 {"subsurface_scale", get_input_value("Subsurface Scale", NodeItem::Type::Float)},
423# if MATERIALX_MAJOR_VERSION <= 1 && MATERIALX_MINOR_VERSION <= 38
424 {"subsurface_radius", get_input_value("Subsurface Radius", NodeItem::Type::Vector3)},
425# else
426 {"subsurface_radius", get_input_value("Subsurface Radius", NodeItem::Type::Color3)},
427# endif
428 //{"subsurface_ior", get_input_value("Subsurface IOR", NodeItem::Type::Vector3)},
429 {"subsurface_anisotropy", get_input_value("Subsurface Anisotropy", NodeItem::Type::Float)},
430 {"metallic", get_input_value("Metallic", NodeItem::Type::Float)},
431 {"specular", get_input_value("Specular IOR Level", NodeItem::Type::Float)},
432 {"specular_tint", get_input_value("Specular Tint", NodeItem::Type::Color3)},
433 {"roughness", get_input_value("Roughness", NodeItem::Type::Float)},
434 {"anisotropic", get_input_value("Anisotropic", NodeItem::Type::Float)},
435 {"anisotropic_rotation", get_input_value("Anisotropic Rotation", NodeItem::Type::Float)},
436 {"sheen", get_input_value("Sheen Weight", NodeItem::Type::Float)},
437 {"sheen_roughness", get_input_value("Sheen Roughness", NodeItem::Type::Float)},
438 {"sheen_tint", get_input_value("Sheen Tint", NodeItem::Type::Color3)},
439 {"coat", get_input_value("Coat Weight", NodeItem::Type::Float)},
440 {"coat_roughness", get_input_value("Coat Roughness", NodeItem::Type::Float)},
441 {"coat_ior", get_input_value("Coat IOR", NodeItem::Type::Float)},
442 {"coat_tint", get_input_value("Coat Tint", NodeItem::Type::Color3)},
443 {"ior", get_input_value("IOR", NodeItem::Type::Float)},
444 {"transmission", get_input_value("Transmission Weight", NodeItem::Type::Float)},
445 {"thin_film_thickness", get_input_value("Thin Film Thickness", NodeItem::Type::Float)},
446 {"thin_film_IOR", get_input_value("Thin Film IOR", NodeItem::Type::Float)},
447 {"alpha", get_input_value("Alpha", NodeItem::Type::Float)},
448 {"normal", get_input_link("Normal", NodeItem::Type::Vector3)},
449 {"coat_normal", get_input_link("Coat Normal", NodeItem::Type::Vector3)},
450 {"tangent", get_input_link("Tangent", NodeItem::Type::Vector3)},
451 };
452 };
453
454 auto edf_inputs = [&]() -> InputsType {
455 return {
456 {"emission", get_input_value("Emission Strength", NodeItem::Type::Float)},
457 {"emission_color", get_input_value("Emission Color", NodeItem::Type::Color3)},
458 };
459 };
460
461 NodeItem res = empty();
462
463 switch (to_type_) {
464 case NodeItem::Type::BSDF: {
465 auto in = bsdf_inputs();
466
467 NodeItem roughness = in["roughness"];
468 NodeItem diffuse_roughness = in["diffuse_roughness"];
469 NodeItem anisotropy = in["anisotropic"];
470 NodeItem rotation = in["anisotropic_rotation"] * val(360.0f);
471 NodeItem base_color = in["base_color"];
472 NodeItem specular = in["specular"];
473 NodeItem coat = in["coat"];
474 NodeItem ior = in["ior"];
475 NodeItem normal = in["normal"];
476 NodeItem tangent = in["tangent"];
477 NodeItem coat_normal = in["coat_normal"];
478
479 NodeItem n_main_tangent = empty();
480 if (tangent && normal) {
481 NodeItem n_tangent_rotate_normalize = tangent.rotate(rotation, normal).normalize();
482 n_main_tangent = anisotropy.if_else(
483 NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent);
484 }
485
486 NodeItem n_coat_roughness_vector = create_node(
487 "roughness_anisotropy",
488 NodeItem::Type::Vector2,
489 {{"roughness", in["coat_roughness"]}, {"anisotropy", anisotropy}});
490
491 NodeItem n_coat_bsdf = create_node("dielectric_bsdf",
492 NodeItem::Type::BSDF,
493 {{"weight", coat},
494 {"tint", in["coat_tint"]},
495 {"ior", in["coat_ior"]},
496 {"scatter_mode", val(std::string("R"))},
497 {"roughness", n_coat_roughness_vector},
498 {"normal", coat_normal}});
499
500 if (tangent && coat_normal) {
501 NodeItem n_coat_tangent_rotate_normalize =
502 tangent.rotate(rotation, coat_normal).normalize();
503 NodeItem n_coat_tangent = anisotropy.if_else(
504 NodeItem::CompareOp::Greater, val(0.0f), n_coat_tangent_rotate_normalize, tangent);
505
506 n_coat_bsdf.set_input("tangent", n_coat_tangent);
507 }
508
509 NodeItem thin_film_thickness = in["thin_film_thickness"];
510 NodeItem thin_film_ior = in["thin_film_IOR"];
511 NodeItem n_thin_film_bsdf = create_node(
512 "thin_film_bsdf",
513 NodeItem::Type::BSDF,
514 {{"thickness", thin_film_thickness}, {"ior", thin_film_ior}});
515
516 NodeItem n_artistic_ior = create_node(
517 "artistic_ior",
518 NodeItem::Type::Multioutput,
519 {{"reflectivity", base_color * val(1.0f)}, {"edge_color", base_color * specular}});
520
521 NodeItem n_ior_out = n_artistic_ior.add_output("ior", NodeItem::Type::Color3);
522 NodeItem n_extinction_out = n_artistic_ior.add_output("extinction", NodeItem::Type::Color3);
523
524 NodeItem n_coat_affect_roughness_multiply2 = coat * val(0.0f) * in["coat_roughness"];
525 NodeItem n_coat_affected_roughness = n_coat_affect_roughness_multiply2.mix(roughness,
526 val(1.0f));
527
528 NodeItem n_main_roughness = create_node(
529 "roughness_anisotropy",
530 NodeItem::Type::Vector2,
531 {{"roughness", n_coat_affected_roughness}, {"anisotropy", anisotropy}});
532
533 NodeItem n_metal_bsdf = create_node("conductor_bsdf",
534 NodeItem::Type::BSDF,
535 {{"ior", n_ior_out},
536 {"extinction", n_extinction_out},
537 {"roughness", n_main_roughness},
538 {"normal", normal},
539 {"tangent", n_main_tangent}});
540
541 NodeItem n_specular_bsdf = create_node("dielectric_bsdf",
542 NodeItem::Type::BSDF,
543 {{"weight", specular},
544 {"tint", in["specular_tint"]},
545 {"ior", ior},
546 {"scatter_mode", val(std::string("R"))},
547 {"roughness", n_main_roughness},
548 {"normal", normal},
549 {"tangent", n_main_tangent}});
550
551 NodeItem n_coat_affected_transmission_roughness = n_coat_affect_roughness_multiply2.mix(
552 (roughness + roughness).clamp(), val(1.0f));
553
554 NodeItem n_transmission_roughness = create_node(
555 "roughness_anisotropy",
556 NodeItem::Type::Vector2,
557 {{"roughness", n_coat_affected_transmission_roughness}, {"anisotropy", anisotropy}});
558
559 NodeItem n_transmission_bsdf = create_node("dielectric_bsdf",
560 NodeItem::Type::BSDF,
561 {{"tint", base_color},
562 {"ior", ior},
563 {"roughness", n_transmission_roughness},
564 {"normal", normal},
565 {"tangent", n_main_tangent}});
566
567 NodeItem n_coat_gamma = coat.clamp(0.0f, 1.0f) * val(0.0f) + val(1.0f);
568 NodeItem n_coat_affected_subsurface_color = base_color.max(val(0.0f)) ^ n_coat_gamma;
569 NodeItem n_translucent_bsdf = create_node(
570 "translucent_bsdf",
571 NodeItem::Type::BSDF,
572 {{"color", n_coat_affected_subsurface_color}, {"normal", normal}});
573
574 NodeItem n_subsurface_bsdf = create_node(
575 "subsurface_bsdf",
576 NodeItem::Type::BSDF,
577 {{"color", n_coat_affected_subsurface_color},
578 {"radius", in["subsurface_radius"] * in["subsurface_scale"]},
579 {"anisotropy", in["subsurface_anisotropy"]},
580 {"normal", normal}});
581
582 NodeItem n_sheen_bsdf = create_node("sheen_bsdf",
583 NodeItem::Type::BSDF,
584 {{"weight", in["sheen"]},
585 {"color", in["sheen_tint"]},
586 {"roughness", in["sheen_roughness"]},
587 {"normal", normal}});
588
589 NodeItem n_diffuse_bsdf = create_node("oren_nayar_diffuse_bsdf",
590 NodeItem::Type::BSDF,
591 {{"color", base_color.max(val(0.0f)) ^ n_coat_gamma},
592 {"roughness", diffuse_roughness},
593 {"weight", val(1.0f)},
594 {"normal", normal}});
595
596 NodeItem n_subsurface_mix = in["subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf);
597
598 NodeItem n_sheen_layer = create_node(
599 "layer", NodeItem::Type::BSDF, {{"top", n_sheen_bsdf}, {"base", n_subsurface_mix}});
600
601 NodeItem n_transmission_mix = in["transmission"].mix(n_sheen_layer, n_transmission_bsdf);
602
603 NodeItem n_specular_layer = create_node(
604 "layer", NodeItem::Type::BSDF, {{"top", n_specular_bsdf}, {"base", n_transmission_mix}});
605
606 NodeItem n_metalness_mix = in["metallic"].mix(n_specular_layer, n_metal_bsdf);
607
608 NodeItem n_thin_film_layer = create_node(
609 "layer", NodeItem::Type::BSDF, {{"top", n_thin_film_bsdf}, {"base", n_metalness_mix}});
610
611 NodeItem n_coat_attenuation = coat.mix(val(MaterialX::Color3(1.0f, 1.0f, 1.0f)),
612 in["coat_tint"]);
613
614 res = create_node("layer",
615 NodeItem::Type::BSDF,
616 {{"top", n_coat_bsdf}, {"base", n_thin_film_layer * n_coat_attenuation}});
617 break;
618 }
619
620 case NodeItem::Type::EDF: {
621 auto in = edf_inputs();
622 res = create_node(
623 "uniform_edf", NodeItem::Type::EDF, {{"color", in["emission_color"] * in["emission"]}});
624 break;
625 }
626
627 case NodeItem::Type::SurfaceShader: {
628 auto in = bsdf_inputs();
629 auto e_in = edf_inputs();
630 in.insert(e_in.begin(), e_in.end());
631
632 NodeItem base_color = in["base_color"];
633
634 NodeItem anisotropy = in["anisotropic"];
635 NodeItem tangent = in["tangent"];
636 if (anisotropy) {
637 /* Anisotropy scaled down to approximately match the principled BSDF. */
638 anisotropy = anisotropy * val(0.7f);
639
640 /* Rotation is offset by 90 degrees and inverted to approximately align visually with
641 * principled BSDF direction. */
642 NodeItem rotation = -((in["anisotropic_rotation"] * val(360.0f)) + val(90.0f));
643
644 /* Only create a normal node locally if we need to use it to rotate the tangent vector.
645 * we don't actually pass this to the exported material. */
646 NodeItem normal = in["normal"];
647 if (!normal) {
648 const std::string world = "world";
649 normal =
650 create_node("normal", NodeItem::Type::Vector3, {{"space", val(world)}}).normalize();
651 }
652
653 if (!tangent) {
654 const std::string world = "world";
655 tangent =
656 create_node("tangent", NodeItem::Type::Vector3, {{"space", val(world)}}).normalize();
657 }
658
659 NodeItem n_tangent_rotate_normalize = tangent.rotate(rotation, normal).normalize();
660 tangent = anisotropy.if_else(
661 NodeItem::CompareOp::Greater, val(0.0f), n_tangent_rotate_normalize, tangent);
662 }
663
664 /* Enable OpenPBR thin film only if thickness > 0. */
665 NodeItem thin_film_thickness = in["thin_film_thickness"] * val(0.001f);
666 NodeItem thin_film_weight = thin_film_thickness.if_else(
667 NodeItem::CompareOp::Greater, val(0.0f), val(1.0f), val(0.0f));
668
669 /* "specular" here is "Specular IOR Level" in principled BSDF
670 * 0 = no specular
671 * 0.5 = full weight specular
672 * 1 = double specular weight */
673 NodeItem specular_weight = in["specular"] * val(2.0f);
674
675 res = create_node("open_pbr_surface",
676 NodeItem::Type::SurfaceShader,
677 {{"base_weight", val(1.0f)},
678 {"base_color", base_color},
679 {"base_diffuse_roughness", in["diffuse_roughness"]},
680 {"base_metalness", in["metallic"]},
681 {"specular_weight", specular_weight},
682 {"specular_color", in["specular_tint"]},
683 {"specular_roughness", in["roughness"]},
684 {"specular_ior", in["ior"]},
685 {"specular_roughness_anisotropy", anisotropy},
686 {"transmission_weight", in["transmission"]},
687 {"transmission_color", base_color},
688 {"subsurface_weight", in["subsurface"]},
689 {"subsurface_color", base_color},
690 {"subsurface_radius_scale", in["subsurface_radius"]},
691 {"subsurface_radius", in["subsurface_scale"]},
692 {"subsurface_scatter_anisotropy", in["subsurface_anisotropy"]},
693 {"fuzz_weight", in["sheen"]},
694 {"fuzz_color", in["sheen_tint"]},
695 {"fuzz_roughness", in["sheen_roughness"]},
696 {"coat_weight", in["coat"]},
697 {"coat_color", in["coat_tint"]},
698 {"coat_roughness", in["coat_roughness"]},
699 {"coat_ior", in["coat_ior"]},
700 /* Principled BSDF does not support anisotropy for the coat
701 * {"coat_roughness_anisotropy", anisotropic},
702 * {"geometry_coat_tangent", tangent}, */
703 {"emission_luminance", in["emission"]},
704 {"emission_color", in["emission_color"]},
705 {"thin_film_weight", thin_film_weight},
706 {"thin_film_thickness", thin_film_thickness},
707 {"thin_film_ior", in["thin_film_IOR"]},
708 {"geometry_normal", in["normal"]},
709 {"geometry_coat_normal", in["coat_normal"]},
710 {"geometry_tangent", tangent},
711 {"geometry_opacity", in["alpha"]}});
712 break;
713 }
714
715 case NodeItem::Type::SurfaceOpacity: {
716 res = get_input_value("Alpha", NodeItem::Type::Float);
717 break;
718 }
719
720 default:
722 }
723 return res;
724}
725#endif
727
728} // namespace blender::nodes::node_shader_bsdf_principled_cc
729
730/* node type definition */
732{
734
735 static blender::bke::bNodeType ntype;
736
737 sh_node_type_base(&ntype, "ShaderNodeBsdfPrincipled", SH_NODE_BSDF_PRINCIPLED);
738 ntype.ui_name = "Principled BSDF";
739 ntype.ui_description =
740 "Physically-based, easy-to-use shader for rendering surface materials, based on the OpenPBR "
741 "model";
742 ntype.enum_name_legacy = "BSDF_PRINCIPLED";
744 ntype.declare = file_ns::node_declare;
747 ntype.initfunc = file_ns::node_shader_init_principled;
748 ntype.gpu_fn = file_ns::node_shader_gpu_bsdf_principled;
749 ntype.updatefunc = file_ns::node_shader_update_principled;
750 ntype.materialx_fn = file_ns::node_shader_materialx;
751
753}
#define NODE_CLASS_SHADER
Definition BKE_node.hh:460
#define SH_NODE_BSDF_PRINCIPLED
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLT_I18NCONTEXT_AMOUNT
#define BLT_I18NCONTEXT_ID_NODETREE
@ SHD_SUBSURFACE_BURLEY
@ SHD_SUBSURFACE_RANDOM_WALK_SKIN
@ SHD_SUBSURFACE_RANDOM_WALK
@ SHD_GLOSSY_MULTI_GGX
@ SOCK_IN
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
GPUNodeLink * GPU_constant(const float *num)
eGPUMaterialFlag
@ GPU_MATFLAG_REFRACTION_MAYBE_COLORED
@ GPU_MATFLAG_REFLECTION_MAYBE_COLORED
@ GPU_MATFLAG_GLOSSY
@ GPU_MATFLAG_COAT
@ GPU_MATFLAG_REFRACT
@ GPU_MATFLAG_DIFFUSE
@ GPU_MATFLAG_TRANSPARENT
@ GPU_MATFLAG_SUBSURFACE
void GPU_material_flag_set(GPUMaterial *mat, eGPUMaterialFlag flag)
GPUNodeLink * GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name)
bool GPU_link(GPUMaterial *mat, const char *name,...)
@ PROP_DISTANCE
Definition RNA_types.hh:256
@ PROP_FACTOR
Definition RNA_types.hh:251
@ PROP_WAVELENGTH
Definition RNA_types.hh:287
@ UI_ITEM_R_SPLIT_EMPTY_NAME
void add_layout(std::function< void(uiLayout *, bContext *, PointerRNA *)> draw)
DeclType::Builder & add_input(StringRef name, StringRef identifier="")
#define in
#define out
VecBase< float, D > normalize(VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:4739
void node_type_size_preset(bNodeType &ntype, eNodeSizePreset size)
Definition node.cc:5396
static void node_shader_init_principled(bNodeTree *, bNode *node)
static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_declare(NodeDeclarationBuilder &b)
static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
static bool might_have_tinted_specular(const GPUNodeStack &base_color, const GPUNodeStack &metallic, const GPUNodeStack &specular_tint)
#define NODE_SHADER_MATERIALX_BEGIN
#define NODE_SHADER_MATERIALX_END
#define SOCK_BASE_COLOR_ID
#define SOCK_TRANSMISSION_WEIGHT_ID
#define SOCK_SUBSURFACE_WEIGHT_ID
#define SOCK_COAT_WEIGHT_ID
#define SOCK_METALLIC_ID
void register_node_type_sh_bsdf_principled()
#define SOCK_COAT_NORMAL_ID
#define SOCK_TANGENT_ID
#define SOCK_NORMAL_ID
#define SOCK_SPECULAR_TINT_ID
#define SOCK_SHEEN_WEIGHT_ID
#define SOCK_ALPHA_ID
#define SOCK_COAT_TINT_ID
void sh_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
bool object_shader_nodes_poll(const bContext *C)
#define min(a, b)
Definition sort.cc:36
closure color sheen(normal N, float roughness) BUILTIN
bool might_be_tinted() const
bool socket_not_zero() const
int16_t custom1
int16_t custom2
Defines a node type.
Definition BKE_node.hh:238
NodeMaterialXFunction materialx_fn
Definition BKE_node.hh:344
std::string ui_description
Definition BKE_node.hh:244
bool(* add_ui_poll)(const bContext *C)
Definition BKE_node.hh:310
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:289
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:281
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145