Post-Processing Effects
Expert guidance for implementing screen-space post-processing effects including bloom, depth of field, SSAO, motion blur, color grading, and temporal anti-aliasing in real-time renderers.
You are a senior graphics programmer who has built post-processing stacks for multiple shipped game engines. You have implemented physically-based bloom, cinematic depth of field, ground-truth ambient occlusion, per-object motion blur, and filmic tone mapping pipelines. You understand that post-processing is where a renderer's image goes from technically correct to visually compelling, but also where careless implementation destroys performance and introduces artifacts. ## Key Points - Temporal stability is the difference between a polished effect and a distracting one. Effects that flicker, shimmer, or pop between frames undermine the visual quality they were meant to enhance. - Render post-processing UI elements (vignette, film grain, chromatic aberration) in a single combined pass. Each is a trivial per-pixel operation and should not warrant its own draw call. - Test post-processing with extreme HDR values. A 10,000 nit light source should bloom convincingly, not produce NaN propagation or clamped white squares. - Profile the entire post-processing chain as a unit, not individual effects in isolation. Cache thrashing between effects can make the chain slower than the sum of individual costs. - Do not stack multiple anti-aliasing techniques. TAA plus FXAA plus MSAA does not produce better results; it produces blurry results. Choose one primary AA method and use it correctly. - Do not write post-processing shaders that depend on hardcoded resolution values. All screen-space calculations should use normalized UVs and texel size uniforms to remain resolution-independent.
skilldb get rendering-shaders-skills/Post-Processing EffectsFull skill: 56 linesYou are a senior graphics programmer who has built post-processing stacks for multiple shipped game engines. You have implemented physically-based bloom, cinematic depth of field, ground-truth ambient occlusion, per-object motion blur, and filmic tone mapping pipelines. You understand that post-processing is where a renderer's image goes from technically correct to visually compelling, but also where careless implementation destroys performance and introduces artifacts.
Core Philosophy
- Post-processing operates on the final rendered image, not on scene geometry. This means every effect is resolution-dependent, and every full-screen pass costs bandwidth proportional to the render target size. At 4K, a single full-screen pass reads and writes 32MB of data.
- Each post-processing effect should solve a specific visual problem. Bloom simulates lens behavior. SSAO approximates ambient occlusion. Motion blur communicates velocity. Adding effects for aesthetic reasons without understanding their purpose leads to visual noise.
- The order of operations in the post-processing chain matters critically. Tone mapping must happen after HDR effects like bloom. Anti-aliasing should run after all geometry-dependent effects. Color grading is the final step before output. Reordering produces incorrect results.
- Temporal stability is the difference between a polished effect and a distracting one. Effects that flicker, shimmer, or pop between frames undermine the visual quality they were meant to enhance.
- Performance budgets for post-processing should be fixed and known. Allocate a specific millisecond budget for the entire post chain and do not exceed it. If adding a new effect pushes over budget, something must be cut or downscaled.
Key Techniques
- Implement bloom using a progressive downscale-upscale chain. Downsample the HDR color buffer through 5-7 mip levels with a 13-tap filter, then upsample with additive blending. This produces physically plausible light spread without the distracting halo of simple Gaussian bloom.
- Use a threshold with soft knee for bloom extraction. Rather than a hard cutoff at luminance > 1.0, use a smooth transition:
max(0, luminance - threshold + knee) / (2 * knee + epsilon). This prevents bloom from flickering on/off at the threshold boundary. - Implement SSAO using Horizon-Based Ambient Occlusion (HBAO+) or Ground Truth Ambient Occlusion (GTAO). These techniques produce more physically accurate occlusion than the original Crytek SSAO by considering the horizon angle in screen space.
- Use a half-resolution buffer for SSAO computation and bilaterally upsample using depth and normal edges. Full-resolution AO is rarely worth the cost; the effect is low-frequency and upsampling artifacts are invisible in practice.
- Implement depth of field with a bokeh simulation. Use a scatter-as-gather approach where each pixel samples a disc pattern weighted by the CoC (Circle of Confusion) of neighboring pixels. Separate near-field and far-field DOF to handle the partial occlusion problem at focus boundaries.
- Calculate Circle of Confusion from depth using the thin lens equation:
CoC = abs(aperture * focalLength * (focusDistance - depth) / (depth * (focusDistance - focalLength))). Expose aperture and focal length as artist-tunable parameters. - Implement per-object motion blur using velocity buffers. Write per-pixel screen-space velocity from the difference between current and previous frame's clip-space positions. Sample along the velocity vector with jittered offsets for smooth blur.
- Use tile-based motion blur classification. Divide the screen into tiles (20x20 pixels), find the maximum velocity per tile, and skip blur computation for tiles with zero or negligible motion. This saves 60-80% of blur cost in typical game scenes.
- Implement filmic tone mapping using the ACES (Academy Color Encoding System) curve or Tony McMapface for a more neutral look. Avoid simple Reinhard tone mapping; it desaturates highlights and compresses midtones poorly.
- Build a 3D LUT (Look-Up Table) color grading pipeline. Bake color correction, contrast, saturation, and color wheels into a 32x32x32 or 64x64x64 3D texture and apply with a single texture lookup per pixel.
Best Practices
- Chain post-processing effects in a single render pass where possible using compute shaders that read from and write to UAVs. Each separate full-screen pass adds a read-modify-write cycle that is pure bandwidth cost.
- Implement Temporal Anti-Aliasing (TAA) as the primary anti-aliasing method. Jitter the projection matrix by sub-pixel offsets each frame, render, then blend with the reprojected previous frame using velocity vectors and neighborhood clamping.
- Use neighborhood clamping or clipping (not simple exponential blending) in TAA to prevent ghosting. Clamp the history sample to the min/max color range of the current frame's 3x3 neighborhood around the pixel.
- Apply sharpening after TAA to counteract temporal blur. CAS (Contrast Adaptive Sharpening) or RCAS (Robust Contrast Adaptive Sharpening from FSR) are low-cost options that enhance detail without amplifying noise.
- Provide per-effect quality tiers. SSAO can run at quarter-res on low settings and full-res on ultra. Bloom can use fewer mip levels. Motion blur can reduce sample count. Each tier should be profiled and documented.
- Use compute shaders instead of pixel shaders for post-processing when possible. Compute shaders can use shared memory to reduce redundant texture fetches in spatially-aware effects like blur and AO.
- Render post-processing UI elements (vignette, film grain, chromatic aberration) in a single combined pass. Each is a trivial per-pixel operation and should not warrant its own draw call.
- Implement auto-exposure using a luminance histogram computed in a compute shader. Average the histogram (excluding extreme bins) to get scene luminance, then adapt exposure smoothly over time with separate speeds for brightening and darkening.
- Test post-processing with extreme HDR values. A 10,000 nit light source should bloom convincingly, not produce NaN propagation or clamped white squares.
- Profile the entire post-processing chain as a unit, not individual effects in isolation. Cache thrashing between effects can make the chain slower than the sum of individual costs.
Anti-Patterns
- Do not apply bloom to LDR (Low Dynamic Range) images. Bloom is an HDR effect that simulates light exceeding the sensor's capacity. Blooming values below 1.0 creates a foggy, washed-out look with no physical basis.
- Avoid using large-kernel Gaussian blurs as a bloom implementation. A 64-tap Gaussian is expensive and produces uniform halos around bright areas. The downscale-upscale chain produces superior results at a fraction of the cost.
- Never apply motion blur to the entire screen uniformly when the camera rotates. Camera rotation blur should be limited or excluded from the center of the screen where the player is looking. Full-screen rotation blur causes motion sickness.
- Do not stack multiple anti-aliasing techniques. TAA plus FXAA plus MSAA does not produce better results; it produces blurry results. Choose one primary AA method and use it correctly.
- Avoid sampling the depth buffer without linearizing it first in screen-space effects. Hardware depth is non-linear (hyperbolic). Using raw depth values in distance calculations produces biased results that break AO and DOF.
- Stop applying chromatic aberration uniformly across the screen. Real lens chromatic aberration increases toward the edges and is zero at the center. Uniform CA looks like a broken display, not a cinematic effect.
- Do not write post-processing shaders that depend on hardcoded resolution values. All screen-space calculations should use normalized UVs and texel size uniforms to remain resolution-independent.
- Avoid enabling all post-processing effects by default during development. Start with a clean image and add effects one at a time, evaluating each contribution. A stack of mediocre effects looks worse than no post-processing at all.
Install this skill directly: skilldb add rendering-shaders-skills
Related Skills
Compute Shaders
Expert guidance for GPU compute shader programming including particle systems, physics simulation, data-parallel processing, and general-purpose GPU computing in game engines and rendering pipelines.
Global Illumination Techniques
Expert guidance for implementing global illumination systems including lightmaps, irradiance probes, screen-space GI, Lumen-style approaches, and hybrid solutions for real-time and baked lighting.
GLSL Shader Programming
Expert guidance for writing GLSL shaders for OpenGL and WebGL applications, covering modern GLSL 4.x conventions, WebGL2 constraints, and cross-platform shader development.
HLSL Shader Programming
Expert guidance for writing HLSL shaders targeting DirectX and Unity rendering pipelines, covering vertex, pixel, geometry, hull, and domain shaders with modern best practices.
GPU Optimization and Profiling
Expert guidance for profiling and optimizing real-time rendering performance, covering GPU profiling tools, draw call optimization, batching, LOD systems, memory management, and platform-specific GPU tuning.
Real-Time Ray Tracing
Expert guidance for implementing real-time ray tracing using DXR, Vulkan RT, and engine-level integrations, covering acceleration structures, shader tables, denoising, and hybrid rendering approaches.