Ajout du projet Depths sur Git

This commit is contained in:
2026-04-30 12:24:52 +02:00
commit a143ea22c7
6651 changed files with 77423 additions and 0 deletions
@@ -0,0 +1,69 @@
#include "mx_microfacet_specular.glsl"
vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd)
{
// Generate tangent frame.
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);
mat3 tangentToWorld = mat3(X, Y, N);
// Transform the view vector to tangent space.
V = vec3(dot(V, X), dot(V, Y), dot(V, N));
// Compute derived properties.
float NdotV = clamp(V.z, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(alpha);
float G1V = mx_ggx_smith_G1(NdotV, avgAlpha);
// Integrate outgoing radiance using filtered importance sampling.
// http://cgg.mff.cuni.cz/~jaroslav/papers/2008-egsr-fis/2008-egsr-fis-final-embedded.pdf
vec3 radiance = vec3(0.0);
int envRadianceSamples = $envRadianceSamples;
for (int i = 0; i < envRadianceSamples; i++)
{
vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples);
// Compute the half vector and incoming light direction.
vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, alpha);
vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, H, fd.ior.x) : -reflect(V, H);
// Compute dot products for this sample.
float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);
// Sample the environment light from the given direction.
vec3 Lw = tangentToWorld * L;
float pdf = mx_ggx_NDF(H, alpha) * G1V / (4.0 * NdotV);
float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples);
vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance);
// Compute the Fresnel term.
vec3 F = mx_compute_fresnel(VdotH, fd);
// Compute the geometric term.
float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha);
// Compute the combined FG term, which is inverted for refraction.
vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G;
// Add the radiance contribution of this sample.
// From https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
// incidentLight = sampleColor * NdotL
// microfacetSpecular = D * F * G / (4 * NdotL * NdotV)
// pdf = D * G1V / (4 * NdotV);
// radiance = incidentLight * microfacetSpecular / pdf
radiance += sampleColor * FG;
}
// Apply the global component of the geometric term and normalize.
radiance /= G1V * float(envRadianceSamples);
// Return the final radiance.
return radiance * $envLightIntensity;
}
vec3 mx_environment_irradiance(vec3 N)
{
vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance);
return Li * $envLightIntensity;
}
@@ -0,0 +1,11 @@
#include "mx_microfacet_specular.glsl"
vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 roughness, int distribution, FresnelData fd)
{
return vec3(0.0);
}
vec3 mx_environment_irradiance(vec3 N)
{
return vec3(0.0);
}
@@ -0,0 +1,30 @@
#include "mx_microfacet_specular.glsl"
// Return the mip level associated with the given alpha in a prefiltered environment.
float mx_latlong_alpha_to_lod(float alpha)
{
float lodBias = (alpha < 0.25) ? sqrt(alpha) : 0.5 * alpha + 0.375;
return lodBias * float($envRadianceMips - 1);
}
vec3 mx_environment_radiance(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd)
{
N = mx_forward_facing_normal(N, V);
vec3 L = fd.refraction ? mx_refraction_solid_sphere(-V, N, fd.ior.x) : -reflect(V, N);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(alpha);
vec3 F = mx_compute_fresnel(NdotV, fd);
float G = mx_ggx_smith_G2(NdotV, NdotV, avgAlpha);
vec3 FG = fd.refraction ? vec3(1.0) - (F * G) : F * G;
vec3 Li = mx_latlong_map_lookup(L, $envMatrix, mx_latlong_alpha_to_lod(avgAlpha), $envRadiance);
return Li * FG * $envLightIntensity;
}
vec3 mx_environment_irradiance(vec3 N)
{
vec3 Li = mx_latlong_map_lookup(N, $envMatrix, 0.0, $envIrradiance);
return Li * $envLightIntensity;
}
@@ -0,0 +1,10 @@
#include "mx_microfacet_sheen.glsl"
#include "mx_microfacet_specular.glsl"
vec3 mx_generate_dir_albedo_table()
{
vec2 uv = gl_FragCoord.xy / $albedoTableSize;
vec2 ggxDirAlbedo = mx_ggx_dir_albedo(uv.x, uv.y, vec3(1, 0, 0), vec3(0, 1, 0)).xy;
float sheenDirAlbedo = mx_imageworks_sheen_dir_albedo(uv.x, uv.y);
return vec3(ggxDirAlbedo, sheenDirAlbedo);
}
@@ -0,0 +1,78 @@
#include "mx_microfacet_specular.glsl"
// Construct an orthonormal basis from a unit vector.
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
mat3 mx_orthonormal_basis(vec3 N)
{
float sign = (N.z < 0.0) ? -1.0 : 1.0;
float a = -1.0 / (sign + N.z);
float b = N.x * N.y * a;
vec3 X = vec3(1.0 + sign * N.x * N.x * a, sign * b, -sign * N.x);
vec3 Y = vec3(b, sign + N.y * N.y * a, -N.y);
return mat3(X, Y, N);
}
// Return the alpha associated with the given mip level in a prefiltered environment.
float mx_latlong_lod_to_alpha(float lod)
{
float lodBias = lod / float($envRadianceMips - 1);
return (lodBias < 0.5) ? mx_square(lodBias) : 2.0 * (lodBias - 0.375);
}
// The inverse of mx_latlong_projection.
vec3 mx_latlong_map_projection_inverse(vec2 uv)
{
float latitude = (uv.y - 0.5) * M_PI;
float longitude = (uv.x - 0.5) * M_PI * 2.0;
float x = -cos(latitude) * sin(longitude);
float y = -sin(latitude);
float z = cos(latitude) * cos(longitude);
return vec3(x, y, z);
}
vec3 mx_generate_prefilter_env()
{
// The tangent view vector is aligned with the normal.
vec3 V = vec3(0.0, 0.0, 1.0);
float NdotV = 1.0;
// Compute derived properties.
vec2 uv = gl_FragCoord.xy * pow(2.0, $envPrefilterMip) / vec2(textureSize($envRadiance, 0));
vec3 worldN = mx_latlong_map_projection_inverse(uv);
mat3 tangentToWorld = mx_orthonormal_basis(worldN);
float alpha = mx_latlong_lod_to_alpha(float($envPrefilterMip));
float G1V = mx_ggx_smith_G1(NdotV, alpha);
// Integrate the LD term for the given environment and alpha.
vec3 radiance = vec3(0.0, 0.0, 0.0);
float weight = 0.0;
int envRadianceSamples = 1024;
for (int i = 0; i < envRadianceSamples; i++)
{
vec2 Xi = mx_spherical_fibonacci(i, envRadianceSamples);
// Compute the half vector and incoming light direction.
vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha));
vec3 L = -V + 2.0 * H.z * H;
// Compute dot products for this sample.
float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0);
// Compute the geometric term.
float G = mx_ggx_smith_G2(NdotL, NdotV, alpha);
// Sample the environment light from the given direction.
vec3 Lw = tangentToWorld * L;
float pdf = mx_ggx_NDF(H, vec2(alpha)) * G1V / (4.0 * NdotV);
float lod = mx_latlong_compute_lod(Lw, pdf, float($envRadianceMips - 1), envRadianceSamples);
vec3 sampleColor = mx_latlong_map_lookup(Lw, $envMatrix, lod, $envRadiance);
// Add the radiance contribution of this sample.
radiance += G * sampleColor;
weight += G;
}
return radiance / weight;
}
@@ -0,0 +1,77 @@
#define M_PI 3.1415926535897932
#define M_PI_INV (1.0 / M_PI)
float mx_pow5(float x)
{
return mx_square(mx_square(x)) * x;
}
// Standard Schlick Fresnel
float mx_fresnel_schlick(float cosTheta, float F0)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return F0 + (1.0 - F0) * x5;
}
vec3 mx_fresnel_schlick(float cosTheta, vec3 F0)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return F0 + (1.0 - F0) * x5;
}
// Generalized Schlick Fresnel
float mx_fresnel_schlick(float cosTheta, float F0, float F90)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return mix(F0, F90, x5);
}
vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return mix(F0, F90, x5);
}
// Generalized Schlick Fresnel with a variable exponent
float mx_fresnel_schlick(float cosTheta, float F0, float F90, float exponent)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
return mix(F0, F90, pow(x, exponent));
}
vec3 mx_fresnel_schlick(float cosTheta, vec3 F0, vec3 F90, float exponent)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
return mix(F0, F90, pow(x, exponent));
}
// Enforce that the given normal is forward-facing from the specified view direction.
vec3 mx_forward_facing_normal(vec3 N, vec3 V)
{
return (dot(N, V) < 0.0) ? -N : N;
}
// https://www.graphics.rwth-aachen.de/publication/2/jgt.pdf
float mx_golden_ratio_sequence(int i)
{
const float GOLDEN_RATIO = 1.6180339887498948;
return fract((float(i) + 1.0) * GOLDEN_RATIO);
}
// https://people.irisa.fr/Ricardo.Marques/articles/2013/SF_CGF.pdf
vec2 mx_spherical_fibonacci(int i, int numSamples)
{
return vec2((float(i) + 0.5) / float(numSamples), mx_golden_ratio_sequence(i));
}
// Generate a uniform-weighted sample in the unit hemisphere.
vec3 mx_uniform_sample_hemisphere(vec2 Xi)
{
float phi = 2.0 * M_PI * Xi.x;
float cosTheta = 1.0 - Xi.y;
float sinTheta = sqrt(1.0 - mx_square(cosTheta));
return vec3(cos(phi) * sinTheta,
sin(phi) * sinTheta,
cosTheta);
}
@@ -0,0 +1,84 @@
#include "mx_microfacet.glsl"
// Based on the OSL implementation of Oren-Nayar diffuse, which is in turn
// based on https://mimosa-pudica.net/improved-oren-nayar.html.
float mx_oren_nayar_diffuse(vec3 L, vec3 V, vec3 N, float NdotL, float roughness)
{
float LdotV = clamp(dot(L, V), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float s = LdotV - NdotL * NdotV;
float stinv = (s > 0.0f) ? s / max(NdotL, NdotV) : 0.0;
float sigma2 = mx_square(roughness * M_PI);
float A = 1.0 - 0.5 * (sigma2 / (sigma2 + 0.33));
float B = 0.45 * sigma2 / (sigma2 + 0.09);
return A + B * stinv;
}
// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf
// Section 5.3
float mx_burley_diffuse(vec3 L, vec3 V, vec3 N, float NdotL, float roughness)
{
vec3 H = normalize(L + V);
float LdotH = clamp(dot(L, H), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float F90 = 0.5 + (2.0 * roughness * mx_square(LdotH));
float refL = mx_fresnel_schlick(NdotL, 1.0, F90);
float refV = mx_fresnel_schlick(NdotV, 1.0, F90);
return refL * refV;
}
// Compute the directional albedo component of Burley diffuse for the given
// view angle and roughness. Curve fit provided by Stephen Hill.
float mx_burley_diffuse_dir_albedo(float NdotV, float roughness)
{
float x = NdotV;
float fit0 = 0.97619 - 0.488095 * mx_pow5(1.0 - x);
float fit1 = 1.55754 + (-2.02221 + (2.56283 - 1.06244 * x) * x) * x;
return mix(fit0, fit1, roughness);
}
// Evaluate the Burley diffusion profile for the given distance and diffusion shape.
// Based on https://graphics.pixar.com/library/ApproxBSSRDF/
vec3 mx_burley_diffusion_profile(float dist, vec3 shape)
{
vec3 num1 = exp(-shape * dist);
vec3 num2 = exp(-shape * dist / 3.0);
float denom = max(dist, M_FLOAT_EPS);
return (num1 + num2) / denom;
}
// Integrate the Burley diffusion profile over a sphere of the given radius.
// Inspired by Eric Penner's presentation in http://advances.realtimerendering.com/s2011/
vec3 mx_integrate_burley_diffusion(vec3 N, vec3 L, float radius, vec3 mfp)
{
float theta = acos(dot(N, L));
// Estimate the Burley diffusion shape from mean free path.
vec3 shape = vec3(1.0) / max(mfp, 0.1);
// Integrate the profile over the sphere.
vec3 sumD = vec3(0.0);
vec3 sumR = vec3(0.0);
const int SAMPLE_COUNT = 32;
const float SAMPLE_WIDTH = (2.0 * M_PI) / float(SAMPLE_COUNT);
for (int i = 0; i < SAMPLE_COUNT; i++)
{
float x = -M_PI + (float(i) + 0.5) * SAMPLE_WIDTH;
float dist = radius * abs(2.0 * sin(x * 0.5));
vec3 R = mx_burley_diffusion_profile(dist, shape);
sumD += R * max(cos(theta + x), 0.0);
sumR += R;
}
return sumD / sumR;
}
vec3 mx_subsurface_scattering_approx(vec3 N, vec3 L, vec3 P, vec3 albedo, vec3 mfp)
{
float curvature = length(fwidth(N)) / length(fwidth(P));
float radius = 1.0 / max(curvature, 0.01);
return albedo * mx_integrate_burley_diffusion(N, L, radius, mfp) / vec3(M_PI);
}
@@ -0,0 +1,92 @@
#include "mx_microfacet.glsl"
// http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
// Equation 2
float mx_imageworks_sheen_NDF(float NdotH, float roughness)
{
float invRoughness = 1.0 / max(roughness, 0.005);
float cos2 = NdotH * NdotH;
float sin2 = 1.0 - cos2;
return (2.0 + invRoughness) * pow(sin2, invRoughness * 0.5) / (2.0 * M_PI);
}
float mx_imageworks_sheen_brdf(float NdotL, float NdotV, float NdotH, float roughness)
{
// Microfacet distribution.
float D = mx_imageworks_sheen_NDF(NdotH, roughness);
// Fresnel and geometry terms are ignored.
float F = 1.0;
float G = 1.0;
// We use a smoother denominator, as in:
// https://blog.selfshadow.com/publications/s2013-shading-course/rad/s2013_pbs_rad_notes.pdf
return D * F * G / (4.0 * (NdotL + NdotV - NdotL*NdotV));
}
// Rational quadratic fit to Monte Carlo data for Imageworks sheen directional albedo.
float mx_imageworks_sheen_dir_albedo_analytic(float NdotV, float roughness)
{
vec2 r = vec2(13.67300, 1.0) +
vec2(-68.78018, 61.57746) * NdotV +
vec2(799.08825, 442.78211) * roughness +
vec2(-905.00061, 2597.49308) * NdotV * roughness +
vec2(60.28956, 121.81241) * mx_square(NdotV) +
vec2(1086.96473, 3045.55075) * mx_square(roughness);
return r.x / r.y;
}
float mx_imageworks_sheen_dir_albedo_table_lookup(float NdotV, float roughness)
{
#if DIRECTIONAL_ALBEDO_METHOD == 1
if (textureSize($albedoTable, 0).x > 1)
{
return texture($albedoTable, vec2(NdotV, roughness)).b;
}
#endif
return 0.0;
}
float mx_imageworks_sheen_dir_albedo_monte_carlo(float NdotV, float roughness)
{
NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0);
vec3 V = vec3(sqrt(1.0f - mx_square(NdotV)), 0, NdotV);
float radiance = 0.0;
const int SAMPLE_COUNT = 64;
for (int i = 0; i < SAMPLE_COUNT; i++)
{
vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT);
// Compute the incoming light direction and half vector.
vec3 L = mx_uniform_sample_hemisphere(Xi);
vec3 H = normalize(L + V);
// Compute dot products for this sample.
float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0);
float NdotH = clamp(H.z, M_FLOAT_EPS, 1.0);
// Compute sheen reflectance.
float reflectance = mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness);
// Add the radiance contribution of this sample.
// uniform_pdf = 1 / (2 * PI)
// radiance = reflectance * NdotL / uniform_pdf;
radiance += reflectance * NdotL * 2.0 * M_PI;
}
// Return the final directional albedo.
return radiance / float(SAMPLE_COUNT);
}
float mx_imageworks_sheen_dir_albedo(float NdotV, float roughness)
{
#if DIRECTIONAL_ALBEDO_METHOD == 0
float dirAlbedo = mx_imageworks_sheen_dir_albedo_analytic(NdotV, roughness);
#elif DIRECTIONAL_ALBEDO_METHOD == 1
float dirAlbedo = mx_imageworks_sheen_dir_albedo_table_lookup(NdotV, roughness);
#else
float dirAlbedo = mx_imageworks_sheen_dir_albedo_monte_carlo(NdotV, roughness);
#endif
return clamp(dirAlbedo, 0.0, 1.0);
}
@@ -0,0 +1,606 @@
#include "mx_microfacet.glsl"
// Fresnel model options.
const int FRESNEL_MODEL_DIELECTRIC = 0;
const int FRESNEL_MODEL_CONDUCTOR = 1;
const int FRESNEL_MODEL_SCHLICK = 2;
const int FRESNEL_MODEL_AIRY = 3;
const int FRESNEL_MODEL_SCHLICK_AIRY = 4;
// XYZ to CIE 1931 RGB color space (using neutral E illuminant)
const mat3 XYZ_TO_RGB = mat3(2.3706743, -0.5138850, 0.0052982, -0.9000405, 1.4253036, -0.0146949, -0.4706338, 0.0885814, 1.0093968);
// Parameters for Fresnel calculations.
struct FresnelData
{
int model;
// Physical Fresnel
vec3 ior;
vec3 extinction;
// Generalized Schlick Fresnel
vec3 F0;
vec3 F90;
float exponent;
// Thin film
float tf_thickness;
float tf_ior;
// Refraction
bool refraction;
#ifdef __METAL__
FresnelData(int _model = 0,
vec3 _ior = vec3(0.0f),
vec3 _extinction = vec3(0.0f),
vec3 _F0 = vec3(0.0f),
vec3 _F90 = vec3(0.0f),
float _exponent = 0.0f,
float _tf_thickness = 0.0f,
float _tf_ior = 0.0f,
bool _refraction = false) :
model(_model),
ior(_ior),
extinction(_extinction),
F0(_F0), F90(_F90), exponent(_exponent),
tf_thickness(_tf_thickness),
tf_ior(_tf_ior),
refraction(_refraction) {}
#endif
};
// https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf
// Appendix B.2 Equation 13
float mx_ggx_NDF(vec3 H, vec2 alpha)
{
vec2 He = H.xy / alpha;
float denom = dot(He, He) + mx_square(H.z);
return 1.0 / (M_PI * alpha.x * alpha.y * mx_square(denom));
}
// https://ggx-research.github.io/publication/2023/06/09/publication-ggx.html
vec3 mx_ggx_importance_sample_VNDF(vec2 Xi, vec3 V, vec2 alpha)
{
// Transform the view direction to the hemisphere configuration.
V = normalize(vec3(V.xy * alpha, V.z));
// Sample a spherical cap in (-V.z, 1].
float phi = 2.0 * M_PI * Xi.x;
float z = (1.0 - Xi.y) * (1.0 + V.z) - V.z;
float sinTheta = sqrt(clamp(1.0 - z * z, 0.0, 1.0));
float x = sinTheta * cos(phi);
float y = sinTheta * sin(phi);
vec3 c = vec3(x, y, z);
// Compute the microfacet normal.
vec3 H = c + V;
// Transform the microfacet normal back to the ellipsoid configuration.
H = normalize(vec3(H.xy * alpha, max(H.z, 0.0)));
return H;
}
// https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
// Equation 34
float mx_ggx_smith_G1(float cosTheta, float alpha)
{
float cosTheta2 = mx_square(cosTheta);
float tanTheta2 = (1.0 - cosTheta2) / cosTheta2;
return 2.0 / (1.0 + sqrt(1.0 + mx_square(alpha) * tanTheta2));
}
// Height-correlated Smith masking-shadowing
// http://jcgt.org/published/0003/02/03/paper.pdf
// Equations 72 and 99
float mx_ggx_smith_G2(float NdotL, float NdotV, float alpha)
{
float alpha2 = mx_square(alpha);
float lambdaL = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotL));
float lambdaV = sqrt(alpha2 + (1.0 - alpha2) * mx_square(NdotV));
return 2.0 / (lambdaL / NdotL + lambdaV / NdotV);
}
// Rational quadratic fit to Monte Carlo data for GGX directional albedo.
vec3 mx_ggx_dir_albedo_analytic(float NdotV, float alpha, vec3 F0, vec3 F90)
{
float x = NdotV;
float y = alpha;
float x2 = mx_square(x);
float y2 = mx_square(y);
vec4 r = vec4(0.1003, 0.9345, 1.0, 1.0) +
vec4(-0.6303, -2.323, -1.765, 0.2281) * x +
vec4(9.748, 2.229, 8.263, 15.94) * y +
vec4(-2.038, -3.748, 11.53, -55.83) * x * y +
vec4(29.34, 1.424, 28.96, 13.08) * x2 +
vec4(-8.245, -0.7684, -7.507, 41.26) * y2 +
vec4(-26.44, 1.436, -36.11, 54.9) * x2 * y +
vec4(19.99, 0.2913, 15.86, 300.2) * x * y2 +
vec4(-5.448, 0.6286, 33.37, -285.1) * x2 * y2;
vec2 AB = clamp(r.xy / r.zw, 0.0, 1.0);
return F0 * AB.x + F90 * AB.y;
}
vec3 mx_ggx_dir_albedo_table_lookup(float NdotV, float alpha, vec3 F0, vec3 F90)
{
#if DIRECTIONAL_ALBEDO_METHOD == 1
if (textureSize($albedoTable, 0).x > 1)
{
vec2 AB = texture($albedoTable, vec2(NdotV, alpha)).rg;
return F0 * AB.x + F90 * AB.y;
}
#endif
return vec3(0.0);
}
// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
vec3 mx_ggx_dir_albedo_monte_carlo(float NdotV, float alpha, vec3 F0, vec3 F90)
{
NdotV = clamp(NdotV, M_FLOAT_EPS, 1.0);
vec3 V = vec3(sqrt(1.0 - mx_square(NdotV)), 0, NdotV);
vec2 AB = vec2(0.0);
const int SAMPLE_COUNT = 64;
for (int i = 0; i < SAMPLE_COUNT; i++)
{
vec2 Xi = mx_spherical_fibonacci(i, SAMPLE_COUNT);
// Compute the half vector and incoming light direction.
vec3 H = mx_ggx_importance_sample_VNDF(Xi, V, vec2(alpha));
vec3 L = -reflect(V, H);
// Compute dot products for this sample.
float NdotL = clamp(L.z, M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);
// Compute the Fresnel term.
float Fc = mx_fresnel_schlick(VdotH, 0.0, 1.0);
// Compute the per-sample geometric term.
// https://hal.inria.fr/hal-00996995v2/document, Algorithm 2
float G2 = mx_ggx_smith_G2(NdotL, NdotV, alpha);
// Add the contribution of this sample.
AB += vec2(G2 * (1.0 - Fc), G2 * Fc);
}
// Apply the global component of the geometric term and normalize.
AB /= mx_ggx_smith_G1(NdotV, alpha) * float(SAMPLE_COUNT);
// Return the final directional albedo.
return F0 * AB.x + F90 * AB.y;
}
vec3 mx_ggx_dir_albedo(float NdotV, float alpha, vec3 F0, vec3 F90)
{
#if DIRECTIONAL_ALBEDO_METHOD == 0
return mx_ggx_dir_albedo_analytic(NdotV, alpha, F0, F90);
#elif DIRECTIONAL_ALBEDO_METHOD == 1
return mx_ggx_dir_albedo_table_lookup(NdotV, alpha, F0, F90);
#else
return mx_ggx_dir_albedo_monte_carlo(NdotV, alpha, F0, F90);
#endif
}
float mx_ggx_dir_albedo(float NdotV, float alpha, float F0, float F90)
{
return mx_ggx_dir_albedo(NdotV, alpha, vec3(F0), vec3(F90)).x;
}
// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf
// Equations 14 and 16
vec3 mx_ggx_energy_compensation(float NdotV, float alpha, vec3 Fss)
{
float Ess = mx_ggx_dir_albedo(NdotV, alpha, 1.0, 1.0);
return 1.0 + Fss * (1.0 - Ess) / Ess;
}
float mx_ggx_energy_compensation(float NdotV, float alpha, float Fss)
{
return mx_ggx_energy_compensation(NdotV, alpha, vec3(Fss)).x;
}
// Compute the average of an anisotropic alpha pair.
float mx_average_alpha(vec2 alpha)
{
return sqrt(alpha.x * alpha.y);
}
// Convert a real-valued index of refraction to normal-incidence reflectivity.
float mx_ior_to_f0(float ior)
{
return mx_square((ior - 1.0) / (ior + 1.0));
}
// Convert normal-incidence reflectivity to real-valued index of refraction.
float mx_f0_to_ior(float F0)
{
float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99));
return (1.0 + sqrtF0) / (1.0 - sqrtF0);
}
vec3 mx_f0_to_ior_colored(vec3 F0)
{
vec3 sqrtF0 = sqrt(clamp(F0, 0.01, 0.99));
return (vec3(1.0) + sqrtF0) / (vec3(1.0) - sqrtF0);
}
// https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/
float mx_fresnel_dielectric(float cosTheta, float ior)
{
if (cosTheta < 0.0)
return 1.0;
float g = ior*ior + cosTheta*cosTheta - 1.0;
// Check for total internal reflection
if (g < 0.0)
return 1.0;
g = sqrt(g);
float gmc = g - cosTheta;
float gpc = g + cosTheta;
float x = gmc / gpc;
float y = (gpc * cosTheta - 1.0) / (gmc * cosTheta + 1.0);
return 0.5 * x * x * (1.0 + y * y);
}
void mx_fresnel_dielectric_polarized(float cosTheta, float n, out float Rp, out float Rs)
{
if (cosTheta < 0.0) {
Rp = 1.0;
Rs = 1.0;
return;
}
float cosTheta2 = cosTheta * cosTheta;
float sinTheta2 = 1.0 - cosTheta2;
float n2 = n * n;
float t0 = n2 - sinTheta2;
float a2plusb2 = sqrt(t0 * t0);
float t1 = a2plusb2 + cosTheta2;
float a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0));
float t2 = 2.0 * a * cosTheta;
Rs = (t1 - t2) / (t1 + t2);
float t3 = cosTheta2 * a2plusb2 + sinTheta2 * sinTheta2;
float t4 = t2 * sinTheta2;
Rp = Rs * (t3 - t4) / (t3 + t4);
}
void mx_fresnel_dielectric_polarized(float cosTheta, float eta1, float eta2, out float Rp, out float Rs)
{
float n = eta2 / eta1;
mx_fresnel_dielectric_polarized(cosTheta, n, Rp, Rs);
}
void mx_fresnel_conductor_polarized(float cosTheta, vec3 n, vec3 k, out vec3 Rp, out vec3 Rs)
{
cosTheta = clamp(cosTheta, 0.0, 1.0);
float cosTheta2 = cosTheta * cosTheta;
float sinTheta2 = 1.0 - cosTheta2;
vec3 n2 = n * n;
vec3 k2 = k * k;
vec3 t0 = n2 - k2 - vec3(sinTheta2);
vec3 a2plusb2 = sqrt(t0 * t0 + 4.0 * n2 * k2);
vec3 t1 = a2plusb2 + vec3(cosTheta2);
vec3 a = sqrt(max(0.5 * (a2plusb2 + t0), 0.0));
vec3 t2 = 2.0 * a * cosTheta;
Rs = (t1 - t2) / (t1 + t2);
vec3 t3 = cosTheta2 * a2plusb2 + vec3(sinTheta2 * sinTheta2);
vec3 t4 = t2 * sinTheta2;
Rp = Rs * (t3 - t4) / (t3 + t4);
}
void mx_fresnel_conductor_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 Rp, out vec3 Rs)
{
vec3 n = eta2 / eta1;
vec3 k = kappa2 / eta1;
mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs);
}
vec3 mx_fresnel_conductor(float cosTheta, vec3 n, vec3 k)
{
vec3 Rp, Rs;
mx_fresnel_conductor_polarized(cosTheta, n, k, Rp, Rs);
return 0.5 * (Rp + Rs);
}
// Phase shift due to a dielectric material
void mx_fresnel_dielectric_phase_polarized(float cosTheta, float eta1, float eta2, out float phiP, out float phiS)
{
float cosB = cos(atan(eta2 / eta1)); // Brewster's angle
if (eta2 > eta1) {
phiP = cosTheta < cosB ? M_PI : 0.0f;
phiS = 0.0f;
} else {
phiP = cosTheta < cosB ? 0.0f : M_PI;
phiS = M_PI;
}
}
// Phase shift due to a conducting material
void mx_fresnel_conductor_phase_polarized(float cosTheta, float eta1, vec3 eta2, vec3 kappa2, out vec3 phiP, out vec3 phiS)
{
if (dot(kappa2, kappa2) == 0.0 && eta2.x == eta2.y && eta2.y == eta2.z) {
// Use dielectric formula to increase performance
float phiPx, phiSx;
mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2.x, phiPx, phiSx);
phiP = vec3(phiPx, phiPx, phiPx);
phiS = vec3(phiSx, phiSx, phiSx);
return;
}
vec3 k2 = kappa2 / eta2;
vec3 sinThetaSqr = vec3(1.0) - cosTheta * cosTheta;
vec3 A = eta2*eta2*(vec3(1.0)-k2*k2) - eta1*eta1*sinThetaSqr;
vec3 B = sqrt(A*A + mx_square(2.0*eta2*eta2*k2));
vec3 U = sqrt((A+B)/2.0);
vec3 V = max(vec3(0.0), sqrt((B-A)/2.0));
phiS = atan(2.0*eta1*V*cosTheta, U*U + V*V - mx_square(eta1*cosTheta));
phiP = atan(2.0*eta1*eta2*eta2*cosTheta * (2.0*k2*U - (vec3(1.0)-k2*k2) * V),
mx_square(eta2*eta2*(vec3(1.0)+k2*k2)*cosTheta) - eta1*eta1*(U*U+V*V));
}
// Evaluation XYZ sensitivity curves in Fourier space
vec3 mx_eval_sensitivity(float opd, vec3 shift)
{
// Use Gaussian fits, given by 3 parameters: val, pos and var
float phase = 2.0*M_PI * opd;
vec3 val = vec3(5.4856e-13, 4.4201e-13, 5.2481e-13);
vec3 pos = vec3(1.6810e+06, 1.7953e+06, 2.2084e+06);
vec3 var = vec3(4.3278e+09, 9.3046e+09, 6.6121e+09);
vec3 xyz = val * sqrt(2.0*M_PI * var) * cos(pos * phase + shift) * exp(- var * phase*phase);
xyz.x += 9.7470e-14 * sqrt(2.0*M_PI * 4.5282e+09) * cos(2.2399e+06 * phase + shift[0]) * exp(- 4.5282e+09 * phase*phase);
return xyz / 1.0685e-7;
}
// A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence
// https://belcour.github.io/blog/research/publication/2017/05/01/brdf-thin-film.html
vec3 mx_fresnel_airy(float cosTheta, vec3 ior, vec3 extinction, float tf_thickness, float tf_ior,
vec3 f0, vec3 f90, float exponent, bool use_schlick)
{
// Convert nm -> m
float d = tf_thickness * 1.0e-9;
// Assume vacuum on the outside
float eta1 = 1.0;
float eta2 = max(tf_ior, eta1);
vec3 eta3 = use_schlick ? mx_f0_to_ior_colored(f0) : ior;
vec3 kappa3 = use_schlick ? vec3(0.0) : extinction;
// Compute the Spectral versions of the Fresnel reflectance and
// transmitance for each interface.
float R12p, T121p, R12s, T121s;
vec3 R23p, R23s;
// Reflected and transmitted parts in the thin film
mx_fresnel_dielectric_polarized(cosTheta, eta1, eta2, R12p, R12s);
// Reflected part by the base
float scale = eta1 / eta2;
float cosThetaTSqr = 1.0 - (1.0-cosTheta*cosTheta) * scale*scale;
float cosTheta2 = sqrt(cosThetaTSqr);
if (use_schlick)
{
vec3 f = mx_fresnel_schlick(cosTheta2, f0, f90, exponent);
R23p = 0.5 * f;
R23s = 0.5 * f;
}
else
{
mx_fresnel_conductor_polarized(cosTheta2, eta2, eta3, kappa3, R23p, R23s);
}
// Check for total internal reflection
if (cosThetaTSqr <= 0.0f)
{
R12s = 1.0;
R12p = 1.0;
}
// Compute the transmission coefficients
T121p = 1.0 - R12p;
T121s = 1.0 - R12s;
// Optical path difference
float D = 2.0 * eta2 * d * cosTheta2;
float phi21p, phi21s;
vec3 phi23p, phi23s, r123s, r123p;
// Evaluate the phase shift
mx_fresnel_dielectric_phase_polarized(cosTheta, eta1, eta2, phi21p, phi21s);
if (use_schlick)
{
phi23p = vec3(
(eta3[0] < eta2) ? M_PI : 0.0,
(eta3[1] < eta2) ? M_PI : 0.0,
(eta3[2] < eta2) ? M_PI : 0.0);
phi23s = phi23p;
}
else
{
mx_fresnel_conductor_phase_polarized(cosTheta2, eta2, eta3, kappa3, phi23p, phi23s);
}
phi21p = M_PI - phi21p;
phi21s = M_PI - phi21s;
r123p = max(vec3(0.0), sqrt(R12p*R23p));
r123s = max(vec3(0.0), sqrt(R12s*R23s));
// Evaluate iridescence term
vec3 I = vec3(0.0);
vec3 C0, Cm, Sm;
// Iridescence term using spectral antialiasing for Parallel polarization
vec3 S0 = vec3(1.0);
// Reflectance term for m=0 (DC term amplitude)
vec3 Rs = (T121p*T121p*R23p) / (vec3(1.0) - R12p*R23p);
C0 = R12p + Rs;
I += C0 * S0;
// Reflectance term for m>0 (pairs of diracs)
Cm = Rs - T121p;
for (int m=1; m<=2; ++m)
{
Cm *= r123p;
Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23p+vec3(phi21p)));
I += Cm*Sm;
}
// Iridescence term using spectral antialiasing for Perpendicular polarization
// Reflectance term for m=0 (DC term amplitude)
vec3 Rp = (T121s*T121s*R23s) / (vec3(1.0) - R12s*R23s);
C0 = R12s + Rp;
I += C0 * S0;
// Reflectance term for m>0 (pairs of diracs)
Cm = Rp - T121s ;
for (int m=1; m<=2; ++m)
{
Cm *= r123s;
Sm = 2.0 * mx_eval_sensitivity(float(m)*D, float(m)*(phi23s+vec3(phi21s)));
I += Cm*Sm;
}
// Average parallel and perpendicular polarization
I *= 0.5;
// Convert back to RGB reflectance
I = clamp(XYZ_TO_RGB * I, vec3(0.0), vec3(1.0));
return I;
}
FresnelData mx_init_fresnel_data(int model)
{
return FresnelData(model, vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0), 0.0, 0.0, 0.0, false);
}
FresnelData mx_init_fresnel_dielectric(float ior)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_DIELECTRIC);
fd.ior = vec3(ior);
return fd;
}
FresnelData mx_init_fresnel_conductor(vec3 ior, vec3 extinction)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_CONDUCTOR);
fd.ior = ior;
fd.extinction = extinction;
return fd;
}
FresnelData mx_init_fresnel_schlick(vec3 F0)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK);
fd.F0 = F0;
fd.F90 = vec3(1.0);
fd.exponent = 5.0f;
return fd;
}
FresnelData mx_init_fresnel_schlick(vec3 F0, vec3 F90, float exponent)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK);
fd.F0 = F0;
fd.F90 = F90;
fd.exponent = exponent;
return fd;
}
FresnelData mx_init_fresnel_schlick_airy(vec3 F0, vec3 F90, float exponent, float tf_thickness, float tf_ior)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_SCHLICK_AIRY);
fd.F0 = F0;
fd.F90 = F90;
fd.exponent = exponent;
fd.tf_thickness = tf_thickness;
fd.tf_ior = tf_ior;
return fd;
}
FresnelData mx_init_fresnel_dielectric_airy(float ior, float tf_thickness, float tf_ior)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_AIRY);
fd.ior = vec3(ior);
fd.tf_thickness = tf_thickness;
fd.tf_ior = tf_ior;
return fd;
}
FresnelData mx_init_fresnel_conductor_airy(vec3 ior, vec3 extinction, float tf_thickness, float tf_ior)
{
FresnelData fd = mx_init_fresnel_data(FRESNEL_MODEL_AIRY);
fd.ior = ior;
fd.extinction = extinction;
fd.tf_thickness = tf_thickness;
fd.tf_ior = tf_ior;
return fd;
}
vec3 mx_compute_fresnel(float cosTheta, FresnelData fd)
{
if (fd.model == FRESNEL_MODEL_DIELECTRIC)
{
return vec3(mx_fresnel_dielectric(cosTheta, fd.ior.x));
}
else if (fd.model == FRESNEL_MODEL_CONDUCTOR)
{
return mx_fresnel_conductor(cosTheta, fd.ior, fd.extinction);
}
else if (fd.model == FRESNEL_MODEL_SCHLICK)
{
return mx_fresnel_schlick(cosTheta, fd.F0, fd.F90, fd.exponent);
}
else
{
return mx_fresnel_airy(cosTheta, fd.ior, fd.extinction, fd.tf_thickness, fd.tf_ior,
fd.F0, fd.F90, fd.exponent,
fd.model == FRESNEL_MODEL_SCHLICK_AIRY);
}
}
// Compute the refraction of a ray through a solid sphere.
vec3 mx_refraction_solid_sphere(vec3 R, vec3 N, float ior)
{
R = refract(R, N, 1.0 / ior);
vec3 N1 = normalize(R * dot(R, N) - N * 0.5);
return refract(R, N1, ior);
}
vec2 mx_latlong_projection(vec3 dir)
{
float latitude = -asin(dir.y) * M_PI_INV + 0.5;
float longitude = atan(dir.x, -dir.z) * M_PI_INV * 0.5 + 0.5;
return vec2(longitude, latitude);
}
vec3 mx_latlong_map_lookup(vec3 dir, mat4 transform, float lod, sampler2D envSampler)
{
vec3 envDir = normalize((transform * vec4(dir,0.0)).xyz);
vec2 uv = mx_latlong_projection(envDir);
return textureLod(envSampler, uv, lod).rgb;
}
// Return the mip level with the appropriate coverage for a filtered importance sample.
// https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html
// Section 20.4 Equation 13
float mx_latlong_compute_lod(vec3 dir, float pdf, float maxMipLevel, int envSamples)
{
const float MIP_LEVEL_OFFSET = 1.5;
float effectiveMaxMipLevel = maxMipLevel - MIP_LEVEL_OFFSET;
float distortion = sqrt(1.0 - mx_square(dir.y));
return max(effectiveMaxMipLevel - 0.5 * log2(float(envSamples) * pdf * distortion), 0.0);
}
@@ -0,0 +1,23 @@
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-8-summed-area-variance-shadow-maps
float mx_variance_shadow_occlusion(vec2 moments, float fragmentDepth)
{
const float MIN_VARIANCE = 0.00001;
// One-tailed inequality valid if fragmentDepth > moments.x.
float p = (fragmentDepth <= moments.x) ? 1.0 : 0.0;
// Compute variance.
float variance = moments.y - mx_square(moments.x);
variance = max(variance, MIN_VARIANCE);
// Compute probabilistic upper bound.
float d = fragmentDepth - moments.x;
float pMax = variance / (variance + mx_square(d));
return max(p, pMax);
}
vec2 mx_compute_depth_moments()
{
float depth = gl_FragCoord.z;
return vec2(depth, mx_square(depth));
}
@@ -0,0 +1,6 @@
#include "mx_microfacet_specular.glsl"
vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint)
{
return tint;
}
@@ -0,0 +1,14 @@
#include "mx_microfacet_specular.glsl"
vec3 mx_surface_transmission(vec3 N, vec3 V, vec3 X, vec2 alpha, int distribution, FresnelData fd, vec3 tint)
{
// Approximate the appearance of surface transmission as glossy
// environment map refraction, ignoring any scene geometry that might
// be visible through the surface.
fd.refraction = true;
if ($refractionTwoSided)
{
tint = mx_square(tint);
}
return mx_environment_radiance(N, V, X, alpha, distribution, fd) * tint;
}
@@ -0,0 +1,4 @@
void mx_add_edf(vec3 N, vec3 L, EDF in1, EDF in2, out EDF result)
{
result = in1 + in2;
}
@@ -0,0 +1,4 @@
void mx_anisotropic_vdf(vec3 absorption, vec3 scattering, float anisotropy, inout BSDF bsdf)
{
// TODO: Add some approximation for volumetric light absorption.
}
@@ -0,0 +1,17 @@
void mx_artistic_ior(vec3 reflectivity, vec3 edge_color, out vec3 ior, out vec3 extinction)
{
// "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
// http://jcgt.org/published/0003/04/03/paper.pdf
vec3 r = clamp(reflectivity, 0.0, 0.99);
vec3 r_sqrt = sqrt(r);
vec3 n_min = (1.0 - r) / (1.0 + r);
vec3 n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt);
ior = mix(n_max, n_min, edge_color);
vec3 np1 = ior + 1.0;
vec3 nm1 = ior - 1.0;
vec3 k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r);
k2 = max(k2, 0.0);
extinction = sqrt(k2);
}
@@ -0,0 +1,48 @@
/// XYZ to Rec.709 RGB colorspace conversion
const mat3 XYZ_to_RGB = mat3( 3.2406, -0.9689, 0.0557,
-1.5372, 1.8758, -0.2040,
-0.4986, 0.0415, 1.0570);
void mx_blackbody(float temperatureKelvin, out vec3 colorValue)
{
float xc, yc;
float t, t2, t3, xc2, xc3;
// if value outside valid range of approximation clamp to accepted temperature range
temperatureKelvin = clamp(temperatureKelvin, 1667.0, 25000.0);
t = 1000.0 / temperatureKelvin;
t2 = t * t;
t3 = t * t * t;
// Cubic spline approximation for Kelvin temperature to sRGB conversion
// (https://en.wikipedia.org/wiki/Planckian_locus#Approximation)
if (temperatureKelvin < 4000.0) { // 1667K <= temperatureKelvin < 4000K
xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910;
}
else { // 4000K <= temperatureKelvin <= 25000K
xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390;
}
xc2 = xc * xc;
xc3 = xc * xc * xc;
if (temperatureKelvin < 2222.0) { // 1667K <= temperatureKelvin < 2222K
yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683;
}
else if (temperatureKelvin < 4000.0) { // 2222K <= temperatureKelvin < 4000K
yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867;
}
else { // 4000K <= temperatureKelvin <= 25000K
yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483;
}
if (yc <= 0.0) { // avoid division by zero
colorValue = vec3(1.0);
return;
}
vec3 XYZ = vec3(xc / yc, 1.0, (1.0 - xc - yc) / yc);
colorValue = XYZ_to_RGB * XYZ;
colorValue = max(colorValue, vec3(0.0));
}
@@ -0,0 +1,36 @@
#include "lib/mx_microfacet_diffuse.glsl"
void mx_burley_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0);
bsdf.response = color * occlusion * weight * NdotL * M_PI_INV;
bsdf.response *= mx_burley_diffuse(L, V, normal, NdotL, roughness);
}
void mx_burley_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
float NdotV = clamp(dot(normal, V), M_FLOAT_EPS, 1.0);
vec3 Li = mx_environment_irradiance(normal) *
mx_burley_diffuse_dir_albedo(NdotV, roughness);
bsdf.response = Li * color * weight;
}
@@ -0,0 +1,70 @@
#include "lib/mx_microfacet_specular.glsl"
void mx_conductor_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, vec3 N, vec3 X, int distribution, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);
vec3 H = normalize(L + V);
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N));
FresnelData fd;
if (bsdf.thickness > 0.0)
fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, bsdf.thickness, bsdf.ior);
else
fd = mx_init_fresnel_conductor(ior_n, ior_k);
vec3 F = mx_compute_fresnel(VdotH, fd);
float D = mx_ggx_NDF(Ht, safeAlpha);
float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
// Note: NdotL is cancelled out
bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV);
}
void mx_conductor_bsdf_indirect(vec3 V, float weight, vec3 ior_n, vec3 ior_k, vec2 roughness, vec3 N, vec3 X, int distribution, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd;
if (bsdf.thickness > 0.0)
fd = mx_init_fresnel_conductor_airy(ior_n, ior_k, bsdf.thickness, bsdf.ior);
else
fd = mx_init_fresnel_conductor(ior_n, ior_k);
vec3 F = mx_compute_fresnel(NdotV, fd);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd);
bsdf.response = Li * comp * weight;
}
@@ -0,0 +1,116 @@
#include "lib/mx_microfacet_specular.glsl"
void mx_dielectric_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);
vec3 H = normalize(L + V);
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N));
FresnelData fd;
vec3 safeTint = max(tint, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_dielectric(ior);
}
vec3 F = mx_compute_fresnel(VdotH, fd);
float D = mx_ggx_NDF(Ht, safeAlpha);
float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha);
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;
bsdf.throughput = 1.0 - dirAlbedo * weight;
// Note: NdotL is cancelled out
bsdf.response = D * F * G * comp * safeTint * occlusion * weight / (4.0 * NdotV);
}
void mx_dielectric_bsdf_transmission(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd;
vec3 safeTint = max(tint, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_dielectric(ior);
}
vec3 F = mx_compute_fresnel(NdotV, fd);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
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;
bsdf.throughput = 1.0 - dirAlbedo * weight;
if (scatter_mode != 0)
{
bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeTint) * weight;
}
}
void mx_dielectric_bsdf_indirect(vec3 V, float weight, vec3 tint, float ior, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd;
vec3 safeTint = max(tint, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_dielectric_airy(ior, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_dielectric(ior);
}
vec3 F = mx_compute_fresnel(NdotV, fd);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
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;
bsdf.throughput = 1.0 - dirAlbedo * weight;
vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd);
bsdf.response = Li * safeTint * comp * weight;
}
@@ -0,0 +1,5 @@
void mx_displacement_float(float disp, float scale, out displacementshader result)
{
result.offset = vec3(disp);
result.scale = scale;
}
@@ -0,0 +1,5 @@
void mx_displacement_vector3(vec3 disp, float scale, out displacementshader result)
{
result.offset = disp;
result.scale = scale;
}
@@ -0,0 +1,119 @@
#include "lib/mx_microfacet_specular.glsl"
void mx_generalized_schlick_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);
vec3 H = normalize(L + V);
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float VdotH = clamp(dot(V, H), M_FLOAT_EPS, 1.0);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 Ht = vec3(dot(H, X), dot(H, Y), dot(H, N));
FresnelData fd;
vec3 safeColor0 = max(color0, 0.0);
vec3 safeColor90 = max(color90, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent);
}
vec3 F = mx_compute_fresnel(VdotH, fd);
float D = mx_ggx_NDF(Ht, safeAlpha);
float G = mx_ggx_smith_G2(NdotL, NdotV, avgAlpha);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp;
float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0));
bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight);
// Note: NdotL is cancelled out
bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV);
}
void mx_generalized_schlick_bsdf_transmission(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd;
vec3 safeColor0 = max(color0, 0.0);
vec3 safeColor90 = max(color90, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent);
}
vec3 F = mx_compute_fresnel(NdotV, fd);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp;
float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0));
bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight);
if (scatter_mode != 0)
{
float avgF0 = dot(safeColor0, vec3(1.0 / 3.0));
fd.ior = vec3(mx_f0_to_ior(avgF0));
bsdf.response = mx_surface_transmission(N, V, X, safeAlpha, distribution, fd, safeColor0) * weight;
}
}
void mx_generalized_schlick_bsdf_indirect(vec3 V, float weight, vec3 color0, vec3 color90, float exponent, vec2 roughness, vec3 N, vec3 X, int distribution, int scatter_mode, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd;
vec3 safeColor0 = max(color0, 0.0);
vec3 safeColor90 = max(color90, 0.0);
if (bsdf.thickness > 0.0)
{
fd = mx_init_fresnel_schlick_airy(safeColor0, safeColor90, exponent, bsdf.thickness, bsdf.ior);
}
else
{
fd = mx_init_fresnel_schlick(safeColor0, safeColor90, exponent);
}
vec3 F = mx_compute_fresnel(NdotV, fd);
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, safeColor0, safeColor90) * comp;
float avgDirAlbedo = dot(dirAlbedo, vec3(1.0 / 3.0));
bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight);
vec3 Li = mx_environment_radiance(N, V, X, safeAlpha, distribution, fd);
bsdf.response = Li * comp * weight;
}
@@ -0,0 +1,9 @@
#include "lib/mx_microfacet.glsl"
void mx_generalized_schlick_edf(vec3 N, vec3 V, vec3 color0, vec3 color90, float exponent, EDF base, out EDF result)
{
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
vec3 f = mx_fresnel_schlick(NdotV, color0, color90, exponent);
result = base * f;
}
@@ -0,0 +1,36 @@
#include "lib/mx_microfacet_diffuse.glsl"
void mx_oren_nayar_diffuse_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0);
bsdf.response = color * occlusion * weight * NdotL * M_PI_INV;
if (roughness > 0.0)
{
bsdf.response *= mx_oren_nayar_diffuse(L, V, normal, NdotL, roughness);
}
}
void mx_oren_nayar_diffuse_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
vec3 Li = mx_environment_irradiance(normal);
bsdf.response = Li * color * weight;
}
@@ -0,0 +1,15 @@
void mx_roughness_anisotropy(float roughness, float anisotropy, out vec2 result)
{
float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0);
if (anisotropy > 0.0)
{
float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98));
result.x = min(roughness_sqr / aspect, 1.0);
result.y = roughness_sqr * aspect;
}
else
{
result.x = roughness_sqr;
result.y = roughness_sqr;
}
}
@@ -0,0 +1,9 @@
void mx_roughness_dual(vec2 roughness, out vec2 result)
{
if (roughness.y < 0.0)
{
roughness.y = roughness.x;
}
result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0);
result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0);
}
@@ -0,0 +1,43 @@
#include "lib/mx_microfacet_sheen.glsl"
void mx_sheen_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, float roughness, vec3 N, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
vec3 H = normalize(L + V);
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float NdotH = clamp(dot(N, H), M_FLOAT_EPS, 1.0);
vec3 fr = color * mx_imageworks_sheen_brdf(NdotL, NdotV, NdotH, roughness);
float dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness);
bsdf.throughput = vec3(1.0 - dirAlbedo * weight);
// We need to include NdotL from the light integral here
// as in this case it's not cancelled out by the BRDF denominator.
bsdf.response = fr * NdotL * occlusion * weight;
}
void mx_sheen_bsdf_indirect(vec3 V, float weight, vec3 color, float roughness, vec3 N, inout BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
return;
}
N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
float dirAlbedo = mx_imageworks_sheen_dir_albedo(NdotV, roughness);
bsdf.throughput = vec3(1.0 - dirAlbedo * weight);
vec3 Li = mx_environment_irradiance(N);
bsdf.response = Li * color * dirAlbedo * weight;
}
@@ -0,0 +1,34 @@
#include "lib/mx_microfacet_diffuse.glsl"
void mx_subsurface_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, vec3 radius, float anisotropy, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
vec3 sss = mx_subsurface_scattering_approx(normal, L, P, color, radius);
float NdotL = clamp(dot(normal, L), M_FLOAT_EPS, 1.0);
float visibleOcclusion = 1.0 - NdotL * (1.0 - occlusion);
bsdf.response = sss * visibleOcclusion * weight;
}
void mx_subsurface_bsdf_indirect(vec3 V, float weight, vec3 color, vec3 radius, float anisotropy, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
normal = mx_forward_facing_normal(normal, V);
// For now, we render indirect subsurface as simple indirect diffuse.
vec3 Li = mx_environment_irradiance(normal);
bsdf.response = Li * color * weight;
}
@@ -0,0 +1,29 @@
// We fake diffuse transmission by using diffuse reflection from the opposite side.
// So this BTDF is really a BRDF.
void mx_translucent_bsdf_reflection(vec3 L, vec3 V, vec3 P, float occlusion, float weight, vec3 color, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
// Invert normal since we're transmitting light from the other side
float NdotL = dot(L, -normal);
if (NdotL <= 0.0 || weight < M_FLOAT_EPS)
{
return;
}
bsdf.response = color * weight * NdotL * M_PI_INV;
}
void mx_translucent_bsdf_indirect(vec3 V, float weight, vec3 color, vec3 normal, inout BSDF bsdf)
{
bsdf.throughput = vec3(0.0);
if (weight < M_FLOAT_EPS)
{
return;
}
// Invert normal since we're transmitting light from the other side
vec3 Li = mx_environment_irradiance(-normal);
bsdf.response = Li * color * weight;
}
@@ -0,0 +1,4 @@
void mx_uniform_edf(vec3 N, vec3 L, vec3 color, out EDF result)
{
result = color;
}
@@ -0,0 +1,80 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genglsl" nodedef="ND_oren_nayar_diffuse_bsdf" file="mx_oren_nayar_diffuse_bsdf.glsl" function="mx_oren_nayar_diffuse_bsdf" target="genglsl" />
<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genglsl" nodedef="ND_burley_diffuse_bsdf" file="mx_burley_diffuse_bsdf.glsl" function="mx_burley_diffuse_bsdf" target="genglsl" />
<!-- <translucent_bsdf> -->
<implementation name="IM_translucent_bsdf_genglsl" nodedef="ND_translucent_bsdf" file="mx_translucent_bsdf.glsl" function="mx_translucent_bsdf" target="genglsl" />
<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genglsl" nodedef="ND_dielectric_bsdf" file="mx_dielectric_bsdf.glsl" function="mx_dielectric_bsdf" target="genglsl" />
<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genglsl" nodedef="ND_conductor_bsdf" file="mx_conductor_bsdf.glsl" function="mx_conductor_bsdf" target="genglsl" />
<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genglsl" nodedef="ND_generalized_schlick_bsdf" file="mx_generalized_schlick_bsdf.glsl" function="mx_generalized_schlick_bsdf" target="genglsl" />
<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genglsl" nodedef="ND_subsurface_bsdf" file="mx_subsurface_bsdf.glsl" function="mx_subsurface_bsdf" target="genglsl" />
<!-- <sheen_bsdf> -->
<implementation name="IM_sheen_bsdf_genglsl" nodedef="ND_sheen_bsdf" file="mx_sheen_bsdf.glsl" function="mx_sheen_bsdf" target="genglsl" />
<!-- <anisotropic_vdf> -->
<implementation name="IM_anisotropic_vdf_genglsl" nodedef="ND_anisotropic_vdf" file="mx_anisotropic_vdf.glsl" function="mx_anisotropic_vdf" target="genglsl" />
<!-- <thin_film_bsdf> -->
<implementation name="IM_thin_film_bsdf_genglsl" nodedef="ND_thin_film_bsdf" target="genglsl" />
<!-- <layer> -->
<implementation name="IM_layer_bsdf_genglsl" nodedef="ND_layer_bsdf" target="genglsl" />
<implementation name="IM_layer_vdf_genglsl" nodedef="ND_layer_vdf" target="genglsl" />
<!-- <mix> -->
<implementation name="IM_mix_bsdf_genglsl" nodedef="ND_mix_bsdf" target="genglsl" />
<implementation name="IM_mix_edf_genglsl" nodedef="ND_mix_edf" target="genglsl" />
<!-- <add> -->
<implementation name="IM_add_bsdf_genglsl" nodedef="ND_add_bsdf" target="genglsl" />
<implementation name="IM_add_edf_genglsl" nodedef="ND_add_edf" target="genglsl" />
<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genglsl" nodedef="ND_multiply_bsdfC" target="genglsl" />
<implementation name="IM_multiply_bsdfF_genglsl" nodedef="ND_multiply_bsdfF" target="genglsl" />
<implementation name="IM_multiply_edfC_genglsl" nodedef="ND_multiply_edfC" target="genglsl" />
<implementation name="IM_multiply_edfF_genglsl" nodedef="ND_multiply_edfF" target="genglsl" />
<!-- <uniform_edf> -->
<implementation name="IM_uniform_edf_genglsl" nodedef="ND_uniform_edf" file="mx_uniform_edf.glsl" function="mx_uniform_edf" target="genglsl" />
<!-- <generalized_schlick_edf> -->
<implementation name="IM_generalized_schlick_edf_genglsl" nodedef="ND_generalized_schlick_edf" file="mx_generalized_schlick_edf.glsl" function="mx_generalized_schlick_edf" target="genglsl" />
<!-- <surface> -->
<implementation name="IM_surface_genglsl" nodedef="ND_surface" target="genglsl" />
<!-- <displacement> -->
<implementation name="IM_displacement_float_genglsl" nodedef="ND_displacement_float" file="mx_displacement_float.glsl" function="mx_displacement_float" target="genglsl" />
<implementation name="IM_displacement_vector3_genglsl" nodedef="ND_displacement_vector3" file="mx_displacement_vector3.glsl" function="mx_displacement_vector3" target="genglsl" />
<!-- <light> -->
<implementation name="IM_light_genglsl" nodedef="ND_light" target="genglsl" />
<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genglsl" nodedef="ND_roughness_anisotropy" file="mx_roughness_anisotropy.glsl" function="mx_roughness_anisotropy" target="genglsl" />
<!-- <roughness_dual> -->
<implementation name="IM_roughness_dual_genglsl" nodedef="ND_roughness_dual" file="mx_roughness_dual.glsl" function="mx_roughness_dual" target="genglsl" />
<!-- <artistic_ior> -->
<implementation name="IM_artistic_ior_genglsl" nodedef="ND_artistic_ior" file="mx_artistic_ior.glsl" function="mx_artistic_ior" target="genglsl" />
<!-- <blackbody> -->
<implementation name="IM_blackbody_genglsl" nodedef="ND_blackbody" file="mx_blackbody.glsl" function="mx_blackbody" target="genglsl" />
</materialx>
@@ -0,0 +1,99 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genmdl" nodedef="ND_oren_nayar_diffuse_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_oren_nayar_diffuse_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}})" target="genmdl" />
<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genmdl" nodedef="ND_burley_diffuse_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_burley_diffuse_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}})" target="genmdl" />
<!-- <translucent_bsdf> -->
<implementation name="IM_translucent_bsdf_genmdl" nodedef="ND_translucent_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_translucent_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_normal:{{normal}})" target="genmdl" />
<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genmdl" nodedef="ND_dielectric_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_dielectric_bsdf(mxp_weight:{{weight}}, mxp_tint:{{tint}}, mxp_ior:{{ior}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}})" target="genmdl" />
<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genmdl" nodedef="ND_conductor_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_conductor_bsdf(mxp_weight:{{weight}}, mxp_ior:{{ior}}, mxp_extinction:{{extinction}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}})" target="genmdl" />
<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genmdl" nodedef="ND_generalized_schlick_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_bsdf(mxp_weight:{{weight}}, mxp_color0:{{color0}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}},mxp_roughness:{{roughness}}, mxp_normal:{{normal}}, mxp_tangent:{{tangent}}, mxp_distribution:{{distribution}}, mxp_scatter_mode:{{scatter_mode}}, mxp_base:{{base}}, mxp_thinfilm_thickness:{{thinfilm_thickness}}, mxp_thinfilm_ior:{{thinfilm_ior}})" target="genmdl" />
<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genmdl" nodedef="ND_subsurface_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_subsurface_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_radius:{{radius}}, mxp_anisotropy:{{anisotropy}}, mxp_normal:{{normal}})" target="genmdl" />
<!-- <sheen_bsdf> -->
<implementation name="IM_sheen_bsdf_genmdl" nodedef="ND_sheen_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_sheen_bsdf(mxp_weight:{{weight}}, mxp_color:{{color}}, mxp_roughness:{{roughness}}, mxp_normal:{{normal}}, mxp_base:{{base}})" target="genmdl" />
<!-- <thin_film_bsdf> -->
<implementation name="IM_thin_film_bsdf_genmdl" nodedef="ND_thin_film_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_thin_film_bsdf(mxp_thickness:{{thickness}}, mxp_ior:{{ior}}, mxp_base:{{base}})" target="genmdl" />
<!-- <uniform_edf> -->
<implementation name="IM_uniform_edf_genmdl" nodedef="ND_uniform_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_uniform_edf(mxp_color:{{color}})" target="genmdl" />
<!-- <conical_edf> -->
<implementation name="IM_conical_edf_genmdl" nodedef="ND_conical_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_conical_edf(mxp_color:{{color}}, mxp_normal:{{normal}}, mxp_inner_angle:{{inner_angle}}, mxp_outer_angle:{{outer_angle}})" target="genmdl" />
<!-- <measured_edf> -->
<implementation name="IM_measured_edf_genmdl" nodedef="ND_measured_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_measured_edf(mxp_color:{{color}}, mxp_normal:{{normal}}, mxp_file:{{file}}" target="genmdl" />
<!-- <generalized_schlick_edf> -->
<implementation name="IM_generalized_schlick_edf_genmdl" nodedef="ND_generalized_schlick_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_generalized_schlick_edf(mxp_color0:{{color0}}, mxp_color90:{{color90}}, mxp_exponent:{{exponent}}, mxp_base:{{base}})" target="genmdl" />
<!-- <absorption_vdf> -->
<implementation name="IM_absorption_vdf_genmdl" nodedef="ND_absorption_vdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_absorption_vdf(mxp_absorption:{{absorption}})" target="genmdl" />
<!-- <anisotropic_vdf> -->
<implementation name="IM_anisotropic_vdf_genmdl" nodedef="ND_anisotropic_vdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_anisotropic_vdf(mxp_absorption:{{absorption}}, mxp_scattering:{{scattering}}, mxp_anisotropy:{{anisotropy}})" target="genmdl" />
<!-- <surface> -->
<implementation name="IM_surface_genmdl" nodedef="ND_surface" target="genmdl" />
<!-- <thin_surface> -->
<implementation name="IM_thin_surface_genmdl" nodedef="ND_thin_surface" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_thin_surface(mxp_front_bsdf:{{front_bsdf}}, mxp_front_edf:{{front_edf}}, mxp_back_bsdf:{{back_bsdf}}, mxp_back_edf:{{back_edf}}, mxp_opacity:{{opacity}})" target="genmdl" />
<!-- <volume> -->
<implementation name="IM_volume_genmdl" nodedef="ND_volume" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_volume(mxp_vdf:{{vdf}}, mxp_edf:{{edf}})" target="genmdl" />
<!-- <light> -->
<implementation name="IM_light_genmdl" nodedef="ND_light" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_light(mxp_edf:{{edf}}, mxp_intensity:{{intensity}}, mxp_exposure:{{exposure}})" target="genmdl" />
<!-- <displacement> -->
<implementation name="IM_displacement_float_genmdl" nodedef="ND_displacement_float" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_displacement_float(mxp_displacement:{{displacement}}, mxp_scale:{{scale}})" target="genmdl" />
<implementation name="IM_displacement_vector3_genmdl" nodedef="ND_displacement_vector3" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_displacement_vector3(mxp_displacement:{{displacement}}, mxp_scale:{{scale}})" target="genmdl" />
<!-- <layer> -->
<implementation name="IM_layer_bsdf_genmdl" nodedef="ND_layer_bsdf" target="genmdl" />
<implementation name="IM_layer_vdf_genmdl" nodedef="ND_layer_vdf" target="genmdl" />
<!-- <mix> -->
<implementation name="IM_mix_bsdf_genmdl" nodedef="ND_mix_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_mix_bsdf(mxp_fg:{{fg}}, mxp_bg:{{bg}}, mxp_mix:{{mix}})" target="genmdl" />
<implementation name="IM_mix_edf_genmdl" nodedef="ND_mix_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_mix_edf(mxp_fg:{{fg}}, mxp_bg:{{bg}}, mxp_mix:{{mix}})" target="genmdl" />
<implementation name="IM_mix_vdf_genmdl" nodedef="ND_mix_vdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_mix_vdf(mxp_fg:{{fg}}, mxp_bg:{{bg}}, mxp_mix:{{mix}})" target="genmdl" />
<!-- <add> -->
<implementation name="IM_add_bsdf_genmdl" nodedef="ND_add_bsdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_add_bsdf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_add_edf_genmdl" nodedef="ND_add_edf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_add_edf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_add_vdf_genmdl" nodedef="ND_add_vdf" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_add_vdf(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genmdl" nodedef="ND_multiply_bsdfC" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_bsdf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_bsdfF_genmdl" nodedef="ND_multiply_bsdfF" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_bsdf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_edfC_genmdl" nodedef="ND_multiply_edfC" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_edf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_edfF_genmdl" nodedef="ND_multiply_edfF" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_edf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_vdfC_genmdl" nodedef="ND_multiply_vdfC" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_vdf_color3(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<implementation name="IM_multiply_vdfF_genmdl" nodedef="ND_multiply_vdfF" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_multiply_vdf_float(mxp_in1:{{in1}}, mxp_in2:{{in2}})" target="genmdl" />
<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genmdl" nodedef="ND_roughness_anisotropy" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_roughness_anisotropy(mxp_roughness:{{roughness}}, mxp_anisotropy:{{anisotropy}})" target="genmdl" />
<!-- <roughness_dual> -->
<implementation name="IM_roughness_dual_genmdl" nodedef="ND_roughness_dual" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_roughness_dual(mxp_roughness:{{roughness}})" target="genmdl" />
<!-- <artistic_ior> -->
<implementation name="IM_artistic_ior_genmdl" nodedef="ND_artistic_ior" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_artistic_ior(mxp_reflectivity:{{reflectivity}}, mxp_edge_color:{{edge_color}})" target="genmdl" />
<!-- <blackbody> -->
<implementation name="IM_blackbody_genmdl" nodedef="ND_blackbody" sourcecode="materialx::pbrlib_{{MDL_VERSION_SUFFIX}}::mx_blackbody(mxp_temperature:{{temperature}})" target="genmdl" />
</materialx>
@@ -0,0 +1,77 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genmsl" nodedef="ND_oren_nayar_diffuse_bsdf" file="../genglsl/mx_oren_nayar_diffuse_bsdf.glsl" function="mx_oren_nayar_diffuse_bsdf" target="genmsl" />
<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genmsl" nodedef="ND_burley_diffuse_bsdf" file="../genglsl/mx_burley_diffuse_bsdf.glsl" function="mx_burley_diffuse_bsdf" target="genmsl" />
<!-- <translucent_bsdf> -->
<implementation name="IM_translucent_bsdf_genmsl" nodedef="ND_translucent_bsdf" file="../genglsl/mx_translucent_bsdf.glsl" function="mx_translucent_bsdf" target="genmsl" />
<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genmsl" nodedef="ND_dielectric_bsdf" file="../genglsl/mx_dielectric_bsdf.glsl" function="mx_dielectric_bsdf" target="genmsl" />
<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genmsl" nodedef="ND_conductor_bsdf" file="../genglsl/mx_conductor_bsdf.glsl" function="mx_conductor_bsdf" target="genmsl" />
<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genmsl" nodedef="ND_generalized_schlick_bsdf" file="../genglsl/mx_generalized_schlick_bsdf.glsl" function="mx_generalized_schlick_bsdf" target="genmsl" />
<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genmsl" nodedef="ND_subsurface_bsdf" file="../genglsl/mx_subsurface_bsdf.glsl" function="mx_subsurface_bsdf" target="genmsl" />
<!-- <sheen_bsdf> -->
<implementation name="IM_sheen_bsdf_genmsl" nodedef="ND_sheen_bsdf" file="../genglsl/mx_sheen_bsdf.glsl" function="mx_sheen_bsdf" target="genmsl" />
<!-- <anisotropic_vdf> -->
<implementation name="IM_anisotropic_vdf_genmsl" nodedef="ND_anisotropic_vdf" file="../genglsl/mx_anisotropic_vdf.glsl" function="mx_anisotropic_vdf" target="genmsl" />
<!-- <thin_film_bsdf> -->
<implementation name="IM_thin_film_bsdf_genmsl" nodedef="ND_thin_film_bsdf" target="genmsl" />
<!-- <layer> -->
<implementation name="IM_layer_bsdf_genmsl" nodedef="ND_layer_bsdf" target="genmsl" />
<implementation name="IM_layer_vdf_genmsl" nodedef="ND_layer_vdf" target="genmsl" />
<!-- <mix> -->
<implementation name="IM_mix_bsdf_genmsl" nodedef="ND_mix_bsdf" target="genmsl" />
<implementation name="IM_mix_edf_genmsl" nodedef="ND_mix_edf" target="genmsl" />
<!-- <add> -->
<implementation name="IM_add_bsdf_genmsl" nodedef="ND_add_bsdf" target="genmsl" />
<implementation name="IM_add_edf_genmsl" nodedef="ND_add_edf" target="genmsl" />
<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genmsl" nodedef="ND_multiply_bsdfC" target="genmsl" />
<implementation name="IM_multiply_bsdfF_genmsl" nodedef="ND_multiply_bsdfF" target="genmsl" />
<implementation name="IM_multiply_edfC_genmsl" nodedef="ND_multiply_edfC" target="genmsl" />
<implementation name="IM_multiply_edfF_genmsl" nodedef="ND_multiply_edfF" target="genmsl" />
<!-- <uniform_edf> -->
<implementation name="IM_uniform_edf_genmsl" nodedef="ND_uniform_edf" file="../genglsl/mx_uniform_edf.glsl" function="mx_uniform_edf" target="genmsl" />
<!-- <surface> -->
<implementation name="IM_surface_genmsl" nodedef="ND_surface" target="genmsl" />
<!-- <displacement> -->
<implementation name="IM_displacement_float_genmsl" nodedef="ND_displacement_float" file="../genglsl/mx_displacement_float.glsl" function="mx_displacement_float" target="genmsl" />
<implementation name="IM_displacement_vector3_genmsl" nodedef="ND_displacement_vector3" file="../genglsl/mx_displacement_vector3.glsl" function="mx_displacement_vector3" target="genmsl" />
<!-- <light> -->
<implementation name="IM_light_genmsl" nodedef="ND_light" target="genmsl" />
<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genmsl" nodedef="ND_roughness_anisotropy" file="../genglsl/mx_roughness_anisotropy.glsl" function="mx_roughness_anisotropy" target="genmsl" />
<!-- <roughness_dual> -->
<implementation name="IM_roughness_dual_genmsl" nodedef="ND_roughness_dual" file="../genglsl/mx_roughness_dual.glsl" function="mx_roughness_dual" target="genmsl" />
<!-- <artistic_ior> -->
<implementation name="IM_artistic_ior_genmsl" nodedef="ND_artistic_ior" file="../genglsl/mx_artistic_ior.glsl" function="mx_artistic_ior" target="genmsl" />
<!-- <blackbody> -->
<implementation name="IM_blackbody_genmsl" nodedef="ND_blackbody" file="../genglsl/mx_blackbody.glsl" function="mx_blackbody" target="genmsl" />
</materialx>
@@ -0,0 +1,5 @@
void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf)
{
// Not implemented in vanilla OSL
vdf = 0; // volume_henyey_greenstein(color(absorption), color(scattering), color(0.0), anisotropy);
}
@@ -0,0 +1,6 @@
void mx_burley_diffuse_bsdf(float weight, color reflectance, float roughness, normal N, output BSDF bsdf)
{
// TODO: Implement properly.
bsdf.response = reflectance * weight * oren_nayar(N, roughness);
bsdf.throughput = color(0.0);
}
@@ -0,0 +1,32 @@
#include "../lib/mx_microfacet_specular.osl"
void mx_conductor_bsdf(float weight, color ior_n, color ior_k, vector2 roughness, normal N, vector U, string distribution, output BSDF bsdf)
{
bsdf.throughput = color(0.0);
if (weight < M_FLOAT_EPS)
{
bsdf.response = 0;
return;
}
// Calculate conductor fresnel
//
// Fresnel should be based on microfacet normal
// but we have no access to that from here, so just use
// view direction and surface normal instead
//
float NdotV = fabs(dot(N,-I));
color F = mx_fresnel_conductor(NdotV, ior_n, ior_k);
// Calculate compensation for multiple scattering.
// This should normally be done inside the closure
// but since vanilla OSL doesen't support this we
// add it here in shader code instead.
vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
// Set ior to 0.0 to disable the internal dielectric fresnel
bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, false);
}
@@ -0,0 +1,36 @@
#include "../lib/mx_microfacet_specular.osl"
void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
if (scatter_mode == "T")
{
bsdf.response = tint * weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1);
bsdf.throughput = tint * weight;
return;
}
float NdotV = clamp(dot(N,-I), M_FLOAT_EPS, 1.0);
float F0 = mx_ior_to_f0(ior);
float F = mx_fresnel_schlick(NdotV, F0);
// Calculate compensation for multiple scattering.
// This should normally be done inside the closure
// but since vanilla OSL doesen't support this we
// add it here in shader code instead.
vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
float comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
// Calculate throughput from directional albedo.
float dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, ior) * comp;
bsdf.throughput = 1.0 - dirAlbedo * weight;
if (scatter_mode == "R")
{
bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 0);
}
else
{
bsdf.response = tint * weight * comp * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 2);
}
}
@@ -0,0 +1,38 @@
#include "../lib/mx_microfacet_specular.osl"
void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
float avgF0 = dot(color0, color(1.0 / 3.0));
float ior = mx_f0_to_ior(avgF0);
if (scatter_mode == "T")
{
bsdf.response = weight * microfacet(distribution, N, U, roughness.x, roughness.y, ior, 1);
bsdf.throughput = weight;
return;
}
float NdotV = fabs(dot(N,-I));
color F = mx_fresnel_schlick(NdotV, color0, color90, exponent);
// Calculate compensation for multiple scattering.
// This should normally be done inside the closure
// but since vanilla OSL doesen't support this we
// add it here in shader code instead.
vector2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);
color comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
// Calculate throughput from directional albedo.
color dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, color0, color90) * comp;
float avgDirAlbedo = dot(dirAlbedo, color(1.0 / 3.0));
bsdf.throughput = 1.0 - avgDirAlbedo * weight;
// Calculate the reflection response, setting IOR to zero to disable internal Fresnel.
bsdf.response = F * comp * weight * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, 0.0, 0);
if (scatter_mode == "RT")
{
bsdf.response += bsdf.throughput * microfacet(distribution, N, U, safeAlpha.x, safeAlpha.y, ior, 1);
}
}
@@ -0,0 +1,5 @@
void mx_oren_nayar_diffuse_bsdf(float weight, color _color, float roughness, normal N, output BSDF bsdf)
{
bsdf.response = _color * weight * oren_nayar(N, roughness);
bsdf.throughput = color(0.0);
}
@@ -0,0 +1,24 @@
#include "../lib/mx_microfacet_sheen.osl"
// TODO: Vanilla OSL doesn't have a proper sheen closure,
// so use 'diffuse' scaled by sheen directional albedo for now.
void mx_sheen_bsdf(float weight, color Ks, float roughness, vector N, output BSDF bsdf)
{
if (weight < M_FLOAT_EPS)
{
bsdf.response = 0;
bsdf.throughput = color(1.0);
return;
}
// TODO: Normalization should not be needed. My suspicion is that
// BSDF sampling of new outgoing direction in 'testrender' needs
// to be fixed.
vector V = normalize(-I);
float NdotV = fabs(dot(N,V));
float alpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float albedo = weight * mx_imageworks_sheen_dir_albedo(NdotV, alpha);
bsdf.response = albedo * Ks * diffuse(N);
bsdf.throughput = 1.0 - albedo;
}
@@ -0,0 +1,6 @@
void mx_subsurface_bsdf(float weight, color _color, vector radius, float anisotropy, normal N, output BSDF bsdf)
{
// TODO: Subsurface closure is not supported by vanilla OSL.
bsdf.response = _color * weight * diffuse(N);
bsdf.throughput = color(0.0);
}
@@ -0,0 +1,6 @@
void mx_surface(BSDF bsdf, EDF edf, float opacity, output surfaceshader result)
{
result.bsdf = bsdf.response;
result.edf = edf;
result.opacity = clamp(opacity, 0.0, 1.0);
}
@@ -0,0 +1,5 @@
void mx_translucent_bsdf(float weight, color _color, normal N, output BSDF bsdf)
{
bsdf.response = _color * weight * translucent(N);
bsdf.throughput = color(0.0);
}
@@ -0,0 +1,78 @@
float mx_square(float x)
{
return x*x;
}
vector2 mx_square(vector2 x)
{
return x*x;
}
vector mx_square(vector x)
{
return x*x;
}
vector4 mx_square(vector4 x)
{
return x*x;
}
float mx_pow5(float x)
{
return mx_square(mx_square(x)) * x;
}
color mx_fresnel_conductor(float cosTheta, vector n, vector k)
{
float c2 = cosTheta*cosTheta;
vector n2_k2 = n*n + k*k;
vector nc2 = 2.0 * n * cosTheta;
vector rs_a = n2_k2 + c2;
vector rp_a = n2_k2 * c2 + 1.0;
vector rs = (rs_a - nc2) / (rs_a + nc2);
vector rp = (rp_a - nc2) / (rp_a + nc2);
return 0.5 * (rs + rp);
}
// Standard Schlick Fresnel
float mx_fresnel_schlick(float cosTheta, float F0)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return F0 + (1.0 - F0) * x5;
}
color mx_fresnel_schlick(float cosTheta, color F0)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return F0 + (1.0 - F0) * x5;
}
// Generalized Schlick Fresnel
float mx_fresnel_schlick(float cosTheta, float F0, float F90)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return mix(F0, F90, x5);
}
color mx_fresnel_schlick(float cosTheta, color F0, color F90)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
float x5 = mx_pow5(x);
return mix(F0, F90, x5);
}
// Generalized Schlick Fresnel with a variable exponent
color mx_fresnel_schlick(float cosTheta, float f0, float f90, float exponent)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
return mix(f0, f90, pow(x, exponent));
}
color mx_fresnel_schlick(float cosTheta, color f0, color f90, float exponent)
{
float x = clamp(1.0 - cosTheta, 0.0, 1.0);
return mix(f0, f90, pow(x, exponent));
}
@@ -0,0 +1,15 @@
#include "mx_microfacet.osl"
// Rational curve fit approximation for the directional albedo of Imageworks sheen.
float mx_imageworks_sheen_dir_albedo_analytic(float NdotV, float roughness)
{
float a = 5.25248 - 7.66024 * NdotV + 14.26377 * roughness;
float b = 1.0 + 30.66449 * NdotV + 32.53420 * roughness;
return a / b;
}
float mx_imageworks_sheen_dir_albedo(float NdotV, float roughness)
{
float dirAlbedo = mx_imageworks_sheen_dir_albedo_analytic(NdotV, roughness);
return clamp(dirAlbedo, 0.0, 1.0);
}
@@ -0,0 +1,68 @@
#include "mx_microfacet.osl"
// Compute the average of an anisotropic alpha pair.
float mx_average_alpha(vector2 alpha)
{
return sqrt(alpha.x * alpha.y);
}
// Convert a real-valued index of refraction to normal-incidence reflectivity.
float mx_ior_to_f0(float ior)
{
return mx_square((ior - 1.0) / (ior + 1.0));
}
// Convert normal-incidence reflectivity to real-valued index of refraction.
float mx_f0_to_ior(float F0)
{
float sqrtF0 = sqrt(clamp(F0, 0.01, 0.99));
return (1.0 + sqrtF0) / (1.0 - sqrtF0);
}
// Rational quadratic fit to Monte Carlo data for GGX directional albedo.
color mx_ggx_dir_albedo(float NdotV, float alpha, color F0, color F90)
{
float x = NdotV;
float y = alpha;
float x2 = mx_square(x);
float y2 = mx_square(y);
vector4 r = vector4(0.1003, 0.9345, 1.0, 1.0) +
vector4(-0.6303, -2.323, -1.765, 0.2281) * x +
vector4(9.748, 2.229, 8.263, 15.94) * y +
vector4(-2.038, -3.748, 11.53, -55.83) * x * y +
vector4(29.34, 1.424, 28.96, 13.08) * x2 +
vector4(-8.245, -0.7684, -7.507, 41.26) * y2 +
vector4(-26.44, 1.436, -36.11, 54.9) * x2 * y +
vector4(19.99, 0.2913, 15.86, 300.2) * x * y2 +
vector4(-5.448, 0.6286, 33.37, -285.1) * x2 * y2;
vector2 AB = vector2(r.x, r.y) / vector2(r.z, r.w);
AB.x = clamp(AB.x, 0.0, 1.0);
AB.y = clamp(AB.y, 0.0, 1.0);
return F0 * AB.x + F90 * AB.y;
}
float mx_ggx_dir_albedo(float NdotV, float alpha, float F0, float F90)
{
color result = mx_ggx_dir_albedo(NdotV, alpha, color(F0), color(F90));
return result[0];
}
float mx_ggx_dir_albedo(float NdotV, float alpha, float ior)
{
color result = mx_ggx_dir_albedo(NdotV, alpha, color(mx_ior_to_f0(ior)), color(1.0));
return result[0];
}
// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf
// Equations 14 and 16
color mx_ggx_energy_compensation(float NdotV, float alpha, color Fss)
{
float Ess = mx_ggx_dir_albedo(NdotV, alpha, 1.0, 1.0);
return 1.0 + Fss * (1.0 - Ess) / Ess;
}
float mx_ggx_energy_compensation(float NdotV, float alpha, float Fss)
{
color result = mx_ggx_energy_compensation(NdotV, alpha, color(Fss));
return result[0];
}
@@ -0,0 +1,6 @@
void mx_anisotropic_vdf(vector absorption, vector scattering, float anisotropy, output VDF vdf)
{
// TODO: Need to remap parameters to match the new closure,
// or change the MaterialX spec to OSL parameterization.
vdf = 0;
}
@@ -0,0 +1,17 @@
void mx_artistic_ior(color reflectivity, color edge_color, output vector ior, output vector extinction)
{
// "Artist Friendly Metallic Fresnel", Ole Gulbrandsen, 2014
// http://jcgt.org/published/0003/04/03/paper.pdf
color r = clamp(reflectivity, 0.0, 0.99);
color r_sqrt = sqrt(r);
color n_min = (1.0 - r) / (1.0 + r);
color n_max = (1.0 + r_sqrt) / (1.0 - r_sqrt);
ior = mix(n_max, n_min, edge_color);
color np1 = ior + 1.0;
color nm1 = ior - 1.0;
color k2 = (np1*np1 * r - nm1*nm1) / (1.0 - r);
k2 = max(k2, 0.0);
extinction = sqrt(k2);
}
@@ -0,0 +1,49 @@
void mx_blackbody(float temp, output color color_value)
{
float xc, yc;
float t, t2, t3, xc2, xc3;
// if value outside valid range of approximation clamp to accepted temperature range
float temperature = clamp(temp, 1667.0, 25000.0);
t = 1000.0 / temperature;
t2 = t * t;
t3 = t * t * t;
// Cubic spline approximation for Kelvin temperature to sRGB conversion
// (https://en.wikipedia.org/wiki/Planckian_locus#Approximation)
if (temperature < 4000.0) { // 1667K <= temperature < 4000K
xc = -0.2661239 * t3 - 0.2343580 * t2 + 0.8776956 * t + 0.179910;
}
else { // 4000K <= temperature <= 25000K
xc = -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t + 0.240390;
}
xc2 = xc * xc;
xc3 = xc * xc * xc;
if (temperature < 2222.0) { // 1667K <= temperature < 2222K
yc = -1.1063814 * xc3 - 1.34811020 * xc2 + 2.18555832 * xc - 0.20219683;
}
else if (temperature < 4000.0) { // 2222K <= temperature < 4000K
yc = -0.9549476 * xc3 - 1.37418593 * xc2 + 2.09137015 * xc - 0.16748867;
}
else { // 4000K <= temperature <= 25000K
yc = 3.0817580 * xc3 - 5.87338670 * xc2 + 3.75112997 * xc - 0.37001483;
}
if (yc <= 0.0) { // avoid division by zero
color_value = color(1.0);
return;
}
vector XYZ = vector(xc / yc, 1.0, (1 - xc - yc) / yc);
/// XYZ to Rec.709 RGB colorspace conversion
matrix XYZ_to_RGB = matrix( 3.2406, -0.9689, 0.0557, 0.0,
-1.5372, 1.8758, -0.2040, 0.0,
-0.4986, 0.0415, 1.0570, 0.0,
0.0, 0.0, 0.0, 1.0);
color_value = transform(XYZ_to_RGB, XYZ);
color_value = max(color_value, vector(0.0));
}
@@ -0,0 +1,15 @@
void mx_dielectric_bsdf(float weight, color tint, float ior, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
if (scatter_mode == "R")
{
bsdf = weight * dielectric_bsdf(N, U, tint, color(0.0), roughness.x, roughness.y, ior, distribution);
}
else if (scatter_mode == "T")
{
bsdf = weight * dielectric_bsdf(N, U, color(0.0), tint, roughness.x, roughness.y, ior, distribution);
}
else
{
bsdf = weight * dielectric_bsdf(N, U, tint, tint, roughness.x, roughness.y, ior, distribution);
}
}
@@ -0,0 +1,4 @@
void mx_displacement_float(float displacement, float scale, output displacementshader result)
{
result = vector(displacement * scale);
}
@@ -0,0 +1,4 @@
void mx_displacement_vector3(vector displacement, float scale, output displacementshader result)
{
result = displacement * scale;
}
@@ -0,0 +1,15 @@
void mx_generalized_schlick_bsdf(float weight, color color0, color color90, float exponent, vector2 roughness, normal N, vector U, string distribution, string scatter_mode, output BSDF bsdf)
{
if (scatter_mode == "R")
{
bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(0.0), roughness.x, roughness.y, color0, color90, exponent, distribution);
}
else if (scatter_mode == "T")
{
bsdf = weight * generalized_schlick_bsdf(N, U, color(0.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution);
}
else
{
bsdf = weight * generalized_schlick_bsdf(N, U, color(1.0), color(1.0), roughness.x, roughness.y, color0, color90, exponent, distribution);
}
}
@@ -0,0 +1,8 @@
#include "lib/mx_microfacet.osl"
void mx_generalized_schlick_edf(color color0, color color90, float exponent, EDF base, output EDF result)
{
float NdotV = fabs(dot(N,-I));
color f = mx_fresnel_schlick(NdotV, color0, color90, exponent);
result = base * f;
}
@@ -0,0 +1,15 @@
void mx_roughness_anisotropy(float roughness, float anisotropy, output vector2 result)
{
float roughness_sqr = clamp(roughness*roughness, M_FLOAT_EPS, 1.0);
if (anisotropy > 0.0)
{
float aspect = sqrt(1.0 - clamp(anisotropy, 0.0, 0.98));
result.x = min(roughness_sqr / aspect, 1.0);
result.y = roughness_sqr * aspect;
}
else
{
result.x = roughness_sqr;
result.y = roughness_sqr;
}
}
@@ -0,0 +1,12 @@
void mx_roughness_dual(vector2 roughness, output vector2 result)
{
result.x = clamp(roughness.x * roughness.x, M_FLOAT_EPS, 1.0);
if (roughness.y < 0.0)
{
result.y = result.x;
}
else
{
result.y = clamp(roughness.y * roughness.y, M_FLOAT_EPS, 1.0);
}
}
@@ -0,0 +1,5 @@
void mx_subsurface_bsdf(float weight, color _color, vector radius, float anisotropy, normal N, output BSDF bsdf)
{
// TODO: Subsurface closure is not supported by vanilla OSL.
bsdf = _color * weight * diffuse(N);
}
@@ -0,0 +1,6 @@
void mx_surface(BSDF bsdf, EDF edf, float opacity, output surfaceshader result)
{
result.bsdf = bsdf;
result.edf = edf;
result.opacity = clamp(opacity, 0.0, 1.0);
}
@@ -0,0 +1,77 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!-- <oren_nayar_diffuse_bsdf> -->
<implementation name="IM_oren_nayar_diffuse_bsdf_genosl" nodedef="ND_oren_nayar_diffuse_bsdf" sourcecode="{{weight}} * oren_nayar_diffuse_bsdf({{normal}}, {{color}}, {{roughness}})" target="genosl" />
<!-- <burley_diffuse_bsdf> -->
<implementation name="IM_burley_diffuse_bsdf_genosl" nodedef="ND_burley_diffuse_bsdf" sourcecode="{{weight}} * burley_diffuse_bsdf({{normal}}, {{color}}, {{roughness}})" target="genosl" />
<!-- <translucent_bsdf> -->
<implementation name="IM_translucent_bsdf_genosl" nodedef="ND_translucent_bsdf" sourcecode="{{weight}} * translucent_bsdf({{normal}}, {{color}})" target="genosl" />
<!-- <dielectric_bsdf> -->
<implementation name="IM_dielectric_bsdf_genosl" nodedef="ND_dielectric_bsdf" file="mx_dielectric_bsdf.osl" function="mx_dielectric_bsdf" target="genosl" />
<!-- <conductor_bsdf> -->
<implementation name="IM_conductor_bsdf_genosl" nodedef="ND_conductor_bsdf" sourcecode="{{weight}} * conductor_bsdf({{normal}}, {{tangent}}, {{roughness}}.x, {{roughness}}.y, {{ior}}, {{extinction}}, {{distribution}})" target="genosl" />
<!-- <generalized_schlick_bsdf> -->
<implementation name="IM_generalized_schlick_bsdf_genosl" nodedef="ND_generalized_schlick_bsdf" file="mx_generalized_schlick_bsdf.osl" function="mx_generalized_schlick_bsdf" target="genosl" />
<!-- <subsurface_bsdf> -->
<implementation name="IM_subsurface_bsdf_genosl" nodedef="ND_subsurface_bsdf" file="mx_subsurface_bsdf.osl" function="mx_subsurface_bsdf" target="genosl" />
<!-- <sheen_bsdf> -->
<implementation name="IM_sheen_bsdf_genosl" nodedef="ND_sheen_bsdf" sourcecode="{{weight}} * sheen_bsdf({{normal}}, {{color}}, {{roughness}})" target="genosl" />
<!-- <anisotropic_vdf> -->
<implementation name="IM_anisotropic_vdf_genosl" nodedef="ND_anisotropic_vdf" file="mx_anisotropic_vdf.osl" function="mx_anisotropic_vdf" target="genosl" />
<!-- <thin_film_bsdf> -->
<implementation name="IM_thin_film_bsdf_genosl" nodedef="ND_thin_film_bsdf" target="genosl" />
<!-- <uniform_edf> -->
<implementation name="IM_uniform_edf_genosl" nodedef="ND_uniform_edf" sourcecode="uniform_edf({{color}})" target="genosl" />
<!-- <generalized_schlick_edf> -->
<implementation name="IM_generalized_schlick_edf_genosl" nodedef="ND_generalized_schlick_edf" file="mx_generalized_schlick_edf.osl" function="mx_generalized_schlick_edf" target="genosl" />
<!-- <layer> -->
<implementation name="IM_layer_bsdf_genosl" nodedef="ND_layer_bsdf" target="genosl" />
<implementation name="IM_layer_vdf_genosl" nodedef="ND_layer_vdf" target="genosl" />
<!-- <mix> -->
<implementation name="IM_mix_bsdf_genosl" nodedef="ND_mix_bsdf" sourcecode="mix({{bg}}, {{fg}}, {{mix}})" target="genosl" />
<implementation name="IM_mix_edf_genosl" nodedef="ND_mix_edf" sourcecode="mix({{bg}}, {{fg}}, {{mix}})" target="genosl" />
<!-- <add> -->
<implementation name="IM_add_bsdf_genosl" nodedef="ND_add_bsdf" sourcecode="({{in1}} + {{in2}})" target="genosl" />
<implementation name="IM_add_edf_genosl" nodedef="ND_add_edf" sourcecode="({{in1}} + {{in2}})" target="genosl" />
<!-- <multiply> -->
<implementation name="IM_multiply_bsdfC_genosl" nodedef="ND_multiply_bsdfC" sourcecode="({{in2}} * {{in1}})" target="genosl" />
<implementation name="IM_multiply_bsdfF_genosl" nodedef="ND_multiply_bsdfF" sourcecode="({{in2}} * {{in1}})" target="genosl" />
<implementation name="IM_multiply_edfC_genosl" nodedef="ND_multiply_edfC" sourcecode="({{in2}} * {{in1}})" target="genosl" />
<implementation name="IM_multiply_edfF_genosl" nodedef="ND_multiply_edfF" sourcecode="({{in2}} * {{in1}})" target="genosl" />
<!-- <surface> -->
<implementation name="IM_surface_genosl" nodedef="ND_surface" file="mx_surface.osl" function="mx_surface" target="genosl" />
<!-- <displacement> -->
<implementation name="IM_displacement_float_genosl" nodedef="ND_displacement_float" file="mx_displacement_float.osl" function="mx_displacement_float" target="genosl" />
<implementation name="IM_displacement_vector3_genosl" nodedef="ND_displacement_vector3" file="mx_displacement_vector3.osl" function="mx_displacement_vector3" target="genosl" />
<!-- <roughness_anisotropy> -->
<implementation name="IM_roughness_anisotropy_genosl" nodedef="ND_roughness_anisotropy" file="mx_roughness_anisotropy.osl" function="mx_roughness_anisotropy" target="genosl" />
<!-- <roughness_dual> -->
<implementation name="IM_roughness_dual_genosl" nodedef="ND_roughness_dual" file="mx_roughness_dual.osl" function="mx_roughness_dual" target="genosl" />
<!-- <artistic_ior> -->
<implementation name="IM_artistic_ior_genosl" nodedef="ND_artistic_ior" file="mx_artistic_ior.osl" function="mx_artistic_ior" target="genosl" />
<!-- <blackbody> -->
<implementation name="IM_blackbody_genosl" nodedef="ND_blackbody" file="mx_blackbody.osl" function="mx_blackbody" target="genosl" />
</materialx>
@@ -0,0 +1,420 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!--
Copyright Contributors to the MaterialX Project
SPDX-License-Identifier: Apache-2.0
Declarations of standard data types and nodes included in the MaterialX specification.
-->
<!-- ======================================================================== -->
<!-- Data Types -->
<!-- ======================================================================== -->
<typedef name="BSDF" doc="Bidirectional scattering distribution function" />
<typedef name="EDF" doc="Emission distribution function" />
<typedef name="VDF" doc="Volume distribution function" />
<!-- ======================================================================== -->
<!-- BSDF Nodes -->
<!-- ======================================================================== -->
<!--
Node: <oren_nayar_diffuse_bsdf>
A BSDF node for diffuse reflection.
-->
<nodedef name="ND_oren_nayar_diffuse_bsdf" node="oren_nayar_diffuse_bsdf" bsdf="R" nodegroup="pbr" doc="A BSDF node for diffuse reflections.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color" type="color3" value="0.18, 0.18, 0.18" />
<input name="roughness" type="float" value="0.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <burley_diffuse_bsdf>
A BSDF node for Burley diffuse reflection.
-->
<nodedef name="ND_burley_diffuse_bsdf" node="burley_diffuse_bsdf" bsdf="R" nodegroup="pbr" doc="A BSDF node for Burley diffuse reflections.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color" type="color3" value="0.18, 0.18, 0.18" />
<input name="roughness" type="float" value="0.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <translucent_bsdf>
A BSDF node for diffuse transmission.
-->
<nodedef name="ND_translucent_bsdf" node="translucent_bsdf" bsdf="R" nodegroup="pbr" doc="A BSDF node for pure diffuse transmission.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <dielectric_bsdf>
A reflection/transmission BSDF node based on a microfacet model and a Fresnel curve for dielectrics.
-->
<nodedef name="ND_dielectric_bsdf" node="dielectric_bsdf" nodegroup="pbr" doc="A reflection/transmission BSDF node based on a microfacet model and a Fresnel curve for dielectrics.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="tint" type="color3" value="1.0, 1.0, 1.0" />
<input name="ior" type="float" value="1.5" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<input name="tangent" type="vector3" defaultgeomprop="Tworld" />
<input name="distribution" type="string" value="ggx" enum="ggx" uniform="true" />
<input name="scatter_mode" type="string" value="R" enum="R,T,RT" uniform="true" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <conductor_bsdf>
A reflection BSDF node based on a microfacet model and a Fresnel curve for conductors/metals.
-->
<nodedef name="ND_conductor_bsdf" node="conductor_bsdf" bsdf="R" nodegroup="pbr" doc="A reflection BSDF node based on a microfacet model and a Fresnel curve for conductors/metals.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="ior" type="color3" value="0.183, 0.421, 1.373" colorspace="none" />
<input name="extinction" type="color3" value="3.424, 2.346, 1.770" colorspace="none" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<input name="tangent" type="vector3" defaultgeomprop="Tworld" />
<input name="distribution" type="string" value="ggx" enum="ggx" uniform="true" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <generalized_schlick_bsdf>
A reflection/transmission BSDF node based on a microfacet model and a generalized Schlick Fresnel curve.
-->
<nodedef name="ND_generalized_schlick_bsdf" node="generalized_schlick_bsdf" nodegroup="pbr" doc="A reflection/transmission BSDF node based on a microfacet model and a generalized Schlick Fresnel curve.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color0" type="color3" value="1.0, 1.0, 1.0" />
<input name="color90" type="color3" value="1.0, 1.0, 1.0" />
<input name="exponent" type="float" value="5.0" />
<input name="roughness" type="vector2" value="0.05, 0.05" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<input name="tangent" type="vector3" defaultgeomprop="Tworld" />
<input name="distribution" type="string" value="ggx" enum="ggx" uniform="true" />
<input name="scatter_mode" type="string" value="R" enum="R,T,RT" uniform="true" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <subsurface_bsdf>
A subsurface scattering BSDF for true subsurface scattering.
-->
<nodedef name="ND_subsurface_bsdf" node="subsurface_bsdf" bsdf="R" nodegroup="pbr" doc="A subsurface scattering BSDF for true subsurface scattering.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color" type="color3" value="0.18, 0.18, 0.18" />
<input name="radius" type="vector3" value="1.0, 1.0, 1.0" />
<input name="anisotropy" type="float" value="0.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <sheen_bsdf>
A microfacet BSDF for the back-scattering properties of cloth-like materials.
-->
<nodedef name="ND_sheen_bsdf" node="sheen_bsdf" bsdf="R" nodegroup="pbr" doc="A microfacet BSDF for the back-scattering properties of cloth-like materials.">
<input name="weight" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
<input name="roughness" type="float" value="0.3" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <thin_film_bsdf>
Adds an iridescent thin film layer over a microfacet base BSDF.
-->
<nodedef name="ND_thin_film_bsdf" node="thin_film_bsdf" bsdf="R" nodegroup="pbr" doc="Adds an iridescent thin film layer over a microfacet base BSDF.">
<input name="thickness" type="float" value="550" unittype="distance" unit="nanometer" />
<input name="ior" type="float" value="1.5" />
<output name="out" type="BSDF" />
</nodedef>
<!-- ======================================================================== -->
<!-- EDF Nodes -->
<!-- ======================================================================== -->
<!--
Node: <uniform_edf>
An EDF node for uniform emission.
-->
<nodedef name="ND_uniform_edf" node="uniform_edf" nodegroup="pbr" doc="An EDF node for uniform emission.">
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
<output name="out" type="EDF" />
</nodedef>
<!--
Node: <conical_edf>
Constructs an EDF emitting light inside a cone around the normal direction.
-->
<nodedef name="ND_conical_edf" node="conical_edf" nodegroup="pbr" doc="Constructs an EDF emitting light inside a cone around the normal direction.">
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<input name="inner_angle" type="float" value="60.0" />
<input name="outer_angle" type="float" value="0.0" />
<output name="out" type="EDF" />
</nodedef>
<!--
Node: <measured_edf>
Constructs an EDF emitting light according to a measured IES light profile.
-->
<nodedef name="ND_measured_edf" node="measured_edf" nodegroup="pbr" doc="Constructs an EDF emitting light according to a measured IES light profile.">
<input name="color" type="color3" value="1.0, 1.0, 1.0" />
<input name="normal" type="vector3" defaultgeomprop="Nworld" />
<input name="file" type="filename" value="" uniform="true" />
<output name="out" type="EDF" />
</nodedef>
<!--
Node: <generalized_schlick_edf>
Modifies an EDF with a directional factor. Attenuates the emission distribution of the base EDF according to
a generalized Schlick fresnel function.
-->
<nodedef name="ND_generalized_schlick_edf" node="generalized_schlick_edf" nodegroup="pbr" doc="Modifies an EDF with a directional factor.">
<input name="color0" type="color3" value="1.0, 1.0, 1.0" />
<input name="color90" type="color3" value="1.0, 1.0, 1.0" />
<input name="exponent" type="float" value="5.0" />
<input name="base" type="EDF" value="" />
<output name="out" type="EDF" />
</nodedef>
<!-- ======================================================================== -->
<!-- VDF Nodes -->
<!-- ======================================================================== -->
<!--
Node: <absorption_vdf>
Constructs a VDF for pure light absorption.
-->
<nodedef name="ND_absorption_vdf" node="absorption_vdf" nodegroup="pbr" doc="Constructs a VDF for pure light absorption.">
<input name="absorption" type="vector3" value="0.0, 0.0, 0.0" />
<output name="out" type="VDF" />
</nodedef>
<!--
Node: <anisotropic_vdf>
Constructs a VDF scattering light for a participating medium, based on the
Henyey-Greenstein phase function.
-->
<nodedef name="ND_anisotropic_vdf" node="anisotropic_vdf" nodegroup="pbr" doc="Constructs a VDF scattering light for a participating medium, based on the Henyey-Greenstein phase function.">
<input name="absorption" type="vector3" value="0.0, 0.0, 0.0" />
<input name="scattering" type="vector3" value="0.0, 0.0, 0.0" />
<input name="anisotropy" type="float" value="0.0" />
<output name="out" type="VDF" />
</nodedef>
<!-- ======================================================================== -->
<!-- Shader Nodes -->
<!-- ======================================================================== -->
<!--
Node: <surface>
Construct a surface shader from scattering and emission distribution functions.
-->
<nodedef name="ND_surface" node="surface" nodegroup="pbr" doc="A constructor node for the surfaceshader type.">
<input name="bsdf" type="BSDF" value="" doc="Distribution function for surface scattering." />
<input name="edf" type="EDF" value="" doc="Distribution function for surface emission." />
<input name="opacity" type="float" value="1.0" doc="Surface cutout opacity" />
<output name="out" type="surfaceshader" />
</nodedef>
<!--
Node: <thin_surface>
Construct a surface shader from scattering and emission distribution functions for non-closed "thin" objects.
-->
<nodedef name="ND_thin_surface" node="thin_surface" nodegroup="pbr" doc="A constructor node for the surfaceshader type for non-closed 'thin' objects.">
<input name="front_bsdf" type="BSDF" value="" doc="Distribution function for front-side surface scattering." />
<input name="front_edf" type="EDF" value="" doc="Distribution function for front-side surface emission." />
<input name="back_bsdf" type="BSDF" value="" doc="Distribution function for back-side surface scattering." />
<input name="back_edf" type="EDF" value="" doc="Distribution function for back-side surface emission." />
<input name="opacity" type="float" value="1.0" doc="Surface cutout opacity" />
<output name="out" type="surfaceshader" />
</nodedef>
<!--
Node: <volume>
Construct a volume shader describing a participating medium.
-->
<nodedef name="ND_volume" node="volume" nodegroup="pbr" doc="A constructor node for the volumeshader type.">
<input name="vdf" type="VDF" value="" doc="Volume distribution function for the medium." />
<input name="edf" type="EDF" value="" doc="Emission distribution function for the medium." />
<output name="out" type="volumeshader" />
</nodedef>
<!--
Node: <light>
Construct a light shader from emission distribution functions.
-->
<nodedef name="ND_light" node="light" nodegroup="pbr" doc="A constructor node for the lightshader type.">
<input name="edf" type="EDF" value="" doc="Distribution function for light emission." />
<input name="intensity" type="float" value="1.0" doc="Multiplier for the light intensity" />
<input name="exposure" type="float" value="0.0" doc="Exposure control for the light intensity" />
<output name="out" type="lightshader" />
</nodedef>
<!--
Node: <displacement>
Construct a displacement shader.
-->
<nodedef name="ND_displacement_float" node="displacement" nodegroup="pbr" doc="A constructor node for the displacementshader type.">
<input name="displacement" type="float" value="0.0" doc="Scalar displacement amount along the surface normal direction." />
<input name="scale" type="float" value="1.0" doc="Scale factor for the displacement vector" />
<output name="out" type="displacementshader" />
</nodedef>
<nodedef name="ND_displacement_vector3" node="displacement" nodegroup="pbr" doc="A constructor node for the displacementshader type.">
<input name="displacement" type="vector3" value="0.0, 0.0, 0.0" doc="Vector displacement in (dPdu, dPdv, N) tangent/normal space." />
<input name="scale" type="float" value="1.0" doc="Scale factor for the displacement vector" />
<output name="out" type="displacementshader" />
</nodedef>
<!-- ======================================================================== -->
<!-- Utility Nodes -->
<!-- ======================================================================== -->
<!--
Node: <layer>
-->
<nodedef name="ND_layer_bsdf" node="layer" nodegroup="pbr" defaultinput="top" doc="Layer two BSDF's with vertical layering.">
<input name="top" type="BSDF" value="" />
<input name="base" type="BSDF" value="" />
<output name="out" type="BSDF" />
</nodedef>
<nodedef name="ND_layer_vdf" node="layer" nodegroup="pbr" defaultinput="top" doc="Layer a BSDF over a VDF describing the interior media.">
<input name="top" type="BSDF" value="" />
<input name="base" type="VDF" value="" />
<output name="out" type="BSDF" />
</nodedef>
<!--
Node: <mix>
-->
<nodedef name="ND_mix_bsdf" node="mix" nodegroup="pbr" defaultinput="bg" doc="Mix two BSDF's according to an input mix amount.">
<input name="fg" type="BSDF" value="" />
<input name="bg" type="BSDF" value="" />
<input name="mix" type="float" value="0.0" uimin="0.0" uimax="1.0" doc="Mixing weight, range [0, 1]." />
<output name="out" type="BSDF" />
</nodedef>
<nodedef name="ND_mix_edf" node="mix" nodegroup="pbr" defaultinput="bg" doc="Mix two EDF's according to an input mix amount.">
<input name="fg" type="EDF" value="" />
<input name="bg" type="EDF" value="" />
<input name="mix" type="float" value="0.0" uimin="0.0" uimax="1.0" doc="Mixing weight, range [0, 1]." />
<output name="out" type="EDF" />
</nodedef>
<nodedef name="ND_mix_vdf" node="mix" nodegroup="pbr" defaultinput="bg" doc="Mix two VDF's according to an input mix amount.">
<input name="fg" type="VDF" value="" />
<input name="bg" type="VDF" value="" />
<input name="mix" type="float" value="0.0" uimin="0.0" uimax="1.0" doc="Mixing weight, range [0, 1]." />
<output name="out" type="VDF" />
</nodedef>
<!--
Node: <add>
-->
<nodedef name="ND_add_bsdf" node="add" nodegroup="pbr" defaultinput="bg" doc="A node for additive blending of BSDF's.">
<input name="in1" type="BSDF" value="" doc="First BSDF." />
<input name="in2" type="BSDF" value="" doc="Second BSDF." />
<output name="out" type="BSDF" />
</nodedef>
<nodedef name="ND_add_edf" node="add" nodegroup="pbr" defaultinput="bg" doc="A node for additive blending of EDF's.">
<input name="in1" type="EDF" value="" doc="First EDF." />
<input name="in2" type="EDF" value="" doc="Second EDF." />
<output name="out" type="EDF" />
</nodedef>
<nodedef name="ND_add_vdf" node="add" nodegroup="pbr" defaultinput="bg" doc="A node for additive blending of VDF's.">
<input name="in1" type="VDF" value="" doc="First VDF." />
<input name="in2" type="VDF" value="" doc="Second VDF." />
<output name="out" type="VDF" />
</nodedef>
<!--
Node: <multiply>
-->
<nodedef name="ND_multiply_bsdfC" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of a BSDF with a weight.">
<input name="in1" type="BSDF" value="" doc="The BSDF to scale." />
<input name="in2" type="color3" value="1.0, 1.0, 1.0" doc="Scaling weight." />
<output name="out" type="BSDF" />
</nodedef>
<nodedef name="ND_multiply_bsdfF" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of a BSDF with a weight.">
<input name="in1" type="BSDF" value="" doc="The BSDF to scale." />
<input name="in2" type="float" value="1.0" doc="Scaling weight." />
<output name="out" type="BSDF" />
</nodedef>
<nodedef name="ND_multiply_edfC" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of an EDF with a weight.">
<input name="in1" type="EDF" value="" doc="The EDF to scale." />
<input name="in2" type="color3" value="1.0, 1.0, 1.0" doc="Scaling weight." />
<output name="out" type="EDF" />
</nodedef>
<nodedef name="ND_multiply_edfF" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of an EDF with a weight.">
<input name="in1" type="EDF" value="" doc="The EDF to scale." />
<input name="in2" type="float" value="1.0" doc="Scaling weight." />
<output name="out" type="EDF" />
</nodedef>
<nodedef name="ND_multiply_vdfC" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of an VDF with a weight.">
<input name="in1" type="VDF" value="" doc="The VDF to scale." />
<input name="in2" type="color3" value="1.0, 1.0, 1.0" doc="Scaling weight." />
<output name="out" type="VDF" />
</nodedef>
<nodedef name="ND_multiply_vdfF" node="multiply" nodegroup="pbr" defaultinput="in1" doc="A node for adjusting the contribution of an VDF with a weight.">
<input name="in1" type="VDF" value="" doc="The VDF to scale." />
<input name="in2" type="float" value="1.0" doc="Scaling weight." />
<output name="out" type="VDF" />
</nodedef>
<!--
Node: <roughness_anisotropy>
Calculates anisotropic surface roughness from a scalar roughness and anisotropy parameterization.
-->
<nodedef name="ND_roughness_anisotropy" node="roughness_anisotropy" nodegroup="pbr" doc="Calculates anisotropic surface roughness from a scalar roughness/anisotropy parameterization.">
<input name="roughness" type="float" value="0.0" />
<input name="anisotropy" type="float" value="0.0" />
<output name="out" type="vector2" />
</nodedef>
<!--
Node: <roughness_dual>
Calculates anisotropic surface roughness from a dual surface roughness parameterization.
-->
<nodedef name="ND_roughness_dual" node="roughness_dual" nodegroup="pbr" doc="Calculates anisotropic surface roughness from a dual surface roughness parameterization.">
<input name="roughness" type="vector2" value="0.0, 0.0" />
<output name="out" type="vector2" />
</nodedef>
<!--
Node: <glossiness_anisotropy>
Calculates anisotropic surface roughness from a scalar glossiness and anisotropy parameterization.
-->
<nodedef name="ND_glossiness_anisotropy" node="glossiness_anisotropy" nodegroup="pbr" doc="Calculates anisotropic surface roughness from a scalar glossiness/anisotropy parameterization.">
<input name="glossiness" type="float" value="1.0" uimin="0.0" uimax="1.0" />
<input name="anisotropy" type="float" value="0.0" uimin="0.0" uimax="1.0" />
<output name="out" type="vector2" />
</nodedef>
<!--
Node: <blackbody>
Returns the radiant emittance of a blackbody radiator with the given temperature.
-->
<nodedef name="ND_blackbody" node="blackbody" nodegroup="pbr" doc="Returns the radiant emittance of a blackbody radiator with the given temperature.">
<input name="temperature" type="float" value="5000.0" />
<output name="out" type="color3" />
</nodedef>
<!--
Node: <artistic_ior>
Converts the artistic parameterization reflectivity and edge_color to complex IOR values.
-->
<nodedef name="ND_artistic_ior" node="artistic_ior" nodegroup="pbr" doc="Converts the artistic parameterization reflectivity and edge_color to complex IOR values.">
<input name="reflectivity" type="color3" value="0.944, 0.776, 0.373" colorspace="lin_rec709" />
<input name="edge_color" type="color3" value="0.998, 0.981, 0.751" colorspace="lin_rec709" />
<output name="ior" type="color3" />
<output name="extinction" type="color3" />
</nodedef>
</materialx>
@@ -0,0 +1,22 @@
<?xml version="1.0"?>
<materialx version="1.38">
<!--
Copyright Contributors to the MaterialX Project
SPDX-License-Identifier: Apache-2.0
Graph definitions of standard nodes included in the MaterialX specification.
-->
<!-- <glossiness_anisotropy> -->
<nodegraph name="IMP_glossiness_anisotropy" nodedef="ND_glossiness_anisotropy">
<invert name="invert1" type="float">
<input name="in" type="float" interfacename="glossiness" />
</invert>
<roughness_anisotropy name="roughness1" type="vector2">
<input name="roughness" type="float" nodename="invert1" />
<input name="anisotropy" type="float" interfacename="anisotropy" />
</roughness_anisotropy>
<output name="out" type="vector2" nodename="roughness1" />
</nodegraph>
</materialx>