Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build
dist
.DS_Store
CMakeUserPresets.json
15 changes: 13 additions & 2 deletions documents/Specification/MaterialX.PBRSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,16 +200,19 @@ Implementations are expected to preserve energy as the roughness of the surface

The `tint` input colors the reflected and transmitted light but should be left at white (1,1,1) for physically correct results. Setting the `ior` input to zero disables the Fresnel curve, allowing reflectivity to be controlled purely by weight and tint.

The `scatter_mode` controls whether the surface reflects light (`R`), transmits light (`T`), or both (`RT`). In `RT` mode, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, total internal reflection may occur even when transmission modes are selected.
Setting `retroreflective` to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction[^Raab2025].

Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value.

The `scatter_mode` controls whether the surface reflects light (`R`), transmits light (`T`), or both (`RT`). In `RT` mode, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, total internal reflection may occur even when transmission modes are selected.

|Port |Description |Type |Default |Accepted Values|
|--------------------|---------------------------------------------------------------|-------|-------------|---------------|
|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
|`tint` |Color weight to tint the reflected and transmitted light |color3 |1.0, 1.0, 1.0| |
|`ior` |Index of refraction of the surface |float |1.5 | |
|`roughness` |Surface roughness along the tangent and bitangent |vector2|0.05, 0.05 |[0, 1] |
|`retroeflective` |Enable retroreflection mode for the BSDF |boolean|false | |
|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers |float |0.0 | |
|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | |
|`normal` |Normal vector of the surface |vector3|Nworld | |
Expand All @@ -227,6 +230,8 @@ Implementations are expected to preserve energy as the roughness of the surface

The default values for `ior` and `extinction` represent approximate values for gold.

Setting `retroreflective` to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction[^Raab2025].

Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value.

|Port |Description |Type |Default |Accepted Values|
Expand All @@ -235,6 +240,7 @@ Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_
|`ior` |Index of refraction |color3 |0.183, 0.421, 1.373 | |
|`extinction` |Extinction coefficient |color3 |3.424, 2.346, 1.770 | |
|`roughness` |Surface roughness |vector2|0.05, 0.05 |[0, 1] |
|`retroreflective` |Enable retroreflection mode for the BSDF |boolean|false | |
|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers|float |0.0 | |
|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | |
|`normal` |Normal vector of the surface |vector3|Nworld | |
Expand All @@ -251,10 +257,12 @@ Implementations are expected to preserve energy as the roughness of the surface

The `color82` input provides a multiplier on reflectivity at 82 degrees, useful for capturing the characteristic "dip" in the reflectance curve of metallic surfaces. Setting it to (1,1,1) effectively disables this feature for backward compatibility.

The `scatter_mode` behavior matches that of `dielectric_bsdf`: in `RT` mode, reflection and transmission occur both when entering and leaving a surface, with intensities controlled by the Fresnel curve. Total internal reflection may occur depending on the incident angle.
Setting `retroreflective` to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction[^Raab2025].

Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value.

The `scatter_mode` behavior matches that of `dielectric_bsdf`: in `RT` mode, reflection and transmission occur both when entering and leaving a surface, with intensities controlled by the Fresnel curve. Total internal reflection may occur depending on the incident angle.

|Port |Description |Type |Default |Accepted Values|
|--------------------|---------------------------------------------------------------|-------|-------------|---------------|
|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
Expand All @@ -263,6 +271,7 @@ Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_
|`color90` |Reflectivity per color component at grazing angles |color3 |1.0, 1.0, 1.0| |
|`exponent` |Exponent for Schlick blending between color0 and color90 |float |5.0 | |
|`roughness` |Surface roughness along the tangent and bitangent |vector2|0.05, 0.05 |[0, 1] |
|`retroreflective` |Enable retroreflection mode for the BSDF |boolean|false | |
|`thinfilm_thickness`|Thickness of the iridescent thin-film layer in nanometers |float |0.0 | |
|`thinfilm_ior` |Index of refraction of the thin-film layer |float |1.5 | |
|`normal` |Normal vector of the surface |vector3|Nworld | |
Expand Down Expand Up @@ -702,6 +711,8 @@ Path Tracing**, <https://media.disneyanimation.com/uploads/production/publicatio

[^Portsmouth2025]: Portsmouth et al., **EON: A practical energy-preserving rough diffuse BRDF**, <https://www.jcgt.org/published/0014/01/06/>, 2025.

