Skip to content

Latest commit

 

History

History
2760 lines (1981 loc) · 188 KB

File metadata and controls

2760 lines (1981 loc) · 188 KB

MaterialX Physically Based Shading Nodes

Version 1.39
Niklas Harrysson - Lumiere Software
Doug Smythe - Industrial Light & Magic
Jonathan Stone - Lucasfilm Advanced Development Group
June 5, 2026

Introduction

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.

Table of Contents

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

Shading Translation Graphs

Appendix: Extended Reflectance Models
EON Reflectance Model
Subsurface Scattering Model
Zeltner Sheen Model
Chiang Hair Model
Thin-Film Iridescence Model

References


Physical Material 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.

Scope

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.

Physically Plausible Materials

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.

Quantities and Units

Radiometric quantities are used by the material model for interactions with the renderer. The fundamental radiometric quantity is radiance (measured in $W\,m^{-2}\,sr^{-1}$) and gives the intensity of light arriving at, or leaving from, a given point in a given direction. If incident radiance is integrated over all directions we get irradiance (measured in $W\,m^{-2}$), and if we integrate this over surface area we get power (measured in $W$). Input parameters for materials and lights specified in photometric units can be suitably converted to their radiometric counterparts before being submitted to the renderer.

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.

Color Management

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.

Surfaces

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.

Physically Based Shading Diagram

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.

Layering

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".

Bump and Normal Mapping

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.

Volumes

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 $m^{-1}$.

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 $W\,m^{-3}\,sr^{-1}$. Because a participating medium has no surface normal to orient the distribution, volume emission is assumed to be isotropic.

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.

Lights

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.

Scattering Framework

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.

Symbols

In scattering equations, the subscript $_i$ denotes a quantity related to the incoming direction, and the subscript $_o$ denotes a quantity related to the outgoing direction. Depending on the rendering algorithm in use, these notions may be reversed or not well-defined. For the purposes of this document, we assume a unidirectional path-tracing algorithm: the outgoing direction $\omega_o$ points along the path toward the eye, and the incoming direction $\omega_i$ points along the path away from the eye. Both vectors are defined at a position $p$ and both point away from that position.

Symbol Description
$L_i$ Incident radiance at $p$ along direction $\omega_i$
$L_o$ Exitant radiance at $p$ along direction $\omega_o$
$L_e$ Emitted radiance at $p$ along direction $\omega_o$
$p$ Position of a scattering event on a surface or in a volume
$n$ Unit surface normal vector at $p$
$\omega_i$ Direction from $p$ along which incident radiance arrives
$\omega_o$ Direction from $p$ along which exitant radiance leaves
$\omega_h = \dfrac{\omega_i + \omega_o}{\lVert \omega_i + \omega_o \rVert}$ Half-vector between $\omega_i$ and $\omega_o$
$\theta$ Elevation angle of a direction from the surface normal
$\theta_i$ Elevation angle of the incident direction
$\theta_o$ Elevation angle of the exitant direction
$\theta_t$ Elevation angle of the exitant transmitted direction, measured from the inverted surface normal
$\phi$ Azimuthal angle of a direction around the surface normal
$\phi_i$ Azimuthal angle of the incident direction
$\phi_o$ Azimuthal angle of the exitant direction
$\Omega_i$ Hemisphere of incident directions around the surface normal
$\mathbb{S}^2$ Unit sphere of directions around $p$
$\eta_i$ Absolute index of refraction of the medium on the incident side of an interface
$\eta_t$ Absolute index of refraction of the medium on the transmitted side of an interface
$\eta = \eta_t / \eta_i$ Relative index of refraction across an interface

Media, Interfaces, and Scattering Events

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 $p$ from direction $\omega_i$ is redirected along a new direction $\omega_o$. The energy arriving along $\omega_i$ need not be fully redirected along $\omega_o$ — the remainder is absorbed or scattered in other directions.

Bidirectional Scattering Distribution Function

The bidirectional scattering distribution function (BSDF) describes the proportion of radiance scattered at a surface from an incoming direction $\omega_i$ to an outgoing direction $\omega_o$:

$$f(\omega_i, \omega_o) = \frac{dL_o}{L_i \cos\theta_i \; d\omega_i}$$

The bidirectional reflectance distribution function $f_r(\omega_i, \omega_o)$ (BRDF) and bidirectional transmittance distribution function $f_t(\omega_i, \omega_o)$ (BTDF) are specializations of the BSDF. For the BRDF, $\omega_i$ and $\omega_o$ lie in the same hemisphere; for the BTDF, they lie in opposite hemispheres.

Further specializations include the bidirectional curve-scattering distribution function $f_c$ (BCSDF), which defines scattering between directions from an infinitesimally thin cylinder as used by <chiang_hair_bsdf>, and the bidirectional subsurface-scattering distribution function $f_{\text{sss}}(\omega_i, \omega_o, p_i, p_o)$, which defines scattering between directions and between positions on a surface as used by <subsurface_bsdf>.

Emission Distribution Function

The emission distribution function (EDF) describes the radiance emitted at a position $p$ along an outgoing direction $\omega_o$. For a surface emitting radiant flux $\Phi_e$, the emitted radiance is:

$$L_e(\omega_o) = \frac{d^2\Phi_e}{dA \, \cos\theta_o \; d\omega_o}$$

where $dA$ is the differential area around $p$. Unlike the BSDF, the EDF is a function of a single direction and carries no dependence on an incident direction or cosine factor. For surface EDFs, $L_e$ has units of $W\,m^{-2}\,sr^{-1}$; for volume EDFs, $W\,m^{-3}\,sr^{-1}$.

Reflection and Transmission

Reflection is a scattering event where the exitant direction $\omega_o$ lies in the same hemisphere as the incident direction $\omega_i$, that is:

$$\mathrm{sgn}(\omega_i \cdot n) = \mathrm{sgn}(\omega_o \cdot n)$$

Transmission is a scattering event where $\omega_o$ lies in the opposite hemisphere from $\omega_i$, that is:

$$\mathrm{sgn}(\omega_i \cdot n) \ne \mathrm{sgn}(\omega_o \cdot n)$$

The reflectance and transmittance are the fractions of incident energy leaving a scattering event via reflection and transmission, respectively.

The reflection direction $\omega_r$ of $\omega_i$ about a surface or microfacet normal is:

$$\omega_r = 2(\omega_i \cdot n) n - \omega_i$$

The refraction direction $\omega_t$ of $\omega_i$ about a surface or microfacet normal, for media with incident and transmitted indices of refraction $\eta_i$ and $\eta_t$, is:

$$\cos\theta_t = \sqrt{1 - \left(\frac{\eta_i}{\eta_t}\right)^2 \sin^2\theta_i}$$

$$\omega_t = -\frac{\eta_i}{\eta_t} \omega_i + \left(\frac{\eta_i}{\eta_t}\cos\theta_i - \cos\theta_t\right) n$$

Diffuse, Glossy, and Specular

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.

Reflectance Models

This section defines the shared reflectance models referenced by multiple BSDF nodes in the MaterialX PBS Library below.

Microfacet Model

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 $D$ and masking-shadowing function $G_2$, and differ in their geometric and Fresnel terms. The Fresnel reflectance $F$ is defined per node.

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.

Microfacet BRDF

$$f_r(\omega_i, \omega_o) = \frac{D(\omega_h) F(\omega_i, \omega_h) G_2(\omega_i, \omega_o)}{4 \cos\theta_i \cos\theta_o}$$

where $\omega_h$ is the half-vector between $\omega_i$ and $\omega_o$ as defined in the Symbols table.

Microfacet BTDF

The microfacet BTDF uses a transmission half-vector that accounts for the change in index of refraction across the interface:

$$\omega_{ht} = -\frac{\eta_i \omega_i + \eta_t \omega_o}{\lVert \eta_i \omega_i + \eta_t \omega_o \rVert}$$

where $\eta_i$ and $\eta_t$ are the absolute indices of refraction of the incident and transmitted media, whose ratio $\eta_t/\eta_i$ is the relative index $\eta$ of the Symbols table. The BTDF is:

$$f_t(\omega_i, \omega_o) = \frac{|\omega_i \cdot \omega_{ht}| \cdot |\omega_o \cdot \omega_{ht}|}{\cos\theta_i \cos\theta_t} \cdot \frac{\eta_t^2 (1 - F(\omega_i, \omega_{ht})) D(\omega_{ht}) G_2(\omega_i, \omega_o)}{(\eta_i (\omega_i \cdot \omega_{ht}) + \eta_t (\omega_o \cdot \omega_{ht}))^2}$$

where $1 - F$ is the Fresnel transmittance, the complement of the Fresnel reflectance defined per node.

GGX Normal Distribution Function

The microfacet normal distribution is the anisotropic GGX (Trowbridge-Reitz) function1:

$$D(\omega_h) = \frac{1}{\pi \alpha_x \alpha_y\left(\left(\dfrac{h_x}{\alpha_x}\right)^2 + \left(\dfrac{h_y}{\alpha_y}\right)^2 + h_z^2\right)^2}$$

where $\alpha_x$ and $\alpha_y$ are the roughness values along the surface tangent and bitangent, and $h_x$, $h_y$, $h_z$ are the components of $\omega_h$ (or $\omega_{ht}$ for transmission) in the local tangent frame.

The pair $(\alpha_x, \alpha_y)$ is supplied directly by the 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.

Height-Correlated Smith Masking-Shadowing

The joint masking-shadowing function is the height-correlated form of the Smith function2. Define the direction-dependent stretched-vector length:

$$L(\omega) = \sqrt{\alpha_x^2\omega_x^2 + \alpha_y^2\omega_y^2 + \omega_z^2}$$

Then:

$$G_2(\omega_i, \omega_o) = \frac{2|\omega_{i,z}||\omega_{o,z}|} {|\omega_{i,z}|L(\omega_o) + |\omega_{o,z}|L(\omega_i)}$$

This is equivalent to evaluating the Smith $\Lambda$ function with the roughness projected independently onto each direction, as given by Heitz2. In the isotropic case, $\alpha_x = \alpha_y = \alpha$, this reduces to the usual scalar-roughness expression.

Directional Albedo and Energy Conservation

The directional albedo $E_o$ of a BSDF is its integral over all incident directions, for a fixed exitant direction $\omega_o$:

$$E_o = \int_{\Omega_i} f(\omega_i, \omega_o) \cos\theta_i \; d\omega_i$$

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.

Energy Compensation

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:

$$f_r^{\text{comp}}(\omega_i, \omega_o) = f_r(\omega_i, \omega_o)\left(1 + F_{\text{ss}} \frac{1 - E_{\text{ss}}}{E_{\text{ss}}}\right)$$

where $E_{\text{ss}}$ is the directional albedo of the microfacet BRDF evaluated with unit Fresnel ($F = 1$), and $F_{\text{ss}}$ is the cosine-weighted hemispherical average of the Fresnel reflectance of the BSDF being compensated.

Vertical-Layering Transmittance

Every BSDF defines a vertical-layering transmittance $T_o$: the fraction of incident light that passes through the BSDF to reach the layers beneath it, when the BSDF is used as the top input of a <layer> node. Like the directional albedo, the transmittance is evaluated for a fixed exitant direction $\omega_o$; it is a color quantity, with each channel taking a value in $[0, 1]$. All BSDFs in the PBS library are therefore layerable, with the transmittance of each elemental BSDF taking one of two forms:

  • 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 weight input $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 $T_o$ serves as a fixed-exitant-direction approximation of the ideal pass-through factor $P(\omega_i, \omega_o)$ of the layered microfacet model of Weidlich and Wilkie4, in which light reaching the base is attenuated along both its incident and exitant paths through the top layer. Targets that directly simulate light transport through the layer stack may refine the reference model accordingly, for example by evaluating the pass-through of each layer bidirectionally, or by accounting for multiple reflections between layers.

For an energy-conserving BSDF, the directional albedo of the reflection lobes never exceeds the occluded fraction of incident light, $E_o \leq 1 - T_o$, with any difference between the two sides representing energy absorbed by the BSDF. This invariant ensures that vertical layering preserves energy conservation.

Thin-Film Iridescence

The <dielectric_bsdf>, <conductor_bsdf>, and <generalized_schlick_bsdf> nodes support an optional thin-film interference effect5. A thin dielectric film of thickness $d$ (in nanometers) and index of refraction $\eta_2$ is placed between the outer medium ($\eta_1$, assumed to be vacuum with $\eta_1 = 1$) and the node's substrate. The substrate is characterized by its own optical properties: a real-valued IOR $\eta_3$ for dielectrics, a complex IOR $(\eta_3, \kappa_3)$ for conductors, or Schlick reflectance values mapped to an effective $\eta_3$.

When thinfilm_thickness is set to a non-zero value, the standard Fresnel reflectance $F$ defined by each node is replaced by the Airy reflectance $F_{\text{airy}}$, computed by summing the contributions of successive reflections between the two interfaces of the film. The reflectance is evaluated independently for the parallel (p) and perpendicular (s) polarization states and averaged:

$$F_{\text{airy}} = \tfrac{1}{2} \sum_{\text{pol} \in \{p,s\}} \left[ R_{12} + \frac{T_{12}^2 R_{23}}{1 - R_{12} R_{23}} + \sum_{m=1}^{M} C_m S_m \right]$$

where $R_{12}$ and $R_{23}$ are the polarized Fresnel reflectances at the first (air–film) and second (film–substrate) interfaces, $T_{12} = 1 - R_{12}$ is the transmittance through the first interface, $C_m$ are amplitude coefficients that account for successive bounces within the film, and $S_m$ encodes the spectral interference pattern for bounce order $m$ as a function of the optical path difference and accumulated phase shifts. The result is converted from a spectral representation to RGB. The full derivation, including polarized phase shifts and spectral-to-RGB conversion, is given in the Thin-Film Iridescence Model appendix.

Light Transport

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.

The Light Transport Equation

For a surface, the exitant radiance $L_o$ leaving a point $p$ along direction $\omega_o$ is the sum of the radiance emitted at $p$ and the radiance scattered toward $\omega_o$ from all incident directions:

$$L_o(\omega_o) = L_e(\omega_o) + \int_{\mathbb{S}^2} f(\omega_i, \omega_o)\, L_i(\omega_i)\, |\omega_i \cdot n|\; d\omega_i$$

where $f$ is the surface BSDF, $L_e$ is the surface EDF, and $L_i(\omega_i)$ is the radiance incident at $p$ from direction $\omega_i$. The integral is taken over the entire sphere of directions $\mathbb{S}^2$ rather than a single hemisphere, so that transmissive BSDFs — whose incident and exitant directions lie in opposite hemispheres — are included. The factor $|\omega_i \cdot n| = |\cos\theta_i|$ accounts for the projected solid angle of the incident direction.

The Equation of Transfer

For a participating medium, radiance is continuously attenuated by absorption and out-scattering and augmented by emission and in-scattering. The change in radiance $L$ per unit distance traveled along $\omega_o$ is given by the equation of transfer:

$$(\omega_o \cdot \nabla)\, L(p, \omega_o) = -\sigma_t\, L(p, \omega_o) + \sigma_s \int_{\mathbb{S}^2} f_p(\omega_i, \omega_o)\, L(p, \omega_i)\; d\omega_i + L_e(p, \omega_o)$$

