-
Notifications
You must be signed in to change notification settings - Fork 1
Post Processing
SparkEngine provides a configurable post-processing pipeline that chains 14 screen-space effects in a fixed order. Each effect is a self-contained pass with its own settings struct, enable/disable state, and per-pass performance metrics. The pipeline manages render target ping-ponging between passes automatically using two R16G16B16A16_FLOAT textures, and integrates with the editor through the PostProcessingPanel.
Source Files:
-
SparkEngine/Source/Graphics/PostProcessingPipeline.h-- Pipeline class (pass orchestration, render target management) -
SparkEngine/Source/Graphics/PostProcessingPipeline.cpp-- Pipeline implementation -
SparkEngine/Source/Graphics/PostProcessingTypes.h-- All settings structs, enums, and metric types -
SparkEngine/Source/Graphics/PostProcessingEffects.h-- Backward-compatibility re-export of types -
SparkEditor/Source/Panels/PostProcessingPanel.h-- Editor panel for post-processing settings
All enabled passes execute in the fixed order defined by the PostProcessPass enum. Disabled passes are skipped with zero cost. Between each pass, the pipeline swaps source and destination render targets (ping-pong).
Scene Color (HDR input)
|
v
+------+------+------+------+------+------+------+------+------+------+------+------+------+------+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 |11 |12 |13 |14 |
|Bloom |Auto |Tone |Color |FXAA |Depth |Motion|Vign- |Chrom.|Film |Lens |Light |Lens |Sharp-|
| |Expos.|map |Grade | |OfFld |Blur |ette |Aberr.|Grain |Dist. |Shaft |Flare |en |
+------+------+------+------+------+------+------+------+------+------+------+------+------+------+
|
v
Final Output (LDR)
| # | Pass | Category | Description |
|---|---|---|---|
| 1 | Bloom | HDR | Bright pixel extraction + multi-pass blur + composite |
| 2 | AutoExposure | HDR | Luminance histogram eye adaptation |
| 3 | Tonemapping | HDR | HDR-to-LDR conversion (ACES, Filmic, Neutral, Reinhard) |
| 4 | ColorGrading | Color | Lift/Gamma/Gain, temperature, tint, hue shift |
| 5 | FXAA | Anti-Aliasing | Fast Approximate Anti-Aliasing |
| 6 | DepthOfField | Lens | Bokeh blur based on focal distance and aperture |
| 7 | MotionBlur | Temporal | Per-pixel velocity-based blur |
| 8 | Vignette | Lens | Screen-edge darkening |
| 9 | ChromaticAberration | Lens | RGB channel separation at edges |
| 10 | FilmGrain | Cinematic | Animated noise overlay |
| 11 | LensDistortion | Lens | Barrel/pincushion distortion |
| 12 | LightShafts | Volumetric | God rays from bright light sources |
| 13 | LensFlare | Lens | Ghost images and halo from bright sources |
| 14 | Sharpen | Output | Contrast-adaptive sharpening (CAS) |
The pipeline allocates two R16G16B16A16_FLOAT textures at the viewport resolution. Each pass reads from one texture and writes to the other. The SwapTargets() call alternates which texture is source and which is destination. On viewport resize, Resize() recreates both targets.
Extracts bright pixels above a luminance threshold, applies multi-pass Gaussian blur, and composites the result back. Supports a soft knee around the threshold for smooth falloff.
| Setting | Type | Default | Description |
|---|---|---|---|
threshold |
float | 1.0 | Luminance cutoff for bright pixel extraction |
softThreshold |
float | 0.5 | Soft knee width around threshold [0, 1] |
intensity |
float | 0.8 | Final bloom composite strength |
radius |
float | 4.0 | Blur radius in texels |
iterations |
int | 5 | Downscale/blur passes [1, 8] |
scatter |
float | 0.7 | Energy scatter between blur passes [0, 1] |
highQuality |
bool | true | 13-tap dual filter (true) vs 5-tap (false) |
Measures scene luminance via a histogram and smoothly adapts exposure over time, simulating human eye adaptation between bright and dark environments.
| Setting | Type | Default | Description |
|---|---|---|---|
minExposure |
float | 0.25 | Minimum EV (prevents over-darkening) |
maxExposure |
float | 4.0 | Maximum EV (prevents over-brightening) |
adaptSpeedUp |
float | 2.0 | Bright-to-dark adaptation speed (EV/s) |
adaptSpeedDown |
float | 1.0 | Dark-to-bright adaptation speed (EV/s) |
targetLuminance |
float | 0.18 | Middle-grey key value |
histogramMin |
float | -8.0 | Log2 luminance histogram lower bound |
histogramMax |
float | 4.0 | Log2 luminance histogram upper bound |
compensationEV |
float | 0.0 | Manual EV compensation offset |
Converts the HDR scene to LDR display range. Four tonemapping operators are available via the TonemapOperator enum:
| Operator | Description |
|---|---|
ACES |
Academy Color Encoding System -- filmic, industry standard (default) |
Filmic |
Uncharted 2 filmic curve (John Hable) |
Neutral |
Minimal color shift, balanced contrast |
Reinhard |
Simple luminance-based Reinhard |
| Setting | Type | Default | Description |
|---|---|---|---|
op |
TonemapOperator | ACES | Active tonemapping operator |
exposure |
float | 1.0 | Pre-tonemap exposure multiplier |
whitePoint |
float | 11.2 | White point for Filmic/Reinhard |
contrast |
float | 1.0 | Post-tonemap contrast [0.5, 2.0] |
saturation |
float | 1.0 | Post-tonemap saturation [0, 2] |
Professional color correction using Lift/Gamma/Gain (shadows/midtones/highlights) plus global adjustments for temperature, tint, hue, saturation, brightness, and contrast.
| Setting | Type | Default | Description |
|---|---|---|---|
lift |
XMFLOAT3 | (0, 0, 0) | Shadow color offset |
gamma |
XMFLOAT3 | (1, 1, 1) | Midtone power curve |
gain |
XMFLOAT3 | (1, 1, 1) | Highlight multiplier |
temperature |
float | 0.0 | White balance [-1=cool, 1=warm] |
tint |
float | 0.0 | Green-magenta shift [-1, 1] |
hueShift |
float | 0.0 | Global hue rotation in degrees [-180, 180] |
saturation |
float | 1.0 | Global saturation [0=mono, 2=oversaturated] |
brightness |
float | 0.0 | Global brightness offset [-1, 1] |
contrast |
float | 1.0 | Global contrast [0.5, 2.0] |
Fast Approximate Anti-Aliasing -- a single-pass post-process AA that smooths jagged edges based on luminance contrast. Lightweight alternative to MSAA with no geometry cost.
| Setting | Type | Default | Description |
|---|---|---|---|
edgeThreshold |
float | 0.166 | Minimum luminance edge detection [0.063, 0.333] |
edgeThresholdMin |
float | 0.0833 | Darkest edge threshold |
subpixelQuality |
float | 0.75 | Sub-pixel AA quality [0=off, 1=max] |
qualityPreset |
int | 12 | Quality iterations [10=low, 29=ultra] |
Physically-based depth of field with configurable focal plane, aperture, and bokeh shape. Uses the scene depth buffer to compute per-pixel circle of confusion.
| Setting | Type | Default | Description |
|---|---|---|---|
focalDistance |
float | 10.0 | Focus plane distance in meters |
focalLength |
float | 50.0 | Lens focal length in mm |
aperture |
float | 2.8 | F-stop (lower = more blur) |
nearBlurStart / End
|
float | 0.5 / 2.0 | Near blur distance range |
farBlurStart / End
|
float | 20.0 / 100.0 | Far blur distance range |
maxBokehSize |
float | 8.0 | Maximum bokeh diameter in pixels |
blurSamples |
int | 16 | Blur kernel samples |
useCircularBokeh |
bool | true | Circular (true) vs hexagonal (false) |
bokehBrightness |
float | 1.0 | Brightness threshold for bokeh highlights |
Per-pixel motion blur using temporal velocity data. This pass has no dedicated settings struct -- it uses velocity buffer data from the TemporalEffects system.
Darkens screen edges to draw attention to the center. Supports configurable color, center position, and shape.
| Setting | Type | Default | Description |
|---|---|---|---|
intensity |
float | 0.3 | Darkening strength [0, 1] |
smoothness |
float | 0.5 | Edge softness [0, 1] |
roundness |
float | 1.0 | Shape (1=circular, 0=rectangular) |
color |
XMFLOAT3 | (0, 0, 0) | Vignette color (default: black) |
center |
XMFLOAT2 | (0.5, 0.5) | Center in UV space |
Simulates lens imperfection by separating RGB channels, with stronger effect at screen edges.
| Setting | Type | Default | Description |
|---|---|---|---|
intensity |
float | 0.5 | Separation amount [0, 3] |
radialFalloff |
float | 1.0 | Edge emphasis [0=uniform, 2=strong edge] |
channelOffsets |
XMFLOAT3 | (1, 0, -1) | R, G, B offset multipliers |
Animated noise overlay that simulates cinematic film grain. Supports monochrome and colored modes.
| Setting | Type | Default | Description |
|---|---|---|---|
intensity |
float | 0.15 | Grain visibility [0, 1] |
size |
float | 1.6 | Grain particle size |
speed |
float | 1.0 | Animation speed |
luminanceContribution |
float | 0.8 | Luminance influence on grain [0, 1] |
colored |
bool | false | Color noise (true) vs monochrome (false) |
Barrel or pincushion distortion simulating real lens imperfections.
| Setting | Type | Default | Description |
|---|---|---|---|
barrelDistortion |
float | 0.0 | [-1=pincushion, 1=barrel] |
zoomCompensation |
float | 1.0 | Zoom to compensate for distortion |
center |
XMFLOAT2 | (0.5, 0.5) | Distortion center in UV space |
cubicDistortion |
float | 0.0 | Higher-order distortion term |
Screen-space god rays via radial blur from a light source position. Uses ray marching with configurable density and decay.
| Setting | Type | Default | Description |
|---|---|---|---|
lightScreenPos |
XMFLOAT2 | (0.5, 0.3) | Light source screen position |
density |
float | 1.0 | Ray density [0, 1] |
weight |
float | 0.01 | Intensity per sample |
decay |
float | 0.97 | Intensity decay per step [0, 1] |
exposure |
float | 1.0 | Final exposure multiplier |
sampleCount |
int | 64 | Ray marching samples |
color |
XMFLOAT3 | (1.0, 0.95, 0.8) | Shaft color |
Generates ghost images and halo rings from bright light sources in the scene.
| Setting | Type | Default | Description |
|---|---|---|---|
threshold |
float | 0.8 | Brightness threshold for flare trigger |
intensity |
float | 0.5 | Flare overall intensity |
ghostCount |
int | 5 | Number of ghost images |
ghostSpacing |
float | 0.3 | Distance between ghosts |
ghostThreshold |
float | 10.0 | Brightness for ghost generation |
haloRadius |
float | 0.6 | Halo ring radius |
haloThickness |
float | 0.1 | Halo ring width |
chromaticDistortion |
float | 2.5 | Color separation in flare |
Contrast-adaptive sharpening inspired by AMD FidelityFX CAS. Applied last in the chain to counteract any softening from earlier passes.
| Setting | Type | Default | Description |
|---|---|---|---|
amount |
float | 0.5 | Sharpening strength [0, 1] |
threshold |
float | 0.05 | Edge threshold (avoids noise amplification) |
adaptiveSharpening |
bool | true | CAS mode (AMD FidelityFX style) |
#include "Graphics/PostProcessingPipeline.h"
using namespace Spark::Graphics;
// Create and initialize the pipeline
PostProcessingPipeline pipeline;
pipeline.SetDevice(device, context);
pipeline.Initialize(1920, 1080);
// Enable and configure bloom
pipeline.SetEffectEnabled(PostProcessPass::Bloom, true);
pipeline.GetBloomSettings().threshold = 0.9f;
pipeline.GetBloomSettings().intensity = 1.0f;
// Enable tonemapping with ACES
pipeline.SetEffectEnabled(PostProcessPass::Tonemapping, true);
pipeline.GetTonemappingSettings().op = TonemapOperator::ACES;
pipeline.GetTonemappingSettings().exposure = 1.2f;
// Enable vignette
pipeline.SetEffectEnabled(PostProcessPass::Vignette, true);
pipeline.GetVignetteSettings().intensity = 0.4f;
// Enable depth of field
pipeline.SetEffectEnabled(PostProcessPass::DepthOfField, true);
pipeline.GetDOFSettings().focalDistance = 15.0f;
pipeline.GetDOFSettings().aperture = 2.8f;
// Each frame, after scene rendering:
pipeline.SetInputSRV(sceneColorSRV);
pipeline.SetDepthSRV(sceneDepthSRV);
pipeline.Process(deltaTime);
pipeline.Render();
// Handle viewport resize
pipeline.Resize(newWidth, newHeight);
// Query per-pass performance
auto metrics = pipeline.GetPassMetrics();
for (const auto& pm : metrics)
{
if (pm.isEnabled)
{
Logger::Info("{}: {:.2f}ms", pm.name, pm.timeMs);
}
}VolumeManager, owned by the pipeline, lets level designers author
global or local volumes that override a subset of the effect settings
— only the fields whose overrideState was set ever touch the live
settings, so hand-authored values survive volume-less frames. Push the
camera position once per frame and Process() blends the stack:
using namespace Spark::Graphics;
auto& volumes = pipeline.GetVolumeManager();
// Author a global fallback — always applies, lowest priority:
if (Volume* global = volumes.CreateVolume("global_defaults"))
{
global->isGlobal = true;
global->priority = 0;
if (auto* ex = global->AddComponent<ExposureVolumeComponent>())
{
ex->compensationEV.value = 0.0f;
ex->compensationEV.overrideState = true;
}
}
// Author a cave volume — overrides bloom + colour grading when the
// camera is inside the AABB, fading in over `blendDistance` metres:
if (Volume* cave = volumes.CreateVolume("cave"))
{
cave->isGlobal = false;
cave->boundsMin = {-40.0f, -5.0f, -40.0f};
cave->boundsMax = { 40.0f, 20.0f, 40.0f};
cave->blendDistance = 3.0f;
cave->priority = 10;
auto* bloom = cave->AddComponent<BloomVolumeComponent>();
bloom->intensity.value = 0.2f;
bloom->intensity.overrideState = true;
auto* grade = cave->AddComponent<ColorGradingVolumeComponent>();
grade->temperature.value = -0.15f;
grade->temperature.overrideState = true;
grade->saturation.value = 0.8f;
grade->saturation.overrideState = true;
}
// Per frame:
pipeline.SetCameraPosition(camera.worldPosition);
pipeline.Process(deltaTime); // runs VolumeManager::Update + ApplyVolumeStackPost-processing console commands are registered in AdvancedConsoleCommands.cpp (FPS game module):
pp_list # List all post-processing effects and their on/off state
exposure <value> # Set light shaft exposure value
hdr <on/off> # Enable/disable HDR rendering
The pp_list command calls PostProcessingPipeline::Console_ListEffects(), which prints each pass name and its enabled/disabled state along with the total active pass count.
Each pass records its GPU execution time in m_passTimings[]. Call GetPassMetrics() to retrieve a vector of PassMetrics structs:
struct PassMetrics
{
std::string name; // Pass name (e.g., "Bloom", "FXAA")
float timeMs = 0.0f; // GPU time in milliseconds
bool isEnabled = false;
};The GetActivePassCount() method returns how many passes were active in the last frame.
The PostProcessingPanel (SparkEditor::PostProcessingPanel) exposes bloom, tonemapping, fog, sky, and wind parameters through ImGui controls. It reads from and writes to the scene's EnvironmentSettings, which are serialized to scene files. The LightingTools panel also provides post-processing controls for tonemapping, exposure, bloom, contrast, saturation, and brightness as part of the lighting preset system.
| File | Description |
|---|---|
SparkEngine/Source/Graphics/PostProcessingPipeline.h |
Pipeline class declaration |
SparkEngine/Source/Graphics/PostProcessingPipeline.cpp |
Pipeline implementation (pass execution, GPU resources) |
SparkEngine/Source/Graphics/PostProcessingTypes.h |
All enums, settings structs, and metric types |
SparkEngine/Source/Graphics/PostProcessingEffects.h |
Backward-compatibility re-export header |
SparkEditor/Source/Panels/PostProcessingPanel.h |
Editor panel declaration |
SparkEditor/Source/Panels/PostProcessingPanel.cpp |
Editor panel ImGui implementation |
SparkEditor/Source/Lighting/LightingTools.cpp |
Lighting preset post-processing integration |
GameModules/SparkGameFPS/Source/Console/AdvancedConsoleCommands.cpp |
Console command registration |
- Rendering and Graphics -- GraphicsEngine and rendering pipeline overview
- Render Graph -- Render graph pass scheduling system
- Shader Pipeline -- Shader compilation and management
- Camera System -- Camera settings affecting depth of field
- Editor Panels -- PostProcessingPanel and other editor UI
Published from 8fd2c5bdc5cd. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Golden Image Testing
- Utilities
- Testing
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers