Shaders
Once the vertex data is uploaded, a shader program needs to be run to process the data. Shader programs are programs that run on the GPU and are very similar to CPU programs. They reside in memory and can access data structures in memory, they are composed of assembly instructions (GPU assembly), and they run on a processor (the GPU execution units). They differ in that shader programs run as part of the graphics pipeline and have defined roles in processing graphics. They also cannot currently recurse or access heap memory.
The two primary shaders are the vertex shader and the fragment shader. The vertex shader takes as input vertex attributes and outputs at least a vertex position. The fragment shader takes as input interpolated vertex attibutes and outputs a color (almost always). The pipeline looks like this:
The shaders are the blue boxes. The white boxes represent automatic steps that take place. After the vertex shader, the vertex attributes are interpolated across the primitive surface. These interpolated fragments are the input to the fragment shader. After the fragment shader, the fragments are composed into the final output image.
Shader syntax
We will use GLSL as our shading language. It has C style syntax with flexible graphics data types and functions. Loop and conditional constructs are similar to C: if
, for
, while
, etc. Here is an example vertex and fragment shader in GLSL. Vertex shader:
in vec2 pos; in vec3 color; out vec4 smoothColor; void main() { gl_Position=vec4(pos.xy, 0, 1); smoothColor=vec4(color.xyz, 1); }Fragment shader:
in vec4 smoothColor; out vec4 fragColor; void main() { fragColor = smoothColor; }
Types
GLSL supports scalars such as:
float f; //single precision float int i; //signed int uint u; //unsigned int bool b; //booleanIt also supports vector types in the format
[type]vec{n}
where type is the datatype and n is the size:
vec4 a; //vector of 4 float ivec3 b; //vector of 3 signed int uvec2 c; //vector of 2 unsigned int vector bvec2 d; //vector of 2 boolean vectorVectors components are accessed with the
.xyzw
, rgba
, or stpq
members:
vec4 a a.x = 4.0; //set first component to 4 vec2 b = a.yz; //make vec2 from the middle components vec2 c = a.gb; //make vec2 from the middle componentsVectors and scalar can be used naturally:
vec4 a; vec4 b; vec4 c = a * b; //component wise multiply of a and b float d; vec4 c; vec4 e = d * c; //scale c by dVariables can be created with constructors:
float a = float(4); vec4 b = vec4(1, 2, 3, a); vec4 c = vec4(1, b.yz, a);Input and output variables require qualifiers to describe their use. Vertex shader input and output:
in type x; //an input attribute out type y; //an output attribute for interpolation stageFragment shader:
in type z; //an input interpolated fragment (matches vertex output) out type w; //an output color
Making shaders
Shaders are created with the following OpenGL functions:
- glCreateShader
- glShaderSource
- glCompileShader
- glCreateProgram
- glAttachShadershader
- glLinkProgram
shaderHandle = ShaderManager::shaderFromFile(vertPath[], fragPath[], vertPathCount, fragPathCount)
.
- shaderHandle: the returned shader identifier
- vertPath[]: array of paths to vertex shader files
- vertPath[]: array of paths to fragment shader files
- vertPathCount: number of vertex shader paths in the given array
- vertPathCount: number of fragment shader paths in the given array
After creating a shader, you may then use the returned handle:
glUseProgram(shaderHandle); //activate a shader program ... draw stuff ... glUseProgram( 0 ); //deactivate all shader programs
Uniform values
Uploading data to the GPU is time consuming, but you can upload small values that change rarely without too much cost. These small values are generally constant and are called 'uniform' values. You can specify uniforms in shaders with the uniform
qualifier. You can get and use uniforms on the host as follows:
GLint uniformSlot = glGetUniformLocation(shaderHandle, "uniform name in shader"); glUniform1f(uniformSlot, single_value_to_upload);The suffix on
glUniform
controls the details of type and size of the upload.