The first term attenuates radiance by the extinction coefficient $\sigma_t = \sigma_a + \sigma_s$. The second adds radiance scattered into $\omega_o$ from all directions, weighted by the scattering coefficient $\sigma_s$ and the phase function $f_p$. The final term $L_e$ is the volume emission, stated in $W\,m^{-3}\,sr^{-1}$; it corresponds to the product $\sigma_a L_e$ of an absorption coefficient and an emitted radiance in the formulation of Pharr et al.6. The coefficients $\sigma_a$, $\sigma_s$ and the phase function $f_p$ are supplied by the medium's VDF, and $L_e$ by its EDF.


MaterialX PBS Library

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.

Data Types

  • 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.

BSDF Nodes

The equations below use the symbols and notation defined in the Scattering Framework, together with the shared reflectance models defined in Reflectance Models.

oren_nayar_diffuse_bsdf

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 $\rho$, the diffuse albedo, and the roughness input corresponds to $\sigma$, where $\sigma \in [0, 1]$.

Qualitative Oren-Nayar Reflectance Equations

$$A = 1 - 0.5\left(\frac{\sigma^2}{\sigma^2 + 0.33}\right)$$

$$B = 0.45\left(\frac{\sigma^2}{\sigma^2 + 0.09}\right)$$

$$g(\omega_i,\omega_o) = \max\left(0, \cos(\phi_i - \phi_o)\right)\sin\alpha \tan\beta,\quad \alpha = \max(\theta_i,\theta_o),\quad \beta = \min(\theta_i,\theta_o)$$

$$f_r(\omega_i,\omega_o) = \frac{\rho}{\pi}\bigl(A + B g(\omega_i,\omega_o)\bigr)$$

Energy-Preserving Oren-Nayar (EON) Reflectance Equations

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.

burley_diffuse_bsdf

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 $\rho$, the diffuse albedo, and the roughness input corresponds to $\sigma$, a perceptual roughness controlling the transition from Fresnel darkening at grazing angles for smooth surfaces to retroreflection for rough surfaces.

Burley Diffuse Reflectance Equations

The model uses a modified Schlick Fresnel factor with $F_0 = 1$ (no modification at normal incidence) and a roughness-dependent grazing term $F_{D90}$:

$$F_{D90} = \tfrac{1}{2} + 2\sigma (\omega_i \cdot \omega_h)^2$$

$$F_D(\theta) = 1 + (F_{D90} - 1)(1 - \cos\theta)^5$$

$$f_r(\omega_i, \omega_o) = \frac{\rho}{\pi} F_D(\theta_i) F_D(\theta_o)$$

dielectric_bsdf

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 $t$ and the ior input corresponds to $\eta$, the real-valued index of refraction of the surface relative to the exterior medium. The Fresnel formulation below assumes the exterior medium is air/vacuum ($\eta_i \approx 1$), so $\eta$ is equivalently the ratio of the surface IOR to that of the medium on the incident side of the interface. The roughness input provides the pair $(\alpha_x, \alpha_y)$ of anisotropic roughness values along the surface tangent and bitangent, supplied directly to the microfacet model with no internal remapping as described in GGX Normal Distribution Function.

The tint $t$ scales the node's reflection and transmission lobes directly, multiplying the microfacet BRDF and BTDF as $t f_r$ and $t f_t$. It does not modify the Fresnel reflectance $F$ itself, so the Fresnel transmittance $1 - F$ used by the BTDF remains untinted. The node's vertical-layering transmittance is likewise independent of $t$, with the energy removed by the tint classified as absorption within the interface rather than transmission to the base.

Dielectric Fresnel Equations

The Fresnel reflectance $F$ is computed from the standard Fresnel equations for unpolarized light1, using the optimized formulation given by Lagarde12:

$$c = \cos\theta$$

$$g = \sqrt{\eta^2 + c^2 - 1}$$

$$F = \frac{1}{2}\cdot\frac{(g - c)^2}{(g + c)^2}\left(1 + \frac{\bigl(c(g + c) - 1\bigr)^2}{\bigl(c(g - c) + 1\bigr)^2}\right)$$

When $\eta^2 + c^2 &lt; 1$, the quantity $g$ is imaginary and total internal reflection occurs, in which case $F = 1$.

Thin-Film Iridescence

When thinfilm_thickness is non-zero, the Fresnel reflectance $F$ above is replaced by the Airy reflectance $F_{\text{airy}}$ defined in Thin-Film Iridescence. The substrate IOR $\eta_3$ is set to the node's ior input $\eta$, with $\kappa_3 = 0$ (lossless dielectric). The polarized phase shifts at the film–substrate interface are computed using the complex phase formulas given in the Thin-Film Iridescence Model appendix, evaluated with $\kappa_3 = 0$; these capture the phase flip of the parallel polarization at the film–substrate Brewster angle, as well as the continuous phase shifts arising from total internal reflection within the film.

conductor_bsdf

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 $\eta$, the index of refraction per color channel, and the extinction input corresponds to $\kappa$, the extinction coefficient per color channel. Together, these define the complex index of refraction $\eta + i\kappa$ of the conductor. The roughness input provides the pair $(\alpha_x, \alpha_y)$ of anisotropic roughness values along the surface tangent and bitangent, supplied directly to the microfacet model with no internal remapping as described in GGX Normal Distribution Function.

Conductor Fresnel Equations

The reflectance $F$ is the average of the s-polarized ($R_s$) and p-polarized ($R_p$) Fresnel reflectances at a conductor interface12:

$$a^2 + b^2 = \sqrt{(\eta^2 - \kappa^2 - \sin^2\theta)^2 + 4\eta^2 \kappa^2}$$

$$a = \sqrt{\max\left(0, \tfrac{1}{2}(a^2 + b^2 + \eta^2 - \kappa^2 - \sin^2\theta)\right)}$$

$$R_s = \frac{a^2 + b^2 - 2a \cdot \cos\theta + \cos^2\theta}{a^2 + b^2 + 2a \cdot \cos\theta + \cos^2\theta}$$

$$R_p = R_s \cdot \frac{\cos^2\theta (a^2 + b^2) - 2a \cdot \cos\theta\sin^2\theta + \sin^4\theta}{\cos^2\theta (a^2 + b^2) + 2a \cdot \cos\theta\sin^2\theta + \sin^4\theta}$$

$$F = \tfrac{1}{2}(R_s + R_p)$$

Thin-Film Iridescence

When thinfilm_thickness is non-zero, the Fresnel reflectance $F$ above is replaced by the Airy reflectance $F_{\text{airy}}$ defined in Thin-Film Iridescence. The substrate is defined by the node's complex index of refraction, with $\eta_3 = \eta$ and $\kappa_3 = \kappa$. The polarized phase shifts at the film–substrate interface are computed using the complex phase formulas given in the Thin-Film Iridescence Model appendix.

generalized_schlick_bsdf

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 $r_0$ and $r_{90}$, the color82 input corresponds to $t$, and the exponent input corresponds to $q$ in the generalized Schlick model. The roughness input provides the pair $(\alpha_x, \alpha_y)$ of anisotropic roughness values along the surface tangent and bitangent, supplied directly to the microfacet model with no internal remapping as described in GGX Normal Distribution Function.

Generalized Schlick Equations

The Hoffman14 generalization of the Schlick Fresnel curve adds a controllable dip in the reflectance at $\theta_{\max} = \arccos(1/7) \approx 81.79°$, whose depth is set by the color82 multiplier $t$:

$$\cos\theta_{\max} = \frac{1}{7}$$

$$a = \frac{\bigl[r_0 + (r_{90} - r_0)(1 - \cos\theta_{\max})^{q}\bigr](1 - t)}{\cos\theta_{\max}(1 - \cos\theta_{\max})^{6}}$$

$$F_{\theta} = r_0 + (r_{90} - r_0)(1 - \cos\theta)^{q} - a \cdot \cos\theta (1 - \cos\theta)^{6}$$

Thin-Film Iridescence

When thinfilm_thickness is non-zero, the Fresnel reflectance $F_{\theta}$ above is replaced by the Airy reflectance $F_{\text{airy}}$ defined in Thin-Film Iridescence. The substrate IOR $\eta_3$ is derived from the color0 input $r_0$ using the standard Schlick-to-IOR inversion, with $\kappa_3 = 0$. The phase shift at the film–substrate interface uses the step-function approximation given in the Thin-Film Iridescence Model appendix, applied equally to both polarization states.

translucent_bsdf

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 $\rho$, the diffuse transmittance.

Lambertian Transmittance Equation

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):

$$f_t(\omega_i, \omega_o) = \frac{\rho}{\pi}$$

subsurface_bsdf

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

Compositional Structure

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 $g$ (the 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 ($p_i$ and $p_o$), as introduced in the Bidirectional Scattering Distribution Function section.

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.

sheen_bsdf

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 $c$, a non-physical color tint on the sheen lobe, and the roughness input corresponds to $r$, the degree to which the microfibers diverge from the surface normal. As with the tint of <dielectric_bsdf>, the color $c$ attenuates only the scattered response, and does not contribute to the node's vertical-layering transmittance.

Conty-Kulla Sheen Equations

$$D(\theta_h) = \frac{\left(2 + \dfrac{1}{r}\right)\left(1 - \cos^2\theta_h\right)^{\frac{1}{2r}}}{2\pi}$$

$$f_r(\omega_i,\omega_o,\omega_h) = \frac{c D(\theta_h)}{4(\cos\theta_i + \cos\theta_o - \cos\theta_i\cos\theta_o)}$$

Zeltner Sheen Equations

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.

chiang_hair_bsdf

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 $v$ and an azimuthal logistic scale $s$ for each lobe, with (0,0) specifying pure specular scattering. These low-level parameters may be computed from artist-facing longitudinal and azimuthal roughness values using the <chiang_hair_roughness> utility node. The default ior of 1.55 represents the index of refraction for keratin. The cuticle_angle is a normalized value in $[0, 1]$, with 0.5 representing no tilt, and values above 0.5 tilting the scales toward the root of the fiber.

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 $t_R$, $t_{TT}$, $t_{TRT}$; the ior input corresponds to $\eta$, the index of refraction of the hair fiber; the roughness_R, roughness_TT, and roughness_TRT inputs each provide a pair $(v, s)$ of longitudinal variance and azimuthal logistic scale values; the cuticle_angle input corresponds to $\alpha$; and the absorption_coefficient input corresponds to $\sigma_a$.

Chiang Hair Scattering Equations

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 $\theta$ from the fiber's normal plane and azimuth $\phi$ around the fiber, differing from the surface-normal angles used by planar BSDF nodes. The BCSDF is a sum over four scattering lobes: R (surface reflection), TT (double transmission), TRT (internal reflection), and TRRT+ (higher-order paths):

$$f_c(\omega_i, \omega_o) = \sum_{p \in \{R,TT,TRT,TRRT+\}} t_p A_p M_p N_p$$

where $M_p$ is the longitudinal scattering function, $N_p$ is the azimuthal scattering function, and $A_p$ is the attenuation factor combining Fresnel reflectance and volumetric absorption. The longitudinal and azimuthal distributions include the normalization required by the model, so the lobe products require no additional normalization. The higher-order TRRT+ lobe shares the tint $t_{TRT}$ and the roughness values of the TRT lobe. The full definitions of these components are given in the Chiang Hair Model appendix.

EDF Nodes

The equations below use the symbols, notation, and emission conventions defined in the Scattering Framework.

uniform_edf

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 $c$, the emitted radiance.

Uniform Emission Equation

$$L_e(\omega_o) = c$$

For a Lambertian emitter such as this, the equivalent radiant exitance (power per unit area integrated over the hemisphere) is $M = \pi c$.

conical_edf

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 $c$, the peak emitted radiance along the cone axis. The inner_angle and outer_angle inputs are full cone angles in degrees and are halved to obtain the angle from the cone axis.

Conical Falloff Equations

Define:

$$\cos\theta_o = \max(0, \omega_o \cdot n)$$

$$c_{\text{in}} = \cos\!\left(\tfrac{\pi}{360}\cdot\text{inner\_angle}\right), \quad c_{\text{out}} = \cos\!\left(\tfrac{\pi}{360}\cdot\text{outer\_angle}\right)$$

Case 1 — no falloff (outer_angle $\le$ inner_angle): a hard cutoff at the inner cone boundary.

$$L_e(\omega_o) = \begin{cases} c & \text{if } \cos\theta_o \ge c_{\text{in}} \\ 0 & \text{otherwise} \end{cases}$$

Case 2 — smooth falloff (outer_angle $&gt;$ inner_angle): Hermite-smoothstep interpolation in cosine space between the outer and inner cone boundaries.

$$L_e(\omega_o) = c\cdot\mathrm{smoothstep}(c_{\text{out}},\, c_{\text{in}},\, \cos\theta_o)$$

where $\mathrm{smoothstep}(a, b, x) = t^2(3 - 2t)$ with $t = \mathrm{clamp}\!\left(\dfrac{x - a}{b - a},\, 0,\, 1\right)$.

measured_edf

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

generalized_schlick_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 $r_0$ and $r_{90}$, the exponent input corresponds to $q$, and the base input corresponds to $L_e^{\text{base}}$.

Generalized Schlick Emission Equations

The emission scaling factor follows the two-parameter Schlick curve20 evaluated at $\cos\theta_o = \omega_o \cdot n$:

$$F(\cos\theta_o) = r_0 + (r_{90} - r_0)(1 - \cos\theta_o)^{q}$$

$$L_e(\omega_o) = F(\cos\theta_o) \cdot L_e^{\text{base}}(\omega_o)$$

VDF Nodes

absorption_vdf

Constructs a VDF for pure light absorption.

The absorption input represents the absorption rate per distance traveled in the medium, stated in $m^{-1}$, with independent control for each wavelength.

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 $\sigma_a$, the absorption coefficient per color channel, stated in $m^{-1}$.

Beer-Lambert Absorption

As light travels a distance $t$ through a purely absorbing medium, its radiance is attenuated exponentially according to Beer's law:

$$T(t) = e^{-\sigma_a t}$$

where $T$ is the fraction of radiance transmitted.

anisotropic_vdf

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 $m^{-1}$, with independent control for each wavelength.

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 $\sigma_a$, the absorption coefficient per color channel; the scattering input corresponds to $\sigma_s$, the scattering coefficient per color channel; and the anisotropy input corresponds to $g$, the phase function asymmetry parameter. All coefficients are stated in $m^{-1}$.

Extinction

The extinction coefficient is the combined rate of absorption and scattering:

$$\sigma_t = \sigma_a + \sigma_s$$

As light travels a distance $t$ through the medium, its radiance is attenuated by absorption and out-scattering:

$$T(t) = e^{-\sigma_t t}$$

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:

$$\varpi = \frac{\sigma_s}{\sigma_t}$$

Henyey-Greenstein Phase Function

The phase function $f_p$ describes the angular distribution of scattered light at each scattering event. This node uses the Henyey-Greenstein phase function6, parameterized by the asymmetry parameter $g \in [-1, 1]$:

$$f_p(\cos\theta, g) = \frac{1}{4\pi} \cdot \frac{1 - g^2}{(1 + g^2 - 2g\cos\theta)^{3/2}}$$

where $\theta$ is the deflection angle between the incident and scattered directions of propagation. Because $\omega_i$ and $\omega_o$ both point away from $p$, this is $\cos\theta = -(\omega_i \cdot \omega_o)$. For $g = 0$ the distribution is uniform (isotropic scattering), positive values of $g$ produce forward scattering, and negative values produce backward scattering.

PBR Shader Nodes

surface

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 $f$, the edf input corresponds to $L_e$, and the opacity input corresponds to $O$.

Surface Shading Equation

The surface shader evaluates the Light Transport Equation at the shading point, scaled by the cutout opacity $O \in [0, 1]$:

$$L_o(\omega_o) = O \left[ L_e(\omega_o) + \int_{\mathbb{S}^2} f(\omega_i, \omega_o)\, L_i(\omega_i)\, |\omega_i \cdot n|\; d\omega_i \right]$$

The opacity $O$ is the fraction of the surface footprint covered by the material; the remaining uncovered fraction $1 - O$ lets radiance from geometry behind the surface pass through unoccluded, allowing the surface to act as a cutout mask.

Closed and Thin-Walled Surfaces

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.

volume

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 $\sigma_a$, scattering coefficient $\sigma_s$, and phase function $f_p$, and the edf input corresponds to the volume emission $L_e$.

Volume Shading Equation

The volume shader evaluates the Equation of Transfer within the participating medium.

light

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 $L_e^{\text{edf}}$, the intensity input corresponds to $I$, and the exposure input corresponds to $E$.

Light Emission Equation

The light shader scales the emission of the connected EDF by a linear intensity multiplier and a photographic exposure control in stops:

$$L_e(\omega_o) = I \cdot 2^{E} \cdot L_e^{\text{edf}}(\omega_o)$$

Note that the standard library includes definitions for displacement and surface_unlit shader nodes.

Utility Nodes

mix

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 $f_{\text{bg}}$, the fg input corresponds to $f_{\text{fg}}$, and the mix input corresponds to the weight $w$.

Mix Equation

$$f = (1 - w) f_{\text{bg}} + w f_{\text{fg}}$$

When mixing BSDFs, the vertical-layering transmittance of the result interpolates in the same manner:

$$T = (1 - w) T_{\text{bg}} + w T_{\text{fg}}$$

Because $w \in [0, 1]$, the mix of two individually energy-conserving distribution functions is also energy conserving.

layer

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

Layering over a BSDF

In the equations below, the top input corresponds to $f_{\text{top}}$ and the base input corresponds to $f_{\text{base}}$. The quantities $T_{\text{top}}$ and $T_{\text{base}}$ are their respective transmittances, as defined in the Vertical-Layering Transmittance section.

The response of the layered result is:

$$f = f_{\text{top}} + T_{\text{top}} f_{\text{base}}$$

and its transmittance is the product of the transmittances of its inputs:

$$T = T_{\text{top}} T_{\text{base}}$$

This recursive product makes the transmittance of a layer stack independent of its grouping, so that $\mathrm{layer}(\mathrm{layer}(a, b), c)$ and $\mathrm{layer}(a, \mathrm{layer}(b, c))$ occlude the layers beneath them identically.

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 $f_{\text{top}}$ and $f_{\text{base}}$ are individually energy conserving, the layered result is also energy conserving.

Layering over a VDF

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, $f_{r,\text{top}}$ and $f_{t,\text{top}}$ are the reflection and transmission lobes of the top BSDF, $T_{\text{top}}$ is its vertical-layering transmittance, and $T_{\text{vdf}}$ is the transmittance of the medium: the fraction of radiance surviving absorption and out-scattering along the light's path through it, given by $e^{-\sigma_t t}$ for a homogeneous medium traversed over a distance $t$, as defined in the <absorption_vdf> and <anisotropic_vdf> sections. Within the reference transmittance-scaling model, the reflection lobes of the top BSDF are unaffected by the medium, while light transmitted through the surface is attenuated along its path:

$$f = f_{r,\text{top}} + T_{\text{vdf}} \, f_{t,\text{top}}$$

and the transmittance of the composite is the product of the transmittances of the surface and the medium:

$$T = T_{\text{top}} T_{\text{vdf}}$$

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 $t$ from the object's geometry, while targets that do not may approximate it with a fixed distance.

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.

add

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 $f_1$ and the in2 input corresponds to $f_2$.

Add Equation

$$f = f_1 + f_2$$

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

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 $f_1$ and the in2 input corresponds to the scaling weight $s$.

Multiply Equation

$$f = s f_1$$

When $s$ is a color3, each color channel of the distribution function is scaled independently.

roughness_anisotropy

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 $(\alpha_x, \alpha_y)$ supplied directly to the 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

roughness_dual

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 $(\alpha_x, \alpha_y)$ supplied directly to the 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

glossiness_anisotropy

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 $(\alpha_x, \alpha_y)$ supplied directly to the 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

blackbody

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

artistic_ior

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

chiang_hair_roughness

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 $\ell$, the artist-facing longitudinal roughness; the azimuthal input corresponds to $a$, the artist-facing azimuthal roughness; and the scale_TT and scale_TRT inputs correspond to the per-lobe roughness scales $k_{TT}$ and $k_{TRT}$21.

Hair Roughness Conversion Equations

The artist-facing roughness values are converted to the longitudinal variance $v$ and azimuthal logistic scale $s$ consumed by <chiang_hair_bsdf> using empirical fits19:

$$v = \left(0.726\ell + 0.812\ell^2 + 3.7\ell^{20}\right)^2$$

$$s = 0.265 a + 1.194 a^2 + 5.372 a^{22}$$

The per-lobe outputs apply the squared roughness scales to the longitudinal variance:

$$\text{roughness\_R} = (v,\; s), \quad \text{roughness\_TT} = (k_{TT}^2\, v,\; s), \quad \text{roughness\_TRT} = (k_{TRT}^2\, v,\; s)$$

deon_hair_absorption_from_melanin

Converts the hair melanin parameterization to absorption coefficient based on pigments eumelanin and pheomelanin using the mapping method described in 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

chiang_hair_absorption_from_color

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

Shading Models

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.

Shading Model Notation

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, and surfaceshader are 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. Nworld and Tworld denote the default world-space geometric normal and tangent (the defaultgeomprop of 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 as clamp, normalize, and luminance — with arguments corresponding to its input ports. Arguments may be positional (in port order) or named as port = 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 a float or color3. The constant PI may be used wherever a float literal is accepted, denoting the mathematical constant π.

  • Mixing. mix(fg, bg, w) is the <mix> node: it returns fg at w = 1 and bg at w = 0, equal to (1 − w)·bg + w·fg. Note that this argument order — foreground first — is reversed from the mix() 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 — where cond is a boolean or a comparison using >, >=, <, <=, or ==. A boolean maps to an <ifequal> test against true (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) or vectorN(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 indexing v[i] selects channel i. A convert(x) call is the <convert> node, carrying a value across types with the same channel count, as from color3 to vector3.

Shared Functions

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 ($F_0$), the reflectance at normal incidence, of a dielectric interface from its index of refraction:

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 $F_0$, and this attenuated emission is blended in by 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);
}

Autodesk Standard Surface

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

Autodesk Standard Surface Shader Definition

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);
}

