GLSL layout(quads) UV Domain Generation Explained
In a GLSL tessellation evaluation shader (TES), specifying the
layout(quads) input layout qualifier instructs the
primitive generator to create a two-dimensional grid over a normalized
square domain. This overview explains how layout(quads)
redefines the abstract UV coordinate space, dictates the format and
values of the built-in gl_TessCoord variable, changes the
mapping of inner and outer tessellation levels, and enables standard
bilinear interpolation instead of barycentric coordinate math.
The 2D Rectangular Domain
When an input primitive is declared with layout(quads),
the fixed-function primitive generation stage constructs a tessellated
domain defined over the unit square \([0.0,
1.0] \times [0.0, 1.0]\). This is fundamentally different from
layout(triangles), which generates an equilateral triangle
domain governed by barycentric coordinates. The quad domain represents a
continuous UV space with four distinct boundaries:
- \(u = 0.0\) (Left edge)
- \(u = 1.0\) (Right edge)
- \(v = 0.0\) (Bottom edge)
- \(v = 1.0\) (Top edge)
Modification of
gl_TessCoord
The evaluation shader receives the location of each generated vertex
within this domain through the built-in vector
gl_TessCoord. Under layout(quads), the
components of gl_TessCoord behave as follows:
gl_TessCoord.x: Represents the normalized \(u\)-coordinate, ranging from \(0.0\) to \(1.0\).gl_TessCoord.y: Represents the normalized \(v\)-coordinate, ranging from \(0.0\) to \(1.0\).gl_TessCoord.z: Is unused and always set to \(0.0\).
Because only the X and Y components vary, shaders evaluate quad
topology using standard two-dimensional Cartesian coordinates
(gl_TessCoord.xy).
Mapping Tessellation Levels to UV Axes
The distribution and density of generated UV coordinates are governed by the tessellation levels calculated in the tessellation control shader (TCS):
- Inner Levels (
gl_TessLevelInner): A quad uses two inner tessellation levels.gl_TessLevelInner[0]specifies the number of subdivisions along the vertical (\(v\)) axis, whilegl_TessLevelInner[1]specifies the subdivisions along the horizontal (\(u\)) axis. Together, they define the interior grid density of UV samples. - Outer Levels (
gl_TessLevelOuter): A quad uses all four outer levels. Each index directly corresponds to one of the four perimeter edges of the \([0, 1]\) domain:gl_TessLevelOuter[0]: Subdivides the edge where \(u = 0.0\).gl_TessLevelOuter[1]: Subdivides the edge where \(v = 0.0\).gl_TessLevelOuter[2]: Subdivides the edge where \(u = 1.0\).gl_TessLevelOuter[3]: Subdivides the edge where \(v = 1.0\).
Transitioning between the interior grid and perimeter boundaries creates non-uniform UV coordinate stepping near the edges to match neighboring patches with different tessellation factors.
Vertex Position Interpolation
Because layout(quads) produces independent \(u\) and \(v\) coordinates rather than a 3-component
barycentric weight vector, vertex attributes such as position, normals,
and texture coordinates are computed via bilinear interpolation or
tensor product surfaces (such as bicubic Bézier patches). In a standard
four-control-point quad patch, bilinear interpolation is applied
directly using gl_TessCoord.x and
gl_TessCoord.y:
vec4 p0 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);
vec4 p1 = mix(gl_in[3].gl_Position, gl_in[2].gl_Position, gl_TessCoord.x);
gl_Position = mix(p0, p1, gl_TessCoord.y);By switching to layout(quads), the tessellation
evaluation stage transitions from simplex-based coordinate weighting to
structured 2D UV mapping, making it the preferred primitive
configuration for terrain grids, displacement mapping, and parametric
surfaces.