Filament Materials Guide

Filament Materials Guide

This document is part of the Filament project. To report errors in this document please use the project's issue tracker.

# Overview

Filament is a physically based rendering (PBR) engine for Android. Filament offers a customizable material system that you can use to create both simple and complex materials. This document describes all the features available to materials and how to create your own material.

## Core concepts

Material

A material defines the visual appearance of a surface. To completely describe and render a surface, a material provides the following information:

• Material model
• Set of use-controllable named parameters
• Raster state (blending mode, backface culling, etc.)

Material model

Also called shading model or lighting model, the material model defines the intrinsic properties of a surface. These properties have a direct influence on the way lighting is computed and therefore on the appearance of a surface.

Material definition

A text file that describes all the information required by a material. This is the file that you will directly author to create new materials.

Material package

At runtime, materials are loaded from material packages compiled from material definitions using the matc tool. A material package contains all the information required to describe a material, and shaders generated for the target runtime platforms. This is necessary because different platforms (Android, macOS, Linux, etc.) use different graphics APIs or different variants of similar graphics APIs (OpenGL vs OpenGL ES for instance).

Material instance

A material instance is a reference to a material and a set of values for the different values of that material. Material instances are not covered in this document as they are created and manipulated directly from code using Filament's APIs.

# Material models

Filament materials can use one of the following material models:

• Lit (or standard)
• Subsurface
• Cloth
• Unlit
• Specular glossiness (legacy)

## Lit model

The lit model is Filament's standard material model. This physically-based shading model was designed after to offer good interoperability with other common tools and engines such as Unity 5, Unreal Engine 4, Substance Designer or Marmoset Toolbag.

This material model can be used to describe many non-metallic surfaces (dielectrics) or metallic surfaces (conductors).

The appearance of a material using the standard model is controlled using the properties described in table 1.

Property Definition
baseColor Diffuse albedo for non-metallic surfaces, and specular color for metallic surfaces
metallic Whether a surface appears to be dielectric (0.0) or conductor (1.0). Often used as a binary value (0 or 1)
roughness Perceived smoothness (1.0) or roughness (0.0) of a surface. Smooth surfaces exhibit sharp reflections
reflectance Fresnel reflectance at normal incidence for dielectric surfaces. This directly controls the strength of the reflections
sheenColor Strength of the sheen layer
sheenRoughness Perceived smoothness or roughness of the sheen layer
clearCoat Strength of the clear coat layer
clearCoatRoughness Perceived smoothness or roughness of the clear coat layer
anisotropy Amount of anisotropy in either the tangent or bitangent direction
anisotropyDirection Local surface direction in tangent space
ambientOcclusion Defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 and 1.0
normal A detail normal used to perturb the surface using bump mapping (normal mapping)
bentNormal A normal pointing in the average unoccluded direction. Can be used to improve indirect lighting quality
clearCoatNormal A detail normal used to perturb the clear coat layer using bump mapping (normal mapping)
emissive Additional diffuse albedo to simulate emissive surfaces (such as neons, etc.) This property is mostly useful in an HDR pipeline with a bloom pass
postLightingColor Additional color that can be blended with the result of the lighting computations. See postLightingBlending
ior Index of refraction, either for refractive objects or as an alternative to reflectance
transmission Defines how much of the diffuse light of a dielectric is transmitted through the object, in other words this defines how transparent an object is
absorption Absorption factor for refractive objects
microThickness Thickness of the thin layer of refractive objects
thickness Thickness of the solid volume of refractive objects
Table 1: Properties of the standard model

The type and range of each property is described in table 2.

Property Type Range Note
baseColor float4 [0..1] Pre-multiplied linear RGB
metallic float [0..1] Should be 0 or 1
roughness float [0..1]
reflectance float [0..1] Prefer values > 0.35
sheenColor float3 [0..1] Linear RGB
sheenRoughness float [0..1]
clearCoat float [0..1] Should be 0 or 1
clearCoatRoughness float [0..1]
anisotropy float [−1..1] Anisotropy is in the tangent direction when this value is positive
anisotropyDirection float3 [0..1] Linear RGB, encodes a direction vector in tangent space
ambientOcclusion float [0..1]
normal float3 [0..1] Linear RGB, encodes a direction vector in tangent space
bentNormal float3 [0..1] Linear RGB, encodes a direction vector in tangent space
clearCoatNormal float3 [0..1] Linear RGB, encodes a direction vector in tangent space
emissive float4 rgb=[0..n], a=[0..1] Linear RGB intensity in nits, alpha encodes the exposure weight
postLightingColor float4 [0..1] Pre-multiplied linear RGB
ior float [1..n] Optional, usually deduced from the reflectance
transmission float [0..1]
absorption float3 [0..n]
microThickness float [0..n]
thickness float [0..n]
Table 2: Range and type of the standard model's properties

Several material model properties expect RGB colors. Filament materials use RGB colors in linear space and you must take proper care of supplying colors in that space. See the Linear colors section for more information.

Filament materials expect colors to use pre-multiplied alpha. See the Pre-multiplied alpha section for more information.

About absorption

The light attenuation through the material is defined as $$e^{-absorption \cdot distance}$$, and the distance depends on the thickness parameter. If thickness is not provided, then the absorption parameter is used directly and the light attenuation through the material becomes $$1 - absorption$$. To obtain a certain color at a desired distance, the above equation can be inverted such as $$absorption = -\frac{ln(color)}{distance}$$.

About ior and reflectance

The index of refraction (IOR) and the reflectance represent the same physical attribute, therefore they don't need to be both specified. Typically, only the reflectance is specified, and the IOR is deduced automatically. When only the IOR is specified, the reflectance is then deduced automatically. It is possible to specify both, in which case their values are kept as-is, which can lead to physically impossible materials, however, this might be desirable for artistic reasons.

About thickness and microThickness for refraction

thickness represents the thickness of solid objects in the direction of the normal, for satisfactory results, this should be provided per fragment (e.g.: as a texture) or at least per vertex. microThickness represent the thickness of the thin layer of an object, and can generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m, would have a thickness of 1 and a microThickness of 0.001. Currently thickness is not used when refractionType is set to thin.

### Base color

The baseColor property defines the perceived color of an object (sometimes called albedo). The effect of baseColor depends on the nature of the surface, controlled by the metallic property explained in the Metallic section.

Non-metals (dielectrics)

Defines the diffuse color of the surface. Real-world values are typically found in the range $$[10..240]$$ if the value is encoded between 0 and 255, or in the range $$[0.04..0.94]$$ between 0 and 1. Several examples of base colors for non-metallic surfaces can be found in table 3.

Coal 0.19, 0.19, 0.19 #323232

Rubber 0.21, 0.21, 0.21 #353535

Mud 0.33, 0.24, 0.19 #553d31

Wood 0.53, 0.36, 0.24 #875c3c

Vegetation 0.48, 0.51, 0.31 #7b824e

Brick 0.58, 0.49, 0.46 #947d75

Sand 0.69, 0.66, 0.52 #b1a884

Concrete 0.75, 0.75, 0.73 #c0bfbb

Table 3: baseColor for common non-metals

Metals (conductors)

Defines the specular color of the surface. Real-world values are typically found in the range $$[170..255]$$ if the value is encoded between 0 and 255, or in the range $$[0.66..1.0]$$ between 0 and 1. Several examples of base colors for metallic surfaces can be found in table 4.

Silver 0.97, 0.96, 0.91 #f7f4e8

Aluminum 0.91, 0.92, 0.92 #e8eaea

Titanium 0.76, 0.73, 0.69 #c1baaf

Iron 0.77, 0.78, 0.78 #c4c6c6

Platinum 0.83, 0.81, 0.78 #d3cec6

Gold 1.00, 0.85, 0.57 #ffd891

Brass 0.98, 0.90, 0.59 #f9e596

Copper 0.97, 0.74, 0.62 #f7bc9e

Table 4: baseColor for common metals

### Metallic

The metallic property defines whether the surface is a metallic (conductor) or a non-metallic (dielectric) surface. This property should be used as a binary value, set to either 0 or 1. Intermediate values are only truly useful to create transitions between different types of surfaces when using textures.

This property can dramatically change the appearance of a surface. Non-metallic surfaces have chromatic diffuse reflection and achromatic specular reflection (reflected light does not change color). Metallic surfaces do not have any diffuse reflection and chromatic specular reflection (reflected light takes on the color of the surfaced as defined by baseColor).

The effect of metallic is shown in figure 1 (click on the image to see a larger version).

Figure 1: metallic varying from 0.0 (left) to 1.0 (right)

### Roughness

The roughness property controls the perceived smoothness of the surface. When roughness is set to 0, the surface is perfectly smooth and highly glossy. The rougher a surface is, the “blurrier” the reflections are. This property is often called glossiness in other engines and tools, and is simply the opposite of the roughness (roughness = 1 - glossiness).

### Non-metals

The effect of roughness on non-metallic surfaces is shown in figure 2 (click on the image to see a larger version).

Figure 2: Dielectric roughness varying from 0.0 (left) to 1.0 (right)

### Metals

The effect of roughness on metallic surfaces is shown in figure 3 (click on the image to see a larger version).

Figure 3: Conductor roughness varying from 0.0 (left) to 1.0 (right)

### Refraction

When refraction through an object is enabled (using a refractonType of thin or solid), the roughness property will also affect the refractions, as shown in figure 4 (click on the image to see a larger version).

Figure 4: Refractive sphere with roughness varying from 0.0 (left) to 1.0 (right)

### Reflectance

The reflectance property only affects non-metallic surfaces. This property can be used to control the specular intensity and index of refraction of materials. This value is defined between 0 and 1 and represents a remapping of a percentage of reflectance. For instance, the default value of 0.5 corresponds to a reflectance of 4%. Values below 0.35 (2% reflectance) should be avoided as no real-world materials have such low reflectance.

The effect of reflectance on non-metallic surfaces is shown in figure 5 (click on the image to see a larger version).

Figure 5: reflectance varying from 0.0 (left) to 1.0 (right)

Figure 6 shows common values and how they relate to the mapping function.

Figure 6: Common reflectance values

Table 5 describes acceptable reflectance values for various types of materials (no real world material has a value under 2%).

Material Reflectance IOR Linear value
Water 2% 1.33 0.35
Fabric 4% to 5.6% 1.5 to 1.62 0.5 to 0.59
Common liquids 2% to 4% 1.33 to 1.5 0.35 to 0.5
Common gemstones 5% to 16% 1.58 to 2.33 0.56 to 1.0
Plastics, glass 4% to 5% 1.5 to 1.58 0.5 to 0.56
Other dielectric materials 2% to 5% 1.33 to 1.58 0.35 to 0.56
Eyes 2.5% 1.38 0.39
Skin 2.8% 1.4 0.42
Hair 4.6% 1.55 0.54
Teeth 5.8% 1.63 0.6
Default value 4% 1.5 0.5
Table 5: Reflectance of common materials

Note that the reflectance property also defines the index of refraction of the surface. When this property is defined it is not necessary to define the ior property. Setting either of these properties will automatically compute the other property. It is possible to specify both, in which case their values are kept as-is, which can lead to physically impossible materials, however, this might be desirable for artistic reasons.

The reflectance property is designed as a normalized property in the range 0..1 which makes it easy to define from a texture.

See section 3.1.20 for more information about the ior property and refractive indices.

### Sheen color

The sheen color controls the color appearance and strength of an optional sheen layer on top of the base layer described by the properties above. The sheen layer always sits below the clear coat layer if such a layer is present.

The sheen layer can be used to represent cloth and fabric materials. Please refer to section 3.3 for more information about cloth and fabric materials.

The effect of sheenColor is shown in figure 7 (click on the image to see a larger version).

Figure 7: Different sheen colors

If you do not need the other properties offered by the standard lit material model but want to create a cloth-like or fabric-like appearance, it is more efficient to use the dedicated cloth model described in section 3.3.

### Sheen roughness

The sheenRoughness property is similar to the roughness property but applies only to the sheen layer.

The effect of sheenRoughness on a rough metal is shown in figure 8 (click on the image to see a larger version). In this picture, the base layer is a dark blue, with metallic set to 0.0 and roughness set to 1.0.

Figure 8: sheenRoughness varying from 0.0 (left) to 1.0 (right)

### Clear coat

Multi-layer materials are fairly common, particularly materials with a thin translucent layer over a base layer. Real world examples of such materials include car paints, soda cans, lacquered wood and acrylic.

The clearCoat property can be used to describe materials with two layers. The clear coat layer will always be isotropic and dielectric.

Figure 9: Comparison of a carbon-fiber material under the standard material model (left) and the clear coat model (right)

The clearCoat property controls the strength of the clear coat layer. This should be treated as a binary value, set to either 0 or 1. Intermediate values are useful to control transitions between parts of the surface that have a clear coat layers and parts that don't.

The effect of clearCoat on a rough metal is shown in figure 10 (click on the image to see a larger version).

Figure 10: clearCoat varying from 0.0 (left) to 1.0 (right)

The clear coat layer effectively doubles the cost of specular computations. Do not assign a value, even 0.0, to the clear coat property if you don't need this second layer.

The clear coat layer is added on top of the sheen layer if present.

### Clear coat roughness

The clearCoatRoughness property is similar to the roughness property but applies only to the clear coat layer.

The effect of clearCoatRoughness on a rough metal is shown in figure 11 (click on the image to see a larger version).

Figure 11: clearCoatRoughness varying from 0.0 (left) to 1.0 (right)

### Anisotropy

Many real-world materials, such as brushed metal, can only be replicated using an anisotropic reflectance model. A material can be changed from the default isotropic model to an anisotropic model by using the anisotropy property.

Figure 12: Comparison of isotropic material (left) and anistropic material (right)

The effect of anisotropy on a rough metal is shown in figure 13 (click on the image to see a larger version).

Figure 13: anisotropy varying from 0.0 (left) to 1.0 (right)

The figure 14 below shows how the direction of the anisotropic highlights can be controlled by using either positive or negative values: positive values define anisotropy in the tangent direction and negative values in the bitangent direction.

Figure 14: Positive (left) vs negative (right) anisotropy values

The anisotropic material model is slightly more expensive than the standard material model. Do not assign a value (even 0.0) to the anisotropy property if you don't need anisotropy.

### Anisotropy direction

The anisotropyDirection property defines the direction of the surface at a given point and thus control the shape of the specular highlights. It is specified as vector of 3 values that usually come from a texture, encoding the directions local to the surface in tangent space. Because the direction is in tangent space, the Z component should be set to 0.

The effect of anisotropyDirection on a metal is shown in figure 16 (click on the image to see a larger version).

Figure 15: Anisotropic metal rendered with a direction map

The result shown in figure 16 was obtained using the direction map shown in figure 16.

Figure 16: Example of Lighting: specularAmbientOcclusiona direction map

### Ambient occlusion

The ambientOcclusion property defines how much of the ambient light is accessible to a surface point. It is a per-pixel shadowing factor between 0.0 (fully shadowed) and 1.0 (fully lit). This property only affects diffuse indirect lighting (image-based lighting), not direct lights such as directional, point and spot lights, nor specular lighting.

Figure 17: Comparison of materials without diffuse ambient occlusion (left) and with (right)

### Normal

The normal property defines the normal of the surface at a given point. It usually comes from a normal map texture, which allows to vary the property per-pixel. The normal is supplied in tangent space, which means that +Z points outside of the surface.

For example, let's imagine that we want to render a piece of furniture covered in tufted leather. Modeling the geometry to accurately represent the tufted pattern would require too many triangles so we instead bake a high-poly mesh into a normal map. Once the base map is applied to a simplified mesh, we get the result in figure 18.

Note that the normal property affects the base layer and not the clear coat layer.

Figure 18: Low-poly mesh without normal mapping (left) and with (right)

Using a normal map increases the runtime cost of the material model.

### Bent normal

The bentNormal property defines the average unoccluded direction at a point on the surface. It is used to improve the accuracy of indirect lighting. Bent normals can also improve the quality of specular ambient occlusion (see section 4.2.28 about specularAmbientOcclusion).

Bent normals can greatly increase the visual fidelity of an asset with various cavities and concave areas, as shown in figure 19. See the areas of the ears, nostrils and eyes for instance.

Figure 19: Example of a model rendered with and without a bent normal map. Both versions use the same ambient occlusion map.

### Clear coat normal

The clearCoatNormal property defines the normal of the clear coat layer at a given point. It behaves otherwise like the normal property.

Figure 20: A material with a clear coat normal map and a surface normal map

Using a clear coat normal map increases the runtime cost of the material model.

### Emissive

