OpenGL ES 2.0 編程三步曲
OpenGL 與 OpenGL ES的關(guān)系OpenGL ES 是基于桌面版本OpenGL 的:
OpenGL ES 1.0 基于OpenGL 1.3 , 在2003年發(fā)布
OpenGL ES 1.1 基于OpenGL 1.5 , 在2004年發(fā)布
OpenGL ES 2.0 基于OpenGL2.0, 在2007年發(fā)布
OpenGL 2.0 向下兼容OpenGL 1.5 而 OpenGL ES 2.0 和OpenGL ES 1.x 不兼容,是兩種完全不同的實現(xiàn)。
1. 保存全局變量的數(shù)據(jù)結(jié)構(gòu)
以下例子程序均基于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;
[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;
2. 初始化EGL渲染環(huán)境和相關(guān)元素(***步曲)
[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;
- }
3. 生成Program (第二步曲)
3.1 LoadShader
LoadShader主要實現(xiàn)以下功能:
1) 創(chuàng)建Shader對象
2) 裝載Shader源碼
3) 編譯Shader
其實現(xiàn)參考代碼如下:
[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)glCreateShader
它創(chuàng)建一個空的shader對象,它用于維護用來定義shader的源碼字符串。支持以下兩種shader:
(1) GL_VERTEX_SHADER: 它運行在可編程的“頂點處理器”上,用于代替固定功能的頂點處理;
(2) GL_FRAGMENT_SHADER: 它運行在可編程的“片斷處理器”上,用于代替固定功能的片段處理;
2)glShaderSource
shader對象中原來的源碼全部被新的源碼所代替。
3)glCompileShader
編譯存儲在shader對象中的源碼字符串,編譯結(jié)果被當(dāng)作shader對象狀態(tài)的一部分被保存起來,可通過glGetShaderiv函數(shù)獲取編譯狀態(tài)。
4)glGetShaderiv
獲取shader對象參數(shù),參數(shù)包括: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)glCreateProgram
建立一個空的program對象,shader對象可以被連接到program對像
2)glAttachShader
program對象提供了把需要做的事連接在一起的機制。在一個program中,在shader對象被連接在一起之前,必須先把shader連接到program上。
3)glBindAttribLocation
把program的頂點屬性索引與頂點shader中的變量名進(jìn)行綁定。
4)glLinkProgram
連接程序?qū)ο?。如果任何類型為GL_VERTEX_SHADER的shader對象連接到program,它將產(chǎn)生在“可編程頂點處理器”上可執(zhí)行的程 序;如果任何類型為GL_FRAGMENT_SHADER的shader對象連接到program,它將產(chǎn)生在“可編程片斷處理器”上可執(zhí)行的程序。
5)glGetProgramiv
獲取program對象的參數(shù)值,參數(shù)有: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中只實現(xiàn)了Shader的編譯,在3.2中只實現(xiàn)了Program的鏈接,現(xiàn)在還缺少真正供進(jìn)行編譯和鏈接的源碼,其參考代碼如下:
[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;
- }
4. 安裝并執(zhí)行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);
[cpp]view plaincopy
4.1 glClear
清除指定的buffer到預(yù)設(shè)值??汕宄韵滤念恇uffer:
1)GL_COLOR_BUFFER_BIT
2)GL_DEPTH_BUFFER_BIT
3)GL_ACCUM_BUFFER_BIT
4)GL_STENCIL_BUFFER_BIT
預(yù)設(shè)值通過glClearColor, glClearIndex, glClearDepth, glClearStencil, 和glClearAccum來設(shè)置。
1)gClearColor
指定color buffer的清除值,當(dāng)調(diào)用glClear(GL_COLOR_BUFFER_BIT)時才真正用設(shè)定的顏色值清除color buffer。參數(shù)值的范圍為:0~1。
- void glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
2)glClearIndex
指定color index buffer清除值。void glClearIndex( GLfloat c);
3)glClearDepth
指定depth buffer的清除值,取值范圍為:0~1,默認(rèn)值為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,并把它作為當(dāng)前rendering state的一部分。
1) 當(dāng)一個可執(zhí)行程序被安裝到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)當(dāng)一個可執(zhí)行程序被安裝到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
定義一個通用頂點屬性數(shù)組。當(dāng)渲染時,它指定了通用頂點屬性數(shù)組從索引index處開始的位置和數(shù)據(jù)格式。其定義如下:
[cpp]view plaincopy
- void glVertexAttribPointer(
- GLuint index, // 指示將被修改的通用頂點屬性的索引
- GLint size, // 指點每個頂點元素個數(shù)(1~4)
- GLenum type, // 數(shù)組中每個元素的數(shù)據(jù)類型
- GLboolean normalized, //指示定點數(shù)據(jù)值是否被歸一化(歸一化<[-1,1]或[0,1]>:GL_TRUE,直接使用:GL_FALSE)
- GLsizei stride, // 連續(xù)頂點屬性間的偏移量,如果為0,相鄰頂點屬性間緊緊相鄰
- const GLvoid * pointer);//頂點數(shù)組
- :其index應(yīng)該小于#define GL_MAX_VERTEX_ATTRIBS 0x8869
4.4glEnableVertexAttribArray
Enable由索引index指定的通用頂點屬性數(shù)組。
- void glEnableVertexAttribArray( GLuint index);
- void glDisableVertexAttribArray( GLuint index);
默認(rèn)狀態(tài)下,所有客戶端的能力被disabled,包括所有通用頂點屬性數(shù)組。如果被Enable,通用頂點屬性數(shù)組中的值將被訪問并被用于rendering,通過調(diào)用頂點數(shù)組命令: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數(shù)組中起始索引。
3) count: 指明被render的原語個數(shù)。
可以預(yù)先使用單獨的數(shù)據(jù)定義vertex、normal和color,然后通過一個簡單的glDrawArrays構(gòu)造一系列原語。當(dāng)調(diào)用 glDrawArrays時,它使用每個enable的數(shù)組中的count個連續(xù)的元素,來構(gòu)造一系列幾何原語,從第first個元素開始。
4.6 eglSwapBuffers
把EGL surface中的color buffer提交到native window進(jìn)行顯示。
EGLBoolean eglSwapBuffers(EGLDisplay display,EGLSurface surface)
5. 協(xié)調(diào)組織
在前面的描述中,三步曲已經(jīng)完成了:
1)初始化EGL環(huán)境,為繪圖做好準(zhǔn)備
2)生成Program
3)安裝并執(zhí)行Program
只有這三個關(guān)鍵人物,還不能運行,還需要一個協(xié)調(diào)組織者。其參考代碼如下:
[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;
- }
http://www.51testing.com/html/88/377588-836167.html