Book Image

OpenGL ES 3.0 Cookbook

By : Parminder Singh
Book Image

OpenGL ES 3.0 Cookbook

By: Parminder Singh

Overview of this book

<p>"Write once, use anywhere" is truly the power behind OpenGL ES and has made it an embedded industry standard. The library provides cutting-edge, easy-to-use features to build a wide range of applications in the gaming, simulation, augmented-reality, image-processing, and geospatial domains.</p> <p>The book starts by providing you with all the necessary OpenGL ES 3.0 setup guidelines on iOS and Android platforms. You'll go on to master the fundamentals of modern 3D graphics, such as drawing APIs, transformations, buffer objects, the model-view-project analogy, and much more. The book goes on to deal with advanced topics and offers a wide range of recipes on the light shading, real-time rendering techniques with static and procedure textures to create stunning visualizations and runtime effects.</p>
Table of Contents (21 chapters)
OpenGL ES 3.0 Cookbook
Credits
About the Author
Acknowledgments
About the Reviewers
www.PacktPub.com
Preface
Index

Programming OpenGL ES 3.0 Hello World Triangle


This recipe basically comprises of all the knowledge we gathered from our previous recipes in this chapter. The output of this recipe will be a NativeTemplate.h/cpp file that contains OpenGL ES 3.0 code, which demonstrates a rotating colored triangle. The output of this recipe is not executable on its own. It needs a host application that provides the necessary OpenGL ES 3.0 prerequisites to render this program on a device screen. Therefore, this recipe will be used later by the following two recipes, which will provide the host environment for OpenGL ES 3.0 in Android and iOS:

  • Developing Android OpenGL ES 3.0 application

  • Developing iOS OpenGL ES 3.0 application

This recipe will provide all the necessary prerequisites that are required to set up OpenGL ES, rendering and querying necessary attributes from shaders to render our OpenGL ES 3.0 "Hello World Triangle" program. In this program, we will render a simple colored triangle on the screen.

Getting ready

OpenGL ES requires a physical size (pixels) to define a 2D rendering surface called a viewport. This is used to define the OpenGL ES Framebuffer size.

A buffer in OpenGL ES is a 2D array in the memory that represents pixels in the viewport region. OpenGL ES has three types of buffers: color buffer, depth buffer, and stencil buffer. These buffers are collectively known as a framebuffer. All the drawings commands effect the information in the framebuffer.

The life cycle of this recipe is broadly divided into three states:

  • Initialization: Shaders are compiled and linked to create program objects

  • Resizing: This state defines the viewport size of rendering surface

  • Rendering: This state uses the shader program object to render geometry on screen

In our recipe, these states are represented by the GraphicsInit(), GraphicsResize(), and GraphicsRender() functions.

How to do it...