The emissive property can be used to simulate additional light emitted by the surface. It is defined as a float4 value that contains an RGB intensity in nits as well as an exposure weight (in the alpha channel).

The intensity in nits allows an emissive surface to function as a light and can be used to recreate real world surfaces. For instance a computer display has an intensity between 200 and 1,000 nits.

If you prefer to work in EV (or f-stops), you can simplify multiply your emissive color by the output of the API filament::Exposure::luminance(ev). This API returns the luminance in nits of the specific EV. You can perform this conversion yourself using the following formula, where $$L$$ is the final intensity in nits: $$L = 2^{EV - 3}$$.

The exposure weight carried in the alpha channel can be used to undo the camera exposure, and thus force an emissive surface to bloom. When the exposure weight is set to 0, the emissive intensity is not affected by the camera exposure. When the weight is set to 1, the intensity is multiplied by the camera exposure like with any regular light.

### Post-lighting color

The postLightingColor can be used to modify the surface color after lighting computations. This property has no physical meaning and only exists to implement specific effects or to help with debugging. This property is defined as a float4 value containing a pre-multiplied RGB color in linear space.

The post-lighting color is blended with the result of lighting according to the blending mode specified by the postLightingBlending material option. Please refer to the documentation of this option for more information.

postLightingColor can be used as a simpler emissive property by setting postLightingBlending to add and by providing an RGB color with alpha set to 0.0.

### Index of refraction

The ior property only affects non-metallic surfaces. This property can be used to control the index of refraction and the specular intensity of materials. The ior property is intended to be used with refractive (transmissive) materials, which are enabled when the refractionMode is set to cubemap or screenspace. It can also be used on non-refractive objects as an alternative to setting the reflectance.

The index of refraction (or refractive index) of a material is a dimensionless number that describes how fast light travels through that material. The higher the number, the slower light travels through the medium. More importantly for rendering materials, the refractive index determines how the path light travels is bent when entering the material. Higher indices of refraction will cause light to bend further away from the initial path.

Table 6 describes acceptable refractive indices for various types of materials.

Material IOR
Air 1.0
Water 1.33
Common liquids 1.33 to 1.5
Common gemstones 1.58 to 2.33
Plastics, glass 1.5 to 1.58
Other dielectric materials 1.33 to 1.58
Table 6: Index of refraction of common materials

The appearance of a refractive material will greatly depend on the refractionType and refractionMode settings of the material. Refer to section 4.2.17 and section 4.2.16 for more information.

The effect of ior when refractionMode is set to cubemap and refractionType is set to solid can be seen in figure 21 (click on the image to see a larger version).

Figure 21: transmission varying from 1.0 (left) to 1.5 (right)

Figure 22 shows the comparison of a sphere of ior 1.0 with a sphere of ior 1.33, with the refractionMode set to screenspace and the refractionType set to solid (click on the image to see a larger version).

Figure 22: ior of 1.0 (left) and 1.33 (right)

Note that the ior property also defines the reflectance (or specular intensity) of the surface. When this property is defined it is not necessary to define the reflectance property. Setting either of these properties will automatically compute the other property. It is possible to specify both, in which case their values are kept as-is, which can lead to physically impossible materials, however, this might be desirable for artistic reasons.

See the Reflectance section for more information on the reflectance property.

Refractive materials are affected by the roughness property. Rough materials will scatter light, creating a diffusion effect useful to recreate “blurry” appearances such as frosted glass, certain plastics, etc.

### Transmission

The transmission property defines what ratio of diffuse light is transmitted through a refractive material. This property only affects materials with a refractionMode set to cubemap or screenspace.

When transmission is set to 0, no amount of light is transmitted and the diffuse component of the surface is 100% visible. When transmission is set to 1, all the light is transmitted and the diffuse component is not visible anymore, only the specular component is.

The effect of transmission on a glossy dielectric (ior of 1.5, refractionMode set to cubemap, refractionType set to solid) is shown in figure 23 (click on the image to see a larger version).

Figure 23: transmission varying from 0.0 (left) to 1.0 (right)

The transmission property is useful to create decals, paint, etc. at the surface of refractive materials.

### Absorption

The absorption property defines the absorption coefficients of light transmitted through the material. Figure 24 shows the effect of absorption on a refracting object with an index of refraction of 1.5 and a base color set to white.

Figure 24: Refracting object without (left) and with (right) absorption

Transmittance through a volume is exponential with respect to the optical depth (defined either with microThickness or thickness). The computed color follows the following formula:

$$color \cdot e^{-absorption \cdot distance}$$

Where distance is either microThickness or thickness, that is the distance light will travel through the material at a given point. If no thickness/distance is specified, the computed color follows this formula instead:

$$color \cdot (1 - absorption)$$

The effect of varying the absorption coefficients is shown in figure 25 (click on the image to see a larger version). In this picture, the object has a fixed thickness of 4.5 and an index of refraction set to 1.3.

Figure 25: absorption varying from (0.0, 0.02, 0.14) (left) to (0.0, 0.36, 2.3) (right)

Setting the absorption coefficients directly can be unintuitive which is why we recommend working with a transmittance color and a “at distance” factor instead. These two parameters allow an artist to specify the precise color the material should have at a specified distance through the volume. The value to pass to absorption can be computed this way:

$$absorption = -\frac{ln(transmittanceColor)}{atDistance}$$

While this computation can be done in the material itself we recommend doing it offline whenever possible. Filament provides an API for this purpose, Color::absorptionAtDistance().

### Micro-thickness and thickness

The microThickness and thickness properties define the optical depth of the material of a refracting object. microThickness is used when refractionType is set to thin, and thickness is used when refractionType is set to volume.

thickness represents the thickness of solid objects in the direction of the normal, for satisfactory results, this should be provided per fragment (e.g.: as a texture) or at least per vertex.

microThickness represent the thickness of the thin layer (shell) of an object, and can generally be provided as a constant value. For example, a 1mm thin hollow sphere of radius 1m, would have a thickness of 1 and a microThickness of 0.001. Currently thickness is not used when refractionType is set to thin. Both properties are made available for possible future use.

Both thickness and microThickness are used to compute the transmitted color of the material when the absorption property is set. In solid volumes, thickness will also affect how light rays are refracted.

The effect thickness in a solid volume with refractionMode set to screenSpace is shown in figure 26 (click on the image to see a larger version). Note how the thickness value not only changes the effect of absorption but also modifies the direction of the refracted light.

Figure 26: thickness varying from 0.0 (left) to 2.0 (right)

Figure 27 shows what a prism with spatially varying thickness looks like when the refractionType is set to solid and absorption coefficients are set.

Figure 27: thickness varying from 0.0 at the top of the prism to 3.0 at the bottom of the prism

## Cloth model

All the material models described previously are designed to simulate dense surfaces, both at a macro and at a micro level. Clothes and fabrics are however often made of loosely connected threads that absorb and scatter incident light. When compared to hard surfaces, cloth is characterized by a softer specular lob with a large falloff and the presence of fuzz lighting, caused by forward/backward scattering. Some fabrics also exhibit two-tone specular colors (velvets for instance).

Figure 28 shows how the standard material model fails to capture the appearance of a sample of denim fabric. The surface appears rigid (almost plastic-like), more similar to a tarp than a piece of clothing. This figure also shows how important the softer specular lobe caused by absorption and scattering is to the faithful recreation of the fabric.

Figure 28: Comparison of denim fabric rendered using the standard model (left) and the cloth model (right)

Velvet is an interesting use case for a cloth material model. As shown in figure 29 this type of fabric exhibits strong rim lighting due to forward and backward scattering. These scattering events are caused by fibers standing straight at the surface of the fabric. When the incident light comes from the direction opposite to the view direction, the fibers will forward scatter the light. Similarly, when the incident light from the same direction as the view direction, the fibers will scatter the light backward.

Figure 29: Velvet fabric showcasing forward and backward scattering

It is important to note that there are types of fabrics that are still best modeled by hard surface material models. For instance, leather, silk and satin can be recreated using the standard or anisotropic material models.

The cloth material model encompasses all the parameters previously defined for the standard material mode except for metallic and reflectance. Two extra parameters described in table 7 are also available.

Parameter Definition
sheenColor Specular tint to create two-tone specular fabrics (defaults to $$\sqrt{baseColor}$$)
subsurfaceColor Tint for the diffuse color after scattering and absorption through the material
Table 7: Cloth model parameters

The type and range of each property is described in table 8.

Property Type Range Note
sheenColor float3 [0..1] Linear RGB
subsurfaceColor float3 [0..1] Linear RGB
Table 8: Range and type of the cloth model's properties

To create a velvet-like material, the base color can be set to black (or a dark color). Chromaticity information should instead be set on the sheen color. To create more common fabrics such as denim, cotton, etc. use the base color for chromaticity and use the default sheen color or set the sheen color to the luminance of the base color.

To see the effect of the roughness parameter make sure the sheenColor is brighter than baseColor. This can be used to create a fuzz effect. Taking the luminance of baseColor as the sheenColor will produce a fairly natural effect that works for common cloth. A dark baseColor combined with a bright/saturated sheenColor can be used to create velvet.

The subsurfaceColor parameter should be used with care. High values can interfere with shadows in some areas. It is best suited for subtle transmission effects through the material.

### Sheen color

The sheenColor property can be used to directly modify the specular reflectance. It offers better control over the appearance of cloth and gives give the ability to create two-tone specular materials.

The effect of sheenColor is shown in figure 30 (click on the image to see a larger version).

Figure 30: Blue fabric without (left) and with (right) sheen

### Subsurface color

The subsurfaceColor property is not physically-based and can be used to simulate the scattering, partial absorption and re-emission of light in certain types of fabrics. This is particularly useful to create softer fabrics.

The cloth material model is more expensive to compute when the subsurfaceColor property is used.

The effect of subsurfaceColor is shown in figure 31 (click on the image to see a larger version).

Figure 31: White cloth (left column) vs white cloth with brown subsurface scatting (right)

## Unlit model

The unlit material model can be used to turn off all lighting computations. Its primary purpose is to render pre-lit elements such as a cubemap, external content (such as a video or camera stream), user interfaces, visualization/debugging etc. The unlit model exposes only two properties described in table 9.

Property Definition
baseColor Surface diffuse color
emissive Additional diffuse color to simulate emissive surfaces. This property is mostly useful in an HDR pipeline with a bloom pass
postLightingColor Additional color to blend with base color and emissive
Table 9: Properties of the standard model

The type and range of each property is described in table 10.

Property Type Range Note
baseColor float4 [0..1] Pre-multiplied linear RGB
emissive float4 rgb=[0..n], a=[0..1] Linear RGB intensity in nits, alpha encodes the exposure weight
postLightingColor float4 [0..1] Pre-multiplied linear RGB
Table 10: Range and type of the unlit model's properties

The value of postLightingColor is blended with the sum of emissive and baseColor according to the blending mode specified by the postLightingBlending material option.

Figure 32 shows an example of the unlit material model (click on the image to see a larger version).

Figure 32: The unlit model is used to render debug information

## Specular glossiness

This alternative lighting model exists to comply with legacy standards. Since it is not a physically-based formulation, we do not recommend using it except when loading legacy assets.

This model encompasses the parameters previously defined for the standard lit mode except for metallic, reflectance, and roughness. It adds parameters for specularColor and glossiness.

Parameter Definition
baseColor Surface diffuse color
specularColor Specular tint (defaults to black)
glossiness Glossiness (defaults to 0.0)
Table 11: Properties of the specular-glossiness shading model

The type and range of each property is described in table 12.

Property Type Range Note
baseColor float4 [0..1] Pre-multiplied linear RGB
specularColor float3 [0..1] Linear RGB
glossiness float [0..1] Inverse of roughness
Table 12: Range and type of the specular-glossiness model's properties

# Material definitions

A material definition is a text file that describes all the information required by a material:

• Name
• User parameters
• Material model
• Required attributes
• Interpolants (called variables)
• Raster state (blending mode, etc.)

## Format

The material definition format is a format loosely based on JSON that we call JSONish. At the top level a material definition is composed of 3 different blocks that use the JSON object notation:

material {
// material properties
}

vertex {
}

fragment {
}

A minimum viable material definition must contain a material preamble and a fragment block. The vertex block is optional.

### Differences with JSON

In JSON, an object is made of key/value pairs. A JSON pair has the following syntax:

"key" : value

Where value can be a string, number, object, array or a literal (true, false or null). While this syntax is perfectly valid in a material definition, a variant without quotes around strings is also accepted in JSONish:

key : value

Quotes remain mandatory when the string contains spaces.

The vertex and fragment blocks contain unescaped, unquoted GLSL code, which is not valid in JSON.

The key of a pair is case-sensitive.

The value of a pair is not case-sensitive.

### Example

The following code listing shows an example of a valid material definition. This definition uses the lit material model (see Lit model section), uses the default opaque blending mode, requires that a set of UV coordinates be presented in the rendered mesh and defines 3 user parameters. The following sections of this document describe the material and fragment blocks in detail.

material {
name : "Textured material",
parameters : [
{
type : sampler2d,
name : texture
},
{
type : float,
name : metallic
},
{
type : float,
name : roughness
}
],
requires : [
uv0
],
blending : opaque
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.metallic = materialParams.metallic;
material.roughness = materialParams.roughness;
}
}

## Material block

The material block is mandatory block that contains a list of property pairs to describe all non-shader data.

### General: name

 Type string Value Any string. Double quotes are required if the name contains spaces. Description Sets the name of the material. The name is retained at runtime for debugging purpose.

material {
name : stone
}

material {
name : "Wet pavement"
}

 Type string Value Any of lit, subsurface, cloth, unlit, specularGlossiness. Defaults to lit. Description Selects the material model as described in the Material models section.

material {
}

material {
}

### General: parameters

Type

array of parameter objects

Value

Each entry is an object with the properties name and type, both of string type. The name must be a valid GLSL identifier. Entries also have an optional precision, which can be one of default (best precision for the platform, typically high on desktop, medium on mobile), low, medium, high. The type must be one of the types described in table 13.

Type Description
bool Single boolean
bool2 Vector of 2 booleans
bool3 Vector of 3 booleans
bool4 Vector of 4 booleans
float Single float
float2 Vector of 2 floats
float3 Vector of 3 floats
float4 Vector of 4 floats
int Single integer
int2 Vector of 2 integers
int3 Vector of 3 integers
int4 Vector of 4 integers
uint Single unsigned integer
uint2 Vector of 2 unsigned integers
uint3 Vector of 3 unsigned integers
uint4 Vector of 4 unsigned integers
float3×3 Matrix of 3×3 floats
float4×4 Matrix of 4×4 floats
sampler2d 2D texture
sampler2dArray Array of 2D textures
samplerExternal External texture (platform-specific)
samplerCubemap Cubemap texture
Table 13: Material parameter types

Samplers

Sampler types can also specify a format which can be either int or float (defaults to float).

Arrays

A parameter can define an array of values by appending [size] after the type name, where size is a positive integer. For instance: float[9] declares an array of nine float values. This syntax does not apply to samplers as arrays are treated as separate types.

Description

Lists the parameters required by your material. These parameters can be set at runtime using Filament's material API. Accessing parameters from the shaders varies depending on the type of parameter:

• Samplers types: use the parameter name prefixed with materialParams_. For instance, materialParams_myTexture.
• Other types: use the parameter name as the field of a structure called materialParams. For instance, materialParams.myColor.

material {
parameters : [
{
type : float4,
name : albedo
},
{
type      : sampler2d,
format    : float,
precision : high,
name      : roughness
},
{
type : float2,
name : metallicReflectance
}
],
requires : [
uv0
],
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = materialParams.albedo;
material.roughness = texture(materialParams_roughness, getUV0());
material.metallic = materialParams.metallicReflectance.x;
material.reflectance = materialParams.metallicReflectance.y;
}
}

### General: variantFilter

Type

array of string

Value

Each entry must be any of dynamicLighting, directionalLighting, shadowReceiver,skinning or ssr.

Description

Used to specify a list of shader variants that the application guarantees will never be needed. These shader variants are skipped during the code generation phase, thus reducing the overall size of the material. Note that some variants may automatically be filtered out. For instance, all lighting related variants (directionalLighting, etc.) are filtered out when compiling an unlit material. Use the variant filter with caution, filtering out a variant required at runtime may lead to crashes.

Description of the variants:

• directionalLighting, used when a directional light is present in the scene
• dynamicLighting, used when a non-directional light (point, spot, etc.) is present in the scene
• shadowReceiver, used when an object can receive shadows
• skinning, used when an object is animated using GPU skinning
• fog, used when global fog is applied to the scene
• vsm, used when VSM shadows are enabled and the object is a shadow receiver
• ssr, used when screen-space reflections are enabled in the View

