The engine provides a post-processing system through the PostFX namespace. You can enable and configure individual effects, or apply a full preset that sets a curated combination of color grading and SSAO values in a single call.
The simplest way to set up post-effects is to apply one of the built-in presets:
PostFX.apply(.cinematic)That single call configures color grading and SSAO together. No scene wiring or callback setup is needed — it works from anywhere in your game code.
| Preset | Description |
|---|---|
.neutral |
All effects disabled, default values restored |
.cinematic |
Slightly underexposed, desaturated, strong SSAO — moody interior feel |
.highContrast |
Boosted exposure and saturation, punchy SSAO — vivid outdoor scenes |
.softAO |
Subtle color grading, wide-radius soft ambient occlusion |
.archviz |
Bright and airy, clean slightly warm whites, precise SSAO for edge detail — architectural visualization |
Presets can be swapped at any point during gameplay — for example when transitioning between areas:
// Entering a dark dungeon
PostFX.apply(.cinematic)
// Entering a bright outdoor area
PostFX.apply(.highContrast)
// Reset everything to defaults
PostFX.apply(.neutral)If the built-in presets do not fit your scene, create a PostFXPreset directly and apply it:
let sunset = PostFXPreset(
name: "Sunset",
colorGrading: true,
exposure: 0.1,
saturation: 1.3,
temperature: 0.4
)
PostFX.apply(sunset)All parameters have defaults (matching .neutral), so you only need to specify the values you want to change.
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
String |
— | Identifier for the preset |
colorGrading |
Bool |
false |
Enables color grading pass |
exposure |
Float |
0.0 |
EV adjustment (-2.0 to 2.0) |
brightness |
Float |
0.0 |
Additive brightness (-1.0 to 1.0) |
contrast |
Float |
1.0 |
Contrast multiplier (0.5 to 2.0) |
saturation |
Float |
1.0 |
Saturation multiplier (0.0 to 2.0) |
temperature |
Float |
0.0 |
Color temperature (-1.0 cool to +1.0 warm) |
tint |
Float |
0.0 |
Green/magenta tint (-1.0 to 1.0) |
ssao |
Bool |
false |
Enables screen-space ambient occlusion |
ssaoRadius |
Float |
0.5 |
Sample radius in world units (0.1 to 2.0) |
ssaoBias |
Float |
0.025 |
Self-occlusion bias (0.01 to 0.1) |
ssaoIntensity |
Float |
0.0 |
Final SSAO multiplier (0.5 to 2.0) |
For fine-grained control outside of presets, you can enable or disable individual effects:
PostFX.setEnabled(.colorGrading, true)
PostFX.setEnabled(.vignette, true)
PostFX.setEnabled(.chromaticAberration, false)And read their current state:
let isActive = PostFX.isEnabled(.bloom)| Effect | Description |
|---|---|
.colorGrading |
Exposure, brightness, contrast, saturation, temperature, tint |
.colorCorrection |
Lift/gamma/gain per-channel color correction |
.bloomThreshold |
Bright-pass filter for bloom |
.bloomComposite |
Bloom blend pass |
.vignette |
Screen-edge darkening |
.chromaticAberration |
RGB channel fringing |
.depthOfField |
Focus blur |
Each effect exposes its parameters through a shared singleton. Import UntoldEngine and write directly:
// Color grading
ColorGradingParams.shared.exposure = -0.2
ColorGradingParams.shared.contrast = 1.15
ColorGradingParams.shared.saturation = 0.9
ColorGradingParams.shared.temperature = -0.1
// Bloom
BloomThresholdParams.shared.threshold = 0.6
BloomThresholdParams.shared.intensity = 0.8
BloomThresholdParams.shared.enabled = true
// Vignette
VignetteParams.shared.intensity = 0.5
VignetteParams.shared.radius = 0.8
VignetteParams.shared.enabled = true
// SSAO
SSAOParams.shared.radius = 0.8
SSAOParams.shared.intensity = 0.75
SSAOParams.shared.enabled = true