顯示列表可以快速簡單地優化立即模式(glBegin/glEnd)的代碼。在最壞的情況下,顯示列表的命令被預編譯存到命令緩沖區中,然後發送給圖形硬件。在最好的情況下,是編譯後放在圖形硬件中以減少傳輸的帶寬。顯示列表的優化根據實現的不同而有所不同,而且顯示列表一旦被創建就不可以修改,靈活性差。
頂點數組提供了我們想要的靈活性,最壞的結果不過是把數據塊復制給硬件而已(比立即模式快的多)。而索引頂點數組可以減少向硬件傳輸的頂點數據的數量,減少變換的開銷。
OpenGL還提供了一個特性對圖形的吞吐量進行終極的控制。當我們使用頂點數組時,可以把單個數組從客戶內存(CPU可以訪問)傳輸到圖形硬件。這個特性稱為頂點緩沖區對象,允許我們按照類似於管理紋理的方式來管理頂點數組數據,而且頂點緩沖區對象要更靈活。
首先要使用緩沖區對象得有頂點數組。第二步創建頂點緩沖區對象,使用函數:
void glGenBuffers(GLsizei n, GLuint *buffers);
這個函數工作方式像glGenTextures一樣。其對應的刪除緩沖區對象的函數是glDeleteBuffers。
然後綁定頂點緩沖區對象:
void glBindBuffer(GLenum target, GLuint buffer);
這裡的target參數指定了要綁定什麼樣的數組。類型有很多,可以是頂點數組GL_ARRAY_BUFFER,頂點索引數組GL_ELEMENT_ARRAY_BUFFER(用於glDrawElements和其他基於索引的渲染函數)等。
在綁定了緩沖區對象之後,我們就可以往圖形硬件拷貝頂點數組了。
void glBufferData(GLenum target, GLsizeptr size, GLvoid *data, GLenum usage);
target可以是GL_ARRAY_BUFFER或者GL_ELEMENT_ARRAY_BUFFER等。size指定了頂點數組的大小(以字節為單位)。最後一個參數是用法提示。如下表:
用法提示 描述 GL_DYNAMIC_DRAW 存儲在緩沖區對象中的頂點數組經常要更新,並且可能多次作為繪圖的來源。這個提示告訴OpenGL實現把數據放置在更新開銷不大的地方。 GL_STATIC_DRAW 數組很少更新,但可能多次作為繪圖的來源。這個提示告訴OpenGL實現把數據放置在能夠快速渲染但不需要快速更新的地方。 GL_STREAM_DRAW 數據極少變化,並且最多只有幾次作為繪圖的源數據。這個提示告訴OpenGL實現有一些時間敏感的數據(例如動畫)將只使用一次,然後被替換。
從頂點緩沖區對象渲染有兩個地方需要改動。首先,需要在調用glVertexPointer之前綁定緩沖區對象,然後把真實的數組指針改成頂點緩沖區對象的偏移值。例如:
glVertexPointer(3, GL_FLOAT, 0, pVerts);
現在變成了:
glBindBuffer(GL_ARRAY_BUFFER, bufferObjects[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
渲染 就變成了:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferObjects[3]);
glDrawElements(GL_TRIANGLES, nNumIdexes, GL_UNSIGNED_SHORT, 0);
最後一個參數會偏移量。從技術上說,緩沖區對象的這個偏移量基於本地體系結構的NULL指針。在大多數系統中,可設置為0.
生成緩沖區對象標識符glGenBuffers(可選步驟)
綁定一個緩沖區對象,確定它是用於存儲頂點數組還是索引(GL_ARRAY_BUFFER,還是GL_ELEMENT_BUFFER)
請求數據的存儲空間,並且對這些數據元素進行初始化
指定相對於緩沖區起始位置的偏移量。
綁定適當的緩沖區對象,用於渲染。
使用適當的頂點數組渲染函數進行渲染如glDrawArrays glDrawElements
簡單示例:
#include "gltools.h" //宏定義 #define VERTICES 0 #define INDICES 1 #define NUM_BUFFERS 2 //緩沖區標示符 GLuint buffers[NUM_BUFFERS]; static GLfloat cube[]={-1.0f, -1.0f, -5.0f, //前面的正方形 1.0f, -1.0f,-5.0f, 1.0f, 1.0f, -5.0f, -1.0f, 1.0f, -5.0f, -1.0f, -1.0f, -10.0f,//背面的正方形 1.0f, -1.0f, -10.0f, 1.0f, 1.0f, -10.0f, -1.0f, 1.0f, -10.0f}; static GLubyte index[]={0, 1, 2, 3, //前面 0, 3, 7, 4, //左面 5, 6, 2, 1, //右面 7, 6, 5, 4, //後面 3, 2, 6, 7, //上面 1, 0, 4, 5 //地面 }; void SetupRC() { glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //生成緩沖區標示符 glGenBuffers(NUM_BUFFERS, buffers); //綁定緩沖區對象,並設置頂點數組 glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]); glBufferData(GL_ARRAY_BUFFER, sizeof(cube), cube, GL_STATIC_DRAW); glVertexPointer(3, GL_FLOAT, 0, 0); } void RenderScene() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0f, 0.0f, 1.0f); glPushMatrix(); glEnableClientState(GL_VERTEX_ARRAY); //綁定緩沖區對象,並進行渲染 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDICES]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW); glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0); glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); glutSwapBuffers(); } void ChangeSize(GLsizei w, GLsizei h) { if(h == 0) h = 1; glViewport(0, 0, w, h); GLfloat fAspect = (GLfloat)w / (GLfloat)h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(35.0f, fAspect, 1.0f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int args, char* argv[]) { glutInit(&args, argv); glutInitWindowPosition(200, 200); glutInitWindowSize(800, 600); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("VBO"); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); SetupRC(); glutMainLoop(); return 0; }
OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見 http://www.linuxidc.com/Linux/2013-10/91413.htm
OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm
OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm
Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm
OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm
Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm
如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm
更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581