What Does Noperspective Interpolation Do in GLSL?
In OpenGL Shading Language (GLSL), the noperspective
interpolation qualifier forces values passed from a vertex shader to a
fragment shader to interpolate linearly in 2D screen space rather than
using standard perspective-correct interpolation. By disabling
depth-aware weighting during primitive rasterization,
noperspective causes attributes like colors or texture
coordinates to distribute evenly across screen pixels regardless of a
surface's tilt or distance from the camera. This behavior is essential
for rendering screen-aligned graphics, HUDs, flat UI elements, or
achieving specialized non-photorealistic visual effects.
Understanding Interpolation in the Graphics Pipeline
When a triangle or line passes through the fixed-function rasterization stage, hardware calculates the values of varying attributes for every fragment inside the primitive. In 3D rendering, objects undergo perspective projection, meaning that equal distances in world space compress as they recede into the distance.
By default, GLSL applies standard perspective-correct interpolation
(the smooth qualifier). To account for depth distortion,
the rasterizer divides the attribute values by the homogeneous
coordinate \(w\) at each vertex,
linearly interpolates \(attribute / w\)
and \(1 / w\) across the screen-space
primitive, and then reconstructs the correct value at each fragment.
Standard (smooth): Linear in 3D world space (perspective-correct)
noperspective: Linear in 2D screen space (ignores depth differences)
flat: No interpolation (uses the provoking vertex value)
The Exact Effect of Noperspective
When a varying variable is declared with the
noperspective keyword, the hardware completely skips the
perspective division steps during rasterization:
- Pure Screen-Space Linearity: Attribute values change at a uniform rate per pixel across the primitive's screen footprint. If an edge spans 200 pixels on screen, the exact midpoint of the attribute transition occurs at pixel 100, regardless of which end of the edge is closer to the near clipping plane.
- Removal of Depth Warping: In standard rendering, a
checkerboard texture on a receding plane shows smaller tiles far away
and larger tiles up close. Applying
noperspectivecauses the texture coordinates to stretch evenly from top to bottom on the screen, creating strong geometric distortion where distant regions appear unnaturally wide.
// Vertex Shader
#version 330 core
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec2 inTexCoord;
noperspective out vec2 vTexCoord;
void main() {
vTexCoord = inTexCoord;
gl_Position = projectionMatrix * viewMatrix * vec4(inPosition, 1.0);
}
// Fragment Shader
#version 330 core
noperspective in vec2 vTexCoord;
out vec4 fragColor;
uniform sampler2D uTexture;
void main() {
fragColor = texture(uTexture, vTexCoord);
}When to Use Noperspective
While standard perspective interpolation is required for realistic 3D
environments, noperspective serves several specific
technical purposes:
1. Screen-Space Visual Effects
Post-processing passes, screen-aligned quads, and UI elements
projected with complex matrices often require uniform pixel-level
gradients. Applying noperspective prevents unintentional
distortions caused by arbitrary vertex depth values.
2. Specialized Wireframe and Anti-Aliased Line Rendering
Single-pass wireframe algorithms compute barycentric coordinates or distance vectors to triangle edges. To calculate screen-space line widths and anti-aliased margins accurately, these distance metrics must change linearly across screen pixels rather than warping with camera distance.
3. Emulating Retro Graphics Hardware
Early 3D gaming consoles and hardware accelerators (such as the
original Sony PlayStation) lacked hardware support for
perspective-correct texturing. Using noperspective allows
developers to recreate the distinctive texture-warping and shearing
artifacts found in classic 1990s 3D titles.