A shader is a program written in a specialized language (e.g., GLSL - OpenGL Shading Language) that runs on the GPU (Graphics Processing Unit) and is used to control the rendering pipeline in computer graphics applications.

  1. Vertex Shaders: Vertex shaders operate on individual vertices of 3D models. They typically perform transformations on vertex positions (e.g., applying translations, rotations, scaling) and may perform other tasks like lighting calculations or vertex color interpolation.
  2. Fragment Shaders (Pixel Shaders): Fragment shaders operate on individual pixels of the rendered image. They determine the final color of each pixel by applying various effects such as textures, lighting, shading, and color blending.
  3. Geometry Shaders: Geometry shaders operate on entire primitives (e.g., triangles) rather than individual vertices. They can create or modify geometry dynamically, such as generating additional vertices, creating billboards, or implementing tessellation.
  4. Compute Shaders: Compute shaders are more general-purpose shaders used for performing arbitrary computations on the GPU. They are not tied to the graphics pipeline and can be used for tasks like physics simulations, image processing, or general-purpose parallel computing.

In OpenGL, the shader needs to be compiled at runtime.

GLuint createShader(int shaderType, const char *text) {
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, 1, &text, nullptr);
    glCompileShader(shader);
    return shader;
}
// ShaderType can be GL_FRAGMENT_SHADER, GL_VERTEX_SHADER...

Shader code

Uniforms

A uniform is a global Shader variable declared with the "uniform" storage qualifier. These act as parameters that the user of a shader program can pass to that program. Their values are stored in a program object.

Uniforms are so named because they do not change from one shader invocation to the next within a particular rendering call thus their value is uniform among all invocations. This makes them unlike shader stage inputs and outputs, which are often different for each invocation of a shader stage.

uniform float example; // Example of declaration

<aside> 🚨 Do not declare a uniform if you don’t use it since OpenGL would remove any non used uniform and it could lead to errors.

</aside>

In order to define a Uniform on the CPU side, we need to first access the reference and then update the value.

<aside> ⚠️ Make sure to have the targeted program activated (using glUseProgram) before doing that.

</aside>

GLuint uniID = glGetUniformLocation(shaderProgram, "example");
glUniform1f(uniID, 0.5f);
//1f to define a float. the end of the function name depends on the type defined

<aside> 🖌️ If you want to access a Texture as a uniform, define the type as sampler2d in the GLSL code and the texture unit id as an integer using glUniform1i.

</aside>

Pass value from one shader to another