diff --git a/documents/Specification/MaterialX.PBRSpec.md b/documents/Specification/MaterialX.PBRSpec.md
index 298f0fb0b2..67fecd80b3 100644
--- a/documents/Specification/MaterialX.PBRSpec.md
+++ b/documents/Specification/MaterialX.PBRSpec.md
@@ -243,6 +243,21 @@ The PBS nodes also make use of the following standard MaterialX types:
* `normal` (vector3): Normal vector of the surface. Defaults to world space normal.
* `mode` (uniform string): Selects between `conty_kulla` and `zeltner` sheen models. Defaults to `conty_kulla`.
+
+
+* **`chiang_hair_bsdf`**: Constructs a hair BSDF based on the Chiang hair shading model[^Chiang2016]. This node does not support vertical layering.
+ * `tint_R` (color3): Color multiplier for the first R-lobe. Defaults to (1.0, 1.0, 1.0).
+ * `tint_TT` (color3): Color multiplier for the first TT-lobe. Defaults to (1.0, 1.0, 1.0).
+ * `tint_TRT` (color3): Color multiplier for the first TRT-lobe. Defaults to (1.0, 1.0, 1.0).
+ * `ior` (float): Index of refraction. Defaults to 1.55 being the value for keratin.
+ * `roughness_R` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first R-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.1, 0.1).
+ * `roughness_TT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.05, 0.05).
+ * `roughness_TRT` (vector2): Longitudinal and azimuthal roughness (ν, s) for the first TRT-lobe, range [0.0, ∞). With (0, 0) specifying pure specular scattering. Defaults to (0.2, 0.2).
+ * `cuticle_angle` (float): Cuticle angle in radians, Values above 0.5 tilt the scales towards the root of the fiber, range [0.0, 1.0]. With 0.5 specifying no tilt. Defaults to 0.5.
+ * `absorption_coefficient` (vector3): Absorption coefficient normalized to the hair fiber diameter. Defaults to (0.0, 0.0, 0.0).
+ * `normal` (vector3): Normal vector of the surface. Defaults to world space normal.
+ * `curve_direction` (vector3): Direction of the hair geometry. Defaults to world space tangent.
+
## EDF Nodes
@@ -374,6 +389,27 @@ Note that the standard library includes definitions for [**`displacement`**](./M
* `ior` (**output**, vector3): Computed index of refraction.
* `extinction` (**output**, vector3): Computed extinction coefficient.
+
+
+* **`chiang_hair_roughness`**: Converts the artistic parameterization hair roughness to roughness for R, TT and TRT lobes, as described in [^Chiang2016]. Output type `multioutput`, `roughness_R`, `roughness_TT` and `roughness_TRT`, `vector2` type.
+ * `longitudinal` (float): Longitudinal roughness, range [0.0, 1.0]. Defaults to 0.1.
+ * `azimuthal` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2.
+ * `scale_TT` (float): Roughness scale for TT lobe. Defaults to 0.5[^Marschner2003].
+ * `scale_TRT` (float): Roughness scale for TRT lobe. Defaults to 2.0[^Marschner2003].
+
+
+
+* **`deon_hair_absorption_from_melanin`** : Converts the hair melanin parameterization to absorption coefficient based on pigments eumelanin and pheomelanin using the mapping method described in [^d'Eon2011]. The default of `eumelanin_color` and `pheomelanin_color` are `lin_rec709` color converted from the constants[^d'Eon2011] via `exp(-c)`. They may be transformed to scene-linear rendering color space. `Output type `vector3`.
+ * `melanin_concentration` (float): Amount of melanin affected to the output, range [0.0, 1.0]. Defaults to 0.25.
+ * `melanin_redness` (float): Amount of redness affected to the output, range [0.0, 1.0]. Defaults to 0.5.
+ * `eumelanin_color` (color3): Eumelanin color. Defaults to (0.657704, 0.498077, 0.254107)
+ * `pheomelanin_color` (color3): Pheomelanin color. Defaults to (0.829444, 0.67032, 0.349938)
+
+
+
+* **`chiang_hair_absorption_from_color`** : Coverts the hair scattering color to absorption coefficient using the mapping method described in [^Chiang2016]. Output type `vector3`.
+ * `color` (color3): Scattering color. Defaults to (1.0, 1.0, 1.0).
+ * `azimuthal_roughness` (float): Azimuthal roughness, range [0.0, 1.0]. Defaults to 0.2.
# Shading Model Examples
@@ -440,16 +476,23 @@ The MaterialX PBS Library includes a number of nodegraphs that can be used to ap
[^Burley2015]: Brent Burley, **Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering**, , 2015
+[^Chiang2016]: Matt Jen-Yuan Chiang et al., **A Practical and Controllable Hair and Fur Model for Production
+Path Tracing**, , 2016
+
[^Christensen2015]: Per H. Christensen, Brent Burley, **Approximate Reflectance Profiles for Efficient Subsurface Scattering**, 2015
[^Conty2017]: Alejandro Conty, Christopher Kulla, **Production Friendly Microfacet Sheen BRDF**, , 2017
+[^d'Eon2011]: Eugene d'Eon et al., **An Energy-Conserving Hair Reflectance Model**, , 2011
+
[^Georgiev2019]: Iliyan Georgiev et al., **Autodesk Standard Surface**, , 2019.
[^Gulbrandsen2014]: Ole Gulbrandsen, **Artist Friendly Metallic Fresnel**, , 2014
[^Hoffman2023]: Naty Hoffman, **Generalization of Adobe's Fresnel Model**, 2023
+[^Marschner2003]: Stephen R. Marschner et al., **Light Scattering from Human Hair Fibers**, , 2003
+
[^Oren1994]: Michael Oren, Shree K. Nayar, **Generalization of Lambert’s Reflectance Model**, , 1994
[^Pharr2023]: Matt Pharr et al., **Physically Based Rendering: From Theory To Implementation**, , 2023
diff --git a/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl
new file mode 100644
index 0000000000..e3a9ac20d5
--- /dev/null
+++ b/libraries/pbrlib/genglsl/mx_hair_bsdf.glsl
@@ -0,0 +1,343 @@
+#include "lib/mx_microfacet_specular.glsl"
+
+// https://eugenedeon.com/pdfs/egsrhair.pdf
+void mx_deon_hair_absorption_from_melanin(
+ float melanin_concentration,
+ float melanin_redness,
+ // constants converted to color via exp(-c). the defaults are lin_rec709 colors, they may be
+ // transformed to scene-linear rendering color space.
+ vec3 eumelanin_color, // default: (0.657704, 0.498077, 0.254106) == exp(-(0.419, 0.697, 1.37))
+ vec3 pheomelanin_color, // default: (0.829443, 0.670320, 0.349937) == exp(-(0.187, 0.4, 1.05))
+ out vec3 absorption)
+{
+ float melanin = -log(max(1.0 - melanin_concentration, 0.0001));
+ float eumelanin = melanin * (1.0 - melanin_redness);
+ float pheomelanin = melanin * melanin_redness;
+ absorption = max(
+ eumelanin * -log(eumelanin_color) + pheomelanin * -log(pheomelanin_color),
+ vec3(0.0)
+ );
+}
+
+// https://media.disneyanimation.com/uploads/production/publication_asset/152/asset/eurographics2016Fur_Smaller.pdf
+void mx_chiang_hair_absorption_from_color(vec3 color, float betaN, out vec3 absorption)
+{
+ float b2 = betaN* betaN;
+ float b4 = b2 * b2;
+ float b_fac =
+ 5.969 -
+ (0.215 * betaN) +
+ (2.532 * b2) -
+ (10.73 * b2 * betaN) +
+ (5.574 * b4) +
+ (0.245 * b4 * betaN);
+ vec3 sigma = log(min(max(color, 0.001), vec3(1.0))) / b_fac;
+ absorption = sigma * sigma;
+}
+
+void mx_chiang_hair_roughness(
+ float longitudinal,
+ float azimuthal,
+ float scale_TT, // empirical roughenss scale from Marschner et al. (2003).
+ float scale_TRT, // default: scale_TT = 0.5, scale_TRT = 2.0
+ out vec2 roughness_R,
+ out vec2 roughness_TT,
+ out vec2 roughness_TRT
+)
+{
+ float lr = clamp(longitudinal, 0.001, 1.0);
+ float ar = clamp(azimuthal, 0.001, 1.0);
+
+ // longitudinal variance
+ float v = 0.726 * lr + 0.812 * lr * lr + 3.7 * pow(lr, 20);
+ v = v * v;
+
+ float s = 0.265 * ar + 1.194 * ar * ar + 5.372 * pow(ar, 22);
+
+ roughness_R = vec2(v, s);
+ roughness_TT = vec2(v * scale_TT * scale_TT, s);
+ roughness_TRT = vec2(v * scale_TRT * scale_TRT, s);
+}
+
+float mx_hair_transform_sin_cos(float x)
+{
+ return sqrt(max(1.0 - x * x, 0.0));
+}
+
+float mx_hair_I0(float x)
+{
+ float v = 1.0;
+ float n = 1.0;
+ float d = 1.0;
+ float f = 1.0;
+ float x2 = x * x;
+ for (int i = 0; i < 9 ; ++i)
+ {
+ d *= 4.0 * (f * f);
+ n *= x2;
+ v += n / d;
+ f += 1.0;
+ }
+ return v;
+}
+
+float mx_hair_log_I0(float x)
+{
+ if (x > 12.0)
+ return x + 0.5 * (-log(2.0 * M_PI) + log(1.0 / x) + 1.0 / (8.0 * x));
+ else
+ return log(mx_hair_I0(x));
+}
+
+float mx_hair_logistic(float x, float s)
+{
+ if (x > 0.0)
+ x = -x;
+ float f = exp(x / s);
+ return f / (s * (1.0 + f) * (1.0 + f));
+}
+
+float mx_hair_logistic_cdf(float x, float s)
+{
+ return 1.0 / (1.0 + exp(-x / s));
+}
+
+float mx_hair_trimmed_logistic(float x, float s, float a, float b)
+{
+ // the constant can be found in Chiang et al. (2016) Appendix A, eq. (12)
+ s *= 0.626657; // sqrt(M_PI/8)
+ return mx_hair_logistic(x, s) / (mx_hair_logistic_cdf(b, s) - mx_hair_logistic_cdf(a, s));
+}
+
+float mx_hair_phi(int p, float gammaO, float gammaT)
+{
+ return 2.0 * p * gammaT - 2.0 * gammaO + p * M_PI;
+}
+
+float mx_hair_longitudinal_scattering( // Mp
+ float sinThetaI,
+ float cosThetaI,
+ float sinThetaO,
+ float cosThetaO,
+ float v
+)
+{
+ float inv_v = 1.0 / v;
+ float a = cosThetaO * cosThetaI * inv_v;
+ float b = sinThetaO * sinThetaI * inv_v;
+ if (v < 0.1)
+ return exp(mx_hair_log_I0(a) - b - inv_v + 0.6931 + log(0.5 * inv_v));
+ else
+ return ((exp(-b) * mx_hair_I0(a)) / (2.0 * v * sinh(inv_v)));
+}
+
+float mx_hair_azimuthal_scattering( // Np
+ float phi,
+ int p,
+ float s,
+ float gammaO,
+ float gammaT
+)
+{
+ if (p >= 3)
+ return float(0.5 / M_PI);
+
+ float dphi = phi - mx_hair_phi(p, gammaO, gammaT);
+ if (isinf(dphi))
+ return float(0.5 / M_PI);
+
+ while (dphi > M_PI) dphi -= (2.0 * M_PI);
+ while (dphi < (-M_PI)) dphi += (2.0 * M_PI);
+
+ return mx_hair_trimmed_logistic(dphi, s, -M_PI, M_PI);
+}
+
+void mx_hair_alpha_angles(
+ float alpha,
+ float sinThetaI,
+ float cosThetaI,
+ out vec2 angles[4]
+)
+{
+ // 0:R, 1:TT, 2:TRT, 3:TRRT+
+ for (int i = 0; i <= 3; ++i)
+ {
+ if (alpha == 0.0 || i == 3)
+ angles[i] = vec2(sinThetaI, cosThetaI);
+ else
+ {
+ float m = 2.0 - float(i) * 3.0;
+ float sa = sin(m * alpha);
+ float ca = cos(m * alpha);
+ angles[i].x = sinThetaI * ca + cosThetaI * sa;
+ angles[i].y = cosThetaI * ca - sinThetaI * sa;
+ }
+ }
+}
+
+void mx_hair_attenuation(float f, vec3 T, out vec3 Ap[4]) // Ap
+{
+ // 0:R, 1:TT, 2:TRT, 3:TRRT+
+ Ap[0] = vec3(f);
+ Ap[1] = (1.0 - f) * (1.0 - f) * T;
+ Ap[2] = Ap[1] * T * f;
+ Ap[3] = Ap[2] * T * f / (vec3(1.0) - T * f);
+}
+
+vec3 mx_chiang_hair_bsdf(
+ vec3 L,
+ vec3 V,
+ vec3 tint_R,
+ vec3 tint_TT,
+ vec3 tint_TRT,
+ float ior,
+ vec2 roughness_R,
+ vec2 roughness_TT,
+ vec2 roughness_TRT,
+ float cuticle_angle,
+ vec3 absorption_coefficient,
+ vec3 N,
+ vec3 X
+)
+{
+ N = mx_forward_facing_normal(N, V);
+ X = normalize(X - dot(X, N) * N);
+ vec3 Y = cross(N, X);
+
+ float sinThetaO = dot(V, X);
+ float sinThetaI = dot(L, X);
+ float cosThetaO = mx_hair_transform_sin_cos(sinThetaO);
+ float cosThetaI = mx_hair_transform_sin_cos(sinThetaI);
+
+ float y1 = dot(L, N);
+ float x1 = dot(L, Y);
+ float y2 = dot(V, N);
+ float x2 = dot(V, Y);
+ float phi = atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2);
+
+ vec3 k1_p = normalize(V - X * dot(V, X));
+ float cosGammaO = dot(N, k1_p);
+ float sinGammaO = mx_hair_transform_sin_cos(cosGammaO);
+ if (dot(k1_p, Y) > 0.0)
+ sinGammaO = -sinGammaO;
+ float gammaO = asin(sinGammaO);
+
+ float sinThetaT = sinThetaO / ior;
+ float cosThetaT = mx_hair_transform_sin_cos(sinThetaT);
+ float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, 1e-8);
+ float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0);
+ float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT);
+ float gammaT = asin(sinGammaT);
+
+ // attenuation
+ vec3 Ap[4];
+ float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior);
+ vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT));
+ mx_hair_attenuation(fresnel, T, Ap);
+
+ // parameters for each lobe
+ vec2 angles[4];
+ float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2]
+ mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles);
+
+ vec3 tint[4] = vec3[](tint_R, tint_TT, tint_TRT, tint_TRT);
+
+ roughness_R = clamp(roughness_R, 0.001, 1.0);
+ roughness_TT = clamp(roughness_TT, 0.001, 1.0);
+ roughness_TRT = clamp(roughness_TRT, 0.001, 1.0);
+ vec2 vs[4] = vec2[](roughness_R, roughness_TT, roughness_TRT, roughness_TRT);
+
+ // R, TT, TRT, TRRT+
+ vec3 F = vec3(0.0);
+ for (int i = 0; i <= 3; ++i)
+ {
+ if (all(lessThanEqual(tint[i], vec3(0.0))))
+ continue;
+
+ float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x);
+ float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT);
+ F += Mp * Np * tint[i] * Ap[i];
+ }
+
+ return F;
+}
+
+void mx_chiang_hair_bsdf_reflection(
+ vec3 L,
+ vec3 V,
+ vec3 P,
+ float occlusion,
+ vec3 tint_R,
+ vec3 tint_TT,
+ vec3 tint_TRT,
+ float ior,
+ vec2 roughness_R,
+ vec2 roughness_TT,
+ vec2 roughness_TRT,
+ float cuticle_angle,
+ vec3 absorption_coefficient,
+ vec3 N,
+ vec3 X,
+ inout BSDF bsdf
+)
+{
+ vec3 F = mx_chiang_hair_bsdf(
+ L,
+ V,
+ tint_R,
+ tint_TT,
+ tint_TRT,
+ ior,
+ roughness_R,
+ roughness_TT,
+ roughness_TRT,
+ cuticle_angle,
+ absorption_coefficient,
+ N,
+ X
+ );
+
+ bsdf.throughput = vec3(0.0);
+ bsdf.response = F * occlusion * M_PI_INV;
+}
+
+void mx_chiang_hair_bsdf_indirect(
+ vec3 V,
+ vec3 tint_R,
+ vec3 tint_TT,
+ vec3 tint_TRT,
+ float ior,
+ vec2 roughness_R,
+ vec2 roughness_TT,
+ vec2 roughness_TRT,
+ float cuticle_angle,
+ vec3 absorption_coefficient,
+ vec3 N,
+ vec3 X,
+ inout BSDF bsdf
+)
+{
+ // this indirect lighing is *very* rough approximation
+
+ N = mx_forward_facing_normal(N, V);
+
+ float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
+
+ FresnelData fd = mx_init_fresnel_dielectric(ior, 0.0, 1.0);
+ vec3 F = mx_compute_fresnel(NdotV, fd);
+
+ vec2 roughness = (roughness_R + roughness_TT + roughness_TRT) / vec2(3.0); // ?
+ vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
+ float avgAlpha = mx_average_alpha(safeAlpha);
+
+ // use ggx because the environment map for FIS is preintegrated with ggx
+ float F0 = mx_ior_to_f0(ior);
+ vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
+ vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp;
+
+ vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, 0, fd);
+ vec3 tint = (tint_R + tint_TT + tint_TRT) / vec3(3.0); // ?
+
+ bsdf.throughput = vec3(0.0);
+ bsdf.response = Li * comp * tint;
+}
diff --git a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx
index 2a23886640..1c495cb4bd 100644
--- a/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx
+++ b/libraries/pbrlib/genglsl/pbrlib_genglsl_impl.mtlx
@@ -25,6 +25,9 @@
+
+
+
@@ -74,4 +77,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/libraries/pbrlib/pbrlib_defs.mtlx b/libraries/pbrlib/pbrlib_defs.mtlx
index 2e71f80611..0bb75716e6 100644
--- a/libraries/pbrlib/pbrlib_defs.mtlx
+++ b/libraries/pbrlib/pbrlib_defs.mtlx
@@ -136,6 +136,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -404,4 +423,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx
new file mode 100644
index 0000000000..056c79b554
--- /dev/null
+++ b/resources/Materials/Examples/SimpleHair/simple_hair_default.mtlx
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx b/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx
new file mode 100644
index 0000000000..8d95ffe63f
--- /dev/null
+++ b/resources/Materials/TestSuite/pbrlib/bsdf/hair_bsdf.mtlx
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx b/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx
new file mode 100644
index 0000000000..056c79b554
--- /dev/null
+++ b/resources/Materials/TestSuite/pbrlib/surfaceshader/hair_surfaceshader.mtlx
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp
index db75a5ddf6..12a1f33868 100644
--- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp
+++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.cpp
@@ -91,9 +91,14 @@ TEST_CASE("GenShader: MDL Implementation Check", "[genmdl]")
mx::StringSet generatorSkipNodeTypes;
generatorSkipNodeTypes.insert("light");
+
mx::StringSet generatorSkipNodeDefs;
+ generatorSkipNodeDefs.insert("ND_chiang_hair_roughness");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color");
+ generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf");
- GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31);
+ GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35);
}
diff --git a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h
index f40254c5f4..1e617f73fb 100644
--- a/source/MaterialXTest/MaterialXGenMdl/GenMdl.h
+++ b/source/MaterialXTest/MaterialXGenMdl/GenMdl.h
@@ -49,6 +49,10 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
// df_cuda will currently hang on rendering one of the shaders in this file
_skipFiles.insert("heighttonormal_in_nodegraph.mtlx");
}
+
+ _skipFiles.insert("hair_bsdf.mtlx");
+ _skipFiles.insert("hair_surfaceshader.mtlx");
+
ShaderGeneratorTester::addSkipFiles();
}
diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp
index b0309ea44d..414bc3dd5d 100644
--- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp
+++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.cpp
@@ -84,7 +84,12 @@ TEST_CASE("GenShader: MSL Implementation Check", "[genmsl]")
mx::StringSet generatorSkipNodeTypes;
mx::StringSet generatorSkipNodeDefs;
- GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 30);
+ generatorSkipNodeDefs.insert("ND_chiang_hair_roughness");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color");
+ generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf");
+
+ GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 34);
}
TEST_CASE("GenShader: MSL Unique Names", "[genmsl]")
diff --git a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h
index 78cb7a8f4e..692c283fda 100644
--- a/source/MaterialXTest/MaterialXGenMsl/GenMsl.h
+++ b/source/MaterialXTest/MaterialXGenMsl/GenMsl.h
@@ -41,6 +41,12 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
ParentClass::addSkipNodeDefs();
}
+ void addSkipFiles() override
+ {
+ _skipFiles.insert("hair_bsdf.mtlx");
+ _skipFiles.insert("hair_surfaceshader.mtlx");
+ }
+
void setupDependentLibraries() override
{
ParentClass::setupDependentLibraries();
diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp
index f31c3d2a9b..c89f9ab19d 100644
--- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp
+++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.cpp
@@ -87,9 +87,14 @@ TEST_CASE("GenShader: OSL Implementation Check", "[genosl]")
mx::StringSet generatorSkipNodeTypes;
generatorSkipNodeTypes.insert("light");
+
mx::StringSet generatorSkipNodeDefs;
+ generatorSkipNodeDefs.insert("ND_chiang_hair_roughness");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_absorption_from_color");
+ generatorSkipNodeDefs.insert("ND_deon_hair_absorption_from_melanin");
+ generatorSkipNodeDefs.insert("ND_chiang_hair_bsdf");
- GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 31);
+ GenShaderUtil::checkImplementations(context, generatorSkipNodeTypes, generatorSkipNodeDefs, 35);
}
TEST_CASE("GenShader: OSL Unique Names", "[genosl]")
diff --git a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h
index a4ccdc2003..f02f750d26 100644
--- a/source/MaterialXTest/MaterialXGenOsl/GenOsl.h
+++ b/source/MaterialXTest/MaterialXGenOsl/GenOsl.h
@@ -42,6 +42,13 @@ class OslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
{
_skipLibraryFiles.insert( "pbrlib_genosl_arnold_impl.mtlx" );
}
+
+ void addSkipFiles() override
+ {
+ _skipFiles.insert("hair_bsdf.mtlx");
+ _skipFiles.insert("hair_surfaceshader.mtlx");
+ }
+
// Ignore light shaders in the document for OSL
void findLights(mx::DocumentPtr /*doc*/, std::vector& lights) override
{