Skip to main content
Filament provides a comprehensive post-processing pipeline with effects including bloom, depth of field, tone mapping, color grading, and anti-aliasing. These effects run after the main rendering pass to enhance image quality.

Enabling Post-Processing

Post-processing is enabled by default but can be toggled:
// Enable post-processing (default)
view->setPostProcessingEnabled(true);

// Disable all post-processing
view->setPostProcessingEnabled(false);
Disabling post-processing forgoes color correctness and some anti-aliasing. Only disable for debugging, UI overlays, or custom render targets.

Bloom

Bloom simulates light bleeding from bright areas, creating a glow effect around highlights.

Basic Bloom Setup

BloomOptions bloom;
bloom.enabled = true;
bloom.strength = 0.10f;      // Bloom intensity (0-1)
bloom.resolution = 384;      // Vertical resolution
bloom.levels = 6;            // Blur cascade levels (1-11)
bloom.threshold = true;      // Threshold bright areas
bloom.highlight = 1000.0f;   // Clamp highlights before bloom

view->setBloomOptions(bloom);

Advanced Bloom Configuration

BloomOptions bloom;
bloom.enabled = true;
bloom.strength = 0.15f;
bloom.resolution = 512;
bloom.levels = 8;
bloom.blendMode = BloomOptions::BlendMode::ADD;  // or INTERPOLATE
bloom.threshold = true;
bloom.highlight = 1000.0f;
bloom.quality = QualityLevel::HIGH;

// Lens artifacts
bloom.lensFlare = true;
bloom.starburst = true;
bloom.chromaticAberration = 0.005f;
bloom.ghostCount = 4;
bloom.ghostSpacing = 0.6f;
bloom.ghostThreshold = 10.0f;
bloom.haloThickness = 0.1f;
bloom.haloRadius = 0.4f;
bloom.haloThreshold = 10.0f;

// Dirt/smudge texture
bloom.dirt = dirtTexture;       // RGB texture
bloom.dirtStrength = 0.2f;

view->setBloomOptions(bloom);

Bloom Parameters

  • strength: Amount of bloom added (0-1)
  • resolution: Vertical axis resolution (2^levels to 4096)
  • levels: Number of blur cascades (1-11, affects spread)
  • blendMode:
    • ADD: Modulated by strength and added to scene
    • INTERPOLATE: Interpolated with scene using strength
  • threshold: Apply 1.0 threshold to source (required for dirt texture)
  • highlight: Limit bright values before bloom (10+)
  • quality:
    • LOW: Optimized downsampling (default, may artifact with dynamic resolution)
    • MEDIUM: Balanced quality/performance
    • HIGH: Auto-increased resolution, better anamorphic bloom

Lens Flare Effects

bloom.lensFlare = true;              // Enable lens flare
bloom.starburst = true;              // Starburst pattern
bloom.chromaticAberration = 0.005f;  // Color separation
bloom.ghostCount = 4;                // Number of flare ghosts
bloom.ghostSpacing = 0.6f;           // Ghost spacing (0-1)
bloom.ghostThreshold = 10.0f;        // HDR threshold for ghosts
bloom.haloThickness = 0.1f;          // Halo thickness in screen units
bloom.haloRadius = 0.4f;             // Halo radius (0-0.5)
bloom.haloThreshold = 10.0f;         // HDR threshold for halo

Depth of Field

Depth of field simulates camera focus, blurring objects outside the focal plane.

Basic DOF Setup

// Set camera focus distance
camera->setFocusDistance(5.0f);  // Focus at 5 meters

// Configure DOF
DepthOfFieldOptions dof;
dof.enabled = true;
dof.cocScale = 1.0f;            // Circle of confusion scale
dof.maxApertureDiameter = 0.01f; // 1cm aperture

view->setDepthOfFieldOptions(dof);

Advanced DOF Configuration

DepthOfFieldOptions dof;
dof.enabled = true;
dof.cocScale = 1.5f;             // Increase blur amount
dof.cocAspectRatio = 1.0f;       // Circular bokeh (>1 for anamorphic)
dof.maxApertureDiameter = 0.015f; // 1.5cm aperture
dof.filter = DepthOfFieldOptions::Filter::MEDIAN;
dof.nativeResolution = false;    // Process at lower res (faster)

// Quality settings (ring count affects samples: (ringCount*2-1)^2)
dof.foregroundRingCount = 5;     // Foreground: 81 samples (9x9)
dof.backgroundRingCount = 5;     // Background: 81 samples
dof.fastGatherRingCount = 4;     // Fast tiles: 49 samples (7x7)

// Max circle of confusion
dof.maxForegroundCOC = 32;       // Max foreground blur (0-32)
dof.maxBackgroundCOC = 32;       // Max background blur (0-32)

view->setDepthOfFieldOptions(dof);

// Update camera focus
camera->setFocusDistance(3.5f);

DOF Parameters

  • cocScale: Multiplier for blur amount (artistic control)
  • cocAspectRatio: Width/height ratio of bokeh (1.0 = circular)
  • maxApertureDiameter: Maximum aperture in meters
  • filter: Gap-filling filter (NONE, MEDIAN)
  • nativeResolution: Process at full resolution (higher quality, slower)
  • ringCount: Sample count per pixel
    • 3 rings = 25 samples (5x5)
    • 5 rings = 81 samples (9x9)
    • 17 rings = 1089 samples (33x33)
    • 0 = use default (5 desktop, 3 mobile)
Fast tiles are regions where all pixels have similar circle-of-confusion. Lower ring count for fast tiles improves performance with minimal quality loss.

Tone Mapping & Color Grading

Tone mapping converts HDR values to displayable LDR range. Color grading applies artistic color adjustments.

Color Grading Setup

// Create color grading
ColorGrading* colorGrading = ColorGrading::Builder()
    .toneMapping(ColorGrading::ToneMapping::ACES_LEGACY)
    .exposure(0.0f)
    .nightAdaptation(0.5f)
    .build(*engine);

view->setColorGrading(colorGrading);

Tone Mapping Operators

Filament supports multiple tone mapping operators:
  • LINEAR: No tone mapping (linear output)
  • ACES_LEGACY: Legacy ACES filmic (default)
  • ACES: Updated ACES filmic
  • FILMIC: Custom filmic curve
  • GENERIC: Generic tone mapper
  • DISPLAY_RANGE: Clamp to display range

Advanced Color Grading

ColorGrading* grading = ColorGrading::Builder()
    .toneMapping(ColorGrading::ToneMapping::ACES)
    .exposure(0.5f)              // Exposure compensation
    .nightAdaptation(0.5f)       // Night adaptation (0-1)
    .whiteBalance(6500.0f, 0.0f) // Temperature (K) and tint
    .channelMixer({              // RGB channel mixing
        1.0f, 0.0f, 0.0f,        // Red channel
        0.0f, 1.0f, 0.0f,        // Green channel  
        0.0f, 0.0f, 1.0f         // Blue channel
    })
    .shadowsMidtonesHighlights(  // SMH adjustments
        {1.0f, 1.0f, 1.0f, 0.0f}, // Shadows
        {1.0f, 1.0f, 1.0f, 0.0f}, // Midtones
        {1.0f, 1.0f, 1.0f, 0.0f}, // Highlights
        {0.0f, 0.5f, 1.0f, 1.0f}  // Ranges
    )
    .slopeOffsetPower(           // ASC CDL
        {1.0f, 1.0f, 1.0f},      // Slope
        {0.0f, 0.0f, 0.0f},      // Offset
        {1.0f, 1.0f, 1.0f}       // Power
    )
    .contrast(1.0f)              // Contrast (0.5-2.0)
    .vibrance(1.0f)              // Vibrance (0-2)
    .saturation(1.0f)            // Saturation (0-2)
    .curves({1.0f, 0.0f, 0.0f},  // Curve adjustments
            {0.0f, 1.0f, 0.0f},
            {0.0f, 0.0f, 1.0f})
    .build(*engine);

view->setColorGrading(grading);

Anti-Aliasing

Filament supports multiple anti-aliasing techniques that can be combined.

FXAA (Fast Approximate)

// Enable FXAA (default)
view->setAntiAliasing(AntiAliasing::FXAA);

// Disable post-process AA
view->setAntiAliasing(AntiAliasing::NONE);

MSAA (Multi-Sample)

MultiSampleAntiAliasingOptions msaa;
msaa.enabled = true;
msaa.sampleCount = 4;        // Sample count (1, 2, 4, 8)
msaa.customResolve = true;   // Better HDR quality

view->setMultiSampleAntiAliasingOptions(msaa);

TAA (Temporal)

TemporalAntiAliasingOptions taa;
taa.enabled = true;
taa.feedback = 0.12f;        // History feedback (0-1)
taa.filterWidth = 1.0f;      // Filter width
taa.lodBias = -1.0f;         // Texture LOD bias
taa.upscaling = 1.0f;        // Upscaling factor (disables dynamic res)
taa.sharpness = 0.0f;        // Post-TAA sharpening

// Advanced options
taa.jitterPattern = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16;
taa.boxType = TemporalAntiAliasingOptions::BoxType::AABB;
taa.boxClipping = TemporalAntiAliasingOptions::BoxClipping::ACCURATE;
taa.preventFlickering = false;
taa.filterHistory = true;
taa.filterInput = true;
taa.useYCoCg = false;
taa.hdr = true;

view->setTemporalAntiAliasingOptions(taa);
TAA Jitter Patterns:
  • RGSS_X4: 4-sample rotated grid
  • UNIFORM_HELIX_X4: 4-sample uniform helix
  • HALTON_23_X8: 8-sample Halton sequence
  • HALTON_23_X16: 16-sample Halton (default)
  • HALTON_23_X32: 32-sample Halton

Vignette

Vignette darkens the corners of the image:
VignetteOptions vignette;
vignette.enabled = true;
vignette.midPoint = 0.5f;    // Corner restriction (0-1)
vignette.roundness = 0.5f;   // Shape: 0=rect, 0.5=oval, 1=circle
vignette.feather = 0.5f;     // Edge softness (0-1)
vignette.color = {0.0f, 0.0f, 0.0f, 1.0f}; // Vignette color

view->setVignetteOptions(vignette);

Dithering

Dithering reduces color banding:
// Temporal dithering (default, reduces banding)
view->setDithering(Dithering::TEMPORAL);

// Disable dithering
view->setDithering(Dithering::NONE);

Ambient Occlusion

Screen-space ambient occlusion adds contact shadows:
AmbientOcclusionOptions ao;
ao.enabled = true;
ao.aoType = AmbientOcclusionOptions::AmbientOcclusionType::GTAO;
ao.radius = 0.3f;            // AO radius in meters
ao.power = 1.0f;             // Contrast
ao.bias = 0.0005f;           // Self-occlusion bias
ao.resolution = 0.5f;        // Buffer scale (0.5 or 1.0)
ao.intensity = 1.0f;         // Effect strength
ao.quality = QualityLevel::MEDIUM;
ao.lowPassFilter = QualityLevel::HIGH;  // Smoothness
ao.upsampling = QualityLevel::LOW;
ao.bentNormals = true;       // Specular AO

view->setAmbientOcclusionOptions(ao);
AO Types:
  • SAO: Scalable Ambient Occlusion
  • GTAO: Ground Truth-Based Ambient Occlusion (recommended)

Dynamic Resolution

Dynamic resolution adjusts rendering resolution for target framerate:
DynamicResolutionOptions dynRes;
dynRes.enabled = true;
dynRes.minScale = {0.5f, 0.5f};      // Minimum scale
dynRes.maxScale = {1.0f, 1.0f};      // Maximum scale  
dynRes.quality = QualityLevel::HIGH;  // Upscaling quality
dynRes.sharpness = 0.9f;              // Sharpness (0-1)
dynRes.homogeneousScaling = false;    // Force uniform scaling

view->setDynamicResolutionOptions(dynRes);
Upscaling Quality:
  • LOW: Bilinear (fastest)
  • MEDIUM: Qualcomm SGSR 1.0
  • HIGH: AMD FSR1 with mobile optimizations
  • ULTRA: AMD FSR1 full quality

Fog

Large-scale atmospheric fog:
FogOptions fog;
fog.enabled = true;
fog.distance = 10.0f;        // Fog start distance (m)
fog.cutOffDistance = INFINITY; // Far cutoff
fog.maximumOpacity = 1.0f;   // Max opacity
fog.height = 0.0f;           // Sea level (m)
fog.heightFalloff = 1.0f;    // Altitude dissipation (1/m)
fog.color = {0.5f, 0.6f, 0.7f}; // Fog color
fog.density = 0.1f;          // Extinction factor
fog.inScatteringStart = 0.0f;
fog.inScatteringSize = 10.0f; // Sun scattering size
fog.fogColorFromIbl = false; // Sample color from IBL

view->setFogOptions(fog);

Example: Cinematic Post-Processing

// Bloom
BloomOptions bloom;
bloom.enabled = true;
bloom.strength = 0.2f;
bloom.resolution = 512;
bloom.levels = 8;
bloom.quality = QualityLevel::HIGH;
bloom.lensFlare = true;
view->setBloomOptions(bloom);

// Depth of Field
DepthOfFieldOptions dof;
dof.enabled = true;
dof.cocScale = 1.2f;
dof.maxApertureDiameter = 0.02f;
dof.foregroundRingCount = 5;
dof.backgroundRingCount = 5;
view->setDepthOfFieldOptions(dof);
camera->setFocusDistance(4.0f);

// Color Grading
ColorGrading* grading = ColorGrading::Builder()
    .toneMapping(ColorGrading::ToneMapping::ACES)
    .exposure(0.25f)
    .contrast(1.1f)
    .saturation(1.05f)
    .build(*engine);
view->setColorGrading(grading);

// TAA
TemporalAntiAliasingOptions taa;
taa.enabled = true;
taa.feedback = 0.12f;
taa.sharpness = 0.2f;
view->setTemporalAntiAliasingOptions(taa);

// Vignette
VignetteOptions vignette;
vignette.enabled = true;
vignette.midPoint = 0.4f;
vignette.feather = 0.6f;
view->setVignetteOptions(vignette);

Next Steps

Cameras

Configure camera projection and exposure

IBL

Set up image-based lighting

Build docs developers (and LLMs) love