JavaScript EditorFree JavaScript Editor     Ajax Editor 



Main Page
Previous Page
Next Page

7.13. Application Code for Brick Shaders

Each shader is going to be a little bit different. Each vertex shader may use a different set of attribute variables or different uniform variables, attribute variables may be bound to different generic vertex attribute index values, and so on. One of the demo programs whose source code is available for download from the 3Dlabs Web site is called ogl2brick. It is a small, clear example of how to create and use a vertex shader and a fragment shader. The code in ogl2brick was derived from an earlier demo program called ogl2demo, written primarily by Barthold Lichtenbelt with contributions from several others. In ogl2brick an "install" function installs the brick shaders that were presented in Chapter 6. We discuss that shader installation function, but first we define a simple function that make it a little easier to set the values of uniform variables.

GLint getUniLoc(GLuint program, const GLchar *name)
{
    GLint loc;
    
    loc = glGetUniformLocation(program, name);

    if (loc == -1)
        printf("No such uniform named \"%s\"\n", name);

    printOpenGLError();  // Check for OpenGL errors
    return loc;
}

Shaders are passed to OpenGL as strings. For our shader installation function, we assume that each of the shaders has been defined as a single string, and pointers to those strings are passed to the following function. This function does all the work to load, compile, link, and install our brick shaders. The function definition and local variables for this function are declared as follows:

int installBrickShaders(const GLchar *brickVertex,
                        const GLchar *brickFragment)
{
    GLuint brickVS, brickFS, brickProg;   // handles to objects
    GLint  vertCompiled, fragCompiled;    // status values
    GLint  linked;

The argument brickVertex contains a pointer to the string containing the source code for the brick vertex shader, and the argument brickFragment contains a pointer to the source code for the brick fragment shader. Next, we declare variables to refer to three OpenGL objects: a shader object that stores and compiles the brick vertex shader, a second shader object that stores and compiles the brick fragment shader, and a program object to which the shader objects will be attached. Flags to indicate the status of the compile and link operations are defined next.

The first step is to create two empty shader objects, one for the vertex shader and one for the fragment shader:

brickVS = glCreateShader(GL_VERTEX_SHADER);
brickFS = glCreateShader(GL_FRAGMENT_SHADER);

Source code can be loaded into the shader objects after they have been created. The shader objects are empty, and we have a single null terminated string containing the source code for each shader, so we can call glShaderSource as follows:

glShaderSource(brickVS, 1, &brickVertex, NULL);
glShaderSource(brickFS, 1, &brickFragment, NULL);

The shaders are now ready to be compiled. For each shader, we call glCompileShader and then call glGetShader to see what transpired. glCompileShader sets the shader object's GL_COMPILE_STATUS parameter to GL_TRUE if it succeeded and GL_FALSE otherwise. Regardless of whether the compilation succeeded or failed, we print the information log for the shader. If the compilation was unsuccessful, this log will have information about the compilation errors. If the compilation was successful, this log may still have useful information that would help us improve the shader in some way. You would typically check the info log only during application development or after running a shader for the first time on a new platform. The function exits if the compilation of either shader fails.

glCompileShader(brickVS);
printOpenGLError();  // Check for OpenGL errors
glGetShaderiv(brickVS, GL_COMPILE_STATUS, &vertCompiled);
printShaderInfoLog(brickVS);

glCompileShader(brickFS);
printOpenGLError();  // Check for OpenGL errors
glGetShaderiv(brickFS, GL_COMPILE_STATUS, &fragCompiled);
printShaderInfoLog(brickFS);

if (!vertCompiled || !fragCompiled)
    return 0;

This section of code uses the printShaderInfoLog function that we defined previously.

At this point, the shaders have been compiled successfully, and we're almost ready to try them out. First, the shader objects need to be attached to a program object so that they can be linked.

brickProg = glCreateProgram();
glAttachShader(brickProg, brickVS);
glAttachShader(brickProg, brickFS);

The program object is linked with glLinkProgram. Again, we look at the information log of the program object regardless of whether the link succeeded or failed. There may be useful information for us if we've never tried this shader before.

glLinkProgram(brickProg);
printOpenGLError();  // Check for OpenGL errors
glGetProgramiv(brickProg, GL_LINK_STATUS, &linked);
printProgramInfoLog(brickProg);

if (!linked)
    return 0;

If we make it to the end of this code, we have a valid program that can become part of current state simply by calling glUseProgram:

glUseProgram(brickProg);

Before returning from this function, we also want to initialize the values of the uniform variables used in the two shaders. To obtain the location that was assigned by the linker, we query the uniform variable by name, using the getUniLoc function defined previously. Then we use that location to immediately set the initial value of the uniform variable.

glUniform3f(getUniLoc(brickProg, "BrickColor"), 1.0, 0.3, 0.2);
glUniform3f(getUniLoc(brickProg, "MortarColor"), 0.85, 0.86, 0.84);
glUniform2f(getUniLoc(brickProg, "BrickSize"), 0.30, 0.15);
glUniform2f(getUniLoc(brickProg, "BrickPct"), 0.90, 0.85);
glUniform3f(getUniLoc(brickProg, "LightPosition"), 0.0, 0.0, 4.0);

return 1;
}

