Overview
Bloom is this effect:
Similar to the implementation of Bloom in other engines, UE's Bloom also has the following processes:
First, the current SceneColor is downscaled through a series of downsampling steps to a very small size. Then, a Gaussian blur is applied in the X and Y directions to each level and the image from the previous level is added. Finally, the result of Bloom is obtained.
Theory
A simple implementation of Bloom can be seen as the following process:
- Detect pixels on the image that have brightness above a certain threshold.
- Apply a 32 x 32 Gaussian blur to these pixels.
If you have ever studied some introductory tutorials on computer graphics and mentioned the implementation of Bloom, chances are you have learned about this particular approach.
Seperate Filter
Let's first focus on the issue of Kernel Size in Gaussian Blur. Please note that performing a Gaussian blur of size 32 x 32 on each pixel is very computationally expensive. The most naive implementation involves reading a quantity of data equivalent to the screen resolution x 32 x 32.
For an output resolution of 1080p, this would require reading 1920 x 1080 x 32 x 32 = 2,123,366,400 pixels.
By employing a simple technique, we can greatly reduce this quantity. The technique involves separating the 32 x 32 2D Gaussian blur into two 1D Gaussian blur passes. The concept is illustrated below:
This technique can reduce the number of pixels read to 1920 x 1080 x (32 + 32) = 132,710,400, which is 6.25% of the previous solution discussed. We have successfully reduced the amount of data read by 93.75%.
This explains this part of the figure: UE will separate each Gaussian blur into 2 passes.
Threshold?
Next, let's talk about the first part: applying Gaussian blur to which pixels to render Bloom.
For a modern PBR Pipeline, the Scene Color, which is often HDR, is usually preserved with the original brightness values for areas with high actual brightness. Therefore, we no longer need to use thresholds to filter pixels. Instead, we can simply blur the Scene Color directly before it is output to the frame buffer through Tone-mapping.
Downsample
And, why do we need downsampling?
This is because if we need a very large size for the Gaussian blur kernel, the number of samples will also increase as the size increases.
Therefore, if we downsize the image beforehand and then sample it with a smaller kernel on the downsized image, we can actually achieve similar results.
Implementation
Since the content is not complex, interested readers can directly refer to the relevant source code for implementation details.