GLSL 高级教程 – Vertex Shader

来源:互联网 发布:北京国家会计学院知乎 编辑:程序博客网 时间:2024/04/25 23:33

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:

1
2
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 theglDraw* OpenGL command. The variablegl_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:

1
2
3
4
5
out gl_PerVertex {
    vec4  gl_Position;
    floatgl_PointSize;
    floatgl_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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#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;
 
voidmain()
{
    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 namedMatrices containing two common matrices for vertex and normal transformation.

The outputs of the vertex shader are both the user defined attributes, texCoordOut andnormal, and the intrinsic attributegl_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 theGL_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 anarticle where several algorithms are disscussed and tested. Ignacio Castaño has focused on grids on this article.