What Is the Role of the TES in GLSL?
The Tessellation Evaluation Shader (TES) serves as the final programmable stage of the OpenGL tessellation pipeline, responsible for calculating the actual vertex positions and attributes generated by the fixed-function primitive generator. While the Tessellation Control Shader (TCS) determines how finely a patch is subdivided and the hardware Tessellator creates the abstract coordinate grid, the TES takes those abstract parametric coordinates (such as \((u, v)\) or barycentric coordinates) and maps them into real 3D geometry. This makes the TES the critical stage where mathematical surface evaluation, heightmap displacement, and final coordinate transformations occur.
Position in the OpenGL Tessellation Pipeline
To understand the TES, it helps to see where it sits between vertex processing and rasterization:
- Vertex Shader: Processes raw input control points.
- Tessellation Control Shader (TCS): Determines
tessellation levels (
gl_TessLevelInnerandgl_TessLevelOuter) and prepares per-patch data. - Primitive Generator (Fixed-Function): Tessellates the domain based on the levels set by the TCS, producing abstract parametric coordinates.
- Tessellation Evaluation Shader (TES): Evaluates the position and attributes of every generated vertex.
- Geometry / Fragment Shader: Receives the newly generated triangles or quads for optional expansion, shading, and rendering.
Core Responsibilities of the TES
Evaluating Abstract Coordinates
The fixed-function stage does not know about your 3D world; it only
knows domain coordinates. The TES receives the built-in variable
gl_TessCoord, which provides the location of the newly
generated vertex within the abstract patch domain:
- Quads and Isolines:
gl_TessCoordprovides \((u, v)\) coordinates ranging from \(0.0\) to \(1.0\). - Triangles:
gl_TessCoordprovides \((u, v, w)\) barycentric coordinates where \(u + v + w = 1.0\).
The TES uses these coordinates to interpolate between the original
patch control points passed down via gl_in[].
Surface Reconstruction and Interpolation
The primary role of the TES is computing smooth curved surfaces or
parametric patches, including Bézier patches, B-splines, and
PN-triangles (Point-Normal triangles). By applying mathematical blending
formulas to gl_TessCoord and the input control points, the
shader constructs curved surfaces dynamically on the GPU without needing
high-density source meshes from CPU memory.
Displacement Mapping and Heightfields
A widespread use case for the TES is terrain rendering and displacement mapping. A low-resolution base mesh can be subdivided on the fly, and the TES can sample a displacement or height texture using the interpolated UV coordinates. It then offsets the vertex along its normal vector before passing it down the pipeline, creating detailed geometric features with low memory bandwidth overhead.
Applying Coordinate Transformations
Because the TES outputs the final geometric vertices for
rasterization, it typically performs model-view-projection (MVP)
transformations. The vertices output by the TES
(gl_Position) are in clip space, ready for the geometry
shader, clipping, and viewport transformation stages.
Structure of a GLSL Tessellation Evaluation Shader
A standard TES specifies the domain layout and primitive generation spacing at the top of the file:
#version 450 core
// Define patch type, spacing, and winding order
layout(triangles, equal_spacing, ccw) in;
// Uniforms for displacement and matrices
uniform mat4 u_ModelViewProjection;
uniform sampler2D u_DisplacementMap;
// Custom inputs from TCS
in vec2 v_TexCoord[];
in vec3 v_Normal[];
// Custom output to Fragment/Geometry Shader
out vec2 f_TexCoord;
out vec3 f_Normal;
void main()
{
// Retrieve barycentric coordinates
vec3 p = gl_TessCoord;
// Linearly interpolate positions from the 3 patch control points
vec4 pos = p.x * gl_in[0].gl_Position +
p.y * gl_in[1].gl_Position +
p.z * gl_in[2].gl_Position;
// Interpolate texture coordinates and normals
f_TexCoord = p.x * v_TexCoord[0] + p.y * v_TexCoord[1] + p.z * v_TexCoord[2];
f_Normal = normalize(p.x * v_Normal[0] + p.y * v_Normal[1] + p.z * v_Normal[2]);
// Apply height displacement along normal
float height = texture(u_DisplacementMap, f_TexCoord).r;
pos.xyz += f_Normal * height;
// Output final clip-space position
gl_Position = u_ModelViewProjection * pos;
}The Tessellation Evaluation Shader is the essential bridge between abstract tessellation patterns and tangible 3D geometry in GLSL, enabling scalable level-of-detail, dynamic displacement, and smooth procedural surfaces directly on modern GPU hardware.