gl_BaryCoordEXT Barycentric Coordinates in GLSL
The gl_BaryCoordEXT built-in variable provides fragment
shaders with direct access to the perspective-correct barycentric
coordinates of a primitive without requiring manual calculation or data
passing from earlier pipeline stages. Introduced through the
GL_EXT_fragment_shader_barycentric extension, this feature
simplifies techniques such as single-pass wireframe rendering, custom
attribute interpolation, and analytical antialiasing by exposing the
location of the current fragment relative to the primitive's
vertices.
Extension Requirement and Declaration
To use gl_BaryCoordEXT, the fragment shader must first
enable the corresponding extension:
#version 450
#extension GL_EXT_fragment_shader_barycentric : requireOnce enabled, the OpenGL Shading Language (GLSL) runtime exposes
gl_BaryCoordEXT as a built-in input variable.
Data Representation and Coordinate Meaning
The variable is defined as a 3-component floating-point vector:
in vec3 gl_BaryCoordEXT;For a triangular primitive with vertices \(V_0\), \(V_1\), and \(V_2\), gl_BaryCoordEXT
represents the weights \((u, v, w)\) of
the fragment's position relative to those vertices. These coordinates
satisfy the relation:
\[u + v + w = 1.0\]
The component mapping corresponds directly to the primitive's provoking vertices:
gl_BaryCoordEXT.xrepresents the weight associated with \(V_0\). At vertex \(V_0\), this value is1.0, while at \(V_1\) and \(V_2\) it is0.0.gl_BaryCoordEXT.yrepresents the weight associated with \(V_1\).gl_BaryCoordEXT.zrepresents the weight associated with \(V_2\).
Perspective Interpolation vs. Linear Interpolation
gl_BaryCoordEXT produces perspective-correct barycentric
coordinates. During rasterization, the hardware performs
perspective-correct interpolation by dividing the weights by the clip
space \(w\)-component before fragment
evaluation.
If screen-space, linear interpolation without perspective correction is needed, the extension also provides the companion built-in variable:
in vec3 gl_BaryCoordNoPerspEXT;This alternative calculates barycentric weights in screen space, which is beneficial for screen-aligned effects or line rendering where perspective foreshortening is undesirable.
Accessing Explicit Per-Vertex Attributes
In addition to gl_BaryCoordEXT, the extension allows
input attributes to be qualified with the pervertexEXT
keyword. Instead of receiving automatically interpolated values, the
fragment shader receives arrays of size 3 containing the raw,
un-interpolated values from each vertex:
layout(location = 0) in pervertexEXT vec4 inColor[];Using gl_BaryCoordEXT alongside
pervertexEXT, you can manually interpolate vertex
attributes using custom mathematical curves or formulas:
vec4 interpolatedColor = inColor[0] * gl_BaryCoordEXT.x +
inColor[1] * gl_BaryCoordEXT.y +
inColor[2] * gl_BaryCoordEXT.z;Practical Application: Wireframe Rendering
A primary use case for gl_BaryCoordEXT is generating
wireframes within a single rendering pass without using a geometry
shader. The minimum component of gl_BaryCoordEXT indicates
the shortest normalized distance to the nearest triangle edge:
layout(location = 0) out vec4 fragColor;
void main() {
// Find the minimum distance to an edge
float minBary = min(min(gl_BaryCoordEXT.x, gl_BaryCoordEXT.y), gl_BaryCoordEXT.z);
// Compute edge width using screen-space derivatives
vec3 dEdge = fwidth(gl_BaryCoordEXT);
vec3 edgeDist = smoothstep(vec3(0.0), dEdge * 1.5, gl_BaryCoordEXT);
float edgeFactor = min(min(edgeDist.x, edgeDist.y), edgeDist.z);
vec4 surfaceColor = vec4(0.8, 0.8, 0.8, 1.0);
vec4 wireColor = vec4(0.0, 0.0, 0.0, 1.0);
fragColor = mix(wireColor, surfaceColor, edgeFactor);
}By querying gl_BaryCoordEXT, the GPU avoids the memory
bandwidth and geometry shader overhead traditionally required to assign
and forward vertex identifiers or coordinate attributes down the
rendering pipeline.