Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By : David Wolff
Book Image

OpenGL 4 Shading Language Cookbook - Second Edition

By: David 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
About the Author
About the Reviewers

Getting a list of active vertex input attributes and locations

As covered in the previous recipe, the input variables within a vertex shader are linked to generic vertex attribute indices at the time the program is linked. If we need to specify the relationship, we can either use layout qualifiers within the shader, or we could call glBindAttribLocation before linking.

However, it may be preferable to let the linker create the mappings automatically and query for them after program linking is complete. In this recipe, we'll see a simple example that prints all the active attributes and their indices.

Getting ready

Start with an OpenGL program that compiles and links a shader pair. You could use the shaders from the previous recipe.

As in previous recipes, we'll assume that the handle to the shader program is stored in a variable named programHandle.

How to do it...

After linking and enabling the shader program, use the following code to display the list of active attributes:

  1. Start by querying for the number of active attributes:

    GLint numAttribs;
    glGetProgramInterfaceiv(programHandle, GL_PROGRAM_INPUT,GL_ACTIVE_RESOURCES, &numAttribs);
  2. Loop through each attribute and query for the length of the name, the type and the attribute location, and print the results to standard out:

    GLenum properties[] = {GL_NAME_LENGTH, GL_TYPE, GL_LOCATION};
    printf("Active attributes:\n");
    for( int i = 0; i < numAttribs; ++i ) {
      GLint results[3];
      glGetProgramResourceiv(programHhandle, GL_PROGRAM_INPUT,i, 3, properties, 3, NULL, results);
      GLint nameBufSize = results[0] + 1;
      char * name = new char[nameBufSize];
      glGetProgramResourceName(programHandle, GL_PROGRAM_INPUT, i, nameBufSize, NULL, name);
      printf("%-5d %s (%s)\n", results[2], name, getTypeString(results[1]));
      delete [] name;

How it works...

In step 1, we query for the number of active attributes, by calling glGetProgramInterfaceiv. The first argument is the handle to the program object, and the second (GL_PROGRAM_INPUT) indicates that we are querying for information about the program input variables (the vertex attributes). The third argument (GL_ACTIVE_RESOURCES) indicates that we want the number of active resources. The result is stored in the location pointed to by the last argument numAttribs.

Now that we have the number of attributes, we query for information about each one. The indices of the attributes run from 0 to numAttribs-1. We loop over those indices and for each we call glGetProgramResourceiv to get the length of the name, the type and the location. We specify what information we would like to receive by means of an array of GLenum values called properties. The first argument is the handle to the program object, the second is the resource that we are querying (GL_PROGRAM_INPUT). The third is the index of the attribute, the fourth is the number of values in the properties array, which is the fifth argument. The properties array contains GLenums, which specify the specific properties we would like to receive. In this example, the array contains: GL_NAME_LENGTH, GL_TYPE, and GL_LOCATION, which indicates that we want the length of the attribute's name, the data type of the attribute and its location. The sixth argument is the size of the buffer that will receive the results; the seventh argument is a pointer to an integer that would receive the number of results that were written. If that argument is NULL, then no information is provided. Finally, the last argument is a pointer to a GLint array that will receive the results. Each item in the properties array corresponds to the same index in the results array.

Next, we retrieve the name of the attribute by allocating a buffer to store the name and calling glGetProgramResourceName. The results array contains the length of the name in the first element, so we allocate an array of that size with an extra character just for good measure. The OpenGL documentation says that the size returned from glGetProgramResourceiv includes the null terminator, but it doesn't hurt to make sure by making a bit of additional space. In my tests, I've found this to be necessary on the latest NVIDIA drivers.

Finally, we get the name by calling glGetProgramResourceName, and then print the information to the screen. We print the attribute's location, name and type. The location is available in the third element of the results array, and the type is in the second. Note the use of the function getTypeString. This is a simple custom function that just returns a string representation of the data type. The data type is represented by one of the OpenGL defined constants GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, and so on. The getTypeString function consists of just one big switch statement returning a human-readable string corresponding to the value of the parameter (see the source code for glslprogram.cpp in the example code for this book).

The output of the previous code looks like this when it is run on the shaders from the previous recipes:

Active attributes:
1    VertexColor (vec3)
0    VertexPosition (vec3)

There's more...

It should be noted that in order for a vertex shader input variable to be considered active, it must be used within the vertex shader. In other words, a variable is considered active if it is determined by the GLSL linker that it may be accessed during program execution. If a variable is declared within a shader, but not used, the previous code will not display the variable because it is not considered active and effectively ignored by OpenGL.

The previous code is only valid for OpenGL 4.3 and later. Alternatively, you can achieve similar results with the functions glGetProgramiv, glGetActiveAttrib and glGetAttribLocation.

See also

  • The Compiling a shader recipe

  • The Linking a shader program recipe

  • The Sending data to a shader using vertex attributes and vertex buffer objects recipe