[^Raab2025]: Matthias Raab et al., **The Minimal Retroreflective Microfacet Model**, to appear, 2025

[^Turquin2019]: Emmanuel Turquin, **Practical multiple scattering compensation for microfacet models**, <https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf>, 2019.

[^Walter2007]: Bruce Walter et al., **Microfacet Models for Refraction through Rough Surfaces**, <https://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf>, 2007
Expand Down
3 changes: 2 additions & 1 deletion libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "lib/mx_closure_type.glsl"
#include "lib/mx_microfacet_specular.glsl"

void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf)
void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, bool retroreflective, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);

Expand All @@ -13,6 +13,7 @@ void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 i
vec3 V = closureData.V;
vec3 L = closureData.L;

V = retroreflective ? reflect(-V, N) : V;
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);

Expand Down
6 changes: 5 additions & 1 deletion libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "lib/mx_closure_type.glsl"
#include "lib/mx_microfacet_specular.glsl"

void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float ior, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float ior, vec2 roughness, bool retroreflective, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
Expand All @@ -15,6 +15,10 @@ void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float
vec3 V = closureData.V;
vec3 L = closureData.L;

// Retroreflective mode is only supported for reflection and indirect
if (retroreflective && (closureData.closureType != CLOSURE_TYPE_TRANSMISSION))
V = reflect(-V, N);

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);

Expand Down
6 changes: 5 additions & 1 deletion libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "lib/mx_closure_type.glsl"
#include "lib/mx_microfacet_specular.glsl"

void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 color0, vec3 color82, vec3 color90, float exponent, vec2 roughness, bool retroreflective, float thinfilm_thickness, float thinfilm_ior, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
Expand All @@ -15,6 +15,10 @@ void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 col
vec3 V = closureData.V;
vec3 L = closureData.L;

// Retroreflective mode is only supported for reflection and indirect
if (retroreflective && (closureData.closureType != CLOSURE_TYPE_TRANSMISSION))
V = reflect(-V, N);

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);

Expand Down
6 changes: 3 additions & 3 deletions libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
<implementation name="IM_translucent_bsdf_genmdl" nodedef="ND_translucent_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_translucent_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_normal:{{normal}})" target="genmdl" />

<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genmdl" nodedef="ND_dielectric_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_dielectric_bsdf(mxp_weight:{{weight}}, mxp_tint:{{tint}}, mxp_ior:{{ior}}, mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />
<implementation name="IM_dielectric_bsdf_genmdl" nodedef="ND_dielectric_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_dielectric_bsdf(mxp_weight:{{weight}}, mxp_tint:{{tint}}, mxp_ior:{{ior}}, mxp_roughness:{{roughness}}, mxp_retroreflective:{{retroreflective}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />

<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genmdl" nodedef="ND_conductor_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_conductor_bsdf(mxp_weight:{{weight}}, mxp_ior:{{ior}}, mxp_extinction:{{extinction}}, mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}})" target="genmdl" />
<implementation name="IM_conductor_bsdf_genmdl" nodedef="ND_conductor_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_conductor_bsdf(mxp_weight:{{weight}}, mxp_ior:{{ior}}, mxp_extinction:{{extinction}}, mxp_roughness:{{roughness}}, mxp_retroreflective:{{retroreflective}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}})" target="genmdl" />

<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genmdl" nodedef="ND_generalized_schlick_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_bsdf(mxp_weight:{{weight}}, mxp_color0:{{color0}}, mxp_color82:{{color82}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}},mxp_roughness:{{roughness}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />
<implementation name="IM_generalized_schlick_bsdf_genmdl" nodedef="ND_generalized_schlick_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_bsdf(mxp_weight:{{weight}}, mxp_color0:{{color0}}, mxp_color82:{{color82}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}},mxp_roughness:{{roughness}}, mxp_retroreflective:{{retroreflective}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_top_weight:{{top_weight}})" target="genmdl" />

<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genmdl" nodedef="ND_subsurface_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_subsurface_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_radius:{{radius}}, mxp_anisotropy:{{anisotropy}}, mxp_normal:{{normal}})" target="genmdl" />
Expand Down
2 changes: 1 addition & 1 deletion libraries/pbrlib/genosl/mx_dielectric_bsdf.osl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, int retroreflective, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
color reflection_tint = (scatter_mode == "T") ? color(0.0) : tint;
color transmission_tint = (scatter_mode == "R") ? color(0.0) : tint;
Expand Down
2 changes: 1 addition & 1 deletion libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
void mx_generalized_schlick_bsdf(float weight, color color0, color color82, color color90, float exponent, vector2 roughness, int retroreflective, float thinfilm_thickness, float thinfilm_ior, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
color reflection_tint = (scatter_mode == "T") ? color(0.0) : color(1.0);
color transmission_tint = (scatter_mode == "R") ? color(0.0) : color(1.0);
Expand Down
3 changes: 3 additions & 0 deletions libraries/pbrlib/pbrlib_defs.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<input name="tint" type="color3" value="1.0, 1.0, 1.0" />
<input name="ior" type="float" value="1.5" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="retroreflective" type="boolean" value="false" uniform="true" />
<input name="thinfilm_thickness" type="float" value="0" unittype="distance" unit="nanometer" />
<input name="thinfilm_ior" type="float" value="1.5" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
Expand All @@ -82,6 +83,7 @@
<input name="ior" type="color3" value="0.183, 0.421, 1.373" />
<input name="extinction" type="color3" value="3.424, 2.346, 1.770" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="retroreflective" type="boolean" value="false" uniform="true" />
<input name="thinfilm_thickness" type="float" value="0" unittype="distance" unit="nanometer" />
<input name="thinfilm_ior" type="float" value="1.5" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
Expand All @@ -101,6 +103,7 @@
<input name="color90" type="color3" value="1.0, 1.0, 1.0" />
<input name="exponent" type="float" value="5.0" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="retroreflective" type="boolean" value="false" uniform="true" />
<input name="thinfilm_thickness" type="float" value="0" unittype="distance" unit="nanometer" />
<input name="thinfilm_ior" type="float" value="1.5" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
Expand Down
1 change: 1 addition & 0 deletions resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</roughness_anisotropy>
<conductor_bsdf name="conductor_brdf1" type="BSDF">
<input name="roughness" type="vector2" nodename="roughness1" />
<input name="retroreflective" type="boolean" value="false" />
<input name="ior" type="color3" nodename="conductor_brdf1__artistic_ior" output="ior" />
<input name="extinction" type="color3" nodename="conductor_brdf1__artistic_ior" output="extinction" />
</conductor_bsdf>
Expand Down
1 change: 1 addition & 0 deletions resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<dielectric_bsdf name="dielectric_R" type="BSDF">
<input name="weight" type="float" value="1.0" />
<input name="tint" type="color3" value="0.7, 0.7, 0.7" />
<input name="retroreflective" type="boolean" value="false" />
<input name="scatter_mode" type="string" value="R" />
</dielectric_bsdf>
<surface name="surface_R" type="surfaceshader">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<generalized_schlick_bsdf name="schlick_R" type="BSDF">
<input name="color0" type="color3" value="0.8, 0.8, 0.8" />
<input name="roughness" type="vector2" value="0.02, 0.02" />
<input name="retroreflective" type="boolean" value="false" />
<input name="scatter_mode" type="string" value="R" />
</generalized_schlick_bsdf>
<surface name="surface_R" type="surfaceshader">
Expand Down
11 changes: 11 additions & 0 deletions source/MaterialXFormat/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,17 @@ FilePathVec FilePath::getSubDirectories() const

void FilePath::createDirectory() const
{
if (isEmpty() || exists())
{
return;
}

FilePath parent = getParentPath();
if (!parent.isEmpty() && !parent.exists())
{
parent.createDirectory();
}

#if defined(_WIN32)
_mkdir(asString().c_str());
#else
Expand Down
1 change: 1 addition & 0 deletions source/MaterialXGenMdl/mdl/materialx/pbrlib_1_10.mdl
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export material mx_generalized_schlick_bsdf(
color mxp_color90 = color(1.0),
float mxp_exponent = 5.0,
float2 mxp_roughness = float2(0.05),
uniform bool mxp_retroreflective = false [[ anno::unused() ]],
float3 mxp_normal = state::normal(),
float3 mxp_tangent = state::texture_tangent_u(0),
uniform core::mx_distribution_type mxp_distribution = core::mx_distribution_type_ggx [[ anno::unused() ]],
Expand Down
Loading