Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By : David Wolff, David A Wolff
Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By: David Wolff, David A Wolff

Overview of this book

OpenGL Shading Language (GLSL) is a programming language used for customizing parts of the OpenGL graphics pipeline that were formerly fixed-function, and are executed directly on the GPU. It provides programmers with unprecedented flexibility for implementing effects and optimizations utilizing the power of modern GPUs. With Version 4, the language has been further refined to provide programmers with greater power and flexibility, with new stages such as tessellation and compute. OpenGL 4 Shading Language Cookbook provides easy-to-follow examples that first walk you through the theory and background behind each technique, and then go on to provide and explain the GLSL and OpenGL code needed to implement it. Beginner level through to advanced techniques are presented including topics such as texturing, screen-space techniques, lighting, shading, tessellation shaders, geometry shaders, compute shaders, and shadows. OpenGL Shading Language 4 Cookbook is a practical guide that takes you from the fundamentals of programming with modern GLSL and OpenGL, through to advanced techniques. The recipes build upon each other and take you quickly from novice to advanced level code. You'll see essential lighting and shading techniques; examples that demonstrate how to make use of textures for a wide variety of effects and as part of other techniques; examples of screen-space techniques including HDR rendering, bloom, and blur; shadowing techniques; tessellation, geometry, and compute shaders; how to use noise effectively; and animation with particle systems. OpenGL Shading Language 4 Cookbook provides examples of modern shading techniques that can be used as a starting point for programmers to expand upon to produce modern, interactive, 3D computer graphics applications.
Table of Contents (17 chapters)
OpenGL 4 Shading Language Cookbook Second Edition
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Linking a shader program


Once we have compiled our shaders and before we can actually install them into the OpenGL pipeline, we need to link them together into a shader program. Among other things, the linking step involves making the connections between input variables from one shader to output variables of another, and making the connections between the input/output variables of a shader to appropriate locations in the OpenGL environment.

Linking involves steps that are similar to those involved in compiling a shader. We attach each shader object to a new shader program object and then tell the shader program object to link (making sure that the shader objects are compiled before linking).

Getting ready

For this recipe, we'll assume that you've already compiled two shader objects whose handles are stored in the variables vertShader and fragShader.

For this and a few other recipes in this Chapter, we'll use the following source code for the fragment shader:

#version 430

in vec3 Color;

out vec4 FragColor;

void main() {
  FragColor = vec4(Color, 1.0);
}

For the vertex shader, we'll use the source code from the previous recipe, Compiling a shader.

How to do it...

In our OpenGL initialization function, and after the compilation of shader objects referred to by vertShader and fragShader, use the following steps:

  1. Create the program object using the following code:

    GLuint programHandle = glCreateProgram();
    if( 0 == programHandle )
    {
      fprintf(stderr, "Error creating program object.\n");
      exit(1);
    }
  2. Attach the shaders to the program object as follows:

    glAttachShader( programHandle, vertShader );
    glAttachShader( programHandle, fragShader );
  3. Link the program:

    glLinkProgram( programHandle );
  4. Verify the link status:

    GLint status;
    glGetProgramiv( programHandle, GL_LINK_STATUS, &status );
    if( GL_FALSE == status ) {
    
      fprintf( stderr, "Failed to link shader program!\n" );
    
      GLint logLen;
      glGetProgramiv(programHandle, GL_INFO_LOG_LENGTH, &logLen);
      if( logLen > 0 )
      {
        char * log = new char[logLen];
        GLsizei written;
        glGetProgramInfoLog(programHandle, logLen, &written, log);
        fprintf(stderr, "Program log: \n%s", log);
        delete [] log;
      }
    }
  5. If linking is successful, install the program into the OpenGL pipeline:

    else
    {
      glUseProgram( programHandle );
    }

How it works...

We start by calling glCreateProgram to create an empty program object. This function returns a handle to the program object, which we store in a variable named programHandle. If an error occurs with program creation, the function will return 0. We check for that, and if it occurs, we print an error message and exit.

Next, we attach each shader to the program object using glAttachShader. The first argument is the handle to the program object, and the second is the handle to the shader object to be attached.

Then, we link the program by calling glLinkProgram, providing the handle to the program object as the only argument. As with compilation, we check for the success or failure of the link, with the subsequent query.

We check the status of the link by calling glGetProgramiv. Similar to glGetShaderiv, glGetProgramiv allows us to query various attributes of the shader program. In this case, we ask for the status of the link by providing GL_LINK_STATUS as the second argument. The status is returned in the location pointed to by the third argument, in this case named status.

The link status is either GL_TRUE or GL_FALSE indicating the success or failure of the link. If the value of status is GL_FALSE, we retrieve and display the program information log, which should contain additional information and error messages. The program log is retrieved by the call to glGetProgramInfoLog. The first argument is the handle to the program object, the second is the size of the buffer to contain the log, the third is a pointer to a GLsizei variable where the number of bytes written to the buffer will be stored (excluding the null terminator), and the fourth is a pointer to the buffer that will store the log. The buffer can be allocated based on the size returned by the call to glGetProgramiv with the parameter GL_INFO_LOG_LENGTH. The string that is provided in log will be properly null terminated.

Finally, if the link is successful, we install the program into the OpenGL pipeline by calling glUseProgram, providing the handle to the program as the argument.

With the simple fragment shader from this recipe and the vertex shader from the previous recipe compiled, linked, and installed into the OpenGL pipeline, we have a complete OpenGL pipeline and are ready to begin rendering. Drawing a triangle and supplying different values for the Color attribute yields an image of a multi-colored triangle where the vertices are red, green, and blue, and inside the triangle, the three colors are interpolated, causing a blending of colors throughout.

There's more...

You can use multiple shader programs within a single OpenGL program. They can be swapped in and out of the OpenGL pipeline by calling glUseProgram to select the desired program.

Deleting a Shader program

If a program is no longer needed, it can be deleted from OpenGL memory by calling glDeleteProgram, providing the program handle as the only argument. This invalidates the handle and frees the memory used by the program. Note that if the program object is currently in use, it will not be immediately deleted, but will be flagged for deletion when it is no longer in use.

Also, the deletion of a shader program detaches the shader objects that were attached to the program but does not delete them unless those shader objects have already been flagged for deletion by a previous call to glDeleteShader.

See also

  • The Compiling a shader recipe