OpenGL幾種繪製方式

OpenGL幾種繪製方式

本文介紹了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

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超級寶典(第四版)

http://www.songho.ca/opengl/gl_vbo.html

http://www.zwqxin.com/archives/opengl/learn-vbo.html

相關文章
相關標籤/搜索