UsdPreviewSurface

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

UsdPreviewSurface Shader Definition

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);
}

Khronos glTF PBR

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

Khronos glTF PBR Shader Definition

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.

OpenPBR Surface

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

OpenPBR Surface Shader Definition

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);
}

Additional Reference Implementations

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.

Disney Principled BSDF

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

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.


Shading Translation Graphs

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:


Appendix: Extended Reflectance Models

This appendix contains extended equation sets for BSDF nodes whose full derivations would otherwise interrupt the flow of the node catalog.

EON Reflectance Model

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:

$$c_1 = \frac{1}{2} - \frac{2}{3\pi}, \quad c_2 = \frac{2}{3} - \frac{28}{15\pi}$$

In the equations below, the color input corresponds to $\rho$, the diffuse albedo, and the roughness input corresponds to $\sigma$, the surface roughness, where $\sigma \in [0, 1]$.

Single-Scatter Lobe

$$A = \frac{1}{1 + c_1 \sigma}$$

$$s = \omega_i \cdot \omega_o - \cos\theta_i \cos\theta_o$$

$$\frac{s}{t} = \begin{cases} s / \max(\cos\theta_i, \cos\theta_o) & \text{if } s > 0 \\ s & \text{otherwise}\end{cases}$$

$$f_{\text{ss}}(\omega_i, \omega_o) = \frac{\rho}{\pi} A \left(1 + \sigma \frac{s}{t}\right)$$

