How Does GLSL Centroid Sampling Fix MSAA Artifacts?

Multisample Anti-Aliasing (MSAA) smooths jagged polygon edges by evaluating coverage across multiple sub-pixel sample points, but standard interpolation can inadvertently evaluate fragment shader inputs outside a primitive's boundary. When standard center-pixel interpolation extrapolates attribute data beyond a triangle's edge, it triggers severe visual artifacts such as invalid texture lookups, dark halos, or math errors. In the OpenGL Shading Language (GLSL), the centroid interpolation qualifier forces the GPU to evaluate varying attributes strictly inside the covered area of the polygon, eliminating out-of-bounds extrapolation while preserving the edge-smoothing benefits of multisampling.

The Mechanics of Standard Multisampling

In classic MSAA pipelines, color calculation and coverage testing operate on distinct granularities. While a pixel contains several coverage sample points (such as 4x or 8x MSAA), the fragment shader typically runs only once per covered pixel to conserve performance.

By default, GLSL evaluates incoming varying attributes (such as texture coordinates, normals, and colors) at the exact geometric center of the pixel. The GPU then broadcasts this single resulting color to every sample location within that pixel that passed the coverage and depth tests.

Why Standard Center Interpolation Fails at Silhouette Edges

When a polygon partially covers a pixel along a silhouette or geometry edge, the exact center of that pixel often lies entirely outside the polygon's boundaries. Despite the center being outside the primitive, standard pipeline behavior still evaluates the varying inputs at the pixel center via extrapolation.

+-------------------+
|  (Sample 1)       |
|    \              |  Polygon Edge
|=====\=============|==============
|      \ (Center)   |  [Covered Area]
|       \           |
| (Sample 2)        |
+-------------------+

Extrapolating attribute values outside the valid range of a primitive creates several rendering issues:

How the Centroid Qualifier Resolves the Issue

The centroid qualifier changes where the GPU evaluates fragment shader inputs when pixels are partially covered. Instead of rigidly evaluating attributes at the pixel center, centroid dynamically shifts the evaluation location to a position that is simultaneously inside the pixel boundary and inside the primitive's covered region.

In practice, the GPU selects one of the multisample locations currently covered by the polygon. Because the evaluation point is guaranteed to be within the polygon's physical geometry, values are always interpolated within the triangle's actual bounds rather than extrapolated beyond them.

Implementing Centroid Sampling in GLSL

To apply centroid sampling, apply the centroid storage qualifier to interface variables in both the vertex (or previous pipeline stage) and fragment shaders.

Vertex Shader Example

#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

centroid out vec2 vTexCoord;

uniform mat4 uMVP;

void main()
{
    gl_Position = uMVP * vec4(aPos, 1.0);
    vTexCoord = aTexCoord;
}

Fragment Shader Example

#version 330 core

centroid in vec2 vTexCoord;
out vec4 FragColor;

uniform sampler2D uTexture;

void main()
{
    FragColor = texture(uTexture, vTexCoord);
}

Both the output from the generating stage and the input to the fragment stage must match qualifiers. If declared as centroid out in the vertex shader, it must be declared as centroid in in the fragment shader.

Performance and Quality Trade-offs

Using centroid introduces key behavioral differences compared to default center-pixel sampling: