本文介紹了OpenGL的幾種繪製方式及各自特色。繪製方式以下:html
當即模式web
顯示列表數組
頂點數組緩存
VBO函數
最直接的方式,傳統的使用glBegin...glEnd繪製的方式,以下所示:優化
glBegin( GL_TRIANGLES ); glVertex3f(-1.0f, -0.5f, -4.0f); glVertex3f( 1.0f, -0.5f, -4.0f); glVertex3f( 0.0f, 0.5f, -4.0f); glEnd();
這種方式效率較低。緣由是code
glVertex函數每次調用只把一個頂點從客戶端(CPU或內存)傳輸到服務端(GPU),而這個傳輸的過程相對於GPU處理數據的過程是很慢的。orm
glVertex函數的調用次數過多htm
將圖形繪製進行預編譯,把繪製好的圖形放到GPU,使用的時候直接調用。內存
初始化函數
displayList = glGenLists( 1 ); //請求顯示列表名稱 glNewList( displayList, GL_COMPILE ); //建立顯示列表 glBegin( GL_TRIANGLES ); glVertex3f(-1.0f, -0.5f, -4.0f); glVertex3f( 1.0f, -0.5f, -4.0f); glVertex3f( 0.0f, 0.5f, -4.0f); glEnd(); glEndList();
渲染函數
glCallList( displayList );
顯示列表的優化策略是將圖形繪製命令集(數據塊)存儲在GPU中,無須CPU到GPU間的數據傳遞,節省了時間。
然而顯示列表雖然提高了繪製速度,可是它一旦建立了就是不可修改的,若是要修改,只能銷燬並從新建立顯示列表,因此它適用於那些靜態的圖形。
將數據保存在數組中,當執行繪製(glDrawArrays或glDrawElements)的時候一次性將數據從CPU傳遞到GPU中。
//初始化頂點數組 GLfloat vertices[ 3 ][3] = {0}; vertices[0][0] = -1.0f; vertices[0][1] = -0.5f; vertices[0][2] = -4.0f; vertices[1][0] = 1.0f; vertices[1][1] = -0.5f; vertices[1][2] = -4.0f; vertices[2][0] = 0.0f; vertices[2][1] = 0.5f; vertices[2][2] = -4.0f; glEnableClientState( GL_VERTEX_ARRAY ); //啓用頂點數組 glVertexPointer( 3, GL_FLOAT, 0, vertices ); //指定數據 glDrawArrays( GL_TRIANGLES, 0, 3); //進行繪圖 glDisableClientState( GL_VERTEX_ARRAY );
頂點數據的優化策略是減小數據從CPU到GPU的傳遞次數,從而節省了時間。可是它仍然有數據的傳遞,因此繪製效率不如顯示列表高。相比於顯示列表它的優勢是數據能夠動態修改。
VBO將頂點數據存儲在GPU緩存中,無須CPU到GPU的數據傳遞,而且能夠動態修改。
初始化函數
//初始化頂點數組 GLfloat vertices[ 3 ][3] = {0}; vertices[0][0] = -1.0f; vertices[0][1] = -0.5f; vertices[0][2] = -4.0f; vertices[1][0] = 1.0f; vertices[1][1] = -0.5f; vertices[1][2] = -4.0f; vertices[2][0] = 0.0f; vertices[2][1] = 0.5f; vertices[2][2] = -4.0f; glewInit(); glGenBuffers( 1, buffer ); //建立緩衝區 //指定緩衝區數據 glBindBuffer( GL_ARRAY_BUFFER, buffer ); glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 3, vertices, GL_DYNAMIC_DRAW );
渲染函數
glBindBuffer( GL_ARRAY_BUFFER, buffer ); //綁定緩衝區 glEnableClientState( GL_VERTEX_ARRAY ); //使用VBO必須開啓頂點數組 glVertexPointer( 3, GL_FLOAT, 0, 0 ); glDrawArrays( GL_TRIANGLES, 0, 3 ); //繪製 glDisableClientState( GL_VERTEX_ARRAY ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); //取消綁定緩衝區
關於VBO的動態修改,能夠將數據映射到客戶端(內存)中,而後再進行修改。如下是一種刷新全部頂點數據的方法。
//初始化新數組 GLfloat newvertices[3][3] = {0}; newvertices[0][0] = 0.0f; newvertices[0][1] = 0.0f; newvertices[0][2] = 50.0f; ... //映射緩衝區 glBindBuffer( GL_ARRAY_BUFFER, buffer] ); glBufferData( GL_ARRAY_BUFFER, sizeof( GLfloat ) * 3* 3, NULL, GL_STREAM_DRAW ); GLvoid* PositionBuffer = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY ); //刷新數據 memcpy( PositionBuffer, newvertices, sizeof( GLfloat ) * 1002 * 3 ); //刷新到VBO glBindBuffer( GL_ARRAY_BUFFER, buffer ); glUnmapBuffer( GL_ARRAY_BUFFER ); glVertexPointer( 3, GL_FLOAT, 0, 0 );
VBO結合了顯示列表與頂點數組的優勢,既在GPU保存數據避免數據傳輸,提升了繪製效率,又能夠動態修改。
[參考]
OpenGL超級寶典(第四版)