Directional Albedo and Average Albedo

The directional albedo $\hat{E}$ is the hemispherical integral of the single-scatter lobe with unit albedo, and the average albedo $\bar{E}$ is its cosine-weighted average over the hemisphere. Both have closed-form expressions9:

$$G(\theta) = \sin\theta\left(\theta - \sin\theta\cos\theta\right) + \frac{2}{3}\left(\frac{\sin\theta(1 - \sin^3\theta)}{\cos\theta} - \sin\theta\right)$$

$$\hat{E}(\theta, \sigma) = A + \frac{\sigma A}{\pi} G(\theta)$$

$$\bar{E}(\sigma) = \frac{1 + c_2 \sigma}{1 + c_1 \sigma}$$

Multi-Scatter Lobe

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:

$$\rho_{\text{ms}} = \frac{\rho^2 \bar{E}}{1 - \rho(1 - \bar{E})}$$

$$f_{\text{ms}}(\omega_i, \omega_o) = \frac{\rho_{\text{ms}}}{\pi} \cdot \frac{(1 - \hat{E}(\theta_o, \sigma))(1 - \hat{E}(\theta_i, \sigma))}{1 - \bar{E}(\sigma)}$$

Combined BRDF

$$f_r(\omega_i, \omega_o) = f_{\text{ss}}(\omega_i, \omega_o) + f_{\text{ms}}(\omega_i, \omega_o)$$

Subsurface Scattering Model

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 $\rho$, the observed diffuse reflectance per color channel; the radius input corresponds to $\ell$, the mean free path per color channel; and the anisotropy input corresponds to $g$, the phase function asymmetry parameter.

Albedo Inversion

The conversion inverts the diffusion-theory relationship between single-scattering albedo and observed diffuse reflectance15.

An intermediate quantity $d$ is first computed from the observed diffuse reflectance $\rho$:

$$d = 4.09712 + 4.20863\rho - \sqrt{9.59217 + 41.6808\rho + 17.7126\rho^2}$$

The single-scattering albedo for isotropic scattering ($g = 0$) is:

$$\varpi_0 = 1 - d^2$$

When the phase function is anisotropic ($g \ne 0$), the single-scattering albedo is adjusted using the similarity relation16 to account for the directional bias of scattering:

$$\varpi = \frac{\varpi_0}{1 - g(1 - \varpi_0)}$$

The absorption and scattering coefficients are then:

$$\sigma_s = \frac{\varpi}{\ell}, \quad \sigma_a = \frac{1 - \varpi}{\ell}$$

These coefficients, together with $g$, parameterize the <anisotropic_vdf> volume.

Normalized Diffusion Profile

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 $\ell$ (the radius input):

$$R(r) = \frac{e^{-r/\ell} + e^{-r/(3\ell)}}{8\pi \ell r}$$

where $r$ is measured in the same world-space units as $\ell$. The profile integrates to unity over the plane and is scaled by the observed diffuse reflectance $\rho$. Here $r$ denotes the distance between the entry and exit points on the surface; locating such point pairs depends on the mesh geometry and is part of the renderer's sampling strategy.

A renderer may evaluate this model either directly via random-walk volumetric transport, or with the normalized diffusion profile $R(r)$ above; the two approaches are expected to converge to the same result under the assumptions of diffusion theory.

Zeltner Sheen Model

The Zeltner sheen model18 approximates multi-scattering cloth reflectance using a Linearly Transformed Cosine (LTC) lobe. A clamped cosine distribution $D_o(\omega) = \max(\cos\theta, 0) / \pi$ is warped by an inverse transformation matrix $M^{-1}$ to match the shape of the target sheen BRDF. The lobe shape is determined by the exitant direction $\omega_o$ and distributes energy across incident directions $\omega_i$, making the LTC approximation non-reciprocal. Note that the exitant direction of this document is labeled $\omega_i$ in the notation of Zeltner et al18. The roughness is clamped to $r \in [0.01, 1]$, and the directions $\omega_i$ and $\omega_o$ are expressed in a tangent frame aligned to the view-normal plane.

In the equations below, the color input corresponds to $c$, the sheen color tint, and the roughness input corresponds to $r$, the surface roughness.

LTC Inverse Matrix

The inverse matrix has two fitted coefficients $a$ and $b$, each a function of $\cos\theta_o$ and $r$:

$$M^{-1} = \begin{pmatrix} a & 0 & b \\\ 0 & a & 0 \\\ 0 & 0 & 1 \end{pmatrix}$$

Cosine-Weighted BRDF

$$f_r(\omega_i, \omega_o)\cos\theta_i = c \hat{E}(\theta_o, r) D_o\left(\frac{M^{-1}\omega_i}{\lVert M^{-1}\omega_i \rVert}\right) \frac{a^2}{\lVert M^{-1}\omega_i \rVert^3}$$

where $\hat{E}(\theta_o, r)$ is the directional albedo of the sheen lobe.

Fitted Coefficients

The coefficients $a$, $b$, and $\hat{E}$ are closed-form fits to precomputed reference data18, expressed in terms of $x = \cos\theta_o$ and $y = r$:

$$a(x, y) = \frac{(2.58126 x + 0.813703 y) y}{1 + 0.310327 x^2 + 2.60994 x y}$$

$$b(x, y) = \frac{\sqrt{1 - x}(y - 1) y^3}{0.0000254053 + 1.71228 x - 1.71506 x y + 1.34174 y^2}$$

Directional Albedo

The directional albedo $\hat{E}$ uses a Gaussian fit with rational sub-expressions for its standard deviation $s$, mean $m$, and offset $o$:

$$s = \frac{y(0.0206607 + 1.58491 y)}{0.0379424 + y(1.32227 + y)}$$

$$m = \frac{y(-0.193854 + y(-1.14885 + y(1.7932 - 0.95943 y^2)))}{0.046391 + y}$$

$$o = \frac{y(0.000654023 + (-0.0207818 + 0.119681 y) y)}{1.26264 + y(-1.92021 + y)}$$

$$\hat{E}(x, y) = \frac{1}{s\sqrt{2\pi}} \exp\left(-\tfrac{1}{2}\left(\frac{x - m}{s}\right)^2\right) + o$$

Chiang Hair Model

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 $\eta$, the index of refraction; the absorption_coefficient input corresponds to $\sigma_a$, the absorption coefficient; the cuticle_angle input corresponds to $\alpha$, the cuticle angle (remapped from the input range $[0, 1]$ to $[-\pi/2, \pi/2]$); and the roughness_R, roughness_TT, and roughness_TRT inputs provide the longitudinal variance $v$ and azimuthal logistic scale $s$ for their respective lobes.

Hair Fiber Geometry

Directions at a point on the fiber are parameterized by inclination $\theta$ from the normal plane (where $\sin\theta = \omega \cdot u$ and $u$ is the fiber tangent) and azimuthal angle $\phi$ around the fiber. The relative azimuth between the incident and outgoing directions is $\phi = \phi_i - \phi_o$.

A ray intersecting the fiber is further parameterized by its normalized offset $h \in [-1, 1]$ from the fiber axis within the cross-sectional plane, which determines the azimuthal incidence angle $\gamma_o$ through $\sin\gamma_o = h$. Computing $h$ for a given intersection depends on the curve geometry representation and is part of the renderer's intersection and sampling strategy.

