Shader is a silly word. In the late 80's, Pixar invented tiny graphics programs to shade surfaces. In the late 90's, companies started supporting programmable shading in GPU hardware. Today, 'shader' programs do much more than shading surfaces, but the name has not changed.

On GPUs, shaders get some input from GPU memory (the buffers we uploaded), transform the data, and store the results back in GPU memory. Here's a simple shader that takes in 2D vertices, RGB colors, and outputs a new color.

#version 330

in vec2 pos;
in vec3 color;
out vec4 smoothColor;

void main()
    gl_Position = vec4(pos.xy, 0, 1);
    smoothColor = vec4(, 1);

The shader's job is to transform input data. So, we send our data as inputs to the shader (the 'in' variables). This means we need to bind our input data to the shader input. Before drawing, get the shader input slot id. At render time, set the slot to use a buffer on the GPU.

/*** before render ***/
positionSlot = glGetAttribLocation(shaderProg, "pos");

/*** at render ***/
//select the shader program

//activate a buffer
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);

//enable shader input slot

//assign buffer to input slot
glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, 0, 0);

glDrawArrays(GL_LINES, 0, 2);

You should cleanup all this when you are done:

glBindBuffer(GL_ARRAY_BUFFER, 0);

Related API commands:

glGetAttribLocation(program, name)

Other helpful commands: glPointSize() set the rendered point size glLineWidth() set the rendered line width