Skip to content

Post Processing

Cody Glassman requested to merge into master


This MR implements a fully programmable post processing pipeline using Techniques and Passes.

  • Technique at high level equates to an array of passes with some metadata like author, version, and description.
  • A pass is simply a invocation of a compute or pixel-vertex shader. Commonly a pass is in charge of performing post-processing on the input image.

Passes have access to the last pass of the previous technique, and the immediate lass pass, both of which are core to creating many popular effects. This allows for so-called chaining.

I've also added a transparent post-pass, which is a necassary step to accumulate a post-process friendly depth buffer. During this pass, transparent objects populate the resolved depth buffer from the opaque pass with color writes disabled and a minimum alpha clipping threshold.

Let A1, A2, A3 represent these 3 attachments (could be FBO or glDrawBuffer calls). This would be the high level rendering process with 2 techniques of 3 passes each and MSAA enabled.

  1. Draw opaque objects into multisample FBO
  2. Resolve depth into resolve FBO (also used for soft particles)
  3. Draw transparent objects into multisample FBO
  4. Draw transparent objects again into resolve FBO with special clipping shaders and color writes disabled
  5. Resolve color into resolve FBO
  6. Lock A1
  7. Draw Technique 1 Pass 1 to A2
  8. Draw Technique 1 pass 2 to A3
  9. Draw Technique 1 pass 3 to A2
  10. Lock A2
  11. Draw Technique 2 Pass 1 to A1
  12. Draw Technique 2 Pass 2 to A3
  13. Draw Technique 2 Pass 3 to back buffer
  14. Draw GUI to backbuffer
  15. Have final post-processed image with unaffected GUI

Persistent Storage

Every technique has the ability to define a small subset of uniform types as configurable options. These are defined in the .omwfx file and settings automatically populate the F2 menu with widgets. These settings are simply stored in a shaders.yaml file that lives with the openmw.cfg.

A note, with config mode enabled through F2 menu, the configuration variables are treated as actual unfiforms, otherwise you'd need to re-compile the shaders every time a value changed, which would suck. When disabled, the variables are treated as constant in shaders. Toggling between debug mode will have a slight delay because of this, as the active techniques need to be recompiled.


To install a shader, you simply drop it into the root of a shaders/ directory in any data files folder with a .omwfx extension. Live reload is enabled automatically, meaning changes to a file will automatically reload the shader in-game. This is used for writing shaders and is a debug mode. Any custom added shaders will show up the in-game configuration toggled with F2. Currently a combination of arrow keys + Shift let you control order/enabling/disabling in the two lists.

[Post Processing]

# Enables post-processing 
enabled = false

# List of active shaders. This is more easily with the in-game shader HUD, by default accessible with the F2 key.
chain =

# Reload active shaders when modified on local filesystem. This is a DEBUG mode, and should be disabled in normal gameplay.
live reload = false

# Used for eye adaption to control speed at which scene luminance can change from one frame to the next. No effect when HDR is not being utilized.
hdr exposure time = 0.1

# Transparent depth postpass. Re-renders transparent objects with alpha-clipping forced with a fixed threshold.
transparent postpass = true

What's been done

  • Hot reload
  • In-Game interface for controlling technique settings and persistent storage
  • omwfx format
  • post-process friendly depth buffer with blended objects. This will require alpha-testing using diffuse texture in a special pass, similar to how shadows deal with this issue.
  • Lua interface for toggling shaders and controlling uniforms
Edited by Cody Glassman

Merge request reports