Cuticle Tilt

The cuticle scales tilt the effective surface of the fiber, shifting the incidence angle for each lobe. The modified incidence angle for lobe $p$ is:

$$\theta_i^p = \theta_i + (2 - 3p)\alpha$$

where $p = 0$ for R, $p = 1$ for TT, and $p = 2$ for TRT. The TRRT+ lobe uses the unmodified $\theta_i$.

Longitudinal Scattering

The longitudinal scattering function $M_p$ uses the modified Bessel function of the first kind $I_0$:

$$M_p = \frac{\exp\left(-\dfrac{\sin\theta_i^p \sin\theta_o}{v}\right) I_0\left(\dfrac{\cos\theta_i^p \cos\theta_o}{v}\right)}{2v\sinh(1/v)}$$

Azimuthal Scattering

For lobes R, TT, and TRT, the azimuthal scattering function $N_p$ is a trimmed logistic distribution centered at the azimuthal exit angle $\Phi_p$. The exit angle for lobe $p$ is:

$$\Phi_p = 2p\gamma_t - 2\gamma_o + p\pi$$

where $\gamma_o$ is the azimuthal incidence angle on the fiber cross-section and $\gamma_t$ is the refracted angle satisfying $\sin\gamma_o = \eta'\sin\gamma_t$. Here $\eta'$ is the effective index of refraction, corrected for the cylindrical geometry of the fiber, and is the value that must be used for the azimuthal refraction:

$$\eta' = \frac{\sqrt{\eta^2 - \sin^2\theta_o}}{\cos\theta_o}$$

The logistic distribution with scale parameter $s$ has the PDF and CDF:

$$\ell(x, s) = \frac{e^{-x/s}}{s(1 + e^{-x/s})^2}, \quad L(x, s) = \frac{1}{1 + e^{-x/s}}$$

The azimuthal scattering is the logistic PDF trimmed to $[-\pi, \pi]$, with the scale adjusted by a factor of $\sqrt{\pi/8}$19:

$$s' = s\sqrt{\pi/8}$$

