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