When this function returns, the application is ready to draw geometry that will be rendered with our brick shaders. The result of rendering some simple objects with this application code and the shaders described in Chapter 6 is shown in Figure 6.6. The complete C function is shown in Listing 7.3.

Listing 7.3. C function for installing brick shaders

int installBrickShaders(const GLchar *brickVertex,
                        const GLchar *brickFragment)
{
    GLuint brickVS, brickFS, brickProg;   // handles to objects
    GLint  vertCompiled, fragCompiled;    // status values
    GLint  linked;

// Create a vertex shader object and a fragment shader object

brickVS = glCreateShader(GL_VERTEX_SHADER);
brickFS = glCreateShader(GL_FRAGMENT_SHADER);

// Load source code strings into shaders

glShaderSource(brickVS, 1, &brickVertex, NULL);
glShaderSource(brickFS, 1, &brickFragment, NULL);

// Compile the brick vertex shader and print out
// the compiler log file.

glCompileShader(brickVS);
printOpenGLError();  // Check for OpenGL errors
glGetShaderiv(brickVS, GL_COMPILE_STATUS, &vertCompiled);
printShaderInfoLog(brickVS);

// Compile the brick fragment shader and print out
// the compiler log file.

glCompileShader(brickFS);
printOpenGLError();  // Check for OpenGL errors
glGetShaderiv(brickFS, GL_COMPILE_STATUS, &fragCompiled);
printShaderInfoLog(brickFS);

if (!vertCompiled || !fragCompiled)
    return 0;

// Create a program object and attach the two compiled shaders

brickProg = glCreateProgram();
glAttachShader(brickProg, brickVS);
glAttachShader(brickProg, brickFS);

// Link the program object and print out the info log

glLinkProgram(brickProg);
printOpenGLError();  // Check for OpenGL errors
glGetProgramiv(brickProg, GL_LINK_STATUS, &linked);
printProgramInfoLog(brickProg);

if (!linked)
    return 0;

// Install program object as part of current state

glUseProgram(brickProg);

// Set up initial uniform values

   glUniform3f(getUniLoc(brickProg, "BrickColor"), 1.0, 0.3, 0.2);
   glUniform3f(getUniLoc(brickProg, "MortarColor"), 0.85, 0.86, 0.84);
   glUniform2f(getUniLoc(brickProg, "BrickSize"), 0.30, 0.15);
   glUniform2f(getUniLoc(brickProg, "BrickPct"), 0.90, 0.85);
   glUniform3f(getUniLoc(brickProg, "LightPosition"), 0.0, 0.0, 4.0);

   return 1;
}


Previous Page
Next Page



R7
JavaScript EditorAjax Editor     JavaScript Editor