25 b.use_custom_socket_order();
30 .default_value({0.8f, 0.8f, 0.8f, 1.0f})
32 "Color of the material used for diffuse, subsurface, metallic and transmission");
33#define SOCK_BASE_COLOR_ID 0
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
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
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");
64 .description(
"Controls the transparency of the surface, with 1.0 fully opaque");
65#define SOCK_ALPHA_ID 4
67#define SOCK_NORMAL_ID 5
69#define SOCK_WEIGHT_ID 6
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
93 .short_label(
"Weight")
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
99 .default_value({1.0f, 0.2f, 0.1f})
103 .description(
"Scattering radius per color channel (RGB), multiplied with Scale");
104#define SOCK_SUBSURFACE_RADIUS_ID 9
106 .default_value(0.05f)
110 .short_label(
"Scale")
111 .description(
"Scale factor of the subsurface scattering radius");
112#define SOCK_SUBSURFACE_SCALE_ID 10
119 .description(
"Index of Refraction (IOR) used for rays that enter the subsurface component");
120#define SOCK_SUBSURFACE_IOR_ID 11
126 .short_label(
"Anisotropy")
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
144 .short_label(
"IOR Level")
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 "
149#define SOCK_SPECULAR_ID 13
151 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
154 "Tint dielectric reflection at normal incidence for artistic control, and metallic "
155 "reflection at near-grazing incidence to simulate complex index of refraction")
157#define SOCK_SPECULAR_TINT_ID 14
164 "Amount of anisotropy for specular reflection. "
165 "Higher values give elongated highlights along the tangent direction");
166#define SOCK_ANISOTROPIC_ID 15
172 .description(
"Rotates the direction of anisotropy, with 1.0 going full circle");
173#define SOCK_ANISOTROPIC_ROTATION_ID 16
175 "Controls the tangent direction for anisotropy");
176#define SOCK_TANGENT_ID 17
185 .short_label(
"Weight")
186 .description(
"Blend between transmission and other base layer components");
187#define SOCK_TRANSMISSION_WEIGHT_ID 18
196 .short_label(
"Weight")
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
202 .default_value(0.03f)
206 .short_label(
"Roughness")
207 .description(
"The roughness of the coat layer");
208#define SOCK_COAT_ROUGHNESS_ID 20
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
219 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
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)")
226#define SOCK_COAT_TINT_ID 22
228#define SOCK_COAT_NORMAL_ID 23
237 .short_label(
"Weight")
239 "Intensity of the sheen layer, which simulates very small fibers on the surface");
240#define SOCK_SHEEN_WEIGHT_ID 24
246 .short_label(
"Roughness")
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
252 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
255 .description(
"Color of the sheen reflection");
256#define SOCK_SHEEN_TINT_ID 26
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
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")
274#define SOCK_EMISSION_STRENGTH_ID 28
283 .description(
"Thickness of the film in nanometers");
284#define SOCK_THIN_FILM_THICKNESS_ID 29
286 .default_value(1.33f)
289 .
description(
"Index of refraction (IOR) of the thin film");
290#define SOCK_THIN_FILM_IOR_ID 30
355 if (use_transparency) {
381 const float zero = 0.0f;
400 const int sss_method = node->
custom2;
414 using InputsType = std::map<std::string, NodeItem>;
417 auto bsdf_inputs = [&]() -> InputsType {
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)},
426 {
"subsurface_radius", get_input_value(
"Subsurface Radius", NodeItem::Type::Color3)},
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)},
454 auto edf_inputs = [&]() -> InputsType {
456 {
"emission", get_input_value(
"Emission Strength", NodeItem::Type::Float)},
457 {
"emission_color", get_input_value(
"Emission Color", NodeItem::Type::Color3)},
461 NodeItem res = empty();
464 case NodeItem::Type::BSDF: {
465 auto in = bsdf_inputs();
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"];
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);
486 NodeItem n_coat_roughness_vector = create_node(
487 "roughness_anisotropy",
488 NodeItem::Type::Vector2,
489 {{
"roughness",
in[
"coat_roughness"]}, {
"anisotropy", anisotropy}});
491 NodeItem n_coat_bsdf = create_node(
"dielectric_bsdf",
492 NodeItem::Type::BSDF,
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}});
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);
506 n_coat_bsdf.set_input(
"tangent", n_coat_tangent);
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(
513 NodeItem::Type::BSDF,
514 {{
"thickness", thin_film_thickness}, {
"ior", thin_film_ior}});
516 NodeItem n_artistic_ior = create_node(
518 NodeItem::Type::Multioutput,
519 {{
"reflectivity", base_color * val(1.0f)}, {
"edge_color", base_color * specular}});
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);
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,
528 NodeItem n_main_roughness = create_node(
529 "roughness_anisotropy",
530 NodeItem::Type::Vector2,
531 {{
"roughness", n_coat_affected_roughness}, {
"anisotropy", anisotropy}});
533 NodeItem n_metal_bsdf = create_node(
"conductor_bsdf",
534 NodeItem::Type::BSDF,
536 {
"extinction", n_extinction_out},
537 {
"roughness", n_main_roughness},
539 {
"tangent", n_main_tangent}});
541 NodeItem n_specular_bsdf = create_node(
"dielectric_bsdf",
542 NodeItem::Type::BSDF,
543 {{
"weight", specular},
544 {
"tint",
in[
"specular_tint"]},
546 {
"scatter_mode", val(std::string(
"R"))},
547 {
"roughness", n_main_roughness},
549 {
"tangent", n_main_tangent}});
551 NodeItem n_coat_affected_transmission_roughness = n_coat_affect_roughness_multiply2.mix(
552 (roughness + roughness).
clamp(), val(1.0f));
554 NodeItem n_transmission_roughness = create_node(
555 "roughness_anisotropy",
556 NodeItem::Type::Vector2,
557 {{
"roughness", n_coat_affected_transmission_roughness}, {
"anisotropy", anisotropy}});
559 NodeItem n_transmission_bsdf = create_node(
"dielectric_bsdf",
560 NodeItem::Type::BSDF,
561 {{
"tint", base_color},
563 {
"roughness", n_transmission_roughness},
565 {
"tangent", n_main_tangent}});
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(
571 NodeItem::Type::BSDF,
572 {{
"color", n_coat_affected_subsurface_color}, {
"normal", normal}});
574 NodeItem n_subsurface_bsdf = create_node(
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}});
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}});
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}});
596 NodeItem n_subsurface_mix =
in[
"subsurface"].mix(n_diffuse_bsdf, n_subsurface_bsdf);
598 NodeItem n_sheen_layer = create_node(
599 "layer", NodeItem::Type::BSDF, {{
"top", n_sheen_bsdf}, {
"base", n_subsurface_mix}});
601 NodeItem n_transmission_mix =
in[
"transmission"].mix(n_sheen_layer, n_transmission_bsdf);
603 NodeItem n_specular_layer = create_node(
604 "layer", NodeItem::Type::BSDF, {{
"top", n_specular_bsdf}, {
"base", n_transmission_mix}});
606 NodeItem n_metalness_mix =
in[
"metallic"].mix(n_specular_layer, n_metal_bsdf);
608 NodeItem n_thin_film_layer = create_node(
609 "layer", NodeItem::Type::BSDF, {{
"top", n_thin_film_bsdf}, {
"base", n_metalness_mix}});
611 NodeItem n_coat_attenuation = coat.mix(val(MaterialX::Color3(1.0f, 1.0f, 1.0f)),
614 res = create_node(
"layer",
615 NodeItem::Type::BSDF,
616 {{
"top", n_coat_bsdf}, {
"base", n_thin_film_layer * n_coat_attenuation}});
620 case NodeItem::Type::EDF: {
621 auto in = edf_inputs();
623 "uniform_edf", NodeItem::Type::EDF, {{
"color",
in[
"emission_color"] *
in[
"emission"]}});
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());
632 NodeItem base_color =
in[
"base_color"];
634 NodeItem anisotropy =
in[
"anisotropic"];
635 NodeItem tangent =
in[
"tangent"];
638 anisotropy = anisotropy * val(0.7f);
642 NodeItem rotation = -((
in[
"anisotropic_rotation"] * val(360.0f)) + val(90.0f));
646 NodeItem normal =
in[
"normal"];
648 const std::string world =
"world";
650 create_node(
"normal", NodeItem::Type::Vector3, {{
"space", val(world)}}).
normalize();
654 const std::string world =
"world";
656 create_node(
"tangent", NodeItem::Type::Vector3, {{
"space", val(world)}}).
normalize();
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);
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));
673 NodeItem specular_weight =
in[
"specular"] * val(2.0f);
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"]},
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"]}});
715 case NodeItem::Type::SurfaceOpacity: {
716 res = get_input_value(
"Alpha", NodeItem::Type::Float);