Version 1.39
Niklas Harrysson - Lumiere Software
Doug Smythe - Industrial Light & Magic
Jonathan Stone - Lucasfilm Advanced Development Group
June 5, 2026
The MaterialX Specification describes a number of standard nodes that may be used to construct node graphs for the processing of images, procedurally-generated values, coordinates and other data. With the addition of user-defined custom nodes, it is possible to describe complete rendering shaders using node graphs. Up to this point, there has been no standardization of the specific shader-semantic nodes used in these node graph shaders, although with the widespread shift toward physically-based shading, it appears that the industry is settling upon a number of specific BSDF and other functions with standardized parameters and functionality.
This document describes a number of shader-semantic nodes implementing widely-used surface scattering, emission and volume distribution functions and utility nodes useful in constructing complex layered rendering shaders using node graphs. These nodes in combination with other nodes may be used with the MaterialX Shader Generation system.
Physical Material Model
Scope
Physically Plausible Materials
Quantities and Units
Color Management
Surfaces
Layering
Bump and Normal Mapping
Volumes
Lights
Scattering Framework
Symbols
Media, Interfaces, and Scattering Events
Bidirectional Scattering Distribution Function
Emission Distribution Function
Reflection and Transmission
Diffuse, Glossy, and Specular
Reflectance Models
Microfacet Model
Directional Albedo and Energy Conservation
Vertical-Layering Transmittance
Thin-Film Iridescence
Light Transport
The Light Transport Equation
The Equation of Transfer
MaterialX PBS Library
Data Types
BSDF Nodes
EDF Nodes
VDF Nodes
PBR Shader Nodes
Utility Nodes
Shading Models
Shading Model Notation
Shared Functions
Autodesk Standard Surface
UsdPreviewSurface
Khronos glTF PBR
OpenPBR Surface
Additional Reference Implementations
Appendix: Extended Reflectance Models
EON Reflectance Model
Subsurface Scattering Model
Zeltner Sheen Model
Chiang Hair Model
Thin-Film Iridescence Model
This section describes the material model used in the MaterialX Physically Based Shading (PBS) library and the rules we must follow to be physically plausible.
A material describes the properties of a surface or medium that involves how it reacts to light. To be efficient, a material model is split into different parts, where each part handles a specific type of light interaction: light being scattered at the surface, light being emitted from a surface, light being scattered inside a medium, etc. The goal of our material model definition is to describe light-material interactions typical for physically plausible rendering systems, including those in feature film production, real-time preview, and game engines.
Our model has support for surface materials, which includes scattering and emission of light from the surface of objects, and volume materials, which includes scattering and emission of light within a participating medium. For lighting, we support local lights and distant light from environments. Geometric modification is supported in the form of bump and normal mapping as well as displacement mapping.
The initial requirements for a physically-plausible material are that it 1) should be energy conserving and 2) support reciprocity. The energy conserving says that the sum of reflected and transmitted light leaving a surface must be less than or equal to the amount of light reaching it. The reciprocity requirement says that if the direction of the traveling light is reversed, the response from the material remains unchanged. That is, the response is identical if the incoming and outgoing directions are swapped. All materials implemented for ShaderGen should respect these requirements and only in rare cases deviate from it when it makes sense for the purpose of artistic freedom.
Radiometric quantities are used by the material model for interactions with the renderer. The fundamental radiometric quantity is radiance (measured in
When the renderer operates in RGB rather than on a full spectrum, each of the red, green, and blue channels carries the convolution of a spectral radiance distribution with a sensor response function, so the quantity actually transported is neither spectral radiance nor luminance, but an integrated radiance, also called a tristimulus weight. The radiometric units used throughout this document should therefore be understood as nominal: they identify the physical quantity that each value represents in an idealized spectral sense, and fix the relative scaling between quantities, while the absolute scale of emission and the mapping to displayed pixel values are governed by the renderer's exposure and color-management conventions.
The interpretation of the data types returned by surface and volume shaders are unspecified, and left to the renderer and the shader generator for that renderer to decide. For an OpenGL-type renderer they will be tuples of floats containing radiance calculated directly by the shader node, but for an OSL-type renderer they may be closure primitives that are used by the renderer in the light transport simulation.
In general, a color given as input to the renderer is considered to represent a linear RGB color space. However, there is nothing stopping a renderer from interpreting the color type differently, for instance to hold spectral values. In that case, the shader generator for that renderer needs to handle this in the implementation of the nodes involving the color type.
MaterialX supports the use of color management systems to associate colors with specific color spaces. A MaterialX document typically specifies the working color space that is to be used for the document as well as the color space in which input values and textures are given. If these color spaces are different from the rendering color space, it is the application's and shader generator's responsibility to transform them.
The ShaderGen module has an interface that can be used to integrate support for different color management systems. Two implementations are provided: a built-in default color management system that supports a baseline set of ASWF color spaces; and an optional OpenColorIO color management system integration which provides support for a wider set of color spaces.
In our surface shading model the scattering and emission of light is controlled by distribution functions. Incident light can be reflected off, transmitted through, or absorbed by a surface. This is represented by a Bidirectional Scattering Distribution Function (BSDF). Light can also be emitted from a surface, for instance from a light source or glowing material. This is represented by an Emission Distribution Function (EDF). The PBS library introduces the data types BSDF and EDF to represent the distribution functions, and there are nodes for constructing, combining and manipulating them.
Another important property is the index of refraction (IOR), which describes how light is propagated through a medium. It controls how much a light ray is bent when crossing the interface between two media of different refractive indices. It also determines the amount of light that is reflected and transmitted when reaching the interface, as described by the Fresnel equations.
A surface shader is represented with the data type surfaceshader. In the PBS library there is a <surface> node that constructs a surface shader from a BSDF and an EDF. Since there are nodes to combine and modify them, you can easily build surface shaders from different combinations of distribution functions. Inputs on the distribution function nodes can be connected, and nodes from the standard library can be combined into complex calculations, giving flexibility for the artist to author material variations over the surfaces.
It is common for shading models to differentiate between closed surfaces and thin-walled surfaces. A closed surface represents a closed watertight interface with a solid interior. A typical example is a solid glass object. A thin-walled surface on the other hand has an infinitely thin volume, as with a sheet of paper or a soap bubble. For a closed surface there can be no backside visible if the material is opaque. In the case of a transparent closed surface a backside hit is treated as light exiting the closed interface. For a thin-walled surface both the front and back side are visible and it can either have the same material on both sides or different materials on each side. If the material is transparent in this case the thin wall makes the light transmit without refraction or scattering. By default the <surface> node constructs a surface shader for a closed surface, but there is a boolean switch to make it thin-walled.
In order to assign different shaders to each side of a thin-walled object the <surfacematerial> node in the standard library has an input to connect an extra backside surface shader. If any of the sides of a <surfacematerial> has a thin-walled shader connected, both sides are considered to be thin-walled. Hence the thin-walled property takes precedence to avoid ambiguity between the sides. If only one side has a shader connected this is used for both sides. If both sides are connected but none of the shaders are thin-walled the front shader is used. The thin-walled property also takes precedence in the case of mixing surface shaders. If any of the shaders involved in the mix is thin-walled, both shaders are considered to be thin-walled.
Note that in order to have surface shaders set for both sides the geometry has to be set as double-sided. Geometry sidedness is a property not handled by MaterialX and needs to be set elsewhere.
In order to simplify authoring of complex materials, our model supports the notion of layering. Typical examples include: adding a layer of clear coat over a car paint material, or putting a layer of dirt or rust over a metal surface. Layering can be done in a number of different ways:
- Horizontal Layering: A simple way of layering is using per-shading-point linear mixing of different BSDFs where a mix factor is given per BSDF controlling its contribution. Since the weight is calculated per shading point it can be used as a mask to hide contributions on different parts of a surface. The weight can also be calculated dependent on view angle to simulate approximate Fresnel behavior. This type of layering can be done both on a BSDF level and on a surface shader level. The latter is useful for mixing complete shaders which internally contain many BSDFs, e.g. to put dirt over a car paint, grease over a rusty metal or adding decals to a plastic surface. We refer to this type of layering as horizontal layering and the <mix> node in the PBS library can be used to achieve this (see below).
- Vertical Layering: A more physically correct form of layering is also supported where a top BSDF layer is placed over another base BSDF layer, and the light not reflected by the top layer is assumed to be transmitted to the base layer; for example, adding a dielectric coating layer over a substrate. The refraction index and roughness of the coating will then affect the attenuation of light reaching the substrate. The substrate can be a transmissive BSDF, transmitting the light further into lower layers, or a reflective BSDF, reflecting the light back up through the coating to simulate multiple specular lobes. We refer to this type of layering as vertical layering and it can be achieved using the <layer> node in the PBS library. See <dielectric_bsdf> and <sheen_bsdf> below. Every BSDF in the PBS library may be used as the top layer of a vertical layering operation, with the fraction of light it passes on to its base defined by its vertical-layering transmittance.
- Shader Input Blending: Calculating and blending many BSDFs or separate surface shaders can be expensive. In some situations good results can be achieved by blending the texture/value inputs instead, before any illumination calculations. Typically one would use this with an über-shader that can simulate many different materials, and by masking or blending its inputs over the surface you get the appearance of having multiple layers, but with less expensive texture or value blending. Examples of this are given in the main MaterialX Specification "Pre-Shader Compositing Example".
The surface normal used for shading calculations is supplied as input to each BSDF that requires it. The normal can be perturbed by bump or normal mapping, before it is given to the BSDF. As a result, one can supply different normals for different BSDFs for the same shading point. When layering BSDFs, each layer can use different bump and normal maps.
In our volume shader model the scattering of light in a participating medium is controlled by a volume distribution function (VDF), with coefficients controlling the rate of absorption and scattering. The VDF represents what physicists call a phase function, describing how the light is distributed from its current direction when it is scattered in the medium. This is analogous to how a BSDF describes scattering at a surface, but with one important difference: a VDF is normalized, summing to 1.0 if all directions are considered. Additionally, the amount of absorption and scattering is controlled by coefficients that gives the rate (probability) per distance traveled in world space. The absorption coefficient sets the rate (per unit-length) of absorption of light energy traveling through the medium, and the scattering coefficient sets the rate (per unit-length) at which the light is scattered from its current direction. The units for these are
Light can also be emitted from a volume. This is represented by an EDF analog to emission from surfaces, but in this context the emission is given as radiance per distance traveled through the medium. The unit for this is
The <volume> node in the PBS library constructs a volume shader from individual VDF and EDF components. There are also nodes to construct various VDFs, as well as nodes to combine them to build more complex ones.
VDFs can also be used to describe the interior of a surface. A typical example would be to model how light is absorbed or scattered when transmitted through colored glass or turbid water. This is done by layering a BSDF for the surface transmission over the VDF using a <layer> node.
Light sources can be divided into environment lights and local lights. Environment lights represent contributions coming from infinitely far away. All other lights are local lights and have a position and extent in space.
Local lights are specified as light shaders assigned to a locator, modeling an explicit light source, or in the form of emissive geometry using an emissive surface shader. The <light> node in the PBS library constructs a light shader from an EDF. There are also nodes to construct various EDFs as well as nodes to combine them to build more complex ones. Emissive properties of surface shaders are also modelled using EDFs; see the EDF Nodes section below for more information.
Light contributions coming from far away are handled by environment lights. These are typically photographically-captured or procedurally-generated images that surround the whole scene. This category of lights also includes sources like the sun, where the long distance traveled makes the light essentially directional and without falloff. For all shading points, an environment is seen as being infinitely far away.
The Surfaces and Volumes sections above introduce the BSDF, EDF, and VDF informally. This section defines the formal notation, the scattering and emission distribution functions, and the descriptive terminology used by the per-node equations in the MaterialX PBS Library chapter below.
In scattering equations, the subscript
| Symbol | Description |
|---|---|
| Incident radiance at |
|
| Exitant radiance at |
|
| Emitted radiance at |
|
| Position of a scattering event on a surface or in a volume | |
| Unit surface normal vector at |
|
| Direction from |
|
| Direction from |
|
| Half-vector between |
|
| Elevation angle of a direction from the surface normal | |
| Elevation angle of the incident direction | |
| Elevation angle of the exitant direction | |
| Elevation angle of the exitant transmitted direction, measured from the inverted surface normal | |
| Azimuthal angle of a direction around the surface normal | |
| Azimuthal angle of the incident direction | |
| Azimuthal angle of the exitant direction | |
| Hemisphere of incident directions around the surface normal | |
| Unit sphere of directions around |
|
| Absolute index of refraction of the medium on the incident side of an interface | |
| Absolute index of refraction of the medium on the transmitted side of an interface | |
| Relative index of refraction across an interface |
A medium is a distribution of matter contained in some (possibly infinite or semi-infinite) region of space; its properties dictate how it interacts with electromagnetic radiation such as visible light. An interface is a boundary between two media of different properties. A volume is a three-dimensional region of space containing a medium, and a surface is a geometric representation of an interface.
A scattering event occurs when radiance arriving at a position
The bidirectional scattering distribution function (BSDF) describes the proportion of radiance scattered at a surface from an incoming direction
The bidirectional reflectance distribution function
Further specializations include the bidirectional curve-scattering distribution function
The emission distribution function (EDF) describes the radiance emitted at a position
where
Reflection is a scattering event where the exitant direction
Transmission is a scattering event where
The reflectance and transmittance are the fractions of incident energy leaving a scattering event via reflection and transmission, respectively.
The reflection direction
The refraction direction
The terms diffuse, glossy, and specular offer a perceptual classification of scattering distributions. They are not precisely defined, but are useful when describing and comparing BSDFs. The distinction concerns how broadly or narrowly the scattered energy is distributed across exitant directions, rather than which directions receive energy:
- Diffuse: scattered energy is spread broadly across a hemisphere (either upper or lower) around the surface normal, varying only gradually with exitant direction.
- Specular: scattered energy is concentrated entirely, or almost entirely, along the reflection or refraction direction. The idealized perfectly specular case is a Dirac delta distribution that carries all of its energy in that single direction.
- Glossy: scattered energy is concentrated about the reflection or refraction direction but spread more broadly than in the specular case, forming the intermediate regime between diffuse and specular.
This section defines the shared reflectance models referenced by multiple BSDF nodes in the MaterialX PBS Library below.
The <dielectric_bsdf>, <conductor_bsdf>, and <generalized_schlick_bsdf> nodes share a microfacet model1 in which a surface is treated as a collection of infinitesimal, perfectly specular mirrors (microfacets) whose orientations are distributed around the macroscopic surface normal. All three nodes use the microfacet BRDF for reflection. The <dielectric_bsdf> and <generalized_schlick_bsdf> nodes additionally use the microfacet BTDF for transmission when scatter_mode is set to T or RT.
Both the BRDF and BTDF share a common normal distribution function
The retroreflective input of the <dielectric_bsdf>, <conductor_bsdf>, and <generalized_schlick_bsdf> nodes modifies only the reflection lobe. For the <dielectric_bsdf> and <generalized_schlick_bsdf> nodes it therefore applies when scatter_mode is R or RT, and has no effect when scatter_mode is T. The <conductor_bsdf> node has no scatter_mode input and is always reflective, so its retroreflective input always applies.
where
The microfacet BTDF uses a transmission half-vector that accounts for the change in index of refraction across the interface:
where
where
The microfacet normal distribution is the anisotropic GGX (Trowbridge-Reitz) function1:
where
The pair roughness input of each microfacet node, with no internal remapping. These low-level values may be computed from perceptual roughness and glossiness parameterizations using the <roughness_anisotropy>, <roughness_dual>, and <glossiness_anisotropy> utility nodes.
The joint masking-shadowing function is the height-correlated form of the Smith function2. Define the direction-dependent stretched-vector length:
Then:
This is equivalent to evaluating the Smith
The directional albedo
The directional albedo of a node's reflection lobes, evaluated with its physical Fresnel reflectance, determines the vertical-layering transmittance of an interface BSDF, referenced by the <layer> node when vertically layering a top BSDF over a base.
The single-scattering microfacet BRDF does not account for light that scatters multiple times between microfacets before leaving the surface. As roughness increases, the energy lost to these unmodeled paths becomes significant, and is compensated using a multiplicative correction factor3:
where
Every BSDF defines a vertical-layering transmittance
-
Interface BSDFs — <dielectric_bsdf>, <generalized_schlick_bsdf>, and <sheen_bsdf> — represent thin interfaces and coatings that transmit all of the energy they neither reflect nor absorb, giving
$T_o = 1 - E_o$ , where the directional albedo is evaluated over the node's reflection lobes alone, so that light transmitted rather than reflected by a transmissive scatter mode continues to the layers beneath. -
Opaque BSDFs — <oren_nayar_diffuse_bsdf>, <burley_diffuse_bsdf>, <conductor_bsdf>, <subsurface_bsdf>, <translucent_bsdf>, and <chiang_hair_bsdf> — reflect, scatter, or absorb all of the light reaching them, transmitting none through the lobe itself. For these nodes the
weightinput$w$ acts as a statistical coverage of the surface, with the covered fraction fully occluding lower layers and the uncovered fraction passing light through unchanged, giving$T_o = 1 - w$ .
The directional albedo of an interface BSDF is evaluated for this purpose with the node's physical Fresnel reflectance alone, omitting non-physical color inputs such as the tint of <dielectric_bsdf> and the color of <sheen_bsdf>. These inputs attenuate only the scattered response, and the energy they remove is classified as absorption within the interface rather than transmission to the base. In contrast, the Schlick reflectance inputs of <generalized_schlick_bsdf> parameterize the physical Fresnel curve itself, and thus contribute to a color-valued transmittance for that node, as does the Airy reflectance of a thin-film interface.
An opaque BSDF with a weight of zero is thus completely transparent with respect to vertical layering, while an opaque BSDF with a weight of one fully occludes its base, and layering an opaque BSDF over a base is equivalent to a <mix> of the two BSDFs with the coverage as the mixing weight. Since <chiang_hair_bsdf> has no weight input, it takes on an implicit unit coverage.
The <mix> and <layer> nodes compose the transmittances of their inputs, as given in each node's section, so the vertical-layering transmittance is well-defined for graphs of elemental BSDFs combined by these nodes, with the exceptions noted below. The composition of transmittance by the <add> and <multiply> nodes is not yet defined by this specification, and is reserved for a future revision. The transmittance of a medium-bound BSDF nested as a top layer is likewise reserved, as described in Layering over a VDF. These composition rules define the reference transmittance-scaling model. Within this model, the transmittance
For an energy-conserving BSDF, the directional albedo of the reflection lobes never exceeds the occluded fraction of incident light,
The <dielectric_bsdf>, <conductor_bsdf>, and <generalized_schlick_bsdf> nodes support an optional thin-film interference effect5. A thin dielectric film of thickness
When thinfilm_thickness is set to a non-zero value, the standard Fresnel reflectance
where
The BSDF and EDF describe scattering and emission at a single point. The equations in this section describe how those local distributions, together with the radiance arriving from the rest of the scene, determine the radiance leaving a point, following the formulation of Pharr et al.6. The <surface>, <volume>, and <light> shader nodes assemble per-node BSDFs, EDFs, and VDFs into these equations.
For a surface, the exitant radiance
where
For a participating medium, radiance is continuously attenuated by absorption and out-scattering and augmented by emission and in-scattering. The change in radiance
The first term attenuates radiance by the extinction coefficient
MaterialX includes a library of types and nodes for creating physically plausible materials and lights as described above. This section outlines the content of that library.
BSDF: Data type representing a Bidirectional Scattering Distribution Function.EDF: Data type representing an Emission Distribution Function.VDF: Data type representing a Volume Distribution Function.
The PBS nodes also make use of the following standard MaterialX types:
surfaceshader: Data type representing a surface shader.lightshader: Data type representing a light shader.volumeshader: Data type representing a volume shader.displacementshader: Data type representing a displacement shader.
The equations below use the symbols and notation defined in the Scattering Framework, together with the shared reflectance models defined in Reflectance Models.
Constructs a diffuse reflection BSDF based on the Oren-Nayar reflectance model. As an opaque BSDF, this node occludes any vertically layered base in proportion to its weight input, as described in the Vertical-Layering Transmittance section.
A roughness of 0.0 gives Lambertian reflectance.
An energy_compensation boolean selects between the Qualitative Oren-Nayar7 and Energy-Preserving Oren-Nayar8 models of diffuse reflectance.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color |
Diffuse reflectivity or albedo | color3 | 0.18, 0.18, 0.18 | |
roughness |
Surface roughness | float | 0.0 | [0, 1] |
normal |
Normal vector of the surface | vector3 | Nworld | |
energy_compensation |
Enable energy compensation for the BSDF | boolean | false | |
out |
Output: the computed BSDF | BSDF |
In the equations below, the color input corresponds to roughness input corresponds to
When energy_compensation is enabled, the EON model8 decomposes the BRDF into a single-scatter lobe based on Fujii's improved Oren-Nayar formulation9 and a multi-scatter lobe that compensates for inter-reflection energy lost at higher roughness values. The full derivation is given in the EON Reflectance Model appendix.
Constructs a diffuse reflection BSDF based on the corresponding component of the Disney Principled model10. As an opaque BSDF, this node occludes any vertically layered base in proportion to its weight input, as described in the Vertical-Layering Transmittance section.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color |
Diffuse reflectivity or albedo | color3 | 0.18, 0.18, 0.18 | |
roughness |
Surface roughness | float | 0.0 | [0, 1] |
normal |
Normal vector of the surface | vector3 | Nworld | |
out |
Output: the computed BSDF | BSDF |
In the equations below, the color input corresponds to roughness input corresponds to
The model uses a modified Schlick Fresnel factor with
Constructs a reflection and/or transmission BSDF based on a microfacet reflectance model and a Fresnel curve for dielectrics1. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <dielectric_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc.
Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation3 being a popular implementation strategy.
The tint input colors the reflected and transmitted light but should be left at white (1,1,1) for physically correct results. Setting the ior input to zero disables the Fresnel curve, allowing reflectivity to be controlled purely by weight and tint.
Setting retroreflective to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction11.
Thin-film iridescence effects5 may be enabled by setting thinfilm_thickness to a non-zero value.
The scatter_mode controls whether the surface reflects light (R), transmits light (T), or both (RT). In RT mode, reflection and transmission occur both when entering and leaving a surface, with their respective intensities controlled by the Fresnel curve. Depending on the IOR and incident angle, total internal reflection may occur even when transmission modes are selected.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
tint |
Color weight to tint the reflected and transmitted light | color3 | 1.0, 1.0, 1.0 | |
ior |
Index of refraction of the surface | float | 1.5 | |
roughness |
Surface roughness along the tangent and bitangent | vector2 | 0.05, 0.05 | [0, 1] |
retroreflective |
Enable retroreflection mode for the BSDF | boolean | false | |
thinfilm_thickness |
Thickness of the iridescent thin-film layer in nanometers | float | 0.0 | |
thinfilm_ior |
Index of refraction of the thin-film layer | float | 1.5 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
tangent |
Tangent vector of the surface | vector3 | Tworld | |
distribution |
Microfacet distribution type | string | ggx | ggx |
scatter_mode |
Surface Scatter mode, specifying reflection and/or transmission | string | R | R, T, RT |
out |
Output: the computed BSDF | BSDF |
In the equations below, the tint input corresponds to ior input corresponds to roughness input provides the pair
The tint
The Fresnel reflectance
When
When thinfilm_thickness is non-zero, the Fresnel reflectance ior input
Constructs a reflection BSDF based on a microfacet reflectance model10. Uses a Fresnel curve with complex refraction index for conductors/metals. If an artistic parametrization13 is needed the <artistic_ior> utility node can be connected to handle this. As an opaque BSDF, this node occludes any vertically layered base in proportion to its weight input, as described in the Vertical-Layering Transmittance section.
Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation3 being a popular implementation strategy.
The default values for ior and extinction represent approximate values for gold.
Setting retroreflective to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction11.
Thin-film iridescence effects5 may be enabled by setting thinfilm_thickness to a non-zero value.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
ior |
Index of refraction | color3 | 0.183, 0.421, 1.373 | |
extinction |
Extinction coefficient | color3 | 3.424, 2.346, 1.770 | |
roughness |
Surface roughness along the tangent and bitangent | vector2 | 0.05, 0.05 | [0, 1] |
retroreflective |
Enable retroreflection mode for the BSDF | boolean | false | |
thinfilm_thickness |
Thickness of the iridescent thin-film layer in nanometers | float | 0.0 | |
thinfilm_ior |
Index of refraction of the thin-film layer | float | 1.5 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
tangent |
Tangent vector of the surface | vector3 | Tworld | |
distribution |
Microfacet distribution type | string | ggx | ggx |
out |
Output: the computed BSDF | BSDF |
In the equations below, the ior input corresponds to extinction input corresponds to roughness input provides the pair
The reflectance
When thinfilm_thickness is non-zero, the Fresnel reflectance
Constructs a reflection and/or transmission BSDF based on a microfacet model and a generalized Schlick Fresnel curve14. If reflection scattering is enabled the node may be layered vertically over a base BSDF for the surface beneath the dielectric layer. By chaining multiple <generalized_schlick_bsdf> nodes you can describe a surface with multiple specular lobes. If transmission scattering is enabled the node may be layered over a VDF describing the surface interior to handle absorption and scattering inside the medium, useful for colored glass, turbid water, etc.
Implementations are expected to preserve energy as the roughness of the surface increases, with multiple scattering compensation3 being a popular implementation strategy.
The color82 input provides a multiplier on reflectivity at 82 degrees, useful for capturing the characteristic "dip" in the reflectance curve of metallic surfaces. Setting it to (1,1,1) effectively disables this feature for backward compatibility.
Unlike the artistic tint of <dielectric_bsdf>, the Schlick reflectance inputs of this node parameterize its physical Fresnel curve, so they contribute to the node's color-valued vertical-layering transmittance.
Setting retroreflective to true switches the BSDF to retroreflection mode, where light is reflected back toward the incoming direction rather than the mirror reflection direction11.
Thin-film iridescence effects5 may be enabled by setting thinfilm_thickness to a non-zero value.
The scatter_mode behavior matches that of dielectric_bsdf: in RT mode, reflection and transmission occur both when entering and leaving a surface, with intensities controlled by the Fresnel curve. Total internal reflection may occur depending on the incident angle.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color0 |
Reflectivity per color component at facing angles | color3 | 1.0, 1.0, 1.0 | |
color82 |
Reflectivity multiplier at 82 degrees | color3 | 1.0, 1.0, 1.0 | |
color90 |
Reflectivity per color component at grazing angles | color3 | 1.0, 1.0, 1.0 | |
exponent |
Exponent for Schlick blending between color0 and color90 | float | 5.0 | |
roughness |
Surface roughness along the tangent and bitangent | vector2 | 0.05, 0.05 | [0, 1] |
retroreflective |
Enable retroreflection mode for the BSDF | boolean | false | |
thinfilm_thickness |
Thickness of the iridescent thin-film layer in nanometers | float | 0.0 | |
thinfilm_ior |
Index of refraction of the thin-film layer | float | 1.5 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
tangent |
Tangent vector of the surface | vector3 | Tworld | |
distribution |
Microfacet distribution type | string | ggx | ggx |
scatter_mode |
Surface Scatter mode, specifying reflection and/or transmission | string | R | R, T, RT |
out |
Output: the computed BSDF | BSDF |
In the equations below, the color0 and color90 inputs correspond to color82 input corresponds to exponent input corresponds to roughness input provides the pair
The Hoffman14 generalization of the Schlick Fresnel curve adds a controllable dip in the reflectance at color82 multiplier
When thinfilm_thickness is non-zero, the Fresnel reflectance color0 input
Constructs a translucent (diffuse transmission) BSDF based on the Lambert reflectance model. As an opaque BSDF, this node occludes any vertically layered base in proportion to its weight input, as described in the Vertical-Layering Transmittance section.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color |
Diffuse transmittance | color3 | 1.0, 1.0, 1.0 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
out |
Output: the computed BSDF | BSDF |
In the equation below, the color input corresponds to
The node implements a Lambertian BTDF, the transmission analog of the Lambertian BRDF. Incident light is scattered uniformly over the lower hemisphere (the opposite side of the surface from the incident direction):
Constructs a subsurface scattering BSDF for subsurface scattering within a homogeneous medium. The parameterization is chosen to match random walk Monte Carlo methods15 as well as approximate empirical methods16. This node is defined compositionally as a BSDF vertically layered over an <anisotropic_vdf>, as detailed below. As an opaque BSDF, this node occludes any vertically layered base in proportion to its weight input, as described in the Vertical-Layering Transmittance section.
The radius input sets the average distance (mean free path) that light propagates below the surface before scattering back out, and can be set independently for each color channel.
The anisotropy input controls the scattering direction: negative values produce backwards scattering, positive values produce forward scattering, and zero produces uniform scattering.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color |
Diffuse reflectivity (albedo) | color3 | 0.18, 0.18, 0.18 | |
radius |
Mean free path per color channel | color3 | 1.0, 1.0, 1.0 | |
anisotropy |
Anisotropy factor for scattering direction | float | 0.0 | [-1, 1] |
normal |
Normal vector of the surface | vector3 | Nworld | |
out |
Output: the computed BSDF | BSDF |
The node's scattering behavior is equivalent to an untinted Lambertian transmission surface — <translucent_bsdf> with unit color — vertically layered over a participating medium described by <anisotropic_vdf>. Incident light enters the medium through the surface, scatters with phase function asymmetry anisotropy input), and exits at a potentially different surface position; its coloring is determined entirely by the volumetric absorption, not by the surface transmission. The resulting distribution function therefore depends on both the incident and exitant surface positions (
The artist-facing color and radius inputs are converted to the volume's physical absorption and scattering coefficients by an albedo inversion, and a renderer may evaluate the result either directly via random-walk volumetric transport or through an equivalent normalized diffusion approximation. These conversions and the diffusion profile are given in the Subsurface Scattering Model appendix.
Constructs a microfacet BSDF for the back-scattering properties of cloth-like materials. As an interface BSDF, this node may be layered vertically over a base BSDF using a <layer> node, and all energy that is not reflected will be transmitted to the base layer. A mode option selects between two available sheen models, Conty-Kulla17 and Zeltner18.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
weight |
Weight of the BSDF contribution | float | 1.0 | [0, 1] |
color |
Sheen reflectivity | color3 | 1.0, 1.0, 1.0 | |
roughness |
Surface roughness | float | 0.3 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
mode |
Selects between conty_kulla and zeltner sheen models |
string | conty_kulla | conty_kulla, zeltner |
out |
Output: the computed BSDF | BSDF |
In the equations below, the color input corresponds to roughness input corresponds to tint of <dielectric_bsdf>, the color
When mode is set to zeltner, the Zeltner sheen model18 approximates multi-scattering cloth reflectance using a Linearly Transformed Cosine (LTC) lobe. The full derivation and fitted coefficients are given in the Zeltner Sheen Model appendix.
Constructs a hair BSDF based on the Chiang hair shading model19. As an opaque BSDF with no weight input, this node takes on an implicit unit coverage, fully occluding any vertically layered base as described in the Vertical-Layering Transmittance section.
The roughness inputs provide a longitudinal variance ior of 1.55 represents the index of refraction for keratin. The cuticle_angle is a normalized value in
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
tint_R |
Color multiplier for the first R-lobe | color3 | 1.0, 1.0, 1.0 | |
tint_TT |
Color multiplier for the first TT-lobe | color3 | 1.0, 1.0, 1.0 | |
tint_TRT |
Color multiplier for the first TRT-lobe | color3 | 1.0, 1.0, 1.0 | |
ior |
Index of refraction | float | 1.55 | |
roughness_R |
Longitudinal variance and azimuthal scale for R-lobe | vector2 | 0.1, 0.1 | [0, ∞) |
roughness_TT |
Longitudinal variance and azimuthal scale for TT-lobe | vector2 | 0.05, 0.05 | [0, ∞) |
roughness_TRT |
Longitudinal variance and azimuthal scale for TRT-lobe | vector2 | 0.2, 0.2 | [0, ∞) |
cuticle_angle |
Normalized cuticle angle | float | 0.5 | [0, 1] |
absorption_coefficient |
Absorption coefficient normalized to hair fiber diameter | vector3 | 0.0, 0.0, 0.0 | |
normal |
Normal vector of the surface | vector3 | Nworld | |
curve_direction |
Direction of the hair geometry | vector3 | Tworld | |
out |
Output: the computed BSDF | BSDF |
In the equations below, the tint_R, tint_TT, and tint_TRT inputs correspond to per-lobe color tints ior input corresponds to roughness_R, roughness_TT, and roughness_TRT inputs each provide a pair cuticle_angle input corresponds to absorption_coefficient input corresponds to
The Chiang hair model19 treats a hair fiber as a dielectric cylinder with tilted cuticle scales. Directions at a point on the fiber are parameterized by inclination
where
The equations below use the symbols, notation, and emission conventions defined in the Scattering Framework.
Constructs an EDF emitting light uniformly across the hemisphere around the surface normal.
| Port | Description | Type | Default |
|---|---|---|---|
color |
Radiant emittance of light leaving the surface | color3 | 1.0, 1.0, 1.0 |
out |
Output: the computed EDF | EDF |
In the equation below, the color input corresponds to
For a Lambertian emitter such as this, the equivalent radiant exitance (power per unit area integrated over the hemisphere) is
Constructs an EDF emitting light inside a cone around the normal direction.
Light intensity begins to fall off at the inner_angle and reaches zero at the outer_angle (both specified in degrees as full cone angles). If the outer_angle is smaller than the inner_angle, no falloff occurs within the cone.
| Port | Description | Type | Default |
|---|---|---|---|
color |
Radiant emittance of light leaving the surface | color3 | 1.0, 1.0, 1.0 |
normal |
Normal vector of the surface | vector3 | Nworld |
inner_angle |
Angle of inner cone where intensity falloff starts | float | 60.0 |
outer_angle |
Angle of outer cone where intensity goes to zero | float | 0.0 |
out |
Output: the computed EDF | EDF |
In the equations below, the color input corresponds to inner_angle and outer_angle inputs are full cone angles in degrees and are halved to obtain the angle from the cone axis.
Define:
Case 1 — no falloff (outer_angle inner_angle): a hard cutoff at the inner cone boundary.
Case 2 — smooth falloff (outer_angle inner_angle): Hermite-smoothstep interpolation in cosine space between the outer and inner cone boundaries.
where
Constructs an EDF emitting light according to a measured IES light profile.
| Port | Description | Type | Default |
|---|---|---|---|
color |
Radiant emittance of light leaving the surface | color3 | 1.0, 1.0, 1.0 |
normal |
Normal vector of the surface | vector3 | Nworld |
file |
Path to a file containing IES light profile data | filename | empty |
out |
Output: the computed EDF | EDF |
Adds a directionally varying factor to an EDF. Scales the emission distribution of the base EDF according to a generalized Schlick Fresnel curve.
| Port | Description | Type | Default |
|---|---|---|---|
color0 |
Scale factor for emittance at facing angles | color3 | 1.0, 1.0, 1.0 |
color90 |
Scale factor for emittance at grazing angles | color3 | 1.0, 1.0, 1.0 |
exponent |
Exponent for the Schlick blending between color0 and color90 | float | 5.0 |
base |
The base EDF to be modified | EDF | zero |
out |
Output: the computed EDF | EDF |
In the equations below, the color0 and color90 inputs correspond to exponent input corresponds to base input corresponds to
The emission scaling factor follows the two-parameter Schlick curve20 evaluated at
Constructs a VDF for pure light absorption.
The absorption input represents the absorption rate per distance traveled in the medium, stated in
| Port | Description | Type | Default |
|---|---|---|---|
absorption |
Absorption rate for the medium | vector3 | 0.0, 0.0, 0.0 |
out |
Output: the computed VDF | VDF |
In the equation below, the absorption input corresponds to
As light travels a distance
where
Constructs a VDF scattering light for a participating medium, based on the Henyey-Greenstein phase function6. Forward, backward and uniform scattering is supported and controlled by the anisotropy input.
The absorption input represents the absorption rate per distance traveled in the medium, stated in
The anisotropy input controls the scattering direction: negative values produce backwards scattering, positive values produce forward scattering, and 0.0 produces uniform scattering. Both absorption and scattering rates are specified per wavelength.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
absorption |
Absorption rate for the medium | vector3 | 0.0, 0.0, 0.0 | |
scattering |
Scattering rate for the medium | vector3 | 0.0, 0.0, 0.0 | |
anisotropy |
Anisotropy factor for scattering direction | float | 0.0 | [-1, 1] |
out |
Output: the computed VDF | VDF |
In the equations below, the absorption input corresponds to scattering input corresponds to anisotropy input corresponds to
The extinction coefficient is the combined rate of absorption and scattering:
As light travels a distance
At each scattering event, a fraction of the extinguished energy is scattered into a new direction rather than absorbed. This fraction is the single-scattering albedo:
The phase function
where
Constructs a surface shader describing light scattering and emission for surfaces. The thin_walled input selects between closed and thin-walled interpretations of the surface, as described in Closed and Thin-Walled Surfaces below.
If the edf input is left unconnected, no emission will occur from the surface.
| Port | Description | Type | Default |
|---|---|---|---|
bsdf |
Bidirectional scattering distribution function | BSDF | zero |
edf |
Emission distribution function for the surface | EDF | zero |
opacity |
Cutout opacity for the surface | float | 1.0 |
thin_walled |
Set to true to make the surface thin-walled | boolean | false |
out |
Output: the computed surface shader | surfaceshader |
In the equations below, the bsdf input corresponds to edf input corresponds to opacity input corresponds to
The surface shader evaluates the Light Transport Equation at the shading point, scaled by the cutout opacity
The opacity
By default (thin_walled = false) the surface bounds a solid interior: transmissive BSDFs refract incident light according to their index of refraction, and any medium layered beneath the surface attenuates the transmitted radiance. When thin_walled is true the surface represents an infinitely thin shell with matching media on both sides: transmission passes straight through without refraction or interior scattering. Distinct surface shaders may be assigned to the front and back faces of geometry using <surfacematerial> in the standard library, with the rules for sidedness and thin-walled status given in the Surfaces section above.
Constructs a volume shader describing a participating medium.
If the edf input is left unconnected, no emission will occur from the medium.
| Port | Description | Type | Default |
|---|---|---|---|
vdf |
Volume distribution function for the medium | VDF | zero |
edf |
Emission distribution function for the medium | EDF | zero |
out |
Output: the computed volume shader | volumeshader |
In the equations below, the vdf input supplies the absorption coefficient edf input corresponds to the volume emission
The volume shader evaluates the Equation of Transfer within the participating medium.
Constructs a light shader describing an explicit light source. The light shader will emit light according to the connected EDF. If the shader is attached to geometry both sides will be considered for light emission and the EDF controls if light is emitted from both sides or not.
| Port | Description | Type | Default |
|---|---|---|---|
edf |
Emission distribution function for the light source | EDF | zero |
intensity |
Intensity multiplier for the EDF's emittance | float | 1.0 |
exposure |
Exposure control for the EDF's emittance | float | 0.0 |
out |
Output: the computed light shader | lightshader |
In the equation below, the edf input corresponds to the base emission intensity input corresponds to exposure input corresponds to
The light shader scales the emission of the connected EDF by a linear intensity multiplier and a photographic exposure control in stops:
Note that the standard library includes definitions for displacement and surface_unlit shader nodes.
Mix two same-type distribution functions according to a weight. Performs horizontal layering by linear interpolation between the two inputs, using the function "bg∗(1−mix) + fg∗mix".
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
bg |
The first distribution function | BSDF, EDF, or VDF | zero | |
fg |
The second distribution function | Same as bg |
zero | |
mix |
The mixing weight | float | 0.0 | [0, 1] |
out |
Output: the mixed distribution function | Same as bg |
In the equation below, the bg input corresponds to fg input corresponds to mix input corresponds to the weight
When mixing BSDFs, the vertical-layering transmittance of the result interpolates in the same manner:
Because
Vertically layer a BSDF over another BSDF or VDF. Light not scattered by the top layer is passed on to the base, attenuated by the vertical-layering transmittance of the top BSDF. The implementation is target specific, but a standard way of handling this is by transmittance scaling — a generalization of the albedo scaling technique for interface BSDFs — using the function "top + base*transmittance(top)", where the transmittance function calculates the vertical-layering transmittance of a given BSDF.
| Port | Description | Type | Default |
|---|---|---|---|
top |
The top BSDF | BSDF | zero |
base |
The base BSDF or VDF | BSDF or VDF | zero |
out |
Output: the layered distribution | BSDF |
In the equations below, the top input corresponds to base input corresponds to
The response of the layered result is:
and its transmittance is the product of the transmittances of its inputs:
This recursive product makes the transmittance of a layer stack independent of its grouping, so that
For an interface BSDF top, the base is attenuated by exactly the energy not reflected by the top layer, while for an opaque BSDF top, the base is occluded over the fraction of the surface statistically covered by the top. In both cases, if
When the base input is a VDF, the layer node represents a surface boundary bound to an interior medium, rather than a vertical stack of two scattering layers. The transmissive scatter mode of the top BSDF governs entry into the medium, while the VDF governs absorption and scattering after entry, so the fraction of light entering the medium is determined by the Fresnel transmittance of the surface interface. In particular, medium entry is never derived from the complete reflected-plus-transmitted albedo of the top BSDF, which would incorrectly forbid entry through a lossless transmissive interface.
In the equations below,
and the transmittance of the composite is the product of the transmittances of the surface and the medium:
This product allows a surface bound to a medium to take part in further vertical layering as the base beneath a coating, with the medium remaining the innermost element of the stack. In this position the medium retains its interior reading: when the composite bounds a closed object, targets that trace light transport through the medium determine the path length
When a medium-bound BSDF is instead used as the top input of a <layer> node, it describes a thin slab, and no geometry is available to define the path length through its medium. The transmittance of a medium in this nested position depends upon an explicit slab thickness, which is not yet expressible in the PBS library, so its definition is reserved for a future revision of this specification. The elemental <subsurface_bsdf> remains well-defined as a top layer, with its vertical-layering transmittance given by its opaque coverage rather than by the transmittance of its interior medium.
Additively blend two distribution functions of the same type.
| Port | Description | Type | Default |
|---|---|---|---|
in1 |
The first distribution function | BSDF, EDF, or VDF | zero |
in2 |
The second distribution function | Same as in1 |
zero |
out |
Output: the added distribution functions | Same as in1 |
In the equation below, the in1 input corresponds to in2 input corresponds to
Note that unlike <mix> and <layer>, the add node does not guarantee energy conservation. The sum of two energy-conserving distribution functions may reflect more energy than is incident, so the author is responsible for ensuring that the combined result remains physically plausible.
Multiply the contribution of a distribution function by a scaling weight. The weight is either a float to attenuate the channels uniformly, or a color which can attenuate the channels separately. To be energy conserving the scaling weight should be no more than 1.0 in any channel.
| Port | Description | Type | Default |
|---|---|---|---|
in1 |
The distribution function to scale | BSDF, EDF, or VDF | zero |
in2 |
The scaling weight | float or color3 | 1.0 |
out |
Output: the scaled distribution function | Same as in1 |
In the equation below, the in1 input corresponds to in2 input corresponds to the scaling weight
When color3, each color channel of the distribution function is scaled independently.
Calculates anisotropic surface roughness from a scalar roughness and anisotropy parameterization. An anisotropy value above 0.0 stretches the roughness in the direction of the surface's "tangent" vector. An anisotropy value of 0.0 gives isotropic roughness. The roughness value is squared to achieve a more linear roughness look over the input range [0,1]. The computed output is the roughness pair roughness input of the microfacet BSDF nodes with no internal remapping, as described in GGX Normal Distribution Function.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
roughness |
Perceptual roughness value | float | 0.0 | [0, 1] |
anisotropy |
Amount of anisotropy | float | 0.0 | [0, 1] |
out |
Output: the computed roughness pair | vector2 | 0.0, 0.0 |
Calculates anisotropic surface roughness from a dual surface roughness parameterization. The roughness is squared to achieve a more linear roughness look over the input range [0,1]. The computed output is the roughness pair roughness input of the microfacet BSDF nodes with no internal remapping, as described in GGX Normal Distribution Function.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
roughness |
Perceptual roughness along the tangent and bitangent | vector2 | 0.0, 0.0 | [0, 1] |
out |
Output: the computed roughness pair | vector2 | 0.0, 0.0 |
Calculates anisotropic surface roughness from a scalar glossiness and anisotropy parameterization. This node gives the same result as roughness anisotropy except that the glossiness value is an inverted roughness value. To be used as a convenience for shading models using the glossiness parameterization. The computed output is the roughness pair roughness input of the microfacet BSDF nodes with no internal remapping, as described in GGX Normal Distribution Function.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
glossiness |
Glossiness value | float | 1.0 | [0, 1] |
anisotropy |
Amount of anisotropy | float | 0.0 | [0, 1] |
out |
Output: the computed roughness pair | vector2 |
Returns the radiant emittance of a blackbody radiator with the given temperature.
| Port | Description | Type | Default |
|---|---|---|---|
temperature |
Temperature in Kelvin | float | 5000.0 |
out |
Output: the radiant emittance | color3 |
Converts the artistic parameterization reflectivity and edge_color to complex IOR values. To be used with the <conductor_bsdf> node.
| Port | Description | Type | Default |
|---|---|---|---|
reflectivity |
Reflectivity per color component at facing angles | color3 | 0.947, 0.776, 0.371 |
edge_color |
Reflectivity per color component at grazing angles | color3 | 1.0, 0.982, 0.753 |
ior |
Output: Computed index of refraction | color3 | |
extinction |
Output: Computed extinction coefficient | color3 |
Converts the artistic parameterization hair roughness to roughness for R, TT and TRT lobes, as described in 19.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
longitudinal |
Longitudinal roughness | float | 0.1 | [0, 1] |
azimuthal |
Azimuthal roughness | float | 0.2 | [0, 1] |
scale_TT |
Roughness scale for TT lobe21 | float | 0.5 | |
scale_TRT |
Roughness scale for TRT lobe21 | float | 2.0 | |
roughness_R |
Output: Roughness for R lobe | vector2 | ||
roughness_TT |
Output: Roughness for TT lobe | vector2 | ||
roughness_TRT |
Output: Roughness for TRT lobe | vector2 |
In the equations below, the longitudinal input corresponds to azimuthal input corresponds to scale_TT and scale_TRT inputs correspond to the per-lobe roughness scales
The artist-facing roughness values are converted to the longitudinal variance
The per-lobe outputs apply the squared roughness scales to the longitudinal variance:
Converts the hair melanin parameterization to absorption coefficient based on pigments eumelanin and pheomelanin using the mapping method described in 22. The default of eumelanin_color and pheomelanin_color are lin_rec709 color converted from the constants22 via exp(-c). They may be transformed to scene-linear rendering color space.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
melanin_concentration |
Amount of melanin affected to the output | float | 0.25 | [0, 1] |
melanin_redness |
Amount of redness affected to the output | float | 0.5 | [0, 1] |
eumelanin_color |
Eumelanin color | color3 | 0.657704, 0.498077, 0.254107 | |
pheomelanin_color |
Pheomelanin color | color3 | 0.829444, 0.67032, 0.349938 | |
absorption |
Output: the computed absorption coefficient | vector3 |
Converts the hair scattering color to absorption coefficient using the mapping method described in 19.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
color |
Scattering color | color3 | 1.0, 1.0, 1.0 | |
azimuthal_roughness |
Azimuthal roughness | float | 0.2 | [0, 1] |
absorption |
Output: the computed absorption coefficient | vector3 |
This section presents a set of complete shading models defined as compositions of the BSDF, EDF, and VDF nodes of the MaterialX PBS Library above, together with the standard math, selection, and utility nodes of the MaterialX Standard Nodes document.
The models defined here are the Autodesk Standard Surface, UsdPreviewSurface, Khronos glTF PBR, and OpenPBR Surface, ranging from an intentionally compact preview model to full über-shaders. Each model is presented as a table of its inputs followed by a functional definition in the Shading Model Notation below, with a link to the corresponding renderable nodegraph in the MaterialX data libraries.
These models originate outside this specification. Each was created and specified by its own authors and organizations, and those originating specifications remain the authoritative source for each model's physical and perceptual foundations. They vary in how prescriptive they are: some are presented as papers or talks that convey a model's design and intent but leave implementation details open, while others are formal specifications accompanied by reference implementations.
In every case, realizing a model as a MaterialX graph requires resolving such details concretely — both the choices its originating specification leaves open and the mapping of its prescribed behavior onto MaterialX node primitives. The definitions in this section serve that purpose, giving each model a single, consistent MaterialX realization that follows its originating specification as closely as the MaterialX node set allows. They are intended to complement the originating specifications, not to replace them; where a MaterialX realization must depart from or extend its originating specification, that difference is noted in the model's definition.
For each model defined in this section, the interface table and the functional definition together are the authoritative statement of its MaterialX realization: the interface table defines the model's interface, defaults, and accepted values, and the functional definition defines its composition. Applications and renderers should rely on these definitions for consistent interchange. The corresponding nodedef and nodegraph in the MaterialX data libraries are a renderable expression of the same definition, equivalent in both composition and shading result. If the two are ever found to disagree, this document takes precedence, and the data libraries should be corrected to match it.
The shading models in this section are defined by a compact functional notation that follows the structure of each model's MaterialX nodegraph, so the flow from artist-facing inputs through the composition of node primitives to a final shader can be read directly from the document:
surfaceshader model_name(
float input_a,
color3 input_b)
{
BSDF lobe = some_bsdf(input_a, input_b);
return surface(bsdf = lobe);
}
This functional notation uses the following conventions:
-
Types. The value types (
float,color3,vector3, …) are the standard MaterialX data types;BSDF,EDF,VDF, andsurfaceshaderare the types defined in Data Types. -
Parameters. Each parameter is one of the model's inputs, matching an
<input>of its<nodedef>; defaults and accepted values are given in the interface table rather than repeated here. Parameters are listed in interface order, omitting any inputs the composition does not implement, and consecutive parameters of the same type are grouped after a single type name, with long groups wrapping onto indented continuation lines.NworldandTworlddenote the default world-space geometric normal and tangent (thedefaultgeompropof the corresponding input). -
Bindings. A statement
type name = expression;introduces a named intermediate value, corresponding to a node or small group of nodes in the renderable graph. -
Node calls. A call
node_name(...)instantiates the PBS or standard-library node of that name — including plain math and utility nodes such asclamp,normalize, andluminance— with arguments corresponding to its input ports. Arguments may be positional (in port order) or named asport = value; an omitted argument takes its default, so only inputs that differ from their defaults are shown. A node with multiple outputs is bound by destructuring, as in{ color3 ior, color3 extinction } = artistic_ior(...). -
Operators. The operators
+,-,*,/, and^denote the<add>,<subtract>,<multiply>,<divide>, and<power>nodes, following conventional precedence:^binds most tightly, then*and/, then+and-, with parentheses grouping explicitly. When one operand is a distribution function,*scales it by afloatorcolor3. The constantPImay be used wherever afloatliteral is accepted, denoting the mathematical constant π. -
Mixing.
mix(fg, bg, w)is the<mix>node: it returnsfgatw= 1 andbgatw= 0, equal to (1 −w)·bg+w·fg. Note that this argument order — foreground first — is reversed from themix()intrinsic of GLSL and related shading languages. -
Conditionals.
if (cond) { a } else { b }selects between two values of the same type — the type of the result — wherecondis abooleanor a comparison using>,>=,<,<=, or==. A boolean maps to an<ifequal>test againsttrue(or a<switch>); the comparisons map to the<ifgreater>,<ifgreatereq>, and<ifequal>nodes, with<and<=denoting the mirrored>and>=comparisons. -
Constructors and channels. A constructor
colorN(x)orvectorN(x)broadcasts a scalar to all channels,color3(a, b, c)builds a value from components, an N-tuple(a, b, c)is a literal of the corresponding type, and indexingv[i]selects channeli. Aconvert(x)call is the<convert>node, carrying a value across types with the same channel count, as fromcolor3tovector3.
Several of the models below reuse the same small sub-expressions. To keep their definitions concise and harmonized, these sub-expressions are given here as named functions and called by name in the models that follow.
The ior_to_f0 function returns the Schlick facing reflectance (
float ior_to_f0(float ior)
{
return ((ior - 1.0) / (ior + 1.0)) ^ 2.0;
}
The coated_emission function attenuates an emission distribution as it passes through a clear-coat: the uncoated emission is tinted by coat_color and faded by a Schlick term built from the coat's coat_weight, fading back to the uncoated emission as the coat is removed:
EDF coated_emission(
EDF emission,
color3 coat_color,
float coat_F0, coat_weight)
{
EDF attenuated = generalized_schlick_edf(
color0 = color3(1.0 - coat_F0),
color90 = color3(0.0),
base = emission * coat_color);
return mix(attenuated, emission, coat_weight);
}
This is a surface shading model created by the Solid Angle team for the Arnold renderer and used across Autodesk products. It is an über-shader built from ten components that are layered and mixed hierarchically23.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
base |
Weight of the diffuse reflection | float | 1.0 | [0, 1] |
base_color |
Color of the diffuse reflection | color3 | 0.8, 0.8, 0.8 | |
diffuse_roughness |
Roughness of the diffuse reflection | float | 0.0 | [0, 1] |
metalness |
Blend from dielectric to metallic reflection | float | 0.0 | [0, 1] |
specular |
Weight of the specular reflection | float | 1.0 | [0, 1] |
specular_color |
Color tint on the specular reflection | color3 | 1.0, 1.0, 1.0 | |
specular_roughness |
Roughness of the specular reflection | float | 0.2 | [0, 1] |
specular_IOR |
Index of refraction of the specular reflection | float | 1.5 | |
specular_anisotropy |
Anisotropy of the specular reflection | float | 0.0 | [0, 1] |
specular_rotation |
Rotation of the specular anisotropy axis | float | 0.0 | [0, 1] |
transmission |
Weight of specular transmission through the surface | float | 0.0 | [0, 1] |
transmission_color |
Color tint on the transmitted light | color3 | 1.0, 1.0, 1.0 | |
transmission_depth |
Depth at which light reaches the transmission color | float | 0.0 | |
transmission_scatter |
Scattering coefficient of the interior medium | color3 | 0.0, 0.0, 0.0 | |
transmission_scatter_anisotropy |
Anisotropy of the interior scattering | float | 0.0 | [0, 1] |
transmission_dispersion |
Dispersion of the index of refraction | float | 0.0 | |
transmission_extra_roughness |
Extra roughness added to transmission | float | 0.0 | [-1, 1] |
subsurface |
Blend from diffuse reflection to subsurface scattering | float | 0.0 | [0, 1] |
subsurface_color |
Color of the subsurface scattering | color3 | 1.0, 1.0, 1.0 | |
subsurface_radius |
Mean free path of the subsurface scattering | color3 | 1.0, 1.0, 1.0 | |
subsurface_scale |
Scalar weight on the subsurface radius | float | 1.0 | |
subsurface_anisotropy |
Anisotropy of the subsurface scattering | float | 0.0 | [-1, 1] |
sheen |
Weight of the sheen layer | float | 0.0 | [0, 1] |
sheen_color |
Color of the sheen layer | color3 | 1.0, 1.0, 1.0 | |
sheen_roughness |
Roughness of the sheen layer | float | 0.3 | [0, 1] |
coat |
Weight of the clear-coat layer | float | 0.0 | [0, 1] |
coat_color |
Color tint of the clear-coat layer | color3 | 1.0, 1.0, 1.0 | |
coat_roughness |
Roughness of the clear-coat reflection | float | 0.1 | [0, 1] |
coat_anisotropy |
Anisotropy of the clear-coat reflection | float | 0.0 | [0, 1] |
coat_rotation |
Rotation of the clear-coat anisotropy axis | float | 0.0 | [0, 1] |
coat_IOR |
Index of refraction of the clear-coat layer | float | 1.5 | |
coat_normal |
Normal vector of the clear-coat layer | vector3 | Nworld | |
coat_affect_color |
Coat darkening and saturation of the base layers | float | 0.0 | [0, 1] |
coat_affect_roughness |
Coat roughening of the base specular layers | float | 0.0 | [0, 1] |
thin_film_thickness |
Thickness of the thin-film layer in nanometers | float | 0.0 | |
thin_film_IOR |
Index of refraction of the thin-film layer | float | 1.5 | |
emission |
Weight of the emitted light | float | 0.0 | |
emission_color |
Color of the emitted light | color3 | 1.0, 1.0, 1.0 | |
opacity |
Opacity of the surface | color3 | 1.0, 1.0, 1.0 | |
thin_walled |
Set to true to make the surface thin-walled | boolean | false | |
normal |
Normal vector of the surface | vector3 | Nworld | |
tangent |
Tangent vector of the surface | vector3 | Tworld | |
out |
Output: the surface shader | surfaceshader |
This definition documents version 1.0.1 of the Autodesk Standard Surface model, and the associated nodegraph implementation is provided in the data libraries as standard_surface.mtlx.
The transmission_depth, transmission_scatter, transmission_scatter_anisotropy, and transmission_dispersion inputs describe interior volumetric transport; they are part of the interface but are not implemented by this composition, and so are omitted from its function parameters. In addition, where the originating specification defines opacity as a per-channel color, the <surface> node accepts only a scalar opacity, so this composition reduces the opacity color to its luminance.
In the originating specification, thin-film iridescence applies to the metal, specular reflection, and specular transmission lobes alike. This composition applies the thin-film inputs to the metal and specular reflection lobes only, so specular transmission does not receive thin-film interference.
surfaceshader standard_surface(
float base,
color3 base_color,
float diffuse_roughness, metalness, specular,
color3 specular_color,
float specular_roughness, specular_IOR, specular_anisotropy, specular_rotation, transmission,
color3 transmission_color,
float transmission_extra_roughness, subsurface,
color3 subsurface_color, subsurface_radius,
float subsurface_scale, subsurface_anisotropy, sheen,
color3 sheen_color,
float sheen_roughness, coat,
color3 coat_color,
float coat_roughness, coat_anisotropy, coat_rotation, coat_IOR,
vector3 coat_normal,
float coat_affect_color, coat_affect_roughness, thin_film_thickness, thin_film_IOR, emission,
color3 emission_color, opacity,
boolean thin_walled,
vector3 normal, tangent)
{
// When enabled, the coat darkens and saturates the diffuse and subsurface layers beneath it
// by raising their color to the "coat gamma" power (optional; off when 'coat_affect_color' = 0).
float coat_gamma = clamp(coat) * coat_affect_color + 1.0;
color3 coat_affected_base_color = max(base_color, 0.0) ^ coat_gamma;
color3 coat_affected_subsurface_color = max(subsurface_color, 0.0) ^ coat_gamma;
// Diffuse and subsurface base: thin-walled surfaces scatter through a translucent BSDF,
// while closed surfaces use volumetric subsurface scattering.
BSDF diffuse_lobe = oren_nayar_diffuse_bsdf(base, coat_affected_base_color, diffuse_roughness, normal);
BSDF thin_walled_subsurface_lobe = translucent_bsdf(color = coat_affected_subsurface_color, normal = normal);
BSDF closed_subsurface_lobe = subsurface_bsdf(color = coat_affected_subsurface_color,
radius = subsurface_radius * subsurface_scale, anisotropy = subsurface_anisotropy, normal = normal);
BSDF subsurface_scatter = if (thin_walled) { thin_walled_subsurface_lobe } else { closed_subsurface_lobe };
BSDF diffuse_layer = mix(subsurface_scatter, diffuse_lobe, subsurface);
// Sheen layered over the diffuse/subsurface base.
BSDF sheen_lobe = sheen_bsdf(sheen, sheen_color, sheen_roughness, normal);
BSDF sheen_layer = layer(sheen_lobe, diffuse_layer);
// Roughness and anisotropy tangent shared by the transmission, specular, and metal lobes.
// The coat can also roughen these lobes, driving their roughness toward fully rough (optional;
// off when 'coat_affect_roughness' = 0). The tangent rotates the surface tangent about the
// normal, falling back to the geometric tangent when isotropic.
float coat_affect_roughness_combined = coat_affect_roughness * coat * coat_roughness;
vector2 main_roughness = roughness_anisotropy(
mix(1.0, specular_roughness, coat_affect_roughness_combined), specular_anisotropy);
vector2 transmission_roughness = roughness_anisotropy(
mix(1.0, clamp(specular_roughness + transmission_extra_roughness),
coat_affect_roughness_combined), specular_anisotropy);
vector3 main_rotated = normalize(rotate3d(tangent, specular_rotation * 360.0, normal));
vector3 main_tangent = if (specular_anisotropy > 0.0) { main_rotated } else { tangent };
// Specular transmission (refraction), blended in by 'transmission'.
BSDF transmission_lobe = dielectric_bsdf(
tint = transmission_color,
ior = specular_IOR,
roughness = transmission_roughness,
normal = normal,
tangent = main_tangent,
scatter_mode = "T");
BSDF transmission_layer = mix(transmission_lobe, sheen_layer, transmission);
// Dielectric specular reflection, layered over the result, with optional thin-film.
BSDF specular_lobe = dielectric_bsdf(
weight = specular,
tint = specular_color,
ior = specular_IOR,
roughness = main_roughness,
normal = normal,
tangent = main_tangent,
thinfilm_thickness = thin_film_thickness,
thinfilm_ior = thin_film_IOR);
BSDF specular_layer = layer(specular_lobe, transmission_layer);
// Metallic reflection: the complex IOR is derived from 'base_color' and 'specular_color',
// and the 'metalness' weight blends between the dielectric and metal interpretations.
{ color3 metal_ior, color3 metal_extinction } =
artistic_ior(base_color * base, specular_color * specular);
BSDF metal_lobe = conductor_bsdf(
ior = metal_ior,
extinction = metal_extinction,
roughness = main_roughness,
normal = normal,
tangent = main_tangent,
thinfilm_thickness = thin_film_thickness,
thinfilm_ior = thin_film_IOR);
BSDF metal_or_specular = mix(metal_lobe, specular_layer, metalness);
// Coat: everything beneath is attenuated by 'coat_color', then covered by a
// dielectric coat lobe whose tangent rotates the surface tangent about the coat normal,
// again falling back to the geometric tangent when isotropic.
color3 coat_attenuation = mix(coat_color, color3(1.0), coat);
BSDF coat_base = metal_or_specular * coat_attenuation;
vector3 coat_rotated = normalize(rotate3d(tangent, coat_rotation * 360.0, coat_normal));
vector3 coat_tangent = if (coat_anisotropy > 0.0) { coat_rotated } else { tangent };
vector2 coat_roughness_uv = roughness_anisotropy(coat_roughness, coat_anisotropy);
BSDF coat_lobe = dielectric_bsdf(
weight = coat,
ior = coat_IOR,
roughness = coat_roughness_uv,
normal = coat_normal,
tangent = coat_tangent);
BSDF coat_layer = layer(coat_lobe, coat_base);
// Emission, attenuated under the coat by 'coated_emission' (see Shared Functions),
// evaluated at the coat's facing reflectance (F0).
float coat_F0 = ior_to_f0(coat_IOR);
EDF emission_edf = uniform_edf(emission_color * emission);
EDF surface_emission = coated_emission(emission_edf, coat_color, coat_F0, coat);
// Final surface, with a monochrome opacity from the luminance of the opacity color.
return surface(
bsdf = coat_layer,
edf = surface_emission,
opacity = luminance(opacity)[0],
thin_walled = thin_walled);
}
This is a preview shading model defined by Pixar for USD24. Rather than an über-shader supporting every possible feature, it is an intentionally constrained, basic set of shading controls designed to interchange reliably across film and game pipelines and to be supported natively by the production renderers that ship with USD and Hydra.
UsdPreviewSurface supports two alternative reflection parameterizations, selected by useSpecularWorkflow: a specular workflow driven by an explicit specularColor, and a metalness workflow driven by metallic.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
diffuseColor |
Color of the diffuse reflection | color3 | 0.18, 0.18, 0.18 | |
emissiveColor |
Color of the emitted light | color3 | 0.0, 0.0, 0.0 | |
useSpecularWorkflow |
Selects the specular or metalness workflow | integer | 0 | 0, 1 |
specularColor |
Specular color for the specular workflow | color3 | 0.0, 0.0, 0.0 | |
metallic |
Blend from dielectric to metallic reflection | float | 0.0 | [0, 1] |
roughness |
Surface roughness | float | 0.5 | [0, 1] |
clearcoat |
Weight of the clear-coat layer | float | 0.0 | [0, 1] |
clearcoatRoughness |
Roughness of the clear-coat reflection | float | 0.01 | [0, 1] |
opacity |
Opacity of the surface | float | 1.0 | [0, 1] |
opacityMode |
Transparent or presence interpretation of opacity | integer | 0 | 0, 1 |
opacityThreshold |
Cutout threshold applied to opacity | float | 0.0 | [0, 1] |
ior |
Index of refraction of the surface | float | 1.5 | |
normal |
Tangent-space normal of the surface | vector3 | 0.0, 0.0, 1.0 | |
displacement |
Displacement amount of the surface | float | 0.0 | |
occlusion |
Ambient occlusion of the surface | float | 1.0 | [0, 1] |
out |
Output: the surface shader | surfaceshader |
This definition documents version 2.6 of the UsdPreviewSurface model, and the associated nodegraph implementation is provided in the data libraries as usd_preview_surface.mtlx.
The displacement and occlusion inputs are part of the interface but are not implemented by this composition, and so are omitted from its function parameters; displacement drives a separate displacement shader, and occlusion is applied by the host renderer.
This composition also goes beyond the Schlick reflectance described by the originating specification in two respects: the metalness workflow blends toward a <conductor_bsdf> lobe whose complex index of refraction is derived from diffuseColor, rather than remaining a pure Schlick lobe at high metallic values; and in transparent mode, a fractional opacity is realized as refractive transmission through the surface, where the originating specification instead reduces the diffuse lighting component in favor of transparency.
surfaceshader UsdPreviewSurface(
color3 diffuseColor, emissiveColor,
integer useSpecularWorkflow,
color3 specularColor,
float metallic, roughness, clearcoat, clearcoatRoughness, opacity,
integer opacityMode,
float opacityThreshold, ior,
vector3 normal)
{
// Decode the tangent-space normal input into a world-space shading normal.
vector3 surface_normal = normalmap(normal * 0.5 + 0.5);
// Shared roughness, and the dielectric facing reflectance (F0) derived from the
// IOR, both reused by the specular, metalness, and clearcoat lobes below.
vector2 roughness_uv = roughness_anisotropy(roughness);
float dielectric_F0 = ior_to_f0(ior);
// Diffuse base: in the metalness workflow the diffuse contribution fades out as the
// surface becomes metallic; in the specular workflow it stays at full weight.
float diffuse_weight = if (useSpecularWorkflow == 1) { 1.0 } else { 1.0 - metallic };
BSDF diffuse_lobe = oren_nayar_diffuse_bsdf(weight = diffuse_weight, color = diffuseColor, normal = surface_normal);
// Refractive transmission, blended into the diffuse base. (opacityMode: 0 =
// transparent, 1 = presence.) In transparent mode a fractional 'opacity' reveals the
// transmission unless a cutout threshold is set; presence mode is never transmissive.
BSDF transmission_lobe = dielectric_bsdf(
ior = ior,
roughness = (0.0, 0.0),
normal = surface_normal,
scatter_mode = "T");
float transparent_diffuse_amount = if (opacityThreshold > 0.0) { 1.0 } else { opacity };
float diffuse_amount = if (opacityMode == 0) { transparent_diffuse_amount } else { 1.0 };
BSDF base_substrate = mix(diffuse_lobe, transmission_lobe, diffuse_amount);
// Specular workflow: a generalized Schlick specular lobe whose facing reflectance (F0)
// is 'specularColor', transitioning to a white F90 grazing reflectance.
BSDF specular_workflow_lobe = generalized_schlick_bsdf(
color0 = specularColor,
roughness = roughness_uv,
normal = surface_normal);
BSDF specular_workflow = layer(specular_workflow_lobe, base_substrate);
// Metalness workflow: interpolate the Schlick reflectance from a dielectric Fresnel
// (F0 from 'ior', white F90 grazing reflectance) toward a metallic Fresnel (both F0 and F90
// grazing reflectance 'diffuseColor') as 'metallic' rises, then blend in a conductor lobe whose
// complex IOR is derived from 'diffuseColor'.
color3 metallic_specular_color = mix(diffuseColor, color3(1.0), metallic);
color3 F0 = mix(metallic_specular_color, metallic_specular_color * dielectric_F0, metallic);
BSDF metalness_dielectric_lobe = generalized_schlick_bsdf(
color0 = F0,
color90 = metallic_specular_color,
roughness = roughness_uv,
normal = surface_normal);
BSDF metalness_dielectric_layer = layer(metalness_dielectric_lobe, base_substrate);
{ color3 metal_ior, color3 metal_extinction } = artistic_ior(diffuseColor, diffuseColor);
BSDF metalness_metal_lobe = conductor_bsdf(
ior = metal_ior,
extinction = metal_extinction,
roughness = roughness_uv,
normal = surface_normal);
BSDF metalness_workflow = mix(metalness_metal_lobe, metalness_dielectric_layer, metallic);
// Select the active workflow.
BSDF selected_workflow = if (useSpecularWorkflow == 1) { specular_workflow } else { metalness_workflow };
// Clearcoat: a dielectric generalized Schlick lobe layered over the chosen workflow.
vector2 coat_roughness_uv = roughness_anisotropy(clearcoatRoughness);
BSDF coat_lobe = generalized_schlick_bsdf(
weight = clearcoat,
color0 = color3(dielectric_F0),
roughness = coat_roughness_uv,
normal = surface_normal);
BSDF coat_layer = layer(coat_lobe, selected_workflow);
// Emission.
EDF emission_edf = uniform_edf(emissiveColor);
// Cutout opacity: together, 'opacity', 'opacityThreshold', and 'opacityMode' let the
// surface behave as a translucent material (transparent mode, where translucency is
// instead carried by the transmission lobe above), a fractional-coverage material
// (presence mode), or a hard cutout mask (any mode with a non-zero 'opacityThreshold':
// opaque at or above the threshold, fully cut out below).
float cutout = if (opacity >= opacityThreshold) { 1.0 } else { 0.0 };
float presence_opacity = if (opacityThreshold > 0.0) { cutout } else { opacity };
float surface_opacity = if (opacityMode == 0) { cutout } else { presence_opacity };
return surface(bsdf = coat_layer, edf = emission_edf, opacity = surface_opacity);
}
This is a physically based shading model defined by the Khronos Group for the glTF 3D asset format25. Its core is a metallic-roughness model designed for compact, portable real-time rendering, augmented by a family of KHR_materials_* extensions (adding specular, transmission, sheen, clear-coat, iridescence, anisotropy, interior volume, and emissive strength) whose parameters together make up the interface below.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
base_color |
Base color of the surface | color3 | 1.0, 1.0, 1.0 | |
metallic |
Blend from dielectric to metallic reflection | float | 1.0 | [0, 1] |
roughness |
Surface roughness | float | 1.0 | [0, 1] |
normal |
Normal vector of the surface | vector3 | Nworld | |
tangent |
Tangent vector of the surface | vector3 | Tworld | |
occlusion |
Ambient occlusion of the surface | float | 1.0 | [0, 1] |
transmission |
Weight of specular transmission through the surface | float | 0.0 | [0, 1] |
specular |
Weight of the specular reflection | float | 1.0 | [0, 1] |
specular_color |
Color tint on the specular reflection | color3 | 1.0, 1.0, 1.0 | |
ior |
Index of refraction of the surface | float | 1.5 | |
alpha |
Opacity of the surface | float | 1.0 | [0, 1] |
alpha_mode |
Opaque, mask, or blend interpretation of alpha | integer | 0 | 0, 1, 2 |
alpha_cutoff |
Cutout threshold applied to alpha | float | 0.5 | [0, 1] |
iridescence |
Weight of the thin-film iridescence | float | 0.0 | [0, 1] |
iridescence_ior |
Index of refraction of the thin-film | float | 1.3 | |
iridescence_thickness |
Thickness of the thin-film layer in nanometers | float | 100.0 | |
sheen_color |
Color of the sheen layer | color3 | 0.0, 0.0, 0.0 | |
sheen_roughness |
Roughness of the sheen layer | float | 0.0 | [0, 1] |
clearcoat |
Weight of the clear-coat layer | float | 0.0 | [0, 1] |
clearcoat_roughness |
Roughness of the clear-coat reflection | float | 0.0 | [0, 1] |
clearcoat_normal |
Normal vector of the clear-coat layer | vector3 | Nworld | |
emissive |
Color of the emitted light | color3 | 0.0, 0.0, 0.0 | |
emissive_strength |
Weight of the emitted light | float | 1.0 | |
thickness |
Thickness of the interior volume | float | 0.0 | |
attenuation_distance |
Attenuation distance of the interior volume | float | ||
attenuation_color |
Attenuation color of the interior volume | color3 | 1.0, 1.0, 1.0 | |
anisotropy_strength |
Anisotropy of the specular reflection | float | 0.0 | [0, 1] |
anisotropy_rotation |
Rotation of the specular anisotropy axis | float | 0.0 | [0, 2π] |
dispersion |
Dispersion of the index of refraction | float | 0.0 | |
out |
Output: the surface shader | surfaceshader |
This definition documents version 2.0 of the glTF material model with the KHR_materials_* extensions described above, and the associated nodegraph implementation is provided in the data libraries as gltf_pbr.mtlx.
The occlusion, thickness, attenuation_distance, attenuation_color, and dispersion inputs are part of the interface but are not implemented by this composition, and so are omitted from its function parameters; occlusion is applied by the host renderer, and the interior-volume inputs (thickness, attenuation_distance, and attenuation_color) are discussed in the note following the definition.
surfaceshader gltf_pbr(
color3 base_color,
float metallic, roughness,
vector3 normal, tangent,
float transmission, specular,
color3 specular_color,
float ior, alpha,
integer alpha_mode,
float alpha_cutoff, iridescence, iridescence_ior, iridescence_thickness,
color3 sheen_color,
float sheen_roughness, clearcoat, clearcoat_roughness,
vector3 clearcoat_normal,
color3 emissive,
float emissive_strength, anisotropy_strength, anisotropy_rotation)
{
// Dielectric reflectance: the facing reflectance (F0) is derived from the IOR,
// tinted by 'specular_color' and clamped, then both F0 and the white F90 grazing reflectance are
// scaled by 'specular'.
float ior_F0 = ior_to_f0(ior);
color3 dielectric_F0 = min(specular_color * ior_F0, 1.0) * specular;
color3 dielectric_F90 = color3(1.0) * specular;
// Anisotropic roughness: alpha = roughness^2; the along-tangent component is widened
// toward fully rough by 'anisotropy_strength', the across-tangent component stays at
// alpha, and both are clamped away from zero.
float alpha_roughness = roughness * roughness;
float roughness_along_tangent = mix(1.0, alpha_roughness, anisotropy_strength * anisotropy_strength);
vector2 roughness_uv = (clamp(roughness_along_tangent, 0.00001, 1.0), clamp(alpha_roughness, 0.00001, 1.0));
// Tangent rotated about the normal by 'anisotropy_rotation' (negated and converted from
// radians to degrees by -180/pi), used by the base lobes only when a rotation is set.
vector3 rotated_tangent = normalize(rotate3d(tangent, anisotropy_rotation * -180.0 / PI, normal));
vector3 selected_tangent = if (absval(anisotropy_rotation) > 0.0) { rotated_tangent } else { tangent };
// Dielectric base: Oren-Nayar diffuse with refractive transmission blended in by
// 'transmission'.
BSDF diffuse_lobe = oren_nayar_diffuse_bsdf(color = base_color, normal = normal);
BSDF transmission_lobe = dielectric_bsdf(
tint = base_color,
ior = ior,
roughness = roughness_uv,
normal = normal,
tangent = selected_tangent,
scatter_mode = "T");
BSDF transmission_base = mix(transmission_lobe, diffuse_lobe, transmission);
// Specular reflection, with an iridescent thin-film twin blended in by 'iridescence',
// layered over the transmissive base.
BSDF reflection_lobe = generalized_schlick_bsdf(
color0 = dielectric_F0,
color90 = dielectric_F90,
roughness = roughness_uv,
normal = normal,
tangent = selected_tangent);
BSDF tf_reflection_lobe = generalized_schlick_bsdf(
color0 = dielectric_F0,
color90 = dielectric_F90,
roughness = roughness_uv,
normal = normal,
tangent = selected_tangent,
thinfilm_thickness = iridescence_thickness,
thinfilm_ior = iridescence_ior);
BSDF iridescent_reflection = mix(tf_reflection_lobe, reflection_lobe, iridescence);
BSDF iridescent_dielectric_layer = layer(iridescent_reflection, transmission_base);
// Metal: a generalized Schlick lobe whose facing reflectance (F0) is 'base_color', with its own
// iridescent thin-film twin blended in by 'iridescence'.
BSDF metal_lobe = generalized_schlick_bsdf(
color0 = base_color,
roughness = roughness_uv,
normal = normal,
tangent = selected_tangent);
BSDF tf_metal_lobe = generalized_schlick_bsdf(
color0 = base_color,
roughness = roughness_uv,
normal = normal,
tangent = selected_tangent,
thinfilm_thickness = iridescence_thickness,
thinfilm_ior = iridescence_ior);
BSDF iridescent_metal = mix(tf_metal_lobe, metal_lobe, iridescence);
// Blend between the dielectric and metal interpretations by 'metallic'.
BSDF metal_or_dielectric = mix(iridescent_metal, iridescent_dielectric_layer, metallic);
// Sheen layered over the base; its weight is the maximum component of 'sheen_color' and
// its color is that value normalized to unit intensity.
float sheen_intensity = maxcomponent(sheen_color);
BSDF sheen_lobe = sheen_bsdf(
weight = sheen_intensity,
color = sheen_color / sheen_intensity,
roughness = sheen_roughness * sheen_roughness,
normal = normal);
BSDF sheen_layer = layer(sheen_lobe, metal_or_dielectric);
// Clearcoat: a dielectric lobe at a fixed IOR of 1.5 over its own normal, using the
// unrotated tangent.
vector2 coat_roughness_uv = roughness_anisotropy(clearcoat_roughness);
BSDF coat_lobe = dielectric_bsdf(
weight = clearcoat,
ior = 1.5,
roughness = coat_roughness_uv,
normal = clearcoat_normal,
tangent = tangent);
BSDF coat_layer = layer(coat_lobe, sheen_layer);
// Emission.
EDF emission = uniform_edf(emissive * emissive_strength);
// Opacity. (alpha_mode: 0 = OPAQUE, 1 = MASK, 2 = BLEND.) MASK is a hard cutout at
// 'alpha_cutoff', OPAQUE forces full opacity, and BLEND uses 'alpha' directly.
float opacity_mask_cutoff = if (alpha >= alpha_cutoff) { 1.0 } else { 0.0 };
float opacity_mask = if (alpha_mode == 1) { opacity_mask_cutoff } else { alpha };
float opacity = if (alpha_mode == 0) { 1.0 } else { opacity_mask };
return surface(bsdf = coat_layer, edf = emission, opacity = opacity);
}
The glTF material model also defines an interior volume, parameterized by thickness, attenuation_distance, and attenuation_color. This volume is not part of the definition above: the current data-library graph derives a Beer's law absorption coefficient from attenuation_distance and attenuation_color, but leaves the resulting volume unconnected and does not yet consume thickness. A future revision of the model may implement it by layering the transmission lobe over the interior volume, as the OpenPBR Surface model does, gated by thickness. Relatedly, KHR_materials_transmission specifies transmission through an infinitely thin surface, without refraction; the composition above instead models refractive transmission through a closed surface, a difference that a future revision may address together with the interior volume.
This is an open surface shading model that was designed as a collaboration between Adobe, Autodesk, and other companies in the industry, and is currently maintained as a subproject of MaterialX within the Academy Software Foundation26.
| Port | Description | Type | Default | Accepted Values |
|---|---|---|---|---|
base_weight |
Weight of the diffuse and metallic base | float | 1.0 | [0, 1] |
base_color |
Color of the diffuse and metallic base | color3 | 0.8, 0.8, 0.8 | |
base_diffuse_roughness |
Roughness of the diffuse reflection | float | 0.0 | [0, 1] |
base_metalness |
Blend from dielectric to metallic reflection | float | 0.0 | [0, 1] |
specular_weight |
Weight of the specular reflection | float | 1.0 | |
specular_color |
Color of the specular reflection | color3 | 1.0, 1.0, 1.0 | |
specular_roughness |
Roughness of the specular reflection | float | 0.3 | [0, 1] |
specular_ior |
Index of refraction of the dielectric base | float | 1.5 | |
specular_roughness_anisotropy |
Anisotropy of the specular reflection | float | 0.0 | [0, 1] |
transmission_weight |
Weight of specular transmission through the surface | float | 0.0 | [0, 1] |
transmission_color |
Color of the transparent base | color3 | 1.0, 1.0, 1.0 | |
transmission_depth |
Depth at which light reaches the transmission color | float | 0.0 | |
transmission_scatter |
Scattering color of the transparent base | color3 | 0.0, 0.0, 0.0 | |
transmission_scatter_anisotropy |
Anisotropy of the interior scattering | float | 0.0 | [-1, 1] |
transmission_dispersion_scale |
Scale of the transmission dispersion | float | 0.0 | [0, 1] |
transmission_dispersion_abbe_number |
Abbe number of the transmission dispersion | float | 20.0 | |
subsurface_weight |
Blend from diffuse reflection to subsurface scattering | float | 0.0 | [0, 1] |
subsurface_color |
Color of the subsurface scattering | color3 | 0.8, 0.8, 0.8 | |
subsurface_radius |
Mean free path of the subsurface scattering | float | 1.0 | |
subsurface_radius_scale |
Per-channel scale on the subsurface radius | color3 | 1.0, 0.5, 0.25 | |
subsurface_scatter_anisotropy |
Anisotropy of the subsurface scattering | float | 0.0 | [-1, 1] |
fuzz_weight |
Weight of the fuzz layer | float | 0.0 | [0, 1] |
fuzz_color |
Color of the fuzz layer | color3 | 1.0, 1.0, 1.0 | |
fuzz_roughness |
Roughness of the fuzz layer | float | 0.5 | [0, 1] |
coat_weight |
Weight of the clear-coat layer | float | 0.0 | [0, 1] |
coat_color |
Color tint of the clear-coat layer | color3 | 1.0, 1.0, 1.0 | |
coat_roughness |
Roughness of the clear-coat reflection | float | 0.0 | [0, 1] |
coat_roughness_anisotropy |
Anisotropy of the clear-coat reflection | float | 0.0 | [0, 1] |
coat_ior |
Index of refraction of the clear-coat layer | float | 1.6 | |
coat_darkening |
Strength of the coat darkening effect | float | 1.0 | [0, 1] |
thin_film_weight |
Weight of the thin-film layer | float | 0.0 | [0, 1] |
thin_film_thickness |
Thickness of the thin-film layer in micrometers | float | 0.5 | |
thin_film_ior |
Index of refraction of the thin-film layer | float | 1.4 | |
emission_luminance |
Luminance of the emitted light in nits | float | 0.0 | |
emission_color |
Color of the emitted light | color3 | 1.0, 1.0, 1.0 | |
geometry_opacity |
Opacity of the surface | float | 1.0 | [0, 1] |
geometry_thin_walled |
Set to true to make the surface thin-walled | boolean | false | |
geometry_normal |
Normal vector of the surface | vector3 | Nworld | |
geometry_coat_normal |
Normal vector of the clear-coat layer | vector3 | Nworld | |
geometry_tangent |
Tangent vector of the surface | vector3 | Tworld | |
geometry_coat_tangent |
Tangent vector of the clear-coat layer | vector3 | Tworld | |
out |
Output: the surface shader | surfaceshader |
This definition documents version 1.1.1 of the OpenPBR Surface model, and the associated nodegraph implementation is provided in the data libraries as open_pbr_surface.mtlx.
The specular and coat roughness inputs are remapped by open_pbr_anisotropy rather than the standard <roughness_anisotropy> node used by the other models; its definition follows after the model below.
The transmission_dispersion_scale and transmission_dispersion_abbe_number inputs are part of the interface but are not implemented by this composition, and so are omitted from its function parameters. The interior transmission medium is realized as an anisotropic_vdf whose absorption and scattering are derived from transmission_color, transmission_scatter, and transmission_depth by Beer's law.
In the originating specification, specular_color modulates the dielectric Fresnel factor only for light incident from outside the surface, and when transmission_depth is zero, transmission_color tints only the refraction through the interface, so that internal reflection within a transmissive dielectric receives neither tint. The tint input of <dielectric_bsdf> does not distinguish which side of the interface light arrives from, so this composition departs from that prescription: internal reflections are tinted by specular_color in the same manner as exterior reflections, a difference visible in transmissive materials whose specular_color is not white.
Additionally, the originating specification states that a thin film on a dielectric base should generate color fringes in the transmission lobe as well as in reflection. This composition applies the thin-film inputs to the dielectric reflection and metal lobes only, so specular transmission does not receive thin-film interference.
surfaceshader open_pbr_surface(
float base_weight,
color3 base_color,
float base_diffuse_roughness, base_metalness, specular_weight,
color3 specular_color,
float specular_roughness, specular_ior, specular_roughness_anisotropy, transmission_weight,
color3 transmission_color,
float transmission_depth,
color3 transmission_scatter,
float transmission_scatter_anisotropy, subsurface_weight,
color3 subsurface_color,
float subsurface_radius,
color3 subsurface_radius_scale,
float subsurface_scatter_anisotropy, fuzz_weight,
color3 fuzz_color,
float fuzz_roughness, coat_weight,
color3 coat_color,
float coat_roughness, coat_roughness_anisotropy, coat_ior, coat_darkening, thin_film_weight,
thin_film_thickness, thin_film_ior, emission_luminance,
color3 emission_color,
float geometry_opacity,
boolean geometry_thin_walled,
vector3 geometry_normal, geometry_coat_normal, geometry_tangent, geometry_coat_tangent)
{
// Specular roughness, roughened toward fully rough by the coat (combining the coat and
// specular roughnesses in the fourth power), faded back to the raw roughness as the coat
// is removed, then remapped to an anisotropic (alpha_x, alpha_y) shared by the base lobes.
float coat_affected_specular_roughness =
min(1.0, 2.0 * coat_roughness ^ 4.0 + specular_roughness ^ 4.0) ^ 0.25;
float effective_specular_roughness =
mix(coat_affected_specular_roughness, specular_roughness, coat_weight);
vector2 main_roughness = open_pbr_anisotropy(effective_specular_roughness, specular_roughness_anisotropy);
// Coat facing reflectance (F0), reused by the coat-darkening and emission terms below.
float coat_F0 = ior_to_f0(coat_ior);
// Thin-walled subsurface: diffuse reflection and transmission lobes that share the subsurface
// color as their albedo, with 'subsurface_scatter_anisotropy' shifting weight from reflection
// toward transmission. The two weights sum to one, so the total albedo is the subsurface color.
color3 ss_color = max(subsurface_color, 0.0);
BSDF ss_reflection = oren_nayar_diffuse_bsdf(color = ss_color, roughness = base_diffuse_roughness,
normal = geometry_normal);
BSDF ss_transmission = translucent_bsdf(color = ss_color, normal = geometry_normal);
BSDF subsurface_thin_walled = mix(ss_transmission, ss_reflection,
0.5 * (1.0 + subsurface_scatter_anisotropy));
// Closed (non-thin-walled) subsurface: volumetric scattering over the scaled radius.
BSDF subsurface_volume = subsurface_bsdf(color = ss_color,
radius = subsurface_radius_scale * subsurface_radius,
anisotropy = subsurface_scatter_anisotropy, normal = geometry_normal);
// Opaque dielectric base: Oren-Nayar diffuse, with the selected subsurface scattering blended
// in by 'subsurface_weight'.
BSDF diffuse_lobe = oren_nayar_diffuse_bsdf(weight = base_weight, color = max(base_color, 0.0),
roughness = base_diffuse_roughness, normal = geometry_normal, energy_compensation = true);
BSDF selected_subsurface = if (geometry_thin_walled) { subsurface_thin_walled } else { subsurface_volume };
BSDF opaque_base = mix(selected_subsurface, diffuse_lobe, subsurface_weight);
// Interior volume of the transparent base: extinction and scattering coefficients follow from
// Beer's law over 'transmission_depth'; the absorption is shifted so no component is negative,
// and both terms are gated off unless a finite depth is set.
vector3 extinction_coeff = ln(convert(transmission_color)) / transmission_depth * -1.0;
vector3 scattering_coeff = convert(transmission_scatter) / transmission_depth;
vector3 absorption_coeff = extinction_coeff - scattering_coeff;
float absorption_min = mincomponent(absorption_coeff);
vector3 absorption_nonneg =
if (absorption_min < 0.0) { absorption_coeff - vector3(absorption_min) } else { absorption_coeff };
vector3 volume_absorption = if (transmission_depth > 0.0) { absorption_nonneg } else { vector3(0.0) };
vector3 volume_scattering = if (transmission_depth > 0.0) { scattering_coeff } else { vector3(0.0) };
VDF dielectric_volume = anisotropic_vdf(absorption = volume_absorption,
scattering = volume_scattering, anisotropy = transmission_scatter_anisotropy);
// Specular IOR relative to the coat: OpenPBR's coat total-internal-reflection fix takes
// whichever ratio of 'specular_ior' and 'coat_ior' is greater than one; the result is faded
// toward the raw 'specular_ior' as the coat is removed. The facing reflectance F0 is then
// derived from this eta and scaled by 'specular_weight', and folded back into a single
// modulated IOR that drives the dielectric lobes.
float eta_s = mix(
if (specular_ior / coat_ior > 1.0) { specular_ior / coat_ior } else { coat_ior / specular_ior },
specular_ior, coat_weight);
float specular_F0 = ior_to_f0(eta_s);
float scaled_F0 = clamp(specular_weight * specular_F0, 0.0, 0.99999);
float eta_epsilon = sign(eta_s - 1.0) * sqrt(scaled_F0);
float modulated_eta_s = (1.0 + eta_epsilon) / (1.0 - eta_epsilon);
// Thin-film thickness, converted from micrometers to nanometers for the BSDF inputs.
float thin_film_thickness_nm = thin_film_thickness * 1000.0;
// Specular transmission (refraction) through the interior volume, blended into the opaque base
// by 'transmission_weight'. The tint reverts to white once a finite depth carries color through
// the volume instead.
color3 transmission_tint = if (transmission_depth > 0.0) { color3(1.0) } else { transmission_color };
BSDF dielectric_transmission = dielectric_bsdf(
tint = transmission_tint, ior = modulated_eta_s, roughness = main_roughness,
normal = geometry_normal, tangent = geometry_tangent, scatter_mode = "T");
BSDF dielectric_transmission_vol = layer(dielectric_transmission, dielectric_volume);
BSDF dielectric_substrate = mix(dielectric_transmission_vol, opaque_base, transmission_weight);
// Dielectric specular reflection, with a thin-film twin blended in by 'thin_film_weight',
// layered over the substrate.
BSDF dielectric_reflection = dielectric_bsdf(
tint = specular_color, ior = modulated_eta_s, roughness = main_roughness,
normal = geometry_normal, tangent = geometry_tangent);
BSDF dielectric_reflection_tf = dielectric_bsdf(
tint = specular_color, ior = modulated_eta_s, roughness = main_roughness,
normal = geometry_normal, tangent = geometry_tangent,
thinfilm_thickness = thin_film_thickness_nm, thinfilm_ior = thin_film_ior);
BSDF dielectric_reflection_mix = mix(dielectric_reflection_tf, dielectric_reflection, thin_film_weight);
BSDF dielectric_base = layer(dielectric_reflection_mix, dielectric_substrate);
// Metal: a generalized Schlick lobe in the F82-tint parameterization, where 'color0' is the
// facing reflectance F0 (base_color scaled by base_weight) and 'color82' the edge tint
// ('specular_color'). A thin-film twin is blended in by 'thin_film_weight', and the whole metal
// interpretation is blended against the dielectric base by 'base_metalness'.
color3 metal_reflectivity = base_color * base_weight;
BSDF metal_lobe = generalized_schlick_bsdf(
weight = specular_weight, color0 = metal_reflectivity, color82 = specular_color,
roughness = main_roughness, normal = geometry_normal, tangent = geometry_tangent);
BSDF metal_lobe_tf = generalized_schlick_bsdf(
weight = specular_weight, color0 = metal_reflectivity, color82 = specular_color,
roughness = main_roughness, normal = geometry_normal, tangent = geometry_tangent,
thinfilm_thickness = thin_film_thickness_nm, thinfilm_ior = thin_film_ior);
BSDF metal_lobe_mix = mix(metal_lobe_tf, metal_lobe, thin_film_weight);
BSDF metal_or_dielectric = mix(metal_lobe_mix, dielectric_base, base_metalness);
// Physical coat darkening: the coat traps part of the base's reflected light by re-reflecting it
// downward (fraction Kcoat), and the repeated bounces are absorbed by the base, so the coated base
// is darker than the bare base by the factor (1 - Kcoat) / (1 - Ebase*Kcoat). Kcoat is the coat's
// internal diffuse reflectance and Ebase an albedo estimate of the base; the effect is modulated
// by 'coat_weight' and the artistic 'coat_darkening' control.
float Kcoat = 1.0 - (1.0 - coat_F0) / coat_ior ^ 2.0;
color3 Emetal = base_color * specular_weight;
color3 Edielectric = mix(subsurface_color, base_color, subsurface_weight);
color3 Ebase = mix(Emetal, Edielectric, base_metalness);
color3 base_darkening = color3(1.0 - Kcoat) / (color3(1.0) - Ebase * Kcoat);
color3 modulated_base_darkening = mix(base_darkening, color3(1.0), coat_weight * coat_darkening);
BSDF darkened_base = metal_or_dielectric * modulated_base_darkening;
// Coat: everything beneath is attenuated by 'coat_color' (faded in by 'coat_weight'), then a
// dielectric coat lobe is layered on top over its own normal and tangent.
color3 coat_attenuation = mix(coat_color, color3(1.0), coat_weight);
BSDF coat_substrate = darkened_base * coat_attenuation;
vector2 coat_roughness_uv = open_pbr_anisotropy(coat_roughness, coat_roughness_anisotropy);
BSDF coat_lobe = dielectric_bsdf(
weight = coat_weight, ior = coat_ior, roughness = coat_roughness_uv,
normal = geometry_coat_normal, tangent = geometry_coat_tangent);
BSDF coat_layer = layer(coat_lobe, coat_substrate);
// Fuzz (sheen) layered over the coat, using the Zeltner sheen model.
BSDF fuzz_lobe = sheen_bsdf(weight = fuzz_weight, color = fuzz_color,
roughness = fuzz_roughness, normal = geometry_normal, mode = "zeltner");
BSDF fuzz_layer = layer(fuzz_lobe, coat_layer);
// Emission, attenuated under the coat by 'coated_emission' (see Shared Functions).
EDF uncoated_emission = uniform_edf(emission_color * emission_luminance);
EDF emission_edf = coated_emission(uncoated_emission, coat_color, coat_F0, coat_weight);
// Final surface.
return surface(
bsdf = fuzz_layer,
edf = emission_edf,
opacity = geometry_opacity,
thin_walled = geometry_thin_walled);
}
The open_pbr_anisotropy function called above remaps a scalar roughness and anisotropy to the microfacet (αx, αy) pair that the base and coat lobes take as their roughness input. As anisotropy rises, αx widens and αy narrows, reducing to the isotropic roughness2 in both components when anisotropy is 0:
vector2 open_pbr_anisotropy(
float roughness, anisotropy)
{
float a = 1.0 - anisotropy;
float alpha_x = roughness ^ 2.0 * sqrt(2.0 / (1.0 + a ^ 2.0));
float alpha_y = a * alpha_x;
return (alpha_x, alpha_y);
}
In addition to the models defined above, the MaterialX data libraries provide renderable nodegraph implementations of the following shading models. These are offered as reference implementations: they may be used as shaders by MaterialX materials in the same manner as the models above, but this specification does not yet provide formal definitions of their compositions, and their data-library nodegraphs remain the authoritative statement of their MaterialX realization.
This shading model was presented by Brent Burley of Walt Disney Animation Studios in 201210, with additional refinements presented in 201527. Its MaterialX interface follows the 2015 BSDF form of the model, which extends the original 2012 BRDF with specular transmission and integrated subsurface scattering, and its nodegraph implementation is provided in the data libraries as disney_principled.mtlx.
MaterialX Lama is a modular material layering system developed at Industrial Light & Magic and distributed publicly as part of Pixar's RenderMan28. In place of a single über-shader with a fixed set of layers, Lama provides a set of component nodes from which layered materials of arbitrary structure may be composed: the responses LamaDiffuse, LamaTranslucent, LamaConductor, LamaDielectric, LamaGeneralizedSchlick, LamaIridescence, LamaSheen, LamaSSS, and LamaEmission; the combiners LamaAdd, LamaMix, and LamaLayer; and the LamaSurface node, which constructs a surface shader from the composed material. Nodegraph implementations of these nodes are provided in the bxdf/lama folder of the data libraries.
The MaterialX PBS Library includes a number of nodegraphs that can be used to approximately translate the input parameters for one shading model into values to drive the inputs of a different shading model, to produce the same visual results to the degree the differences between the shading models allow. Currently, the library includes translation graphs for:
- Autodesk Standard Surface to UsdPreviewSurface
- Autodesk Standard Surface to Khronos glTF PBR
- Autodesk Standard Surface to OpenPBR Surface
- OpenPBR Surface to Autodesk Standard Surface
This appendix contains extended equation sets for BSDF nodes whose full derivations would otherwise interrupt the flow of the node catalog.
The EON model8 decomposes the BRDF into a single-scatter lobe based on Fujii's improved Oren-Nayar formulation9 and a multi-scatter lobe that compensates for inter-reflection energy lost at higher roughness values. Two constants are shared across the model:
In the equations below, the color input corresponds to roughness input corresponds to
The directional albedo
The multi-scatter lobe recovers the energy that the single-scatter lobe loses to unmodeled inter-reflections between microfacets. Because each diffuse bounce is tinted by the albedo, the effective multi-scatter color is:
The <subsurface_bsdf> node is defined compositionally as a Lambertian transmission surface over an <anisotropic_vdf> medium, with a parameterization chosen to match random walk Monte Carlo methods15 as well as approximate empirical methods16. This section defines the conversion from the node's artist-facing inputs to the volume's physical coefficients, and the normalized diffusion profile used by diffusion-based renderers.
In the equations below, the color input corresponds to radius input corresponds to anisotropy input corresponds to
The conversion inverts the diffusion-theory relationship between single-scattering albedo and observed diffuse reflectance15.
An intermediate quantity
The single-scattering albedo for isotropic scattering (
When the phase function is anisotropic (
The absorption and scattering coefficients are then:
These coefficients, together with
In highly scattering, optically thick media6, the volumetric transport defined above produces a radially symmetric reflectance profile. Christensen and Burley16 propose the following empirical approximation to this profile, parameterized by the mean free path radius input):
where
A renderer may evaluate this model either directly via random-walk volumetric transport, or with the normalized diffusion profile
The Zeltner sheen model18 approximates multi-scattering cloth reflectance using a Linearly Transformed Cosine (LTC) lobe. A clamped cosine distribution
In the equations below, the color input corresponds to roughness input corresponds to
The inverse matrix has two fitted coefficients
where
The coefficients
The directional albedo
The Chiang hair model19 describes scattering from a hair fiber modeled as a rough dielectric cylinder with tilted cuticle scales, building on the foundational work of Marschner et al.21 and d'Eon et al.22. This section defines the components of the BCSDF introduced in <chiang_hair_bsdf>.
In the equations below, the ior input corresponds to absorption_coefficient input corresponds to cuticle_angle input corresponds to roughness_R, roughness_TT, and roughness_TRT inputs provide the longitudinal variance
Directions at a point on the fiber are parameterized by inclination
A ray intersecting the fiber is further parameterized by its normalized offset
The cuticle scales tilt the effective surface of the fiber, shifting the incidence angle for each lobe. The modified incidence angle for lobe
where
The longitudinal scattering function
For lobes R, TT, and TRT, the azimuthal scattering function
where
The logistic distribution with scale parameter
The azimuthal scattering is the logistic PDF trimmed to
For the TRRT+ lobe, the azimuthal scattering is uniform:
The attenuation factors
where
The thin-film iridescence model5 computes spectrally resolved Fresnel reflectance for a three-layer system — outer medium, thin dielectric film, substrate — using the Airy equations. This section defines the components of the Airy reflectance
In the equations below, the thinfilm_thickness input corresponds to thinfilm_ior input corresponds to
The system consists of three media separated by two parallel interfaces:
| Layer | Medium | IOR |
|---|---|---|
| 1 (outer) | Vacuum | |
| 2 (film) | Thin dielectric film |
thinfilm_ior
|
| 3 (substrate) | Node surface |
|
Light arriving at angle
The polarized Fresnel reflectances at each interface are computed separately for the parallel (p) and perpendicular (s) polarization states.
The first interface is a dielectric–dielectric boundary with IOR ratio
computed per polarization state. If
The second interface is evaluated at the refracted angle
-
Dielectric substrate (<dielectric_bsdf>): The polarized reflectances
$R_{23}^p$ and$R_{23}^s$ are computed using the dielectric Fresnel equations with IOR ratio$\eta_3 / \eta_2$ . -
Conductor substrate (<conductor_bsdf>): The polarized reflectances are computed using the conductor Fresnel equations with
$(\eta_3 / \eta_2, \kappa_3 / \eta_2)$ . -
Schlick substrate (<generalized_schlick_bsdf>): The reflectance is computed using the generalized Schlick Fresnel curve at
$\cos\theta_t$ , applied equally to both polarization states.
Each reflection at an interface introduces a phase shift that depends on the relative indices of refraction. The total phase accumulated per polarization state determines the interference pattern.
The phase shift
For a dielectric or conductor substrate with complex IOR
The polarized phase shifts are computed with the two-argument arctangent
In the dielectric case (
For a Schlick substrate, the phase shift at the film–substrate interface is approximated by the step function:
applied equally to both polarization states, where color0 input.
The optical path difference (OPD) between successive reflected beams within the film is:
where the factor
The reflected intensity
DC term (
Higher-order terms (
where
The spectral sensitivity function
The fitted parameters for the three XYZ channels are:
| Channel | |||
|---|---|---|---|
| X | |||
| Y | |||
| Z |
The X channel uses a second Gaussian lobe to better fit the bimodal shape of the CIE
The resulting XYZ value is normalized by
where lin_rec709 working color space is:
The result is clamped to
Footnotes
-
Bruce Walter et al., Microfacet Models for Refraction through Rough Surfaces, https://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf, 2007 ↩ ↩2 ↩3 ↩4
-
Eric Heitz, Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, http://jcgt.org/published/0003/02/03/paper.pdf, 2014 ↩ ↩2
-
Emmanuel Turquin, Practical multiple scattering compensation for microfacet models, https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf, 2019. ↩ ↩2 ↩3 ↩4
-
Andrea Weidlich, Alexander Wilkie, Arbitrarily Layered Micro-Facet Surfaces, https://www.cg.tuwien.ac.at/research/publications/2007/weidlich_2007_almfs/weidlich_2007_almfs-paper.pdf, 2007 ↩
-
Laurent Belcour, Pascal Barla, 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, 2017 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Matt Pharr et al., Physically Based Rendering: From Theory To Implementation, https://www.pbr-book.org/, 2023 ↩ ↩2 ↩3 ↩4 ↩5
-
Michael Oren, Shree K. Nayar, Generalization of Lambert’s Reflectance Model, https://dl.acm.org/doi/10.1145/192161.192213, 1994 ↩
-
Portsmouth et al., EON: A practical energy-preserving rough diffuse BRDF, https://www.jcgt.org/published/0014/01/06/, 2025. ↩ ↩2 ↩3
-
Yasuhiro Fujii, Improving the Oren-Nayar Diffuse Model, https://mimosa-pudica.net/improved-oren-nayar.html, 2020 ↩ ↩2 ↩3
-
Brent Burley, Physically-Based Shading at Disney, https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf, 2012 ↩ ↩2 ↩3
-
Portsmouth et al., The Minimal Retroreflective Microfacet Model, https://www.jcgt.org/published/0015/01/04/, 2026. ↩ ↩2 ↩3
-
Sébastien Lagarde, Memo on Fresnel equations, https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/, 2013 ↩ ↩2
-
Ole Gulbrandsen, Artist Friendly Metallic Fresnel, http://jcgt.org/published/0003/04/03/paper.pdf, 2014 ↩
-
Naty Hoffman, Generalization of Adobe's Fresnel Model, https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf 2023 ↩ ↩2
-
Christopher Kulla, Alejandro Conty, Revisiting Physically Based Shading at Imageworks, https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf, 2017 ↩ ↩2 ↩3
-
Per H. Christensen, Brent Burley, Approximate Reflectance Profiles for Efficient Subsurface Scattering, https://research.pixar.com/docs/2015.TechnicalReport.CB.pdf, 2015 ↩ ↩2 ↩3 ↩4
-
Alejandro Conty, Christopher Kulla, Production Friendly Microfacet Sheen BRDF, https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf, 2017 ↩
-
Tizian Zeltner et al., Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines, https://tizianzeltner.com/projects/Zeltner2022Practical/, 2022 ↩ ↩2 ↩3 ↩4 ↩5
-
Matt Jen-Yuan Chiang et al., A Practical and Controllable Hair and Fur Model for Production Path Tracing, https://media.disneyanimation.com/uploads/production/publication_asset/152/asset/eurographics2016Fur_Smaller.pdf, 2016 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Christophe Schlick, An Inexpensive BRDF Model for Physically-based Rendering, Computer Graphics Forum, https://doi.org/10.1111/1467-8659.1330233, 1994 ↩
-
Stephen R. Marschner et al., Light Scattering from Human Hair Fibers, http://www.graphics.stanford.edu/papers/hair/hair-sg03final.pdf, 2003 ↩ ↩2 ↩3 ↩4
-
Eugene d'Eon et al., An Energy-Conserving Hair Reflectance Model, https://eugenedeon.com/pdfs/egsrhair.pdf, 2011 ↩ ↩2 ↩3
-
Iliyan Georgiev et al., Autodesk Standard Surface, https://autodesk.github.io/standard-surface/, 2019. ↩
-
Pixar Animation Studios, UsdPreviewSurface Specification, https://openusd.org/release/spec_usdpreviewsurface.html, 2019. ↩
-
The Khronos Group, glTF 2.0 Specification, https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html, 2021. ↩
-
Andersson et al., OpenPBR Surface Specification, https://academysoftwarefoundation.github.io/OpenPBR/, 2024. ↩
-
Brent Burley, Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering, https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf, 2015 ↩
-
Pixar Animation Studios, MaterialX Lama, https://rmanwiki-27.pixar.com/space/REN27/542218994/MaterialX+Lama, 2021. ↩
