Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
OpenGL Development Cookbook

You're reading from   OpenGL Development Cookbook OpenGL brings an added dimension to your graphics by utilizing the remarkable power of modern GPUs. This straight-talking cookbook is perfect for intermediate C++ programmers who want to exploit the full potential of OpenGL.

Arrow left icon
Product type Paperback
Published in Jun 2013
Publisher Packt
ISBN-13 9781849695046
Length 326 pages
Edition 1st Edition
Tools
Arrow right icon
Author (1):
Arrow left icon
Muhammad Mobeen Movania Muhammad Mobeen Movania
Author Profile Icon Muhammad Mobeen Movania
Muhammad Mobeen Movania
Arrow right icon
View More author details
Toc

Table of Contents (10) Chapters Close

Preface 1. Introduction to Modern OpenGL FREE CHAPTER 2. 3D Viewing and Object Picking 3. Offscreen Rendering and Environment Mapping 4. Lights and Shadows 5. Mesh Model Formats and Particle Systems 6. GPU-based Alpha Blending and Global Illumination 7. GPU-based Volume Rendering Techniques 8. Skeletal and Physically-based Simulation on the GPU Index

Designing a GLSL shader class

We will now have a look at how to set up shaders. Shaders are special programs that are run on the GPU. There are different shaders for controlling different stages of the programmable graphics pipeline. In the modern GPU, these include the vertex shader (which is responsible for calculating the clip-space position of a vertex), the tessellation control shader (which is responsible for determining the amount of tessellation of a given patch), the tessellation evaluation shader (which computes the interpolated positions and other attributes on the tessellation result), the geometry shader (which processes primitives and can add additional primitives and vertices if needed), and the fragment shader (which converts a rasterized fragment into a colored pixel and a depth). The modern GPU pipeline highlighting the different shader stages is shown in the following figure.

Designing a GLSL shader class

Note that the tessellation control/evaluation shaders are only available in the hardware supporting OpenGL v4.0 and above. Since the steps involved in shader handling as well as compiling and attaching shaders for use in OpenGL applications are similar, we wrap these steps in a simple class we call GLSLShader.

Getting ready

The GLSLShader class is defined in the GLSLShader.[h/cpp] files. We first declare the constructor and destructor which initialize the member variables. The next three functions, LoadFromString, LoadFromFile, and CreateAndLinkProgram handle the shader compilation, linking, and program creation. The next two functions, Use and UnUse functions bind and unbind the program. Two std::map datastructures are used. They store the attribute's/uniform's name as the key and its location as the value. This is done to remove the redundant call to get the attribute's/uniform's location each frame or when the location is required to access the attribute/uniform. The next two functions, AddAttribute and AddUniform add the locations of the attribute and uniforms into their respective std::map (_attributeList and _uniformLocationList).

class GLSLShader
{
public:
  GLSLShader(void);
  ~GLSLShader(void);
  void LoadFromString(GLenum whichShader, const string& source);
  void LoadFromFile(GLenum whichShader, const string& filename);
  void CreateAndLinkProgram();
  void Use();
  void UnUse();
  void AddAttribute(const string& attribute);
  void AddUniform(const string& uniform);
  GLuint operator[](const string& attribute);
  GLuint operator()(const string& uniform);
  void DeleteShaderProgram();

private:
  enum ShaderType{VERTEX_SHADER,FRAGMENT_SHADER,GEOMETRY_SHADER};
  GLuint  _program;
  int _totalShaders;
  GLuint _shaders[3];
  map<string,GLuint> _attributeList;
  map<string,GLuint> _uniformLocationList;
};

To make it convenient to access the attribute and uniform locations from their maps , we declare the two indexers. For attributes, we overload the square brackets ([]) whereas for uniforms, we overload the parenthesis operation (). Finally, we define a function DeleteShaderProgram for deletion of the shader program object. Following the function declarations are the member fields.

How to do it…

In a typical shader application, the usage of the GLSLShader object is as follows:

  1. Create the GLSLShader object either on stack (for example, GLSLShader shader;) or on the heap (for example, GLSLShader* shader=new GLSLShader();)
  2. Call LoadFromFile on the GLSLShader object reference
  3. Call CreateAndLinkProgram on the GLSLShader object reference
  4. Call Use on the GLSLShader object reference to bind the shader object
  5. Call AddAttribute/AddUniform to store locations of all of the shader's attributes and uniforms respectively
  6. Call UnUse on the GLSLShader object reference to unbind the shader object

Note that the above steps are required at initialization only. We can set the values of the uniforms that remain constant throughout the execution of the application in the Use/UnUse block given above.

At the rendering step, we access uniform(s), if we have uniforms that change each frame (for example, the modelview matrices). We first bind the shader by calling the GLSLShader::Use function. We then set the uniform by calling the glUniform{*} function, invoke the rendering by calling the glDraw{*} function, and then unbind the shader (GLSLShader::UnUse). Note that the glDraw{*} call passes the attributes to the GPU.

How it works…

In a typical OpenGL shader application, the shader specific functions and their sequence of execution are as follows:

glCreateShader
glShaderSource
glCompileShader
glGetShaderInfoLog

Execution of the above four functions creates a shader object. After the shader object is created, a shader program object is created using the following set of functions in the following sequence:

glCreateProgram
glAttachShader
glLinkProgram
glGetProgramInfoLog

Tip

Note that after the shader program has been linked, we can safely delete the shader object.

There's more…

In the GLSLShader class, the first four steps are handled in the LoadFromString function and the later four steps are handled by the CreateAndLinkProgram member function. After the shader program object has been created, we can set the program for execution on the GPU. This process is called shader binding. This is carried out by the glUseProgram function which is called through the Use/UnUse functions in the GLSLShader class.

To enable communication between the application and the shader, there are two different kinds of fields available in the shader. The first are the attributes which may change during shader execution across different shader stages. All per-vertex attributes fall in this category. The second are the uniforms which remain constant throughout the shader execution. Typical examples include the modelview matrix and the texture samplers.

In order to communicate with the shader program, the application must obtain the location of an attribute/uniform after the shader program is bound. The location identifies the attribute/uniform. In the GLSLShader class, for convenience, we store the locations of attributes and uniforms in two separate std::map objects.

For accessing any attribute/uniform location, we provide an indexer in the GLSLShader class. In cases where there is an error in the compilation or linking stage, the shader log is printed to the console. Say for example, our GLSLshader object is called shader and our shader contains a uniform called MVP. We can first add it to the map of GLSLShader by calling shader.AddUniform("MVP"). This function adds the uniform's location to the map. Then when we want to access the uniform, we directly call shader("MVP") and it returns the location of our uniform.

You have been reading a chapter from
OpenGL Development Cookbook
Published in: Jun 2013
Publisher: Packt
ISBN-13: 9781849695046
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime