Chapter 11 It s all about the pipeline: Faster geometry throughput
Outline 三角網格資料結構 一般繪圖方式 硬體加速繪圖方式 Display List Vertex Array 序列式 :gldrawarrays 索引式 :gldrawelements Vertex Buffer Object 序列式 索引式
三角網格資料結構
三角網格資料結構 struct STriangle { float n[3], a[3], b[3], c[3]; }; STriangle * LoadStlBinary(const char * ppathname, int & ntriangles);
一般繪圖方式
一般繪圖方式 glbegin(gl_triangles); for(int i = 0; i < ntriangles; i++) { } glend(); glnormal3fv(triarray[i].n); glvertex3fv(triarray[i].a); glvertex3fv(triarray[i].b); glvertex3fv(triarray[i].c);
Display List 預先將一連串的繪圖指令編譯並儲存, 在需要使用時再行呼叫
Display List 初始化 Gluint _DisplayList = glgenlists(1); glnewlist(_displaylist, GL_COMPILE); ( 一般繪圖方式或想儲存的 OpenGL 函數 ) glendlist(); 繪圖時 glcalllist(_displaylist); 清除 gldeletelists(_displaylist, 1); Display 個數
無法在 Display List 中儲存的 OpenGL 函數
建立多個 Display List GLuint nlist = glgenlists(3); GLuint A_List, B_List, C_List; A_List = nlist; B_List = nlist + 1; C_List = nlist + 2; glnewlist(a_list,cl_compile);. glendlist(); gldeletelists(nlist, 3);
階層式 Display List glnewlist(a); glcalllist(b); gltranslatef(1.0, 0.0, 0.0); glcalllist(c); gltranslatef(1.0, 0.0, 0.0); glcalllist(c); glendlist(); 不能在 glnewlist/glendlist 之間, 包入 glnewlist/glendlist, 但可以 glcalllist 階層限制為 64, 不過這取決於 OpenGL 的實作, 可調用函式來查看階層上限 glgetintegerv(gl_max_list_nesting, GLint *data);
Vertex Array 將 Vertex 資訊存成陣列, 在需要時利用函式呼叫繪出
Vertex Array 1. 啟用 / 關閉 glenableclintstate(glenum array); GL_VERTEX_ARRAY GL_NORMAL_ARRAY 2. 指定 Array 的數據 glvertexpointer(glint size, GLenum type, GLsizei stride, const GLvoid *pointer); size: 每個頂點的座標數量, 必須為 2 3 或 4 type: 座標的數據類型 (GL_SHORT GL_INT ) stride: 連續的頂點之間的偏移量 pointer: 第一個頂點的第一個座標的地址 3. 彩現 (Render)
Vertex Array - 彩現方式 索引式:能隨機呼叫 glarrayelement gldrawelements glmultidrawelements gldrawrangeelements 序列式:只能依序呼叫 gldrawarrays glmultidrawarrays (頂點數量要等於法向量之數量)
Vertex Array - 索引式 以索引值的陣列來指定物件使用的座標點 不必重複儲存重複的座標點 減少傳遞到顯示卡的記憶體量, 以提高運作效率
Vertex Array - 索引式彩現方式 glenableclientstate(gl_vertex_array); glvertexpointer(2, GL_INT, 0, data); glarrayelement glbegin(gl_triangles) glarrayelement(2); glarrayelement(5); glarrayelement(8); glend(); gldrawelements gldrawelements(mode, count, type, index); glmultidrawelements glmultidrawelements(mode, count, type, index, primcount); glbegin(gl_triangles) glvertex2iv(data+(2*2)); glvertex2iv(data+(5*2)); glvertex2iv(data+(8*2)); glend(); glbegin(mode) for(i=0; i<count; i++) glarrayelement(index[i]); glend(); Cubedx.cpp for(i=0; i<primcount; i++) if(count[i]>0) gldrawelements(mode, count[i], type, index[i]);
Vertex Array 序列式彩現方式 gldrawarrays gldrawarrays(mode, first, count); glmultidrawarrays glbegin(mode) for(i=0; i<count; i++) glarrayelement(first+i); glend(); glmultidrawarrays(mode, first, count, primcount); for(i=0; i<primcount; i++) if(count[i]) gldrawarrays(mode, first[i], count[i]);
Vertex Buffer Object 將主記憶體的資料預先放進顯卡記憶體, 需要繪圖時直接繪圖
Vertex Buffer Object VBO 是 OpenGL 提供給使用者的一個將 vertex data( 包含 position, normal vector, color, etc.) 非即時地上傳到顯示卡記憶體的方法 由於 vertex data 是儲存於顯示卡記憶體, 因此, 相較於其他 render 方式, 具有更高的效能 自 OpenGL 1.5 之後成為標準
VBO Step by step 建立 Buffer Object GLuint _VBO[2]; glgenbuffers(2, _VBO); 綁定 Buffer Object glbindbuffer(glenum target, GLuint buffer); Vertex 資料到 Buffer Object 內 glbufferdata(...); 更新 Buffer Object glbuffersubdata(...); glmapbuffer(...) glunmapbuffer(...) 清除 Buffer Object gldeletebuffers(glsizei n, GLuint *buffer);
VBO Bind Buffer glbindbuffer(glenum target, GLuint buffer); target: GL_ARRAY_BUFFER GL_ELEMENT_ARRAY_BUFFER buffer: 指定將綁定的 Buffer Object ( 如 :_VBO[0]) glbindbuffer 有三個功用 當 buffer 為首次使用之非零 UINT 建立一個新的 Buffer Object, 並將 buffer 分配給此 Buffer Object 當作名稱 當綁定到一個以前建立的 Buffer Object, 設定此 Buffer Object 為 Active 當綁定到一個值為零的 buffer 時,OpenGL 會停止使用 Buffer Object
VBO Buffer Data glbufferdata(glenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) 分配 size 個儲存單位 (byte) 的 OpenGL Device Memory, 用於儲存頂點或索引數據 以前所有與當前綁定對象相關聯的數據都將被刪除 target: GL_ARRAY_BUFFER( 頂點數據 ) GL_ELEMENT_ARRAY_BUFFER( 索引數據 ) GL_PIXEL_UNPACK_BUFFER( 傳遞給 OpenGL 的像素數據 ) GL_PIXEL_PACK_BUFFER( 從 OpenGL 獲取的像素數據 ) size : 儲存相關數據所需的記憶體空間 ( 通常是元素個數 各自儲存長度 ) data: 指向主記憶體中相關數據的指標 ( 用於初始化 Buffer Object) usage: GL_STATIC_DRAW GL_DYNAMIC_READ GL_STREAM_COPY STATIC: 在 VBO 中的資料將不會改變 ( 指定一次多次使用 ) DYNAMIC: 資料將經常改變 ( 反覆指定與使用 ) STREAM: 資料在每個 Frame 都會改變 ( 一次指定一次使用 ) DRAW: 資料送到 GPU 繪出 ( 應用程式 GL) READ: 資料會被讀取到應用程式 (GL 應用程式 ) COPY: 資料會被 DRAW 與 READ(GL GL)
VBO Update Buffer void glbuffersubdata(glenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data); 以 data 所指向的資料替換掉 target 所指向的資料, 從 offset 開始的 size 個 byte void *glmapbuffer(glenum target, GLenum access); GLboolean glunmapbuffer(glenum target); 透過 glmapbuffer 取得 buffer 的指標 針對該 buffer 進行修改 調用 glunmapbuffer 通知 OpenGL 已經完成修改