OpenGL幾種繪制方式


OpenGL幾種繪制方式

本文介紹了OpenGL的幾種繪制方式及各自特點。繪制方式如下:

  • 立即模式

  • 顯示列表

  • 頂點數組

  • VBO

1、立即模式

最直接的方式,傳統的使用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();

這種方式效率較低。原因是

  • glVertex函數每次調用只把一個頂點從客戶端(CPU或內存)傳輸到服務端(GPU),而這個傳輸的過程相對於GPU處理數據的過程是很慢的。

  • glVertex函數的調用次數過多

2、顯示列表

將圖形繪制進行預編譯,把繪制好的圖形放到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間的數據傳遞,節省了時間。
然而顯示列表雖然提升了繪制速度,但是它一旦創建了就是不可修改的,如果要修改,只能銷毀並重新創建顯示列表,所以它適用於那些靜態的圖形。

3、頂點數組

將數據保存在數組中,當執行繪制(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的傳遞次數,從而節省了時間。但是它仍然有數據的傳遞,所以繪制效率不如顯示列表高。相比於顯示列表它的優點是數據可以動態修改。

4、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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM