OpenGL ES 2.0 编程三步曲

什么是OpenGL ES?OpenGL ES (为OpenGL for Embedded Syste
首页 新闻资讯 行业资讯 OpenGL ES 2.0 编程三步曲

OpenGL 与 OpenGL ES的关系OpenGL ES 是基于桌面版本OpenGL 的:

OpenGL ES 1.0  基于OpenGL 1.3 , 在2003年发布

OpenGL ES 1.1   基于OpenGL 1.5 ,  在2004年发布

OpenGL ES 2.0  基于OpenGL2.0,   在2007年发布

OpenGL 2.0 向下兼容OpenGL 1.5   而 OpenGL ES 2.0 和OpenGL ES 1.x 不兼容,是两种完全不同的实现。

1. 保存全局变量的数据结构

以下例子程序均基于Linux平台。

[cpp]view plaincopy

复制

typedef struct _escontext   {      void*       userData;                    // Put your user data here...      GLint       width;                          // Window width      GLint       height;                         // Window height      EGLNativeWindowType  hWnd;  // Window handle      EGLDisplay  eglDisplay;             // EGL display      EGLContext  eglContext;            // EGL context      EGLSurface  eglSurface;            // EGL surface      // Callbacks      void (ESCALLBACK *drawFunc) ( struct _escontext * );      void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int );      void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime );   }ESContext;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

[cpp]view plaincopy

复制

typedef struct   {      // Handle to a program object      GLuint programObject;      // Atrribute Location      GLint positionLoc;      GLint textureLoc;      // Uniform location      GLint matrixModeLoc;      GLint matrixViewLoc;      GLint matrixPerspectiveLoc;      // Sampler location      GLint samplerLoc;      // texture      GLuint texture;   } UserData;   
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

2. 初始化EGL渲染环境和相关元素(***步曲)

[cpp]view plaincopy

复制

int InitEGL(ESContext * esContext)   {        NativeWindowType eglWindow = NULL;        EGLDisplay display;        EGLContext context;        EGLSurface surface;        EGLConfig configs[2];        EGLBoolean eRetStatus;        EGLint majorVer, minorVer;        EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};        EGLint numConfigs;        EGLint cfg_attribs[] = {EGL_BUFFER_SIZE,    EGL_DONT_CARE,                                EGL_DEPTH_SIZE,     16,                                EGL_RED_SIZE,       5,                                EGL_GREEN_SIZE,     6,                                EGL_BLUE_SIZE,      5,                                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,                                EGL_NONE};        // Get default display connection         display = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);        if ( display == EGL_NO_DISPLAY )        {             return EGL_FALSE;        }        // Initialize EGL display connection        eRetStatus = eglInitialize(display, &majorVer, &minorVer);        if( eRetStatus != EGL_TRUE )        {             return EGL_FALSE;        }        //Get a list of all EGL frame buffer configurations for a display        eRetStatus = eglGetConfigs (display, configs, 2, &numConfigs);        if( eRetStatus != EGL_TRUE )        {             return EGL_FALSE;        }        // Get a list of EGL frame buffer configurations that match specified attributes        eRetStatus = eglChooseConfig (display, cfg_attribs, configs, 2, &numConfigs);        if( eRetStatus != EGL_TRUE  || !numConfigs)        {             return EGL_FALSE;        }        // Create a new EGL window surface        surface = eglCreateWindowSurface(display, configs[0], eglWindow, NULL);        if (surface == EGL_NO_SURFACE)        {             return EGL_FALSE;        }        // Set the current rendering API (EGL_OPENGL_API, EGL_OPENGL_ES_API,EGL_OPENVG_API)        eRetStatus = eglBindAPI(EGL_OPENGL_ES_API);        if (eRetStatus != EGL_TRUE)        {             return EGL_FALSE;        }        // Create a new EGL rendering context        context = eglCreateContext (display, configs[0], EGL_NO_CONTEXT, context_attribs);        if (context == EGL_NO_CONTEXT)        {             return EGL_FALSE;        }        // Attach an EGL rendering context to EGL surfaces        eRetStatus = eglMakeCurrent (display, surface, surface, context);        if( eRetStatus != EGL_TRUE )        {             return EGL_FALSE;        }        //If interval is set to a value of 0, buffer swaps are not synchronized to a video frame, and the swap happens as soon as the render is complete.        eglSwapInterval(display,0);        // Return the context elements        esContext->eglDisplay = display;        esContext->eglSurface = surface;        esContext->eglContext = context;        return EGL_TRUE;   }   
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

  • 45.

  • 46.

  • 47.

  • 48.

  • 49.

  • 50.

  • 51.

  • 52.

  • 53.

  • 54.

  • 55.

  • 56.

  • 57.

  • 58.

  • 59.

  • 60.

  • 61.

  • 62.

  • 63.

  • 64.

  • 65.

  • 66.

  • 67.

  • 68.

  • 69.

  • 70.

  • 71.

  • 72.

  • 73.

  • 74.

3. 生成Program (第二步曲)

3.1 LoadShader

LoadShader主要实现以下功能:

1) 创建Shader对象

2) 装载Shader源码

3) 编译Shader

其实现参考代码如下:

[cpp]view plaincopy

复制

/* type specifies the Shader type: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER */   GLuint LoadShader ( GLenum type, const char *shaderSrc )   {      GLuint shader;      GLint compiled;            // Create an empty shader object, which maintain the source code strings that define a shader      shader = glCreateShader ( type );      if ( shader == 0 )       return 0;      // Replaces the source code in a shader object      glShaderSource ( shader, 1, &shaderSrc, NULL );            // Compile the shader object      glCompileShader ( shader );      // Check the shader object compile status      glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );      if ( !compiled )       {         GLint infoLen = 0;         glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );                  if ( infoLen > 1 )         {            char* infoLog = malloc (sizeof(char) * infoLen );            glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );            esLogMessage ( "Error compiling shader:\n%s\n", infoLog );                                    free ( infoLog );         }         glDeleteShader ( shader );         return 0;      }      return shader;   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

1)glCreateShader

它创建一个空的shader对象,它用于维护用来定义shader的源码字符串。支持以下两种shader:

(1) GL_VERTEX_SHADER: 它运行在可编程的“顶点处理器”上,用于代替固定功能的顶点处理;

(2) GL_FRAGMENT_SHADER: 它运行在可编程的“片断处理器”上,用于代替固定功能的片段处理;

2)glShaderSource

shader对象中原来的源码全部被新的源码所代替。

3)glCompileShader

编译存储在shader对象中的源码字符串,编译结果被当作shader对象状态的一部分被保存起来,可通过glGetShaderiv函数获取编译状态。

4)glGetShaderiv

获取shader对象参数,参数包括:GL_SHADER_TYPE, GL_DELETE_STATUS, GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH.

3.2 LoadProgram

其参考代码如下:

[cpp]view plaincopy

复制

GLuint LoadProgram ( const char *vShaderStr, const char *fShaderStr )   {      GLuint vertexShader;      GLuint fragmentShader;      GLuint programObject;      GLint linked;      // Load the vertex/fragment shaders      vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );      fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );      // Create the program object      programObject = glCreateProgram ( );      if ( programObject == 0 )         return 0;      // Attaches a shader object to a program object      glAttachShader ( programObject, vertexShader );      glAttachShader ( programObject, fragmentShader );      // Bind vPosition to attribute 0         glBindAttribLocation ( programObject, 0, "vPosition" );      // Link the program object      glLinkProgram ( programObject );      // Check the link status      glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );      if ( !linked )       {         GLint infoLen = 0;         glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );                  if ( infoLen > 1 )         {            char* infoLog = malloc (sizeof(char) * infoLen );            glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );            esLogMessage ( "Error linking program:\n%s\n", infoLog );                                    free ( infoLog );         }         glDeleteProgram ( programObject );         return GL_FALSE;      }          // Free no longer needed shader resources      glDeleteShader ( vertexShader );      glDeleteShader ( fragmentShader );      return programObject;   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

  • 44.

1)glCreateProgram

建立一个空的program对象,shader对象可以被连接到program对像

2)glAttachShader

program对象提供了把需要做的事连接在一起的机制。在一个program中,在shader对象被连接在一起之前,必须先把shader连接到program上。

3)glBindAttribLocation

把program的顶点属性索引与顶点shader中的变量名进行绑定。

4)glLinkProgram

连接程序对象。如果任何类型为GL_VERTEX_SHADER的shader对象连接到program,它将产生在“可编程顶点处理器”上可执行的程 序;如果任何类型为GL_FRAGMENT_SHADER的shader对象连接到program,它将产生在“可编程片断处理器”上可执行的程序。

5)glGetProgramiv

获取program对象的参数值,参数有:GL_DELETE_STATUS, GL_LINK_STATUS,  GL_VALIDATE_STATUS, GL_INFO_LOG_LENGTH, GL_ATTACHED_SHADERS,  GL_ACTIVE_ATTRIBUTES, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,  GL_ACTIVE_UNIFORMS, GL_ACTIVE_UNIFORM_MAX_LENGTH.

3.3 CreateProgram

在3.1中只实现了Shader的编译,在3.2中只实现了Program的链接,现在还缺少真正供进行编译和链接的源码,其参考代码如下:

[cpp]view plaincopy

复制

int CreateProgram(ESContext * esContext)   {        GLuint programObject;        GLbyte vShaderStr[] =           "attribute vec4 vPosition;    \n"         "void main()                  \n"         "{                            \n"         "   gl_Position = vPosition;  \n"         "}                            \n";              GLbyte fShaderStr[] =           "precision mediump float;\n"\         "void main()                                  \n"         "{                                            \n"         "  gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"         "}                                                    \n";              // Create user data        esContext->userData = malloc(sizeof(UserData));       UserData *userData = esContext->userData;       // Load the shaders and get a linked program object       programObject = LoadProgram ( (const char*)vShaderStr, (const char*)fShaderStr );       if(programObject == 0)       {       return GL_FALSE;       }       // Store the program object       userData->programObject = programObject;       // Get the attribute locations       userData->positionLoc = glGetAttribLocation ( g_programObject, "v_position" );       glClearColor ( 0.0f, 0.0f, 0.0f, 1.0f );       return 0;   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

4. 安装并执行Program(第三步) 

[cpp]view plaincopy

复制

void Render ( ESContext *esContext )   {      UserData *userData = esContext->userData;      GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,                               -0.5f, -0.5f, 0.0f,                               0.5f, -0.5f, 0.0f };               // Set the viewport      glViewport ( 0, 0, esContext->width, esContext->height );            // Clear the color buffer      glClear ( GL_COLOR_BUFFER_BIT );      // Use the program object      glUseProgram ( userData->programObject );      // Load the vertex data      glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );      glEnableVertexAttribArray ( 0 );      glDrawArrays ( GL_TRIANGLES, 0, 3 );      eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface); 
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

[cpp]view plaincopy

4.1 glClear

清除指定的buffer到预设值。可清除以下四类buffer:

1)GL_COLOR_BUFFER_BIT

2)GL_DEPTH_BUFFER_BIT

3)GL_ACCUM_BUFFER_BIT

4)GL_STENCIL_BUFFER_BIT

预设值通过glClearColor, glClearIndex, glClearDepth, glClearStencil, 和glClearAccum来设置。

1)gClearColor

指定color buffer的清除值,当调用glClear(GL_COLOR_BUFFER_BIT)时才真正用设定的颜色值清除color buffer。参数值的范围为:0~1。

复制

void glClearColor( GLclampf   red, GLclampf   green,  GLclampf   blue,  GLclampf   alpha);
  • 1.

2)glClearIndex

       指定color index buffer清除值。void glClearIndex( GLfloat   c);

3)glClearDepth

       指定depth buffer的清除值,取值范围为:0~1,默认值为1。

       void glClearDepth( GLclampd   depth);

4)glClearStencil

       指定stencil buffer清除值的索引,初始值为0。void glClearStencil( GLint   s);

5)glClearAccum

       指定accumulation buffer的清除值,初始值为0,取值范围为:-1~1

      void glClearAccum( GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha);

4.2 glUseProgram

安装一个program object,并把它作为当前rendering state的一部分。

1) 当一个可执行程序被安装到vertex processor,下列OpenGL固定功能将被disable:

  • The modelview matrix is not applied to vertex coordinates.

  • The projection matrix is not applied to vertex coordinates.

  • The texture matrices are not applied to texture coordinates.

  • Normals are not transformed to eye coordinates.

  • Normals are not rescaled or normalized.

  • Normalization of GL_AUTO_NORMAL evaluated normals is not performed.

  • Texture coordinates are not generated automatically.

  • Per-vertex lighting is not performed.

  • Color material computations are not performed.

  • Color index lighting is not performed.

  • This list also applies when setting the current raster position.

2)当一个可执行程序被安装到fragment processor,下列OpenGL固定功能将被disable:

  • Texture environment and texture functions are not applied.

  • Texture application is not applied.

  • Color sum is not applied.

  • Fog is not applied.

4.3 glVertexAttribPointer

定义一个通用顶点属性数组。当渲染时,它指定了通用顶点属性数组从索引index处开始的位置和数据格式。其定义如下:

[cpp]view plaincopy

复制

void glVertexAttribPointer(         GLuint   index,           // 指示将被修改的通用顶点属性的索引          GLint   size,             // 指点每个顶点元素个数(1~4)         GLenum   type,            // 数组中每个元素的数据类型          GLboolean   normalized,   //指示定点数据值是否被归一化(归一化<[-1,1]或[0,1]>:GL_TRUE,直接使用:GL_FALSE)         GLsizei   stride,         // 连续顶点属性间的偏移量,如果为0,相邻顶点属性间紧紧相邻          const GLvoid *   pointer);//顶点数组   :其index应该小于#define GL_MAX_VERTEX_ATTRIBS               0x8869
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

4.4glEnableVertexAttribArray

Enable由索引index指定的通用顶点属性数组。

复制

void glEnableVertexAttribArray( GLuint   index); void glDisableVertexAttribArray( GLuint   index); 
  • 1.

  • 2.

默认状态下,所有客户端的能力被disabled,包括所有通用顶点属性数组。如果被Enable,通用顶点属性数组中的值将被访问并被用于rendering,通过调用顶点数组命令:glDrawArrays, glDrawElements, glDrawRangeElements, glArrayElement,  glMultiDrawElements, or glMultiDrawArrays.

4.5 glDrawArrays

 void glDrawArrays( GLenum   mode, 

                                  GLint   first, 

                                  GLsizei   count);

1) mode:指明render原语,如:GL_POINTS,  GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP,  GL_TRIANGLE_FAN, GL_TRIANGLES, GL_QUAD_STRIP, GL_QUADS, 和 GL_POLYGON。

2) first: 指明Enable数组中起始索引。

3) count: 指明被render的原语个数。

可以预先使用单独的数据定义vertex、normal和color,然后通过一个简单的glDrawArrays构造一系列原语。当调用 glDrawArrays时,它使用每个enable的数组中的count个连续的元素,来构造一系列几何原语,从第first个元素开始。

4.6 eglSwapBuffers

把EGL surface中的color buffer提交到native window进行显示。 

EGLBoolean eglSwapBuffers(EGLDisplay display,EGLSurface surface)

5. 协调组织

在前面的描述中,三步曲已经完成了:

1)初始化EGL环境,为绘图做好准备

2)生成Program

3)安装并执行Program

只有这三个关键人物,还不能运行,还需要一个协调组织者。其参考代码如下:   

[cpp]view plaincopy

复制

int main(int argc, char** argv)   {       ESContext esContext;       UserData  userData;       int iFrames;        unsigned long iStartTime,iEndTime;       int iDeltaTime;       memset( &esContext, 0, sizeof( ESContext) );       esContext.userData = &userData;       esContext.width = 1280;       esContext.height = 720;       // Init EGL display, surface and context       if(!InitEGL(&esContext))       {           printf("Init EGL fail\n");           return GL_FALSE;       }       // compile shader, link program        if(!CreateProgram(&esContext))       {           printf("Create Program fail\n");           return GL_FALSE;       }       iStartTime = GetCurTime();       iFrames = 0;       while(1)       {    // render a frame            Render();            iFrames++;                       iEndTime = GetCurTime();       iDeltaTime  = iEndTime - iStartTime;       if(iDeltaTime >= 5000)       {               iStartTime = iEndTime;           float fFrame = iFrames * 1000.0 / iDeltaTime;           iFrames = 0;           printf("Frame.: %f\n", fFrame);       }       }       glDeleteProgram (esContext.userData->programObject);       return GL_TRUE;   }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

  • 21.

  • 22.

  • 23.

  • 24.

  • 25.

  • 26.

  • 27.

  • 28.

  • 29.

  • 30.

  • 31.

  • 32.

  • 33.

  • 34.

  • 35.

  • 36.

  • 37.

  • 38.

  • 39.

  • 40.

  • 41.

  • 42.

  • 43.

http://www.51testing.com/html/88/377588-836167.html

14    2014-04-24 14:00:35    OpenGL ES 2.0 编程