Depth of Field is a visual effect that seems to be a must-have for just about every game that comes out these days. In case you somehow don’t know what it is, it’s an effect designed to simulate camera optics by making certain portions of the screen in-focus or out-of-focus depending on their distance from the camera. This sample will demonstrate a simple post-processing-based technique that’s simple and easy to integrate.
In photography, the term “depth of field” refers to the range of depth that is considered to be “in-focus” for a picture of that scene. Any areas outside of that depth will appear blurred due to the resulting circle of confusion (abbreviated CoC) being large enough that the eye can detect it. This blur is referred to as bokeh, which is also used to refer to the type or quality of blur that occurs in the final image. The bokeh produced is often manipulated by photographers and cinematographers in order to produce artistically-pleasing results. For this reason it has become popular to simulate this effect for real-time graphics, so that they can be used to make video game cutscenes more cinematic and artistic.
This sample will demonstrate 3 techniques for producing the depth of field effect, primarily based on the two techniques presented in this paper.
Technique #1: Blur Buffer
This technique is the simplest of the three. It works by first downscaling the main color render target to 1/16th size and then applying a seperable gaussian blur with 13 taps. A final pass then samples the depth for each fragment from the depth texture, calculates a blurriness factor based on this depth, and then blends between the blurred and original render targets based on this blurriness factor. Since such a large blur is used on a downscaled texture, the out-of-focus areas will be significantly blurred. However this approach has two major drawbacks:
- The Gaussian blur doesn’t really simulate a circle of confusion, therefore the results are less realistic (and possibly less visually appealing)
- Since the blur doesn’t respect depth boundaries, in-focus geometry that is in front of out-of-focus geometry will have a “halo”
Technique #2: Blur Buffer With Depth Checking
This technique addresses the second drawback of the first technique by checking the depth of samples while performing the Gaussian blur. The sample contributes to the blurred output only if its depth is greater-than or equal to the depth of the center sample. This eliminates the halo effect, however artifacts are still present at some areas of overlapping geometry (due to the blur being down at a lower resolution than the depth texture).
Technique #3: Disc Blur
This technique doesn’t use a Gaussian blur, and instead goes for a somewhat more physically-accurate approach. Samples of the original color render target are taken along a disc, with the radius of the disc based on the blur factor calculated from the depth texture. This can produce a more realistic bokeh effect, and also opens up the possibility to simulate the bokeh produced by various lens types. However with this technique you lose the ability to use a seperable blur, as well as the ability to apply the blur to a downscaled version of the main render target. Thus many more samples must be taken (which decreases performance), and also the maximum blur applied to out-of-focus areas is less compared to the previous techniques.
The sample code can be downloaded here.
11 thoughts on “Depth Of Field Sample”
Nice sample and a nice intro to DOF. Awesome!
Great tutorial! I love your site! but god dammit i hate the snapshots popup plugin…
The download link is broken =(
Looks like the SkyDrive servers are down temporarily, I would just try again in a little bit. If it doesn’t come back soon just send me an email and I’ll send it to you as an attachment.
Awesome it works again!
How can you attempt to even accurately create a depth of field without a depth map? My maths are bothering me like flies on a South African bbq!
What is the reasoning behind:
// Compute tap contribution based on depth and blurriness
float fTapContribution = (fTapDepth > fCenterDepth) ? 1.0f : fTapBlur;
Is this to reduce the near blur?
It’s honestly been so long that I don’t exactly remember why I did it that way. I’m pretty sure it was to keep the foreground from bleeding onto background pixels during the gather phase, unless the foreground was also out-of-focus. If you’re looking for something more modern, I would suggest looking at the DOF implementation from BakingLab: https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/PostProcessing.hlsl#L160
download link looks to be broken.