由于《OpenGL ES 2.0 Programming Guide》原书并没有提供第8章的关于VBO的示例代码,书上的代码也只提到关键的步骤,网上的例子大都不够精简,为了加深理解,遂自己实现了一份最简单的C语言版本,希望能够帮助到同样喜欢OpenGL ES 2.0的同学。
废话不多说,直接上代码:
#include "esUtil.h" typedef struct { // Handle to a program object GLuint programObject; GLint positionLoc; GLint colorLoc; // VertexBufferObject Ids GLuint vboIds[3]; } UserData; #define VERTEX_POS_SIZE 3 // x, y and z #define VERTEX_COLOR_SIZE 4 // r, g, b, and a int Init ( ESContext *esContext ) { UserData *userData = esContext->userData; const char vShaderStr[] = "attribute vec3 a_position; \n" "attribute vec4 a_color; \n" "varying vec4 v_color; \n" "void main() \n" "{ \n" " v_color = a_color; \n" " gl_Position = vec4(a_position, 1.0); \n" "} \n"; const char fShaderStr[] = "precision mediump float; \n" "varying vec4 v_color; \n" "void main() \n" "{ \n" " gl_FragColor = v_color; \n" "} \n" ; GLuint programObject; // Create the program object programObject = esLoadProgram ( vShaderStr, fShaderStr ); if ( programObject == 0 ) { return GL_FALSE; } // Store the program object userData->programObject = programObject; userData->vboIds[0] = 0;// pos userData->vboIds[1] = 0;// color userData->vboIds[2] = 0;// index userData->positionLoc = glGetAttribLocation(userData->programObject, "a_position"); userData->colorLoc = glGetAttribLocation(userData->programObject, "a_color"); glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f ); return GL_TRUE; } void DrawPrimitiveWithVBOs ( ESContext *esContext, GLint numVertices, GLfloat *vertexPosBuf, GLfloat *vertexColorBuf, GLint *vtxStrides, GLint numIndices, GLushort *indices ) { UserData *userData = esContext->userData; // vboIds[0] - used to store vertex position // vboIds[1] - used to store vertex color // vboIds[2] - used to store element indices // run only once if ( userData->vboIds[0] == 0 && userData->vboIds[1] == 0 && userData->vboIds[2] == 0 ) { // Only allocate on the first draw glGenBuffers ( 3, userData->vboIds ); glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] ); glBufferData ( GL_ARRAY_BUFFER, vtxStrides[0] * numVertices, vertexPosBuf, GL_STATIC_DRAW ); glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] ); glBufferData ( GL_ARRAY_BUFFER, vtxStrides[1] * numVertices, vertexColorBuf, GL_STATIC_DRAW ); glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] ); glBufferData ( GL_ELEMENT_ARRAY_BUFFER, sizeof ( GLushort ) * numIndices, indices, GL_STATIC_DRAW ); } glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[0] ); glVertexAttribPointer ( userData->positionLoc, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE, vtxStrides[0], 0 ); glEnableVertexAttribArray ( userData->positionLoc ); glBindBuffer ( GL_ARRAY_BUFFER, userData->vboIds[1] ); glVertexAttribPointer ( userData->colorLoc, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE, vtxStrides[1], 0 ); glEnableVertexAttribArray ( userData->colorLoc ); glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, userData->vboIds[2] ); glDrawElements ( GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0 ); eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); // ☆ // --------------------------------------------------- glDisableVertexAttribArray ( userData->positionLoc ); glDisableVertexAttribArray ( userData->colorLoc ); glBindBuffer ( GL_ARRAY_BUFFER, 0 ); glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, 0 ); } void Draw ( ESContext *esContext ) { UserData *userData = esContext->userData; // 3 vertices, with (x,y,z) ,(r, g, b, a) per-vertex GLfloat vertexPos[3 * VERTEX_POS_SIZE] = { 0.0f, 0.5f, 0.0f, // v0 -0.5f, -0.5f, 0.0f, // v1 0.5f, -0.5f, 0.0f // v2 }; GLfloat color[4 * VERTEX_COLOR_SIZE] = { 1.0f, 0.0f, 0.0f, 1.0f, // c0 0.0f, 1.0f, 0.0f, 1.0f, // c1 0.0f, 0.0f, 1.0f, 1.0f // c2 }; GLint vtxStrides[2] = { VERTEX_POS_SIZE * sizeof ( GLfloat ), VERTEX_COLOR_SIZE * sizeof ( GLfloat ) }; // Index buffer data GLushort indices[3] = { 0, 1, 2 }; //GLfloat *vtxBuf[2] = { vertexPos, color }; glViewport ( 0, 0, esContext->width, esContext->height ); glClear ( GL_COLOR_BUFFER_BIT ); glUseProgram ( userData->programObject ); DrawPrimitiveWithVBOs ( esContext, 3, vertexPos, color, vtxStrides, 3, indices ); } void ShutDown ( ESContext *esContext ) { UserData *userData = esContext->userData; glDeleteProgram ( userData->programObject ); glDeleteBuffers ( 3, userData->vboIds ); } int main ( int argc, char *argv[] ) { ESContext esContext; UserData userData; esInitContext ( &esContext ); esContext.userData = &userData; esCreateWindow ( &esContext, "SimpleVBO", 320, 240, ES_WINDOW_RGB ); if ( !Init ( &esContext ) ) { return GL_FALSE; } esRegisterDrawFunc ( &esContext, Draw ); esMainLoop ( &esContext ); ShutDown ( &esContext ); return GL_TRUE; }