Skip to main content

Introduction

Filament implements a physically based rendering (PBR) system that provides accurate material representation and light interaction. This document explains the theory and equations behind the implementation.
This content is derived from Filament’s official PBR documentation, which provides comprehensive details on the rendering equations.

Why Physically Based Rendering?

From Filament.md.html:56-60:
Physically based rendering is a rendering method that provides a more accurate representation of materials and how they interact with light when compared to traditional real-time models. The separation of materials and lighting at the core of the PBR method makes it easier to create realistic assets that look accurate in all lighting conditions.

Core Principles

Filament’s PBR implementation is guided by these principles:

Real-time Mobile Performance

Optimized for OpenGL ES 3.x class GPUs while maintaining quality.

Quality

Emphasis on overall picture quality with acceptable compromises for performance.

Ease of Use

Simple, intuitive parameters that produce physically plausible results.

Physical Units

Uses real-world units: meters, Kelvin, lumens, candelas.

The BRDF Model

Surface Response Equation

The complete surface response is expressed as: f(v,l)=fd(v,l)+fr(v,l)f(v,l) = f_d(v,l) + f_r(v,l) Where:
  • fdf_d is the diffuse component (subsurface scattering)
  • frf_r is the specular component (surface reflection)
  • vv is the view direction
  • ll is the light direction

Microfacet Theory

From Filament.md.html:133-138:
A microfacet BRDF states that surfaces are not smooth at a micro level, but made of a large number of randomly aligned planar surface fragments, called microfacets.
The roughness parameter controls microfacet alignment:
  • Low roughness → Aligned facets → Sharp reflections
  • High roughness → Random facets → Blurred reflections

Specular BRDF (Cook-Torrance)

The specular term uses the Cook-Torrance approximation: fr(v,l)=D(h,α)G(v,l,α)F(v,h,f0)4(nv)(nl)f_r(v,l) = \frac{D(h, \alpha) G(v, l, \alpha) F(v, h, f_0)}{4(n \cdot v)(n \cdot l)} This equation has three key terms:

1. Normal Distribution Function (D)

Filament uses the GGX distribution for realistic highlights: DGGX(h,α)=α2π((nh)2(α21)+1)2D_{GGX}(h,\alpha) = \frac{\alpha^2}{\pi ((n \cdot h)^2 (\alpha^2 - 1) + 1)^2} Implementation from Filament.md.html:222-227:
float D_GGX(float NoH, float roughness) {
    float a = NoH * roughness;
    float k = roughness / (1.0 - NoH * NoH + a * a);
    return k * k * (1.0 / PI);
}
GGX provides long-tailed falloff that matches real-world materials better than older models like Blinn-Phong.

2. Geometric Shadowing (G)

The Smith-GGX visibility function accounts for microfacet masking and shadowing: V(v,l,α)=0.5(nl)(nv)2(1α2)+α2+(nv)(nl)2(1α2)+α2V(v,l,\alpha) = \frac{0.5}{(n \cdot l) \sqrt{(n \cdot v)^2 (1 - \alpha^2) + \alpha^2} + (n \cdot v) \sqrt{(n \cdot l)^2 (1 - \alpha^2) + \alpha^2}} Filament uses an optimized approximation:
Filament.md.html:335-340
float V_SmithGGXCorrelatedFast(float NoV, float NoL, float roughness) {
    float a = roughness;
    float GGXV = NoL * (NoV * (1.0 - a) + a);
    float GGXL = NoV * (NoL * (1.0 - a) + a);
    return 0.5 / (GGXV + GGXL);
}

3. Fresnel Term (F)

The Schlick approximation models how reflectance changes with view angle: FSchlick(v,h,f0,f90)=f0+(f90f0)(1vh)5F_{Schlick}(v,h,f_0,f_{90}) = f_0 + (f_{90} - f_0)(1 - v \cdot h)^5 Implementation:
Filament.md.html:367-370
vec3 F_Schlick(float u, vec3 f0, float f90) {
    return f0 + (vec3(f90) - f0) * pow(1.0 - u, 5.0);
}
The Fresnel effect explains why water appears transparent when viewed straight down but reflective at grazing angles.

Diffuse BRDF

Filament uses a Lambertian diffuse model for efficiency: fd(v,l)=σπf_d(v,l) = \frac{\sigma}{\pi} Where σ\sigma is the diffuse reflectance (albedo).
Filament.md.html:403-407
float Fd_Lambert() {
    return 1.0 / PI;
}

vec3 Fd = diffuseColor * Fd_Lambert();
From Filament.md.html:411-413:
Given our constraints we decided that the extra runtime cost does not justify the slight increase in quality. This sophisticated diffuse model also renders image-based and spherical harmonics more difficult to express and implement.
The Lambertian model provides good results at minimal cost, which is crucial for mobile performance.

Material Types

Dielectrics vs Conductors

From Filament.md.html:179-192:
  • Have both diffuse and specular components
  • Light penetrates surface and scatters internally
  • Achromatic specular reflectance
  • Examples: plastic, wood, water, glass
// Base color = diffuse color
// f0 = achromatic (typically 4%)
vec3 diffuseColor = baseColor * (1.0 - metallic);
vec3 f0 = vec3(0.04);

Energy Conservation

From Filament.md.html:197-199:
Energy conservation states that the total amount of specular and diffuse reflectance energy is less than the total amount of incident energy.
This ensures materials behave physically correctly without manual artist adjustment.

Energy Compensation

The Cook-Torrance BRDF loses energy at high roughness due to single-scattering approximation. Filament adds a compensation term: fms(l,v)=f01E(l)E(l)fss(l,v)f_{ms}(l,v) = f_0 \frac{1 - E(l)}{E(l)} f_{ss}(l,v) Implementation:
Filament.md.html:588-591
vec3 energyCompensation = 1.0 + f0 * (1.0 / dfg.y - 1.0);
// Scale the specular lobe to account for multiscattering
Fr *= pixel.energyCompensation;
Without energy compensation, rough metallic surfaces appear incorrectly darkened.

Complete BRDF Implementation

Here’s the full GLSL implementation:
Filament.md.html:456-501
float D_GGX(float NoH, float a) {
    float a2 = a * a;
    float f = (NoH * a2 - NoH) * NoH + 1.0;
    return a2 / (PI * f * f);
}

vec3 F_Schlick(float u, vec3 f0) {
    return f0 + (vec3(1.0) - f0) * pow(1.0 - u, 5.0);
}

float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
    float a2 = a * a;
    float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
    float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
    return 0.5 / (GGXV + GGXL);
}

float Fd_Lambert() {
    return 1.0 / PI;
}

void BRDF(...) {
    vec3 h = normalize(v + l);

    float NoV = abs(dot(n, v)) + 1e-5;
    float NoL = clamp(dot(n, l), 0.0, 1.0);
    float NoH = clamp(dot(n, h), 0.0, 1.0);
    float LoH = clamp(dot(l, h), 0.0, 1.0);

    // perceptually linear roughness to roughness (see parameterization)
    float roughness = perceptualRoughness * perceptualRoughness;

    float D = D_GGX(NoH, roughness);
    vec3  F = F_Schlick(LoH, f0);
    float V = V_SmithGGXCorrelated(NoV, NoL, roughness);

    // specular BRDF
    vec3 Fr = (D * V) * F;

    // diffuse BRDF
    vec3 Fd = diffuseColor * Fd_Lambert();

    // apply lighting...
}

Material Parameters

Standard Parameters

ParameterTypeRangeDescription
baseColorRGB[0..1]Diffuse albedo for dielectrics, specular color for metals
metallicScalar[0..1]0 = dielectric, 1 = conductor
roughnessScalar[0..1]0 = smooth/glossy, 1 = rough/matte
reflectanceScalar[0..1]Fresnel reflectance at normal incidence (dielectrics only)

Roughness Remapping

Filament remaps roughness for perceptual linearity: α=perceptualRoughness2\alpha = perceptualRoughness^2 From Filament.md.html:740-753:
Without this remapping, shiny metallic surfaces would have to be confined to a very small range between 0.0 and 0.05.

Reflectance to F0 Conversion

For dielectrics: f0=0.16reflectance2f_0 = 0.16 \cdot reflectance^2 This maps reflectance=0.5 to f0=4%, which is typical for common dielectrics.
Use reflectance=0.5 (4%) as the default for most non-metallic materials.

Common Material Values

Dielectric Reflectance

MaterialReflectanceIORLinear Value
Water2%1.330.35
Plastic, glass4-5%1.5-1.580.5-0.56
Common gems5-16%1.58-2.330.56-1.0

Metal F0 Colors (sRGB)

MetalF0 (sRGB)Hex
Silver(0.97, 0.96, 0.91)#f7f4e8
Aluminum(0.91, 0.92, 0.92)#e8eaea
Gold(1.00, 0.85, 0.57)#ffd891
Copper(0.97, 0.74, 0.62)#f7bc9e

Validation Techniques

White Furnace Test

A purely reflective metallic surface (f0 = 1) in a white uniform environment should be indistinguishable from the background at all roughness levels when energy is conserved.

Best Practices

Stick to physically plausible parameter ranges:
  • Dielectric baseColor: 50-240 sRGB (strict) or 30-240 (tolerant)
  • Metallic: close to 0 or 1 (not intermediate values)
  • Reflectance: 0.35-1.0 (never below 0.35)
Always work in linear RGB space for lighting calculations. Convert sRGB textures to linear.
Clamp roughness to avoid precision issues:
roughness = clamp(roughness, 0.089, 1.0);
Verify materials in a white furnace environment to ensure energy conservation.

Advanced Topics

Clear Coat Model

Filament supports multi-layer materials with a clear coat:
  • Second specular lobe for coating
  • Always isotropic and dielectric
  • Simpler visibility function for performance
  • Accounts for energy loss through coating

Anisotropic Reflections

Anisotropic materials (brushed metal) require directional roughness parameters.

Subsurface Scattering

For materials with large mean free path (skin, wax, marble), additional subsurface terms are needed.

Materials Overview

Learn how to create and use materials in practice

Rendering Loop

Understand how PBR fits into the render pipeline

Build docs developers (and LLMs) love