Depth of Field Circle of Confusion in GLSL Shaders

This article explores the fundamental role of the Circle of Confusion (CoC) in rendering depth of field (DoF) effects within OpenGL Shading Language (GLSL) fragment shaders. It examines the optical principles behind the CoC, the mathematical formulas used to compute it from depth buffers, and how fragment shaders use these calculations to govern blur radius, manage foreground-background transitions, and optimize post-processing performance.

In real-world camera optics, light rays passing through a lens converge at a focal point. Objects positioned closer or farther than this focal plane project as blurred discs rather than sharp points onto the camera sensor. This disc of projected light is known as the Circle of Confusion (CoC). In real-time computer graphics, fragment shaders simulate this physical phenomenon by calculating the CoC for each pixel to determine the appropriate amount of blur needed to mimic realistic camera lenses.

The primary role of the CoC calculation in a GLSL fragment shader is to translate linear depth values into a screen-space blur radius. The shader samples the scene's depth buffer, linearizes the depth value, and evaluates it against camera parameters: the focal distance (the distance to the point in sharp focus), focal length, and lens aperture (f-stop). A standard thin-lens model implemented in GLSL often utilizes the following relationship:

float calculateCoC(float depth, float focalDistance, float focalLength, float aperture) {
    return abs(aperture * (focalLength * (depth - focalDistance)) / (depth * (focalDistance - focalLength)));
}

This mathematical evaluation provides the exact diameter, in pixels or UV coordinates, across which the current fragment's color must be scattered or gathered.

Beyond determining blur magnitude, CoC calculations maintain optical correctness through signed values. When the sign of the CoC is preserved, a negative value indicates that the object is in the foreground (closer than the focal plane), while a positive value places it in the background. This distinction is vital in fragment shaders to prevent visual artifacts, such as sharp background elements improperly bleeding over a blurred foreground edge, or blurred foreground elements failing to softly overlap sharp background geometry.

Once computed, the CoC controls the sampling kernel of the shader. During post-processing passes—such as disk sampling, Gaussian blurs, or custom bokeh convolutions—the CoC dictates the offset distances for texture lookups. Larger CoC values widen the sampling radius to simulate deep defocus, while smaller values tighten the radius to preserve sharp details.

Finally, CoC calculations serve as an essential optimization metric in GLSL rendering pipelines. Shaders can check if the calculated CoC falls below a predetermined sub-pixel threshold. When an object resides well inside the depth of field margins (\(CoC \approx 0\)), the fragment shader can branch or exit early, skipping computationally expensive multi-tap sampling entirely and outputting the unaltered color buffer directly.