From 5050f0f0a23e16cadcec2679cd947f4525d68be1 Mon Sep 17 00:00:00 2001
From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com>
Date: Thu, 19 Feb 2026 16:46:21 -0800
Subject: [PATCH 1/7] add retroreflective to specular BSDFs
---
documents/Specification/MaterialX.PBRSpec.md | 94 ++++++++++---------
.../pbrlib/genglsl/mx_conductor_bsdf.glsl | 3 +-
.../pbrlib/genglsl/mx_dielectric_bsdf.glsl | 6 +-
.../genglsl/mx_generalized_schlick_bsdf.glsl | 6 +-
.../pbrlib/genmdl/pbrlib_genmdl_impl.mtlx | 6 +-
.../pbrlib/genosl/mx_dielectric_bsdf.osl | 2 +-
.../genosl/mx_generalized_schlick_bsdf.osl | 2 +-
libraries/pbrlib/pbrlib_defs.mtlx | 3 +
.../TestSuite/pbrlib/bsdf/conductor.mtlx | 1 +
.../TestSuite/pbrlib/bsdf/dielectric.mtlx | 1 +
.../pbrlib/bsdf/generalized_schlick.mtlx | 1 +
.../mdl/materialx/pbrlib_1_10.mdl | 1 +
.../mdl/materialx/pbrlib_1_6.mdl | 3 +
.../mdl/materialx/pbrlib_1_9.mdl | 3 +
14 files changed, 82 insertions(+), 50 deletions(-)
diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 6f19a102e0..861e0293bd 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -200,23 +200,26 @@ 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.
-|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] |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3|Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
-|`out` |Output: the computed BSDF |BSDF | | |
+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] |
+|`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 | |
+|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
+|`out` |Output: the computed BSDF |BSDF | | |
@@ -227,20 +230,23 @@ 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|
-|--------------------|---------------------------------------------------------|-------|----------------------|---------------|
-|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
-|`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] |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3|Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`out` |Output: the computed BSDF |BSDF | | |
+|Port |Description |Type |Default |Accepted Values|
+|--------------------|---------------------------------------------------------|--------|----------------------|---------------|
+|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
+|`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 | |
+|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`out` |Output: the computed BSDF |BSDF | | |
@@ -251,25 +257,28 @@ 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.
-|Port |Description |Type |Default |Accepted Values|
-|--------------------|---------------------------------------------------------------|-------|-------------|---------------|
-|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
-|`color0` |Reflectivity per color component at facing angles |color3 |1.0, 1.0, 1.0| |
-|`color82` |Reflectivity multiplier at 82 degrees |color3 |1.0, 1.0, 1.0| |
-|`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] |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3|Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
-|`out` |Output: the computed BSDF |BSDF | | |
+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] |
+|`color0` |Reflectivity per color component at facing angles |color3 |1.0, 1.0, 1.0| |
+|`color82` |Reflectivity multiplier at 82 degrees |color3 |1.0, 1.0, 1.0| |
+|`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 | |
+|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
+|`out` |Output: the computed BSDF |BSDF | | |
@@ -668,6 +677,7 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap
# References
+[^Raab2025]: Matthias Raab et al., **The Minimal Retroreflective Microfacet Model**, to appear, 2025
[^Andersson2024]: Andersson et al., **OpenPBR Surface Specification**, , 2024.
diff --git a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl
index 633f6d0d50..f44262afa6 100644
--- a/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl
+++ b/libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl
@@ -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);
@@ -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);
diff --git a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl
index 4c59b21802..b92dd18746 100644
--- a/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl
+++ b/libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl
@@ -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)
{
@@ -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);
diff --git a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl
index 08c7311495..c80f413d32 100644
--- a/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl
+++ b/libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl
@@ -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)
{
@@ -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);
diff --git a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
index 86f4694578..d87ac28b4e 100644
--- a/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
+++ b/libraries/pbrlib/genmdl/pbrlib_genmdl_impl.mtlx
@@ -11,13 +11,13 @@
-
+
-
+
-
+
diff --git a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl
index 5d465ea745..dbea9adeb7 100644
--- a/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl
+++ b/libraries/pbrlib/genosl/mx_dielectric_bsdf.osl
@@ -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;
diff --git a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl
index 9a05300b67..7382f4ee73 100644
--- a/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl
+++ b/libraries/pbrlib/genosl/mx_generalized_schlick_bsdf.osl
@@ -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);
diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx
index 039d78bdd6..0f8f5c57ac 100644
--- a/libraries/pbrlib/pbrlib_defs.mtlx
+++ b/libraries/pbrlib/pbrlib_defs.mtlx
@@ -64,6 +64,7 @@
+
@@ -82,6 +83,7 @@
+
@@ -101,6 +103,7 @@
+
diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx
index e2d5540350..d4960fab62 100644
--- a/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx
+++ b/resources/Materials/TestSuite/pbrlib/bsdf/conductor.mtlx
@@ -7,6 +7,7 @@
+
diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx
index c62ba5b35a..320065ee48 100644
--- a/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx
+++ b/resources/Materials/TestSuite/pbrlib/bsdf/dielectric.mtlx
@@ -4,6 +4,7 @@
+
diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx
index bc31308a47..08cfc4e2a9 100644
--- a/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx
+++ b/resources/Materials/TestSuite/pbrlib/bsdf/generalized_schlick.mtlx
@@ -4,6 +4,7 @@
+
diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_10.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_10.mdl
index 44d56163ff..8551482836 100644
--- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_10.mdl
+++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_10.mdl
@@ -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() ]],
diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl
index 31872aa0bf..7a1198d98c 100644
--- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl
+++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_6.mdl
@@ -154,6 +154,7 @@ export material mx_dielectric_bsdf(
color mxp_tint = color(1.0),
float mxp_ior = 1.5,
float2 mxp_roughness = float2(0.0),
+ 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() ]],
@@ -231,6 +232,7 @@ export material mx_conductor_bsdf(
color mxp_ior = color(0.18, 0.42, 1.37),
color mxp_extinction = color(3.42, 2.35, 1.77),
float2 mxp_roughness = float2(0.0),
+ 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() ]],
@@ -275,6 +277,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() ]],
diff --git a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl
index f5cb6d2f40..412d4a7797 100644
--- a/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl
+++ b/source/MaterialXGenMdl/mdl/materialx/pbrlib_1_9.mdl
@@ -173,6 +173,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() ]],
@@ -246,6 +247,7 @@ export material mx_dielectric_bsdf(
color mxp_tint = color(1.0),
float mxp_ior = 1.5,
float2 mxp_roughness = float2(0.0),
+ 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() ]],
@@ -321,6 +323,7 @@ export material mx_conductor_bsdf(
color mxp_ior = color(0.18, 0.42, 1.37),
color mxp_extinction = color(3.42, 2.35, 1.77),
float2 mxp_roughness = float2(0.0),
+ 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() ]],
From aa60adb09c3bdfe9b8062d4c5104330da960068e Mon Sep 17 00:00:00 2001
From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com>
Date: Thu, 19 Feb 2026 16:46:40 -0800
Subject: [PATCH 2/7] address test-related issues
---
source/MaterialXFormat/File.cpp | 11 ++++++++++
source/MaterialXRenderOsl/OslRenderer.cpp | 22 ++++++++++++-------
.../MaterialXRenderMdl/RenderMdl.cpp | 1 +
3 files changed, 26 insertions(+), 8 deletions(-)
diff --git a/source/MaterialXFormat/File.cpp b/source/MaterialXFormat/File.cpp
index f101844de7..3693a5a186 100644
--- a/source/MaterialXFormat/File.cpp
+++ b/source/MaterialXFormat/File.cpp
@@ -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
diff --git a/source/MaterialXRenderOsl/OslRenderer.cpp b/source/MaterialXRenderOsl/OslRenderer.cpp
index 51b3075ed8..9976d655c7 100644
--- a/source/MaterialXRenderOsl/OslRenderer.cpp
+++ b/source/MaterialXRenderOsl/OslRenderer.cpp
@@ -76,8 +76,11 @@ void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, c
const bool isColorClosure = _oslShaderOutputType == "closure color";
const bool isRemappable = REMAPPABLE_TYPES.count(_oslShaderOutputType) != 0;
+ // Resolve to absolute path so that paths remain valid after CWD changes.
+ const FilePath absDir = dirPath.isAbsolute() ? dirPath : (FilePath::getCurrentPath() / dirPath);
+
// Determine the shader path from output path and shader name
- FilePath shaderFilePath(dirPath);
+ FilePath shaderFilePath(absDir);
shaderFilePath = shaderFilePath / shaderName;
string shaderPath = shaderFilePath.asString();
@@ -146,7 +149,7 @@ void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, c
rootPath.setCurrentPath();
// Write scene file
- const string sceneFileName = (dirPath / (shaderName + "_scene_template.xml")).asString();
+ const string sceneFileName = (absDir / (shaderName + "_scene_template.xml")).asString();
std::ofstream shaderFileStream;
shaderFileStream.open(sceneFileName);
if (shaderFileStream.is_open())
@@ -157,8 +160,8 @@ void OslRenderer::renderOSL(const FilePath& dirPath, const string& shaderName, c
// Set oso file paths
string osoPaths(_oslUtilityOSOPath);
- osoPaths += PATH_LIST_SEPARATOR + dirPath.asString();
- osoPaths += PATH_LIST_SEPARATOR + dirPath.getParentPath().asString();
+ osoPaths += PATH_LIST_SEPARATOR + absDir.asString();
+ osoPaths += PATH_LIST_SEPARATOR + absDir.getParentPath().asString();
// Build and run render command
string command(_oslTestRenderExecutable);
@@ -220,8 +223,11 @@ void OslRenderer::renderOSLNetwork(const FilePath& dirPath, const string& shader
throw ExceptionRenderError("Command input arguments are missing");
}
+ // Resolve to absolute path so that paths remain valid after CWD changes.
+ const FilePath absDir = dirPath.isAbsolute() ? dirPath : (FilePath::getCurrentPath() / dirPath);
+
// Determine the shader path from output path and shader name
- FilePath shaderFilePath(dirPath);
+ FilePath shaderFilePath(absDir);
shaderFilePath = shaderFilePath / shaderName;
string shaderPath = shaderFilePath.asString();
@@ -271,7 +277,7 @@ void OslRenderer::renderOSLNetwork(const FilePath& dirPath, const string& shader
rootPath.setCurrentPath();
// Write scene file
- const string sceneFileName = (dirPath / (shaderName + "_scene_template_oslcmd.xml")).asString();
+ const string sceneFileName = (absDir / (shaderName + "_scene_template_oslcmd.xml")).asString();
std::ofstream shaderFileStream;
shaderFileStream.open(sceneFileName);
@@ -284,8 +290,8 @@ void OslRenderer::renderOSLNetwork(const FilePath& dirPath, const string& shader
// Set oso file paths
string osoPaths(_oslUtilityOSOPath);
osoPaths += PATH_LIST_SEPARATOR + _dataLibraryOSOPath.asString();
- osoPaths += PATH_LIST_SEPARATOR + dirPath.asString();
- osoPaths += PATH_LIST_SEPARATOR + dirPath.getParentPath().asString();
+ osoPaths += PATH_LIST_SEPARATOR + absDir.asString();
+ osoPaths += PATH_LIST_SEPARATOR + absDir.getParentPath().asString();
// Build and run render command
string command(_oslTestRenderExecutable);
diff --git a/source/MaterialXTest/MaterialXRenderMdl/RenderMdl.cpp b/source/MaterialXTest/MaterialXRenderMdl/RenderMdl.cpp
index 99e769277a..912c68491b 100644
--- a/source/MaterialXTest/MaterialXRenderMdl/RenderMdl.cpp
+++ b/source/MaterialXTest/MaterialXRenderMdl/RenderMdl.cpp
@@ -50,6 +50,7 @@ class MdlShaderRenderTester : public RenderUtil::ShaderRenderTester
// general it is probably better to give the main object a predictable name and use suffixes
// for internal objects.
_skipFiles.insert("translucent_bsdf.mtlx");
+ _skipFiles.insert("blur.mtlx");
}
mx::DocumentPtr _last_doc;
From 4a381fcfc60f00ae5fbae0527f90a4d8574f0bc6 Mon Sep 17 00:00:00 2001
From: Masuo Suzuki <153872239+msuzuki-nvidia@users.noreply.github.com>
Date: Thu, 19 Feb 2026 16:46:51 -0800
Subject: [PATCH 3/7] add CMakeUserPresets.json to .gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index f2d3d5dccd..7444050b1c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
build
dist
.DS_Store
+CMakeUserPresets.json
\ No newline at end of file
From 6cd0d123746f8dc7e23bcaa4dcd50e95abb1b03c Mon Sep 17 00:00:00 2001
From: Jonathan Stone
Date: Sun, 22 Feb 2026 16:38:25 -0800
Subject: [PATCH 4/7] Minor update to table spacing
Signed-off-by: Jonathan Stone
---
documents/Specification/MaterialX.PBRSpec.md | 86 ++++++++++----------
1 file changed, 43 insertions(+), 43 deletions(-)
diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 861e0293bd..97ca6d8b2c 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -206,20 +206,20 @@ Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_
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] |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
-|`out` |Output: the computed BSDF |BSDF | | |
+|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 | |
+|`tangent` |Tangent vector of the surface |vector3|Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
+|`out` |Output: the computed BSDF |BSDF | | |
@@ -234,19 +234,19 @@ Setting `retroreflective` to true switches the BSDF to retroreflection mode, whe
Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_thickness` to a non-zero value.
-|Port |Description |Type |Default |Accepted Values|
-|--------------------|---------------------------------------------------------|--------|----------------------|---------------|
-|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`out` |Output: the computed BSDF |BSDF | | |
+|Port |Description |Type |Default |Accepted Values|
+|--------------------|---------------------------------------------------------|-------|----------------------|---------------|
+|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
+|`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 | |
+|`tangent` |Tangent vector of the surface |vector3|Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`out` |Output: the computed BSDF |BSDF | | |
@@ -263,22 +263,22 @@ Thin-film iridescence effects[^Belcour2017] may be enabled by setting `thinfilm_
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] |
-|`color0` |Reflectivity per color component at facing angles |color3 |1.0, 1.0, 1.0| |
-|`color82` |Reflectivity multiplier at 82 degrees |color3 |1.0, 1.0, 1.0| |
-|`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 | |
-|`tangent` |Tangent vector of the surface |vector3 |Tworld | |
-|`distribution` |Microfacet distribution type |string |ggx |ggx |
-|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
-|`out` |Output: the computed BSDF |BSDF | | |
+|Port |Description |Type |Default |Accepted Values|
+|--------------------|---------------------------------------------------------------|-------|-------------|---------------|
+|`weight` |Weight of the BSDF contribution |float |1.0 |[0, 1] |
+|`color0` |Reflectivity per color component at facing angles |color3 |1.0, 1.0, 1.0| |
+|`color82` |Reflectivity multiplier at 82 degrees |color3 |1.0, 1.0, 1.0| |
+|`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 | |
+|`tangent` |Tangent vector of the surface |vector3|Tworld | |
+|`distribution` |Microfacet distribution type |string |ggx |ggx |
+|`scatter_mode` |Surface Scatter mode, specifying reflection and/or transmission|string |R |R, T, RT |
+|`out` |Output: the computed BSDF |BSDF | | |
From b661bd6942de0b5fa63610d5728d046d64155c04 Mon Sep 17 00:00:00 2001
From: Jonathan Stone
Date: Sun, 22 Feb 2026 16:39:42 -0800
Subject: [PATCH 5/7] Align columns in dielectric_bsdf
Signed-off-by: Jonathan Stone
---
documents/Specification/MaterialX.PBRSpec.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 97ca6d8b2c..11c0154f49 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -212,7 +212,7 @@ The `scatter_mode` controls whether the surface reflects light (`R`), transmits
|`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 | |
+|`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 | |
From fb8e56a8d1582cca49afe340f316c55117ff3cf2 Mon Sep 17 00:00:00 2001
From: Jonathan Stone
Date: Sun, 22 Feb 2026 16:43:11 -0800
Subject: [PATCH 6/7] State references in alphabetical order
Signed-off-by: Jonathan Stone
---
documents/Specification/MaterialX.PBRSpec.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 11c0154f49..0647607a8d 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -677,8 +677,6 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap
# References
-[^Raab2025]: Matthias Raab et al., **The Minimal Retroreflective Microfacet Model**, to appear, 2025
-
[^Andersson2024]: Andersson et al., **OpenPBR Surface Specification**, , 2024.
[^Belcour2017]: Laurent Belcour, Pascal Barla, **A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence**, , 2017
@@ -712,6 +710,8 @@ Path Tracing**, , 2025.
+[^Raab2025]: Matthias Raab et al., **The Minimal Retroreflective Microfacet Model**, to appear, 2025
+
[^Turquin2019]: Emmanuel Turquin, **Practical multiple scattering compensation for microfacet models**, , 2019.
[^Walter2007]: Bruce Walter et al., **Microfacet Models for Refraction through Rough Surfaces**, , 2007
From b350221391ff9feee912a29d00cb9e08f6fb57d8 Mon Sep 17 00:00:00 2001
From: Jonathan Stone
Date: Sun, 22 Feb 2026 16:44:14 -0800
Subject: [PATCH 7/7] Restore original newline
Signed-off-by: Jonathan Stone
---
documents/Specification/MaterialX.PBRSpec.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 0647607a8d..17114800c6 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -677,6 +677,7 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap
# References
+
[^Andersson2024]: Andersson et al., **OpenPBR Surface Specification**, , 2024.
[^Belcour2017]: Laurent Belcour, Pascal Barla, **A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence**, , 2017