Skip to content

Add post-processing effects chain#146

Merged
bdero merged 11 commits into
masterfrom
bdero/post-processing
May 25, 2026
Merged

Add post-processing effects chain#146
bdero merged 11 commits into
masterfrom
bdero/post-processing

Conversation

@bdero
Copy link
Copy Markdown
Owner

@bdero bdero commented May 25, 2026

Resolves #47

Implements the post-processing effects chain from #47: a declarative built-in suite plus a user-authored custom-effect path, configured per scene through Scene.postProcess. Everything is off by default.

Screen.Recording.2026-05-24.at.10.22.50.PM.mov

Built-in suite (folded into the resolve pass, except bloom):

  • Bloom (HDR threshold then a downsample/upsample mip chain).
  • Color grading (brightness, contrast, saturation, white balance, lift/gamma/gain).
  • Vignette, chromatic aberration, film grain.

Custom effects:

  • PostEffect wraps a user fragment shader, the post-processing twin of ShaderMaterial. The engine binds the current color as input_color (and a PostFrameInfo block when useFrameInfo is set); the author sets their own uniforms and textures by name. Effects run before or after tone mapping and chain through ping-pong buffers.

The example app gained a shared, collapsible settings sidebar (top-right) that drives every example and the stress tests, with controls for each built-in plus a sample custom wave effect. POST_PROCESSING.md documents the authoring contract (sibling of MATERIALS.md).

Built in six staged commits (engine plus example per stage), each verified on macOS. Rebased onto the OpenGL ES Y-flip rework (#144) and verified right-side-up with effects working on web (WebGL2) and macOS (Metal); the final commit binds the new FlipInfo vertex uniform in the bloom and post-effect passes.

The 0.15.0 CHANGELOG entry is included. The version bump and consumer constraint widening are left for the release step.

bdero added 11 commits May 24, 2026 21:32
Prepare the render graph for the post-processing chain.

- TonemapPass becomes ResolvePass (resolve_pass.dart). It gains grading
  and overlays in later stages.
- kHdrColorBlackboardKey becomes kSceneColorBlackboardKey, the current
  scene-color handle that post passes read and republish.
- Mark the before and after resolve insertion points in Scene.render.

Pure rename plus comment seams. Shaders are untouched, so the output is
pixel-identical.

Toward #47.
The first built-in post-processing effect.

- PostProcessSettings with ColorGradingSettings (brightness, contrast,
  saturation, white balance, lift/gamma/gain), reached through
  Scene.postProcess. Effects default off.
- The tonemap shader becomes the resolve shader
  (flutter_scene_resolve.frag): it applies exposure, then color grading,
  then the tone mapping operator and the display EOTF. Grading is gated by
  a uniform flag, so a disabled grade renders identically to before.
- packResolveInfo packs the ResolveInfo uniform block as a pure,
  unit-tested function.

Toward #47.
Add a collapsible settings sidebar (top-right), shared by every example
and the stress tests, with a collapsible Post-processing section holding
color grading controls.

- ExampleSettings holds the shared config; each example applies it to its
  scene before rendering, so one set of controls drives every scene.
- Move the stress-tests back button and the nav-route car-controls menu to
  the top-left, below the example picker, clear of the new sidebar.
Three more built-in post-processing effects, folded into the single
resolve pass.

- New VignetteSettings, ChromaticAberrationSettings, and FilmGrainSettings
  on PostProcessSettings. All off by default.
- The resolve shader samples with per-channel offsets for chromatic
  aberration, then darkens the edges (vignette) and adds animated noise
  (film grain) after tone mapping. Each is gated by a flag, so the
  disabled path is unchanged.
- ResolveInfo grows to carry the new controls plus a time value for the
  grain. packResolveInfo and its tests cover the new layout.

Toward #47.
Extend the shared post-processing sidebar with collapsible sections for
the three new effects, each with an enable switch and sliders. The shared
settings are copied onto every example's scene as before.
A multi-pass HDR bloom built-in: a soft-knee threshold blurred through a
downsample/upsample mip chain, composited back into the scene color
before tone mapping.

- New BloomPass builds the bloom texture from the HDR scene color with
  three shaders (threshold, 13-tap downsample, tent upsample) and a chain
  of transient mips. Each step is its own full-screen pass, so no compute
  or mipmap generation is needed and it runs on WebGL2.
- New BloomSettings (threshold, intensity, scatter) on PostProcessSettings,
  off by default. Scene.render adds BloomPass only when enabled.
- The resolve shader samples the bloom texture and adds it in HDR before
  exposure. ResolveInfo and packResolveInfo carry the bloom controls.

Toward #47.
A Bloom section with an enable switch and threshold/intensity/scatter
sliders, applied to every example's scene like the other effects.
Lets users author their own post-processing effects as fragment shaders,
the post-processing twin of ShaderMaterial.

- New PostEffect (a fragment shader + insertion point + named uniform and
  texture bindings) and a customEffects list on PostProcessSettings.
- PostEffectPass runs one effect as a full-screen pass; the engine binds
  the current color as input_color and, when useFrameInfo is set, a
  PostFrameInfo block (resolution, texel size, time).
- Scene.render chains the effects: beforeTonemap effects ping-pong on HDR
  buffers and feed bloom and the resolve; afterTonemap effects run on the
  resolved image, the last writing the swapchain. The resolve writes to a
  transient when afterTonemap effects need to chain.
- ShaderUniformBindings factors the name-keyed uniform/texture binding so
  PostEffect packs and binds like ShaderMaterial.

Toward #47.
A user-authored wave-distortion shader (shaders/example_wave.frag) wired
through PostEffect and exposed in the settings sidebar with an enable
switch, an after-tone-mapping toggle, and an amplitude slider. Loaded from
the example shader bundle at startup.
POST_PROCESSING.md, a sibling of MATERIALS.md: the built-in suite via
Scene.postProcess, the custom PostEffect shader-authoring contract
(input_color, the opt-in PostFrameInfo block, named uniforms, the two
insertion points and their output contracts), a worked example, and the
limitations.

The 0.15.0 CHANGELOG entry is prepared release notes; the version bump and
consumer-constraint widening are left for the release step.

Toward #47.
Rebasing onto the OpenGL ES Y-flip work moved the render-to-texture
Y-flip into the full-screen vertex shader, which now requires a FlipInfo
uniform. The resolve pass picked it up in the merge, but the bloom and
custom-effect passes are new files that did not bind it, so their
full-screen geometry would collapse. Bind FlipInfo (backendYFlipSign) in
BloomPass and PostEffectPass, matching the resolve pass.

Toward #47.
@bdero bdero merged commit 58110d3 into master May 25, 2026
2 checks passed
@bdero bdero deleted the bdero/post-processing branch May 25, 2026 06:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add post-processing effects chain.

1 participant