Checkerboard rendering with Magnum and OpenGL
An implementation of Checkerboard Rendering using Magnum and OpenGL.
Checkerboard rendering is a temporal upsampling technique that reduces shading work with minimal impact on visual quality. Expensive fragment shader operations are run at half-resolution and then combined with the previous frame's output in a resolve shader.
By always shading 2 MSAA samples and jittering the viewport by one pixel in every odd frame, we can combine the current frame's samples A and B with last frame's samples C and D to fill the full-res framebuffer:
even frame: odd frame: combined frame:
(current) (previous) (full-res)
+---+---+ +---+---+ +---+---+
| | A | | | C | | C | A |
+---+---+ + +---+---+ = +---+---+---+
| B | | | D | | | D | B |
+---+---+ +---+---+ +---+---+
While this is trivial for static scenes, complications arise with moving objects/cameras and (dis)occlusion. The resolve step needs to consider per-pixel velocity between frames and detect and handle fragments being occluded.
For a more thorough introduction, check out Intel's white paper.
This implementation is loosely based on the Intel D3D11 forward shading example, while also introducing improvements from several other papers (see References). Here's a rough overview of all the steps:
The reconstruction shader is run for each full-res fragment. It performs the following steps:
There are a few more edge cases and some extra debug output not mentioned here. The full GLSL code can be found in ReconstructionShader.frag.
OpenGL doesn't have a fixed set of MSAA sample positions, but several extensions exist that allow you to manually specify them:
The ARB extension is based on the NV extension and is in practice only supported by Nvidia hardware.
To enable per-sample fragment shader invocations, ARB_sample_shading (or OpenGL 4.0) is required. Setting a MIN_SAMPLE_SHADING_VALUE
of 1.0 causes per-sample fragment evaluation, as well as exact interpolation of input values to the sample position.
Since screen-space derivatives in the fragment shader are calculated at half-res, they have twice the magnitude compared to full-res rendering. This is especially detrimental for texturing since larger UV derivatives cause higher MIP levels and therefore blurriness. To fix this, use textureGrad
with corrected gradients or add a LOD bias of -0.5 to all texture samplers.
CMake (>= 3.4) is required for building.
Clone repository:
git clone --recursive https://github.com/pezcode/mosaiikki.git
cd mosaiikki
Generate project files:
mkdir build
cd build
# e.g. VS 2019, compile for x64 platform
cmake -G "Visual Studio 16 2019" -A x64 ..
cd ..
Build. Open the project files with your IDE/build tool, or use CMake:
cmake --build build/ --parallel --config Release