OpenGL1.0提供了一系列绘制场景的函数,如设置顶点数组,设置颜色,法向量,贴图坐标.这些函数有极大的灵活性,但其缺点也是显而易见的,对于较大场景,需要多次调用这些函数,对效率影响很大.OpenGL后来版本提供了6个用于指定顶点数组的函数.它们是
glVertexPointer();
glNormalPointer();
glColorPointer();
glIndexPointer();
glTexCoordPointer();
glEdgeFlagPointer();
使用前要调用使能函数打开这些状态,使用顶点数组时有一点要注意,打开的数组一定要使用,并且对其指针的设置要正确,不然会导导致程序无法运行
glEnableClientState( enum_value );
enum_value可以是
GL_VERTEX_ARRAY
GL_NORMAL_ARRAY
GL_COLOR_ARRAY
GL_INDEX_ARRAY
GL_TEXTURE_COORD_ARRAY
GL_EDGE_FLAG_ARRAY
下面介绍
void glArrayElement();
void glDrawArrays();
void glDrawElements();
的用法及区别:
对于每一个点都可以看作一个绘制单元glArrayElement( i )把第 i 个绘制单元的点放入缓存进行绘制
glBegin( GL_TRANGLES );
for( int i = 0; i<VERTEX_NUM; ++i )
glArrayElement( i );
glEnd();
glDrawArrays( enum mode, int first, sizei count )对从first开始的count个单元分别调用glArrayElement();缺点是不支持顶点索引
glDrawElements()支持顶点索引
下面介绍VBO的用法
VBO是vertex buffer object的缩写,OpenGL支持直接数数据放进显存,从而大大提高渲染速度,但并非所有显卡都支持VBO,故在使用VBO之前必须查询显卡是否支持:
int isGLExtensionSupported(const char *extension)
{
const GLubyte *extensions = NULL;
const GLubyte *start;
GLubyte *where, *terminator;
/* Extension names should not have spaces. */
where = (GLubyte *) strchr(extension, ' ');
if (where || *extension == '/0')
return 0;
/* It takes a bit of care to be fool-proof about parsing the
OpenGL extensions string. Don't be fooled by sub-strings,
etc. */
extensions = glGetString(GL_EXTENSIONS);
start = extensions;
for (;;)
{
where = ( GLubyte* ) strstr( (const char *) start, extension );
if ( !where ) break;
terminator = where + strlen(extension);
if ( (where == start || *(where - 1) == ' ') && (*terminator == ' ' || *terminator == '/0') )
return 1;
start = terminator;
}
return 0;
}
使用VBO查询字符串为
isVBOSupported = isGLExtensionSupported( "GL_ARB_vertex_buffer_object" )
返回1为支持.
下面声明VBO扩展函数
// VBO Extension Function Pointers
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; // VBO Name Generation Procedure
PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; // VBO Bind Procedure
PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; // VBO Data Loading Procedure
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; // VBO Deletion Procedure
获取函数地址
if( g_fVBOSupported )
{
// Get Pointers To The GL Functions
glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB");
}
至此,就可以使用VBO函数了,
glGenBuffersARB( 1, &m_nVBOVertices ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*3*sizeof(float), m_pVertices, GL_STATIC_DRAW_ARB );
// Generate And Bind The Texture Coordinate Buffer
glGenBuffersARB( 1, &m_nVBOTexCoords ); // Get A Valid Name
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords ); // Bind The Buffer
// Load The Data
glBufferDataARB( GL_ARRAY_BUFFER_ARB, m_nVertexCount*2*sizeof(float), m_pTexCoords, GL_STATIC_DRAW_ARB );
// Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card
delete [] m_pVertices; m_pVertices = NULL;
delete [] m_pTexCoords; m_pTexCoords = NULL;
渲染阶段代码如下:
// Enable Pointers
glEnableClientState( GL_VERTEX_ARRAY ); // Enable Vertex Arrays
glEnableClientState( GL_TEXTURE_COORD_ARRAY ); // Enable Texture Coord Arrays
// Set Pointers To Our Data
if( isVBOSupported )
{
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOVertices );
// Set The Vertex Pointer To The Vertex Buffer
// 这里必须将后面那个指针设为 NULL
glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );
glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nVBOTexCoords );
// Set The TexCoord Pointer To The TexCoord Buffer
// 这里必须将后面那个指针设为 NULL
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
}
else
{
glVertexPointer( 3, GL_FLOAT, 0, g_pMesh->m_pVertices ); // Set The Vertex Pointer To Our Vertex Data
glTexCoordPointer( 2, GL_FLOAT, 0, g_pMesh->m_pTexCoords ); // Set The Vertex Pointer To Our TexCoord Data
}
// Render
//渲染,如果使用索引,则调用glDrawElements(...);
glDrawArrays( GL_TRIANGLES, 0, g_pMesh->m_nVertexCount ); // Draw All Of The Triangles At Once
// Disable Pointers
glDisableClientState( GL_VERTEX_ARRAY ); // Disable Vertex Arrays
glDisableClientState( GL_TEXTURE_COORD_ARRAY ); // Disable Texture Coord Arrays
最后,当场景数据不再需要时,一定要记着释放显存中的数据
unsigned int nBuffers[2] = { m_nVBOVertices, m_nVBOTexCoords };
glDeleteBuffersARB( 2, nBuffers ); // Free The Memory