material {
blending : transparent,
variantFilter : [ skinning ]
}

### General: flipUV

Type

boolean

Value

true or false. Defaults to true.

Description

When set to true (default value), the Y coordinate of UV attributes will be flipped when read by this material's vertex shader. Flipping is equivalent to y = 1.0 - y. When set to false, flipping is disabled and the UV attributes are read as is.

material {
flipUV : false
}

### General: quality

Type

string

Value

Any of low, normal, high, default. Defaults to default.

Description

Set some global quality parameters of the material. low enables optimizations that can slightly affect correctness and is the default on mobile platforms. normal does not affect correctness and is otherwise similar to low. high enables quality settings that can adversely affect performance and is the default on desktop platforms.

material {
quality : default
}

### General: instanced

Type

boolean

Value

true or false. Defaults to false.

Description

Allows a material to access the instance index (i.e.: gl_InstanceIndex) of instanced primitives using getInstanceIndex() in the material's shader code. Never use gl_InstanceIndex directly. This is typically used with RenderableManager::Builder::instances(). getInstanceIndex() is available in both the vertex and fragment shader.

material {
instanced : true
}

### Vertex and attributes: requires

Type

array of string

Value

Each entry must be any of uv0, uv1, color, position, tangents, custom0 through custom7.

Description

Lists the vertex attributes required by the material. The position attribute is always required and does not need to be specified. The tangents attribute is automatically required when selecting any shading model that is not unlit. See the shader sections of this document for more information on how to access these attributes from the shaders.

material {
parameters : [
{
type : sampler2d,
name : texture
},
],
requires : [
uv0,
custom0
],
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_texture, getUV0());
material.baseColor.rgb *= getCustom0().rgb;
}
}

### Vertex and attributes: variables

Type

array of string

Value

Up to 4 strings, each must be a valid GLSL identifier.

Description

Defines custom interpolants (or variables) that are output by the material's vertex shader. Each entry of the array defines the name of an interpolant. The full name in the fragment shader is the name of the interpolant with the variable_ prefix. For instance, if you declare a variable called eyeDirection you can access it in the fragment shader using variable_eyeDirection. In the vertex shader, the interpolant name is simply a member of the MaterialVertexInputs structure (material.eyeDirection in your example). Each interpolant is of type float4 (vec4) in the shaders.

material {
name : Skybox,
parameters : [
{
type : samplerCubemap,
name : skybox
}
],
variables : [
eyeDirection
],
vertexDomain : device,
depthWrite : false,
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
float3 sky = texture(materialParams_skybox, variable_eyeDirection.xyz).rgb;
material.baseColor = vec4(sky, 1.0);
}
}

vertex {
void materialVertex(inout MaterialVertexInputs material) {
float3 p = getPosition().xyz;
float3 u = mulMat4x4Float3(getViewFromClipMatrix(), p).xyz;
material.eyeDirection.xyz = mulMat3x3Float3(getWorldFromViewMatrix(), u);
}
}

### Vertex and attributes: vertexDomain

Type

string

Value

Any of object, world, view, device. Defaults to object.

Description

Defines the domain (or coordinate space) of the rendered mesh. The domain influences how the vertices are transformed in the vertex shader. The possible domains are:

• Object: the vertices are defined in the object (or model) coordinate space. The vertices are transformed using the rendered object's transform matrix
• World: the vertices are defined in world coordinate space. The vertices are not transformed using the rendered object's transform.
• View: the vertices are defined in view (or eye or camera) coordinate space. The vertices are not transformed using the rendered object's transform.
• Device: the vertices are defined in normalized device (or clip) coordinate space. The vertices are not transformed using the rendered object's transform.

material {
vertexDomain : device
}

### Vertex and attributes: interpolation

Type

string

Value

Any of smooth, flat. Defaults to smooth.

Description

Defines how interpolants (or variables) are interpolated between vertices. When this property is set to smooth, a perspective correct interpolation is performed on each interpolant. When set to flat, no interpolation is performed and all the fragments within a given triangle will be shaded the same.

material {
interpolation : flat
}

### Blending and transparency: blending

Type

string

Value

Any of opaque, transparent, fade, add, masked, multiply, screen. Defaults to opaque.

Description

Defines how/if the rendered object is blended with the content of the render target. The possible blending modes are:

• Opaque: blending is disabled, the alpha channel of the material's output is ignored.
• Transparent: blending is enabled. The material's output is alpha composited with the render target, using Porter-Duff's source over rule. This blending mode assumes pre-multiplied alpha.
• Fade: acts as transparent but transparency is also applied to specular lighting. In transparent mode, the material's alpha values only applies to diffuse lighting. This blending mode is useful to fade lit objects in and out.
• Add: blending is enabled. The material's output is added to the content of the render target.
• Multiply: blending is enabled. The material's output is multiplied with the content of the render target, darkening the content.
• Screen: blending is enabled. Effectively the opposite of the multiply, the content of the render target is brightened.
• Masked: blending is disabled. This blending mode enables alpha masking. The alpha channel of the material's output defines whether a fragment is discarded or not. Additionally, ALPHA_TO_COVERAGE is enabled for non-translucent views. See the maskThreshold section for more information.

material {
blending : transparent
}

### Blending and transparency: postLightingBlending

Type

string

Value

Any of opaque, transparent, add. Defaults to transparent.

Description

Defines how the postLightingColor material property is blended with the result of the lighting computations. The possible blending modes are:

• Opaque: blending is disabled, the material will output postLightingColor directly.
• Transparent: blending is enabled. The material's computed color is alpha composited with the postLightingColor, using Porter-Duff's source over rule. This blending mode assumes pre-multiplied alpha.
• Add: blending is enabled. The material's computed color is added to postLightingColor.
• Multiply: blending is enabled. The material's computed color is multiplied with postLightingColor.
• Screen: blending is enabled. The material's computed color is inverted and multiplied with postLightingColor, and the result is added to the material's computed color.

material {
}

### Blending and transparency: transparency

Type

string

Value

Any of default, twoPassesOneSide or twoPassesTwoSides. Defaults to default.

Description

Controls how transparent objects are rendered. It is only valid when the blending mode is not opaque and refractionMode is none. None of these methods can accurately render concave geometry, but in practice they are often good enough.

The three possible transparency modes are:

• default: the transparent object is rendered normally (as seen in figure 33), honoring the culling mode, etc.
• twoPassesOneSide: the transparent object is first rendered in the depth buffer, then again in the color buffer, honoring the culling mode. This effectively renders only half of the transparent object as shown in figure 34.
• twoPassesTwoSides: the transparent object is rendered twice in the color buffer: first with its back faces, then with its front faces. This mode lets you render both set of faces while reducing or eliminating sorting issues, as shown in figure 35. twoPassesTwoSides can be combined with doubleSided for better effect.

material {
transparency : twoPassesOneSide
}

Figure 33: This double sided model shows the type of sorting issues transparent objects can be subject to in default mode

Figure 34: In twoPassesOneSide mode, only one set of faces is visible and correctly sorted

Figure 35: In twoPassesTwoSides mode, both set of faces are visible and sorting issues are minimized or eliminated

Type

number

Value

A value between 0.0 and 1.0. Defaults to 0.4.

Description

Sets the minimum alpha value a fragment must have to not be discarded when the blending mode is set to masked. If the fragment is not discarded, its source alpha is set to 1. When the blending mode is not masked, this value is ignored. This value can be used to controlled the appearance of alpha-masked objects.

material {
}

### Blending and transparency: refractionMode

Type

string

Value

Any of none, cubemap, screenspace. Defaults to none.

Description

Activates refraction when set to anything but none. A value of cubemap will only use the IBL cubemap as source of refraction, while this is significantly more efficient, no scene objects will be refracted, only the distant environment encoded in the cubemap. This mode is adequate for an object viewer for instance. A value of screenspace will employ the more advanced screen-space refraction algorithm which allows opaque objects in the scene to be refracted. In cubemap mode, refracted rays are assumed to emerge from the center of the object and the thickness parameter is only used for computing the absorption, but has no impact on the refraction itself. In screenspace mode, refracted rays are assumed to travel parallel to the view direction when they exit the refractive medium.

material {
refractionMode : cubemap,
}

### Blending and transparency: refractionType

Type

string

Value

Any of solid, thin. Defaults to solid.

Description

This is only meaningful when refractionMode is set to anything but none. refractionType defines the refraction model used. solid is used for thick objects such as a crystal ball, an ice cube or as sculpture. thin is used for thin objects such as a window, an ornament ball or a soap bubble. In solid mode all refracive objects are assumed to be a sphere tangent to the entry point and of radius thickness. In thin mode, all refractive objects are assumed to be flat and thin and of thickness thickness.

material {
refractionMode : cubemap,
refractionType : thin,
}

### Rasterization: culling

 Type string Value Any of none, front, back, frontAndBack. Defaults to back. Description Defines which triangles should be culled: none, front-facing triangles, back-facing triangles or all.

material {
culling : none
}

### Rasterization: colorWrite

 Type boolean Value true or false. Defaults to true. Description Enables or disables writes to the color buffer.

material {
colorWrite : false
}

### Rasterization: depthWrite

 Type boolean Value true or false. Defaults to true for opaque materials, false for transparent materials. Description Enables or disables writes to the depth buffer.

material {
depthWrite : false
}

### Rasterization: depthCulling

Type

boolean

Value

true or false. Defaults to true.

Description

Enables or disables depth testing. When depth testing is disabled, an object rendered with this material will always appear on top of other opaque objects.

material {
depthCulling : false
}

### Rasterization: doubleSided

Type

boolean

Value

true or false. Defaults to false.

Description

Only available in the unlit shading model. If this property is enabled, the final color computed by the material is multiplied by the shadowing factor (or visibility). This allows to create transparent shadow-receiving objects (for instance an invisible ground plane in AR). This is only supported with shadows from directional lights.

material {
blending : transparent
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
// baseColor defines the color and opacity of the final shadow
material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);
}
}

### Lighting: reflections

Type

string

Value

default or screenspace. Defaults to default.

Description

Controls the source of specular reflections for this material. When this property is set to default, reflections only come image-based lights. When this property is set to screenspace, reflections come from the screen space's color buffer in addition to image-based lights.

material {
name : "Glossy metal",
reflections : screenspace
}

Type

boolean

Value

true or false. Defaults to false.

Description

Only available in the unlit shading model. If this property is enabled, the final color computed by the material is multiplied by the shadowing factor (or visibility). This allows to create transparent shadow-receiving objects (for instance an invisible ground plane in AR). This is only supported with shadows from directional lights.

material {
blending : transparent
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
// baseColor defines the color and opacity of the final shadow
material.baseColor = vec4(0.0, 0.0, 0.0, 0.7);
}
}

Type

boolean

Value

true or false. Defaults to false.

Description

Enables transparent shadows on this material. When this feature is enabled, Filament emulates transparent shadows using a dithering pattern: they work best with variance shadow maps (VSM) and blurring enabled. The opacity of the shadow derives directly from the alpha channel of the material's baseColor property. Transparent shadows can be enabled on opaque objects, making them compatible with refractive/transmissive objects that are otherwise considered opaque.

material {
name : "Clear plastic with stickers",
blending : transparent,
// ...
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor = texture(materialParams_baseColor, getUV0());
}
}

Figure 36: Objects rendered with transparent shadows and blurry VSM with a radius of 4. Model Bottle of Water by T-Art.

### Lighting: clearCoatIorChange

Type

boolean

Value

true or false. Defaults to true.

Description

When adding a clear coat layer, the change in index of refraction (IoR) is taken into account to modify the specular color of the base layer. This appears to darken baseColor. When this effect is disabled, baseColor is left unmodified. See figure 37 for an example of how this property can affect a red metallic base layer.

material {
clearCoatIorChange : false
}

Figure 37: The same rough metallic ball with a clear coat layer rendered with clearCoatIorChange enabled (left) and disabled (right).

### Lighting: multiBounceAmbientOcclusion

Type

boolean

Value

true or false. Defaults to false on mobile, true on desktop.

Description

Multi-bounce ambient occlusion takes into account interreflections when applying ambient occlusion to image-based lighting. Turning this feature on avoids over-darkening occluded areas. It also takes the surface color into account to generate colored ambient occlusion. Figure 38 compares the ambient occlusion term of a surface with and without multi-bounce ambient occlusion. Notice how multi-bounce ambient occlusion introduces color in the occluded areas. Figure 39 toggles between multi-bounce ambient occlusion on and off on a lit brick material to highlight the effects of this property.

material {
multiBounceAmbientOcclusion : true
}

Figure 38: Brick texture amient occlusion map rendered with multi-bounce ambient occclusion enabled (left) and disabled (right).

Figure 39: Brick texture rendered with multi-bounce ambient occclusion enabled and disabled.

### Lighting: specularAmbientOcclusion

Type

string

Value

none, simple or bentNormals. Defaults to none on mobile, simple on desktop. For compatibility reasons, true and false are also accepted and map respectively to simple and none.

Description

Static ambient occlusion maps and dynamic ambient occlusion (SSAO, etc.) apply to diffuse indirect lighting. When setting this property to other than none, a new ambient occlusion term is derived from the surface roughness and applied to specular indirect lighting. This effect helps remove unwanted specular reflections as shown in figure 40. When this value is set to simple, Filament uses a cheap but approximate method of computing the specular ambient occlusion term. If this value is set to bentNormals, Filament will use a much more accurate but much more expensive method.

material {
specularAmbientOcclusion : simple
}

Figure 40: Comparison of specular ambient occlusion on and off. The effect is particularly visible under the hose.

### Anti-aliasing: specularAntiAliasing

Type

boolean

Value

true or false. Defaults to false.

Description

Reduces specular aliasing and preserves the shape of specular highlights as an object moves away from the camera. This anti-aliasing solution is particularly effective on glossy materials (low roughness) but increases the cost of the material. The strength of the anti-aliasing effect can be controlled using two other properties: specularAntiAliasingVariance and specularAntiAliasingThreshold.

material {
specularAntiAliasing : true
}

### Anti-aliasing: specularAntiAliasingVariance

Type

float

Value

A value between 0 and 1, set to 0.15 by default.

Description

Sets the screen space variance of the filter kernel used when applying specular anti-aliasing. Higher values will increase the effect of the filter but may increase roughness in unwanted areas.

material {
specularAntiAliasingVariance : 0.2
}

### Anti-aliasing: specularAntiAliasingThreshold

Type

float

Value

A value between 0 and 1, set to 0.2 by default.

Description

Sets the clamping threshold used to suppress estimation errors when applying specular anti-aliasing. When set to 0, specular anti-aliasing is disabled.

material {
specularAntiAliasingThreshold : 0.1
}

Type

bool

Value

true or false. Defaults to false.

Description

Enables custom surface shading when set to true. When surface shading is enabled, the fragment shader must provide an extra function that will be invoked for every light in the scene that may influence the current fragment. Please refer to the Custom surface shading section below for more information.

material {
}

## Vertex block

The vertex block is optional and can be used to control the vertex shading stage of the material. The vertex block must contain valid ESSL 3.0 code (the version of GLSL supported in OpenGL ES 3.0). You are free to create multiple functions inside the vertex block but you must declare the materialVertex function:

vertex {
void materialVertex(inout MaterialVertexInputs material) {
}
}

This function will be invoked automatically at runtime by the shading system and gives you the ability to read and modify material properties using the MaterialVertexInputs structure. This full definition of the structure can be found in the Material vertex inputs section.

You can use this structure to compute your custom variables/interpolants or to modify the value of the attributes. For instance, the following vertex blocks modifies both the color and the UV coordinates of the vertex over time:

material {
requires : [uv0, color]
}
vertex {
void materialVertex(inout MaterialVertexInputs material) {
material.color *= sin(getUserTime().x);
material.uv0 *= sin(getUserTime().x);
}
}

In addition to the MaterialVertexInputs structure, your vertex shading code can use all the public APIs listed in the Shader public APIs section.

### Material vertex inputs

struct MaterialVertexInputs {
float4 color;              // if the color attribute is required
float2 uv0;                // if the uv0 attribute is required
float2 uv1;                // if the uv1 attribute is required
float3 worldNormal;        // only if the shading model is not unlit
float4 worldPosition;      // always available (see note below about world-space)

mat4   clipSpaceTransform; // default: identity, transforms the clip-space position

// variable* names are replaced with actual names
float4 variable0;          // if 1 or more variables is defined
float4 variable1;          // if 2 or more variables is defined
float4 variable2;          // if 3 or more variables is defined
float4 variable3;          // if 4 or more variables is defined
};