$$N_p(\phi) = \frac{\ell(\phi - \Phi_p,\; s')}{L(\pi,\; s') - L(-\pi,\; s')}$$

For the TRRT+ lobe, the azimuthal scattering is uniform: $N_{TRRT+} = 1/(2\pi)$.

Attenuation Factors

The attenuation factors $A_p$ combine Fresnel reflectance with volumetric absorption inside the fiber, using the effective index of refraction $\eta'$ defined under Azimuthal Scattering. Let $F$ denote the dielectric Fresnel reflectance evaluated at $\cos\theta_o \cos\gamma_o$. The absorption for a single transverse crossing of the fiber follows from Beer's law:

$$T = \exp\left(-\sigma_a \cdot \frac{2\cos\gamma_t}{\cos\theta_t}\right)$$

where $\theta_t$ is the refracted longitudinal angle ($\sin\theta_t = \sin\theta_o / \eta$). The per-lobe attenuation factors are:

$$A_R = F$$

$$A_{TT} = (1 - F)^2 T$$

$$A_{TRT} = (1 - F)^2 F T^2$$

$$A_{TRRT+} = \frac{(1 - F)^2 F^2 T^3}{1 - FT}$$

Thin-Film Iridescence Model

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 $F_{\text{airy}}$ introduced in Thin-Film Iridescence.

In the equations below, the thinfilm_thickness input corresponds to $d$, the film thickness in nanometers, and the thinfilm_ior input corresponds to $\eta_2$, the index of refraction of the film. The substrate optical properties $\eta_3$ (and $\kappa_3$ for conductors) are supplied by the host node as described in its inline thin-film section.

Three-Layer Geometry

The system consists of three media separated by two parallel interfaces:

Layer Medium IOR
1 (outer) Vacuum $\eta_1 = 1$
2 (film) Thin dielectric film $\eta_2$ = thinfilm_ior
3 (substrate) Node surface $\eta_3$ (and $\kappa_3$ for conductors)

Light arriving at angle $\theta$ from the outer medium refracts into the film at angle $\theta_t$ according to Snell's law:

$$\cos\theta_t = \sqrt{1 - \left(\frac{\eta_1}{\eta_2}\right)^2 \sin^2\theta}$$

Interface Reflectances

The polarized Fresnel reflectances at each interface are computed separately for the parallel (p) and perpendicular (s) polarization states.

First Interface (Air–Film)

The first interface is a dielectric–dielectric boundary with IOR ratio $\eta_2 / \eta_1$. The polarized reflectances $R_{12}^p$ and $R_{12}^s$ are computed using the standard dielectric Fresnel equations evaluated at $\cos\theta$. The transmittance through the first interface is:

$$T_{12} = 1 - R_{12}$$

computed per polarization state. If $\cos\theta_t \leq 0$, total internal reflection occurs and $R_{12} = 1$.

Second Interface (Film–Substrate)

The second interface is evaluated at the refracted angle $\theta_t$. The computation depends on the substrate type of the host node:

  • 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.

Phase Shifts

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.

First Interface Phase

The phase shift $\phi_{21}$ at the air–film interface depends on the incidence angle relative to the Brewster angle $\theta_B = \arctan(\eta_2 / \eta_1)$:

$$\phi_{21}^p = \begin{cases} \pi & \text{if } \theta < \theta_B \\ 0 & \text{otherwise} \end{cases}$$

$$\phi_{21}^s = \pi$$

Second Interface Phase (Dielectric and Conductor Substrates)

For a dielectric or conductor substrate with complex IOR $(\eta_3, \kappa_3)$, where $\kappa_3 = 0$ for a lossless dielectric, the phase shifts are computed from the complex Fresnel coefficients. Defining the intermediate quantities:

$$\bar{k} = \kappa_3 / \eta_3$$

$$A = \eta_3^2 (1 - \bar{k}^2) - \eta_2^2 \sin^2\theta_t$$

$$B = \sqrt{A^2 + (2\eta_3^2 \bar{k})^2}$$

$$U = \sqrt{(A + B) / 2}$$

$$V = \max\left(0, \sqrt{(B - A) / 2}\right)$$

The polarized phase shifts are computed with the two-argument arctangent $\mathrm{atan2}(y, x)$, which is required to resolve the correct quadrant:

$$\phi_{23}^s = \mathrm{atan2}\left(2\eta_2 V \cos\theta_t,\; U^2 + V^2 - (\eta_2 \cos\theta_t)^2\right)$$

$$\phi_{23}^p = \mathrm{atan2}\left(2\eta_2 \eta_3^2 \cos\theta_t \left(2\bar{k}U - (1 - \bar{k}^2)V\right),\; \left(\eta_3^2 (1 + \bar{k}^2) \cos\theta_t\right)^2 - \eta_2^2 (U^2 + V^2)\right)$$

In the dielectric case ($\kappa_3 = 0$), these expressions reduce below the critical angle to step functions of $0$ and $\pi$: the perpendicular phase $\phi_{23}^s$ is $\pi$ when $\eta_3 &lt; \eta_2$ and $0$ otherwise, while the parallel phase $\phi_{23}^p$ additionally flips by $\pi$ at the film–substrate Brewster angle $\arctan(\eta_3 / \eta_2)$. Beyond the critical angle, total internal reflection at the film–substrate interface produces continuously varying phase shifts in both polarization states, which the expressions above handle directly.

Second Interface Phase (Schlick Substrate)

For a Schlick substrate, the phase shift at the film–substrate interface is approximated by the step function:

$$\phi_{23} = \begin{cases} \pi & \text{if } \eta_3 < \eta_2 \\ 0 & \text{otherwise} \end{cases}$$

applied equally to both polarization states, where $\eta_3$ is the effective substrate IOR derived from the color0 input.

Optical Path Difference

The optical path difference (OPD) between successive reflected beams within the film is:

$$\Delta = 2\eta_2 \cos\theta_t \cdot d \times 10^{-9}$$

where the factor $10^{-9}$ converts the film thickness $d$ from nanometers to meters, matching the wavelength units used by the spectral sensitivity function.

Airy Summation

The reflected intensity $I$ is accumulated over $M$ bounce orders per polarization state. For each polarization (shown here for p; the s computation is analogous with $R_{12}^s$, $R_{23}^s$, $\phi_{21}^s$, $\phi_{23}^s$):

DC term ($m = 0$): the incoherent reflectance from the geometric series of internal bounces:

$$R_{\text{dc}} = \frac{(T_{12}^p)^2 R_{23}^p}{1 - R_{12}^p R_{23}^p}$$

$$I^p \mathrel{+}= R_{12}^p + R_{\text{dc}}$$

Higher-order terms ($m = 1, \ldots, M$): each successive bounce attenuates the amplitude by the geometric mean reflectance $r_{123} = \sqrt{R_{12} R_{23}}$ and introduces a spectral modulation:

$$C_m = C_{m-1} \cdot r_{123}^p, \quad C_0 = R_{\text{dc}} - T_{12}^p$$

$$S_m = 2\; \mathcal{S}(m\Delta,\; m(\phi_{23}^p + \phi_{21}^p))$$

$$I^p \mathrel{+}= C_m S_m$$

where $\mathcal{S}$ is the spectral sensitivity function defined below. The final Airy reflectance averages the two polarization states:

$$F_{\text{airy}} = \tfrac{1}{2}(I^p + I^s)$$

Spectral Sensitivity and Color Conversion

The spectral sensitivity function $\mathcal{S}$ evaluates the interference pattern at a given OPD and phase shift, returning an XYZ tristimulus value. It uses Gaussian fits to the CIE color matching functions5, parameterized by amplitude $v_k$, center frequency $\mu_k$, and variance $\sigma_k^2$:

$$\varphi = 2\pi\Delta$$

$$\mathcal{S}_k(\Delta, \phi) = v_k \sqrt{2\pi\sigma_k^2} \cos(\mu_k\varphi + \phi) \exp\left(-\sigma_k^2 \varphi^2\right)$$

The fitted parameters for the three XYZ channels are:

Channel $v_k$ $\mu_k$ $\sigma_k^2$
X $5.4856 \times 10^{-13}$ $1.6810 \times 10^{6}$ $4.3278 \times 10^{9}$
Y $4.4201 \times 10^{-13}$ $1.7953 \times 10^{6}$ $9.3046 \times 10^{9}$
Z $5.2481 \times 10^{-13}$ $2.2084 \times 10^{6}$ $6.6121 \times 10^{9}$

The X channel uses a second Gaussian lobe to better fit the bimodal shape of the CIE $\bar{x}$ function:

$$\mathcal{S}_X \mathrel{+}= 9.7470 \times 10^{-14} \sqrt{2\pi \cdot 4.5282 \times 10^{9}} \cos(2.2399 \times 10^{6} \cdot \varphi + \phi) \exp\left(-4.5282 \times 10^{9}\; \varphi^2\right)$$

The resulting XYZ value is normalized by $1.0685 \times 10^{-7}$ and converted to the renderer's linear working color space:

$$\begin{pmatrix} R \\ G \\ B \end{pmatrix} = M_{\text{XYZ} \to \text{working}} \begin{pmatrix} X \\ Y \\ Z \end{pmatrix}$$

where $M_{\text{XYZ} \to \text{working}}$ is a $3 \times 3$ matrix transforming from CIE XYZ to the working color space. Implementations should allow this matrix to be configured to match the linear working color space of the rendering environment. As an example, the matrix for the lin_rec709 working color space is:

$$M_{\text{XYZ} \to \text{lin\_rec709}} = \begin{pmatrix} 3.2404542 & -1.5371385 & -0.4985314 \\ -0.9692660 & 1.8760108 & 0.0415560 \\ 0.0556434 & -0.2040259 & 1.0572252 \end{pmatrix}$$

The result is clamped to $[0, 1]$ per channel.


References

Footnotes

  1. Bruce Walter et al., Microfacet Models for Refraction through Rough Surfaces, https://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf, 2007 ↩ ↩2 ↩3 ↩4

  2. Eric Heitz, Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs, http://jcgt.org/published/0003/02/03/paper.pdf, 2014 ↩ ↩2

  3. Emmanuel Turquin, Practical multiple scattering compensation for microfacet models, https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf, 2019. ↩ ↩2 ↩3 ↩4

  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 ↩

  5. 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

  6. Matt Pharr et al., Physically Based Rendering: From Theory To Implementation, https://www.pbr-book.org/, 2023 ↩ ↩2 ↩3 ↩4 ↩5

  7. Michael Oren, Shree K. Nayar, Generalization of Lambert’s Reflectance Model, https://dl.acm.org/doi/10.1145/192161.192213, 1994 ↩

  8. Portsmouth et al., EON: A practical energy-preserving rough diffuse BRDF, https://www.jcgt.org/published/0014/01/06/, 2025. ↩ ↩2 ↩3

  9. Yasuhiro Fujii, Improving the Oren-Nayar Diffuse Model, https://mimosa-pudica.net/improved-oren-nayar.html, 2020 ↩ ↩2 ↩3

  10. 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

  11. Portsmouth et al., The Minimal Retroreflective Microfacet Model, https://www.jcgt.org/published/0015/01/04/, 2026. ↩ ↩2 ↩3

  12. Sébastien Lagarde, Memo on Fresnel equations, https://seblagarde.wordpress.com/2013/04/29/memo-on-fresnel-equations/, 2013 ↩ ↩2

  13. Ole Gulbrandsen, Artist Friendly Metallic Fresnel, http://jcgt.org/published/0003/04/03/paper.pdf, 2014 ↩

  14. Naty Hoffman, Generalization of Adobe's Fresnel Model, https://renderwonk.com/publications/wp-generalization-adobe/gen-adobe.pdf 2023 ↩ ↩2

  15. 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

  16. 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

  17. Alejandro Conty, Christopher Kulla, Production Friendly Microfacet Sheen BRDF, https://fpsunflower.github.io/ckulla/data/s2017_pbs_imageworks_sheen.pdf, 2017 ↩

  18. Tizian Zeltner et al., Practical Multiple-Scattering Sheen Using Linearly Transformed Cosines, https://tizianzeltner.com/projects/Zeltner2022Practical/, 2022 ↩ ↩2 ↩3 ↩4 ↩5

  19. 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

  20. Christophe Schlick, An Inexpensive BRDF Model for Physically-based Rendering, Computer Graphics Forum, https://doi.org/10.1111/1467-8659.1330233, 1994 ↩

  21. 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

  22. Eugene d'Eon et al., An Energy-Conserving Hair Reflectance Model, https://eugenedeon.com/pdfs/egsrhair.pdf, 2011 ↩ ↩2 ↩3

  23. Iliyan Georgiev et al., Autodesk Standard Surface, https://autodesk.github.io/standard-surface/, 2019. ↩

  24. Pixar Animation Studios, UsdPreviewSurface Specification, https://openusd.org/release/spec_usdpreviewsurface.html, 2019. ↩

  25. The Khronos Group, glTF 2.0 Specification, https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html, 2021. ↩

  26. Andersson et al., OpenPBR Surface Specification, https://academysoftwarefoundation.github.io/OpenPBR/, 2024. ↩

  27. 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 ↩

  28. Pixar Animation Studios, MaterialX Lama, https://rmanwiki-27.pixar.com/space/REN27/542218994/MaterialX+Lama, 2021. ↩