Follow these steps to program this recipe:

  1. Use the NativeTemplate.cpp file and create a createProgramExec function. This is a high-level function to load, compile, and link a shader program. This function will return the program object ID after successful execution:

    GLuint createProgramExec(const char* vertexSource, const
                                       char* fragmentSource) {
    GLuint vsID = loadAndCompileShader(GL_VERTEX_SHADER,
    vertexSource);
    GLuint fsID = loadAndCompileShader(GL_FRAGMENT_SHADER, 
    fragmentSource);
       return linkShader(vsID, fsID);
    }

    Visit the loading and compiling a shader program and linking a shader program recipes for more information on the working of loadAndCompileShader and linkShader.

  2. Use NativeTemplate.cpp, create a function GraphicsInit and create the shader program object by calling createProgramExec:

    GLuint programID; // Global shader program handler
    bool GraphicsInit(){
    
    // Print GLES3.0 system metrics
    printOpenGLESInfo();
      
    // Create program object and cache the ID
    programID = createProgramExec(vertexShader,
    fragmentShader);
        if (!programID) { // Failure !!! return 
           printf("Could not create program."); return false;
        }
        checkGlError("GraphicsInit"); // Check for errors
    }
  3. Create a new function GraphicsResize. This will set the viewport region:

    // Set viewing window dimensions 
    bool GraphicsResize( int width, int height ){
        glViewport(0, 0, width, height);
    }

    The viewport determines the portion of the OpenGL ES surface window on which the rendering of the primitives will be performed. The viewport in OpenGL ES is set using the glViewPort API.

    • Syntax:

      void glViewport( GLint x, GLint y, GLsizei width, GLsizei height);

      Variable

      Description

      x, y

      These represent lower-left rectangle for viewport specified in pixels

      width, height

      This specifies the width and height of the viewport in pixels

  4. Create the gTriangleVertices global variable that contains the vertices of the triangle:

    GLfloat gTriangleVertices[] = { 
    { 0.0f,  0.5f}, // Vertex 0
    {-0.5f, -0.5f}, // Vertex 1
    { 0.5f, -0.5f}  // Vertex 2
    }; // Triangle vertices
  5. Create the GraphicsRender renderer function. This function is responsible for rendering the scene. Add the following code in it and perform the following steps to understand this function:

    bool GraphicsRender(){
        // Which buffer to clear? – color buffer
        glClear( GL_COLOR_BUFFER_BIT );
        
        // Clear color with black color
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        
        // Use shader program and apply 
        glUseProgram( programID );
        radian = degree++/57.2957795;
    
    // Query and send the uniform variable.    
    radianAngle = glGetUniformLocation(programID, "RadianAngle");
        glUniform1f(radianAngle, radian);
    
        // Query 'VertexPosition' from vertex shader
        positionAttribHandle = glGetAttribLocation
                                (programID, "VertexPosition");
        colorAttribHandle    = glGetAttribLocation
                                 (programID, "VertexColor");
    
        // Send data to shader using queried attribute
        glVertexAttribPointer(positionAttribHandle, 2, 
                   GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
        glVertexAttribPointer(colorAttribHandle, 3, 
                  GL_FLOAT, GL_FALSE, 0, gTriangleColors);
      
        // Enable vertex position attribute
        glEnableVertexAttribArray(positionAttribHandle);
        glEnableVertexAttribArray(colorAttribHandle);
        
        // Draw 3 triangle vertices from 0th index
        glDrawArrays(GL_TRIANGLES, 0, 3);
    }
  6. Choose the appropriate buffer from the framebuffer (color, depth, and stencil) that we want to clear each time the frame is rendered using the glClear API. In our recipe, we want to clear color buffer. The glClear API can be used to select the buffers that needs to be cleared. This API accepts a bitwise OR argument mask that can be used to set any combination of buffers.

    • Syntax:

      void glClear( GLbitfield mask )

      Variable

      Description

      mask

      Bitwise OR masks, each mask points to a specific buffer. These masks are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.

      The possible value mask could be a bitwise or of GL_COLOR_BUFFER_BIT (color buffer), GL_DEPTH_BUFFER_BIT (depth buffer) and GL_STENCIL_BUFFER_BIT (stencil buffer).

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  7. Clear the color buffer with black color using the glClearColor API. This buffer is responsible for storing color information of the scene. It accepts the argument as RGBA space that ranges between 0.0 and 1.0.

  8. Use a shader program and set as the current rendering state using the glUseProgram API. The glUseProgram API installs the program object specified by the program as the current rendering state. The program's executable for the vertex shader runs on the programmable vertex processor. Similarly, the fragment shader executable runs on the programmable fragment processor.

    • Syntax:

      void glUseProgram(GLuint program);

      Variable

      Description

      program

      This specifies the handle (ID) of the shader program.

  9. Query the VertexPosition generic vertex attribute location ID from the vertex shader into positionAttribHandle using glGetAttribLocation. This location will be used to send triangle vertex data that is stored in gTriangleVertices to the shader using glVertexAttribPointer. Follow the same instruction in order to get the handle of VertexColor into colorAttributeHandle:

    // Query attribute location & send data using them
    positionAttribHandle = glGetAttribLocation
                             (programID, "VertexPosition");
    colorAttribHandle = glGetAttribLocation
                             (programID, "VertexColor");
    glVertexAttribPointer(positionAttribHandle, 2, GL_FLOAT,
    GL_FALSE, 0, gTriangleVertices);
    glVertexAttribPointer(colorAttribHandle, 3, GL_FLOAT, 
                             GL_FALSE, 0, gTriangleColors);
  10. Enable the generic vertex attribute location using positionAttribHandle before the rendering call and render the triangle geometry. Similarly, for the per-vertex color information, use colorAttribHandle:

    glEnableVertexAttribArray(positionAttribHandle);
    glDrawArrays(GL_TRIANGLES, 0, 3);

How it works...

When the application starts, the control begins with GraphicsInit, where the system metrics are printed out to make sure that the device supports OpenGL ES 3.0. The OpenGL ES programmable pipeline requires vertex shader and fragment shader program executables in the rendering pipeline. The program object contains one or more executables after attaching the compiled shader objects and linking them to program. In the createProgramExec function the vertex and fragment shaders are compiled and linked, in order to generate the program object.

The GraphicsResize function generates the viewport of the given dimension. This is used internally by OpenGL ES 3.0 to maintain the framebuffer. In our current application, it is used to manage color buffer. Refer to the There's more … section for more information on other available buffers in OpenGL ES 3.0.

Finally, the rendering of the scene is performed by GraphicsRender, this function clears the color buffer with black background and renders the triangle on the screen. It uses a shader object program and sets it as the current rendering state using the glUseProgram API.

Each time a frame is rendered, data is sent from the client side (CPU) to the shader executable on the server side (GPU) using glVertexAttribPointer. This function uses the queried generic vertex attribute to bind the data with OpenGL ES pipeline.

There's more...

There are other buffers also available in OpenGL ES 3.0:

  • Depth buffer: This is used to prevent background pixels from rendering if there is a closer pixel available. The rule of prevention of the pixels can be controlled using special depth rules provided by OpenGL ES 3.0. For more information on this, refer to Chapter 2, OpenGL ES 3.0 Essentials.

  • Stencil buffer: The stencil buffer stores the per-pixel information and is used to limit the area of rendering.

The OpenGL ES API allows us to control each buffer separately. These buffers can be enabled and disabled as per the requirement of the rendering. The OpenGL ES can use any of these buffers (including color buffer) directly to act differently. These buffers can be set via preset values by using OpenGL ES APIs, such as glClearColor, glClearDepthf, and glClearStencil.

Note

You can refer to http://www.khronos.org/opengles/sdk/docs/man3/ for more information on glClearDepthf, glClearStencilAPI and all other APIs. The same link can be used to explore OpenGL ES 3.0 official API specifications.

See also

  • Refer to the Depth testing in OpenGL ES 3.0 recipe in Chapter 2, OpenGL ES 3.0 Essentials

  • Developing an Android OpenGL ES 3.0 application

  • Developing an iOS OpenGL ES 3.0 application