worldPosition

To achieve good precision, the worldPosition coordinate in the vertex shader is shifted by the camera position. To get the true world-space position, users can add this to getWorldOffset().

UV attributes

By default the vertex shader of a material will flip the Y coordinate of the UV attributes of the current mesh: material.uv0 = vec2(mesh_uv0.x, 1.0 - mesh_uv0.y). You can control this behavior using the flipUV property and setting it to false.

### Custom vertex attributes

You can use up to 8 custom vertex attributes, all of type float4. These attributes can be accessed using the vertex block shader functions getCustom0() to getCustom7(). However, before using custom attributes, you must declare those attributes as required in the requires property of the material:

material {
requires : [
custom0,
custom1,
custom2
]
}

## Fragment block

The fragment block must be used to control the fragment shading stage of the material. The fragment block must contain valid ESSL 3.0 code (the version of GLSL supported in OpenGL ES 3.0). You are free to create multiple functions inside the fragment block but you must declare the material function:

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
}
}

This function will be invoked automatically at runtime by the shading system and gives you the ability to read and modify material properties using the MaterialInputs structure. This full definition of the structure can be found in the Material fragment inputs section. The full definition of the various members of the structure can be found in the Material models section of this document.

The goal of the material() function is to compute the material properties specific to the selected shading model. For instance, here is a fragment block that creates a glossy red metal using the standard lit shading model:

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor.rgb = vec3(1.0, 0.0, 0.0);
material.metallic = 1.0;
material.roughness = 0.0;
}
}

### prepareMaterial function

Note that you must call prepareMaterial(material) before exiting the material() function. This prepareMaterial function sets up the internal state of the material model. Some of the APIs described in the Fragment APIs section - like shading_normal for instance - can only be accessed after invoking prepareMaterial().

It is also important to remember that the normal property - as described in the Material fragment inputs section - only has an effect when modified before calling prepareMaterial(). Here is an example of a fragment shader that properly modifies the normal property to implement a glossy red plastic with bump mapping:

fragment {
void material(inout MaterialInputs material) {
// fetch the normal in tangent space
vec3 normal = texture(materialParams_normalMap, getUV0()).xyz;
material.normal = normal * 2.0 - 1.0;

// prepare the material
prepareMaterial(material);

// from now on, shading_normal, etc. can be accessed
material.baseColor.rgb = vec3(1.0, 0.0, 0.0);
material.metallic = 0.0;
material.roughness = 1.0;
}
}

### Material fragment inputs

struct MaterialInputs {
float4 baseColor;           // default: float4(1.0)
float4 emissive;            // default: float4(0.0, 0.0, 0.0, 1.0)
float4 postLightingColor;   // default: float4(0.0)

// no other field is available with the unlit shading model
float  roughness;           // default: 1.0
float  metallic;            // default: 0.0, not available with cloth or specularGlossiness
float  reflectance;         // default: 0.5, not available with cloth or specularGlossiness
float  ambientOcclusion;    // default: 0.0

// not available when the shading model is subsurface or cloth
float3 sheenColor;          // default: float3(0.0)
float  sheenRoughness;      // default: 0.0
float  clearCoat;           // default: 1.0
float  clearCoatRoughness;  // default: 0.0
float3 clearCoatNormal;     // default: float3(0.0, 0.0, 1.0)
float  anisotropy;          // default: 0.0
float3 anisotropyDirection; // default: float3(1.0, 0.0, 0.0)

// only available when the shading model is subsurface or refraction is enabled
float  thickness;           // default: 0.5

// only available when the shading model is subsurface
float  subsurfacePower;     // default: 12.234
float3 subsurfaceColor;     // default: float3(1.0)

// only available when the shading model is cloth
float3 sheenColor;          // default: sqrt(baseColor)
float3 subsurfaceColor;     // default: float3(0.0)

// only available when the shading model is specularGlossiness
float3 specularColor;       // default: float3(0.0)
float  glossiness;          // default: 0.0

// not available when the shading model is unlit
// must be set before calling prepareMaterial()
float3 normal;              // default: float3(0.0, 0.0, 1.0)

// only available when refraction is enabled
float transmission;         // default: 1.0
float3 absorption;          // default float3(0.0, 0.0, 0.0)
float ior;                  // default: 1.5
float microThickness;       // default: 0.0, not available with refractionType "solid"
}

When customSurfaceShading is set to true in the material block, the fragment block must declare and implement the surfaceShading function:

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
// prepare material inputs
}

const MaterialInputs materialInputs,
const LightData lightData
) {
return vec3(1.0); // output of custom lighting
}
}

This function will be invoked for every light (directional, spot or point) in the scene that may influence the current fragment. The surfaceShading is invoked with 3 sets of data:

• MaterialInputs, as described in the Material fragment inputs section and prepared in the material function explained above
• ShadingData, a structure containing values derived from MaterialInputs (see below)
• LightData, a structure containing values specific to the light being currently evaluated (see below)

The surfaceShading function must return an RGB color in linear sRGB. Alpha blending and alpha masking are handled outside of this function and must therefore be ignored.

The surfaceShading function is invoked even when a fragment is known to be fully in the shadow of the current light (lightData.NdotL <= 0.0 or lightData.visibility <= 0.0). This gives more flexibility to the surfaceShading function as it provides a simple way to handle constant ambient lighting for instance.

Custom surface shading only works with the lit shading model. Attempting to use any other model will result in an error.

struct ShadingData {
// The material's diffuse color, as derived from baseColor and metallic.
// This color is pre-multiplied by alpha and in the linear sRGB color space.
vec3  diffuseColor;

// The material's specular color, as derived from baseColor and metallic.
// This color is pre-multiplied by alpha and in the linear sRGB color space.
vec3  f0;

// The perceptual roughness is the roughness value set in MaterialInputs,
// with extra processing:
// - Clamped to safe values
// - Filtered if specularAntiAliasing is enabled
// This value is between 0.0 and 1.0.
float perceptualRoughness;

// The roughness value expected by BRDFs. This value is the square of
// perceptualRoughness. This value is between 0.0 and 1.0.
float roughness;
};

#### Light data structure

struct LightData {
// The color (.rgb) and pre-exposed intensity (.w) of the light.
// The color is an RGB value in the linear sRGB color space.
// The pre-exposed intensity is the intensity of the light multiplied by
// the camera's exposure value.
vec4  colorIntensity;

// The normalized light vector, in world space (direction from the
// current fragment's position to the light).
vec3  l;

// The dot product of the shading normal (with normal mapping applied)
// and the light vector. This value is equal to the result of
// saturate(dot(getWorldSpaceNormal(), lightData.l)).
// This value is always between 0.0 and 1.0. When the value is <= 0.0,
// the current fragment is not visible from the light and lighting
// computations can be skipped.
float NdotL;

// The position of the light in world space.
vec3  worldPosition;

// Attenuation of the light based on the distance from the current
// fragment to the light in world space. This value between 0.0 and 1.0
// is computed differently for each type of light (it's always 1.0 for
// directional lights).
float attenuation;

// Visibility factor computed from shadow maps or other occlusion data
// specific to the light being evaluated. This value is between 0.0 and
// 1.0.
float visibility;
};

#### Example

The material below shows how to use custom surface shading to implement a simplified toon shader:

material {
name : Toon,
parameters : [
{
type : float3,
name : baseColor
}
],
}

fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
material.baseColor.rgb = materialParams.baseColor;
}

const MaterialInputs materialInputs,
const LightData lightData
) {
// Number of visible shade transitions
// Ambient intensity
const float ambient = 0.1;

toon *= lightData.visibility * lightData.attenuation;

// Color and intensity
vec3 light = lightData.colorIntensity.rgb * lightData.colorIntensity.w;

return shadingData.diffuseColor * light * toon;
}
}

The result can be seen in figure 41.

### Types

While GLSL types can be used directly (vec4 or mat4) we recommend the use of the following type aliases:

Name GLSL type Description
bool2 bvec2 A vector of 2 booleans
bool3 bvec3 A vector of 3 booleans
bool4 bvec4 A vector of 4 booleans
int2 ivec2 A vector of 2 integers
int3 ivec3 A vector of 3 integers
int4 ivec4 A vector of 4 integers
uint2 uvec2 A vector of 2 unsigned integers
uint3 uvec3 A vector of 3 unsigned integers
uint4 uvec4 A vector of 4 unsigned integers
float2 float2 A vector of 2 floats
float3 float3 A vector of 3 floats
float4 float4 A vector of 4 floats
float4×4 mat4 A 4×4 float matrix
float3×3 mat3 A 3×3 float matrix

### Math

Name Type Description
PI float A constant that represent $$\pi$$
HALF_PI float A constant that represent $$\frac{\pi}{2}$$
saturate(float x) float Clamps the specified value between 0.0 and 1.0
pow5(float x) float Computes $$x^5$$
sq(float x) float Computes $$x^2$$
max3(float3 v) float Returns the maximum value of the specified float3
mulMat4×4Float3(float4×4 m, float3 v) float4 Returns $$m * v$$
mulMat3×3Float3(float4×4 m, float3 v) float4 Returns $$m * v$$

### Matrices

Name Type Description
getViewFromWorldMatrix() float4×4 Matrix that converts from world space to view/eye space
getWorldFromViewMatrix() float4×4 Matrix that converts from view/eye space to world space
getClipFromViewMatrix() float4×4 Matrix that converts from view/eye space to clip (NDC) space
getViewFromClipMatrix() float4×4 Matrix that converts from clip (NDC) space to view/eye space
getClipFromWorldMatrix() float4×4 Matrix that converts from world to clip (NDC) space
getWorldFromClipMatrix() float4×4 Matrix that converts from clip (NDC) space to world space

### Frame constants

Name Type Description
getResolution() float4 Dimensions of the view's effective viewport in pixels: width, height, 1 / width, 1 / height. This might be different from View::getViewport() for instance because of added rendering guard-bands. This can be used in conjunction with getNormalizedViewportCoord() to generate pixel coordinates.
getWorldCameraPosition() float3 Position of the camera/eye in world space
getWorldOffset() float3 The shift required to obtain API-level world space
getTime() float Current time as a remainder of 1 second. Yields a value between 0 and 1
getUserTime() float4 Current time in seconds: time, (double)time - time, 0, 0
getUserTimeMode(float m) float Current time modulo m in seconds
getExposure() float Photometric exposure of the camera
getEV100() float Exposure value at ISO 100 of the camera

world space

To achieve good precision, the “world space” in Filament's shading system does not necessarily match the API-level world space. To obtain the position of the API-level camera, custom materials can add getWorldOffset() to getWorldCameraPosition().

### Vertex only

The following APIs are only available from the vertex block:

Name Type Description
getPosition() float4 Vertex position in the domain defined by the material (default: object/model space)
getCustom0() to getCustom7() float4 Custom vertex attribute
getWorldFromModelMatrix() float4×4 Matrix that converts from model (object) space to world space
getWorldFromModelNormalMatrix() float3×3 Matrix that converts normals from model (object) space to world space
getVertexIndex() int Index of the current vertex

### Fragment only

The following APIs are only available from the fragment block:

Name Type Description
getWorldTangentFrame() float3×3 Matrix containing in each column the tangent (frame[0]), bi-tangent (frame[1]) and normal (frame[2]) of the vertex in world space. If the material does not compute a tangent space normal for bump mapping or if the shading is not anisotropic, only the normal is valid in this matrix.
getWorldPosition() float3 Position of the fragment in world space (see note below about world-space)
getWorldViewVector() float3 Normalized vector in world space from the fragment position to the eye
getWorldNormalVector() float3 Normalized normal in world space, after bump mapping (must be used after prepareMaterial())
getWorldGeometricNormalVector() float3 Normalized normal in world space, before bump mapping (can be used before prepareMaterial())
getWorldReflectedVector() float3 Reflection of the view vector about the normal (must be used after prepareMaterial())
getNormalizedViewportCoord() float3 Normalized viewport position (i.e. NDC coordinates normalized to [0, 1], can be used before prepareMaterial())
getNdotV() float The result of dot(normal, view), always strictly greater than 0 (must be used after prepareMaterial())
getColor() float4 Interpolated color of the fragment, if the color attribute is required
getUV0() float2 First interpolated set of UV coordinates, only available if the uv0 attribute is required
getUV1() float2 First interpolated set of UV coordinates, only available if the uv1 attribute is required
getMaskThreshold() float Returns the mask threshold, only available when blending is set to masked
inverseTonemap(float3) float3 Applies the inverse tone mapping operator to the specified linear sRGB color and returns a linear sRGB color. This operation may be an approximation and works best with the “Filmic” tone mapping operator
inverseTonemapSRGB(float3) float3 Applies the inverse tone mapping operator to the specified non-linear sRGB color and returns a linear sRGB color. This operation may be an approximation and works best with the “Filmic” tone mapping operator
luminance(float3) float Computes the luminance of the specified linear sRGB color
ycbcrToRgb(float, float2) float3 Converts a luminance and CbCr pair to a sRGB color
uvToRenderTargetUV(float2) float2 Transforms a UV coordinate to allow sampling from a RenderTarget attachment

world space

To obtain API-level world space coordinates, custom materials should add getWorldOffset() to getWorldPosition() (et al).

sampling from render targets

When sampling from a filament::Texture that is attached to a filament::RenderTarget for materials in the surface domain, please use uvToRenderTargetUV to transform the texture coordinate. This will flip the coordinate depending on which backend is being used.

# Compiling materials

Material packages can be compiled from material definitions using the command line tool called matc. The simplest way to use matc is to specify an input material definition (car_paint.mat in the example below) and an output material package (car_paint.filamat in the example below):

### —api

By default, matc generates material packages containing shaders for the OpenGL API. You can choose to generate shaders for the Vulkan API in addition to the OpenGL shaders. If you intend on targeting only Vulkan capable devices, you can reduce the size of the material packages by generating only the set of Vulkan shaders:

$matc -a vulkan -o ./materials/bin/car_paint.filamat ./materials/src/car_paint.mat ### —optimize-size This flag applies fewer optimization techniques to try and keep the final material as small as possible. If the compiled material is deemed too large by default, using this flag might be a good compromise between runtime performance and size. ### —reflect This flag was designed to help build tools around matc. It allows you to print out specific metadata in JSON format. The example below prints out the list of parameters defined in Filament's standard skybox material. It produces a list of 2 parameters, named showSun and skybox, respectively a boolean and a cubemap texture. $ matc --reflect parameters filament/src/materials/skybox.mat
{
"parameters": [
{
"name": "showSun",
"type": "bool",
"size": "1"
},
{
"name": "skybox",
"type": "samplerCubemap",
"format": "float",
"precision": "default"
}
]
}

### —variant-filter

This flag can be used to further reduce the size of a compiled material. It is used to specify a list of shader variants that the application guarantees will never be needed. These shader variants are skipped during the code generation phase of matc, thus reducing the overall size of the material.

The variants must be specified as a comma-separated list, using one of the following available variants:

• directionalLighting, used when a directional light is present in the scene
• dynamicLighting, used when a non-directional light (point, spot, etc.) is present in the scene
• shadowReceiver, used when an object can receive shadows
• skinning, used when an object is animated using GPU skinning or vertex morphing
• fog, used when global fog is applied to the scene
• vsm, used when VSM shadows are enabled and the object is a shadow receiver
• ssr, used when screen-space reflections are enabled in the View

Example:

--variant-filter=skinning,shadowReceiver

Note that some variants may automatically be filtered out. For instance, all lighting related variants (directionalLighting, etc.) are filtered out when compiling an unlit material.

When this flag is used, the specified variant filters are merged with the variant filters specified in the material itself.

Use this flag with caution, filtering out a variant required at runtime may lead to crashes.

# Handling colors

## Linear colors

If the color data comes from a texture, simply make sure you use an sRGB texture to benefit from automatic hardware conversion from sRGB to linear. If the color data is passed as a parameter to the material you can convert from sRGB to linear by running the following algorithm on each color channel:

float sRGB_to_linear(float color) {
return color <= 0.04045 ? color / 12.92 : pow((color + 0.055) / 1.055, 2.4);
}

Alternatively you can use one of the two cheaper but less accurate versions shown below:

// Cheaper
linearColor = pow(color, 2.2);
// Cheapest
linearColor = color * color;

## Pre-multiplied alpha

A color uses pre-multiplied alpha if its RGB components are multiplied by the alpha channel:

// Compute pre-multiplied color
color.rgb *= color.a;

If the color is sampled from a texture, you can simply ensure that the texture data is pre-multiplied ahead of time. On Android, any texture uploaded from a Bitmap will be pre-multiplied by default.

formatted by Markdeep 1.13