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; //boolean
It 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 vector
Vectors 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 components
Vectors 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 d
Variables 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 stage
Fragment 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
- glAttachShader
- glLinkProgram
I provide a class that will use these to create shaders for you: ShaderManager. Invoke it like this:
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
Attribute values
Attribute values are the values set for each vertex. These are often things like position and color, but they can be anything. Large arrays of these are uploaded (the Buffer objects) to the GPU. They are then processed by the vertex shader.
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.