Help end child hunger

GLSL Tutorial – Vertex Shader

Prev: Pipeline Next: Primitive Assembly


A vertex shader operates on individual vertices, one vertex at a time. The shader has no knowledge of the other vertices that make up the graphical primitive, and has no clue of what type of primitive the vertex belongs to. For each input vertex, this shader outputs a single vertex.

Each vertex has a set of user defined input attributes, for instance, position, normal vector, and texture coordinates. Vertex shaders also have access to uniform variables, which act as read-only global variables for all vertices in a draw call.

Besides user defined variables, GLSL defines a set of per vertex attributes:

in  int   gl_VertexID;
in  int   gl_InstanceID;

The gl_VertexID refers to the index of the vertex in the attribute arrays.

When using instances the shader is executed n times per input vertex, n being the number of specified instances in the glDraw* OpenGL command. The variable gl_InstanceID reports on the index of the instance. This variable is always zero if not using instances.

The vertex shader receives the input attributes, and outputs vertices, computing their attributes. The following intrinsic output attributes are available for writing in a vertex shader:

out gl_PerVertex {
    vec4  gl_Position;
    float gl_PointSize;
    float gl_ClipDistance[];

Writing in any of these is optional, however, some fixed function steps after the vertex shader expect gl_Position to be written, as this variable is intented to store the homogenous coordinates of the output vertex’s position.

Furthermore, the shader can output user-defined per vertex variables.

Here is a simple example showing some of these features:

#version 410

layout (std140) uniform Matrices {
	mat4 projModelViewMatrix;
	mat3 normalMatrix;

in vec3 position;
in vec3 normal;
in vec2 texCoord;

out VertexData {
	vec2 texCoord;
	vec3 normal;
} VertexOut;

void main()
	VertexOut.texCoord = texCoord;
	VertexOut.normal = normalize(normalMatrix * normal);	
	gl_Position = projModelViewMatrix * vec4(position, 1.0);

The above vertex shader receives three user defined attributes per vertex: position, normal, and texCoord. It receives a uniform block named Matrices containing two common matrices for vertex and normal transformation.

The outputs of the vertex shader are both the user defined attributes, texCoordOut and normal, and the intrinsic attribute gl_Position. Note that the output variables are also enclosed in a named block.

The outputs are computed in the main function. Every type of shader must have a main function, and can define other auxiliary functions as well, in a way similar  to a C program.

Notes regarding performance

Performance wise, there is a vertex cache that stores the outputs of the last n processed vertices. Before a new vertex is processed, its index is checked against the indices in the vertex cache. If the index is in the vertex cache, the respective previously processed data is sent to the remaining of the pipeline without further processing.

Taking advantage of the vertex cache, can therefore improve performance when using indexes, either explicitly, or implicitly, as in triangle strips and fans. For instance, in a triangle strip, at most one vertex per new triangle will be processed. When using indexes with regular triangles, the gain is not as easy to compute, and the indices may require a reorganization of the vertex data to improve vertex cache hits.

When the vertex data is not a strip, it can be converted to a strip or a set of strips. NVTriStrip is a tool from NVIDIA that performes this task. It takes the array of indices and tries to create strips as large as possible. Other approaches, namely Tom Forsyth’s algorithm (based on a cache of vertices using a least recently used (LRU) replacement policy), reorganize the index data to increase hits, keeping the GL_TRIANGLES mode. Tootle, Triangle Order Optimization Tool, is an AMD tool to optimize models, to reduce pixel overdraw and increase post-transform cache and vertex prefecth cache hits. This latter improvment is achieved by the reorganization of the vertex data itself, so that vertices in a triangle are close to each other on memory. Adrian Stone has written an article where several algorithms are disscussed and tested. Ignacio Castaño has focused on grids on this article.


Prev: Pipeline Next: Primitive Assembly

  3 Responses to “GLSL Tutorial – Vertex Shader”

  1. In the definition, you have:

    out VertexData {
    vec2 texCoord;

    However in the main function, you use VertexOut instead of VertexData. Is that a mistake or is the variable VertexData also some kind of intrinsic attribute?

    And when using gl_Position, I don’t have to specify it as the “out” variable in this shader and the “in” variable in the next shader?

    • Oh, never mind the first part of my question. I see it now. It’s like type definition in C. VertexData is a type and VertexOut is a variable of that type. I didn’t see that at first.

  2. BTW, how could I compile the sample program?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: