We needed to add temporal antialiasing to our project that could run in WebGL. We based our implementation on the method described in [Emilio López, 2022]
The following table enumerates all external inputs required by TAA.
Name | Format | Notes |
---|---|---|
Color buffer | APPLICATION SPECIFIED (3x FLOAT) | The color buffer of the current frame provided by the application, in linear space. |
The effect uses a number of parameters to control the quality of the effect organized into the HLSL::TemporalAntiAliasingAttribs
structure. The following table lists the parameters and their descriptions.
Name | Notes |
---|---|
Temporal stability factor | The current implementation of TAA uses linear weighting based on the number of accumulated samples for each pixel. However, we can still determine a minimum alpha when blending the current and previous frames. |
Reset accumulation | If this parameter is set to true, the current frame will be written to the current history buffer without interpolation with the previous history buffer. |
Skip rejection | This parameter allows skipping the disocclusion check stage. Disocclusion check can cause flickering on a high-frequency signal. Use this parameter for static images to achieve honest supersampling. |
The effect can be configured using the TemporalAntiAliasing::FEATURE_FLAGS
enumeration. The following table lists the flags and their descriptions.
Name | Notes |
---|---|
FEATURE_FLAG_GAUSSIAN_WEIGHTING | Use Gaussian weighting in the variance clipping step |
FEATURE_FLAG_BICUBIC_FILTER | Use Catmull-Rom filter to sample from the history buffer |
To integrate TAA into your project, include the following necessary header files:
Now, create the necessary objects:
Next, call the methods to prepare resources for the PostFXContext
and TemporalAntiAliasing
objects. This needs to be done every frame before starting the rendering process.
After that, invoke the PostFXContext::Execute
method. At this stage, some intermediate resources necessary for all post-processing objects dependent on PostFXContext
are calculated. This method can take a constant buffer directly containing an array from the current and previous cameras (for this method, you can refer to this section of the code [0] and [1]). Alternatively, you can pass the corresponding pointers const HLSL::CameraAttribs* pCurrCamera
and const HLSL::CameraAttribs* pPrevCamera
for the current and previous cameras, respectively. You also need to pass the depth of the current and previous frames (the depth buffers should not contain transparent objects), and a buffer with motion vectors in NDC space, into the corresponding ITextureView* pCurrDepthBufferSRV
, ITextureView* pPrevDepthBufferSRV
, ITextureView* pMotionVectorsSRV
pointers.
TAA requires that each frame be rendered with some offset relative to the pixel. Therefore, you need to pass a modified projection matrix and jitter when updating the camera buffer HLSL::CameraAttribs
for the current frame, as in the code below (you can refer to this section of the code [2])
After rendering the entire frame, you need to invoke the TAA computation. Note that the frame passed in the color buffer argument must be in linear space, that is, before the tone mapping, as well as before effects such as Bloom and Depth Of Field. To do this, we call the TemporalAntiAliasing::Execute
method. Before this, we need to fill the passed structures TemporalAntiAliasingAttribs
and TemporalAntiAliasing::RenderAttributes
with the necessary data. Refer to the Input resources section for parameter description.
Now, you can directly obtain a ITextureView
on the texture containing the TAA result using the method TemporalAntiAliasing::GetAccumulatedFrameSRV
. After this, you can pass the TAA result to the tone mapping stage.
In general, all TAA implementations use similar core concepts. For a brief introduction to how the initial implementation of temporal anti-aliasing works, refer to [Emilio López, 2022]. We based our implementation on the one described in the article, but we made some modifications: