Getting Started With Shaders in OpenGL

Elliot Forbes ⏰ 3 Minutes 📅 Apr 15, 2017

The modern OpenGL rendering pipeline rely heavily on shaders to process the huge amounts of data that a highly demanding program like a game requires. These shaders are typically written using the OpenGL Shading Language - GLSL, this language is very similar to C in syntax.

Learning shaders is just about one of the most important things you can do if you are going to get into graphical programming as it enables you to control just about everything when it comes to rendering your models in a game. Each stage grants an extra level of granularity through which you can create a game that looks like no other and whilst graphics don't make the game, having an aesthetically pleasing game can certainly help it.

The 5 Stages of the Graphical Pipeline

The new rendering pipeline was introduced in version 3.1 of OpenGL and whilst I've not necessarily had the pleasure of using the old fixed-function pipeline in my development life, I have been told that the newer method is huge improvement. This programmable pipeline contains 4 main stages and one final compute stage and we can control each of these simply by providing a shader.

##1. Vertex Shading Stage

At this stage of the pipeline we receive the vertex data that we've specified in our vertex buffer objects. These Vertex Buffer Objects are typically held in a Vertex Array Object which I've described in more detail here: To Be Added

##2. The Tessellation Shading Stage

An optional stage which can generate additional geometry within the OpenGL Pipeline.

##3. Geometry Shading Stage

In this stage you have the ability to generate yet more geometry from an input primitive, or convert the type of geometric primitive i.e converting triangles to lines.

##4. The Fragment Shading Stage

The last part of the shading pipeline processes the individual fragments generated by OpenGL's rasterizer and must also have a shader bound to it. In practice this means that for a very basic example we need only provide a vertex and a fragment shader in order for us to have a working shader pipeline.

##5. The Compute Shading Stage

This isn't a part of the graphical pipeline in the same way as the stages above and stands separate. In this stage we can do things like compute post-processing effects.

Writing Our First Shader Program

Now that you've got a little bit of an understanding of what a shader program is, it's time to start analyzing the code that goes into making a simple shader.

// here we specify the version using #version
#version 330 core

// our shader programs entry point, this is the same for
// every shader program we will be writing.
void main()
{
   // all processing code goes here
}

##Universal Variables

Being a typed language, every variable must be declared and have an associated type. All data for our shaders is passed using special global variables. These are entirely separate from any global variables set in your applications code and automatically get passed to the next stage of the programmable pipeline.

#version 330 core

// our global input
in vec4 vColor;

// out global output that gets passed to the next
// stage of the rendering pipeline
out vec4 color;

void
main()
{
    color = vColor;
}

In this example we take in a color global variable and then set our output so that it get's passed to the next section of our programmable pipeline.