OpenGL编程指南6:顶点数组
生活随笔
收集整理的這篇文章主要介紹了
OpenGL编程指南6:顶点数组
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1.前言
前面的例子中,我們可以看到,OpenGL需要進行大量的函數調用才能完成對幾何圖元的渲染。繪制一個20條邊的多邊形至少需要22個函數調用。首先調用一個glBegin(),然后為每個頂點調用一次函數,最后調用1次glEnd().如果我們還要添加其他的額外信息(如多邊形邊界標志或表面法線),在每個頂點上還要增加函數調用。這可能會成倍地增加渲染幾何物體所需要的函數調用數量。在很多系統中,函數調用具有相當大的開銷,可能會影響應用程序的性能。另一個問題是,相鄰多邊形的共享定點的冗余處理。如上圖所示的立方體具有六個面和8個共享頂點。遺憾的是,如果按照標準方法描述這個物體,每個頂點必須被指定3次,因為每個頂點都在三個面上。這樣就造成了大量的冗余。 幸運的是,OpenGL提供了一些頂點數組函數,允許只用少數幾個數組指定大量的與頂點相關的數據,并用少量函數調用(與頂點數組的數量相仿)訪問這些數據。使用頂點數組函數,一個擁有20條邊的多邊形的頂點可以放在一個數組中,并且只通過1個函數進行調用。其實有其他如文理、法向量等,也可以只通過1個函數進行調用。 把數據放在頂點數組中可以提高應用程序的性能。使用頂點數組可以減少函數的調用次數,從而提高性能,也可以避免共享頂點的冗余處理。
2.頂點數組對幾何圖形渲染步驟
1.激活/啟用最多可達8個數組
每個數組用于存儲不同類型的數據:頂點坐標、表面法線、RGBA顏色、輔助顏色、顏色索引、霧坐標、紋理坐標以及多邊形的邊界標志。 該步驟是調用void?glEnableClientState(GLenum array)函數實現。 array指定了需要啟用的數組。其參數可以是下面常量:GL_VERTEX_ARRAY / GL_COLOR_ARRAY / GL_SECONDARY_COLOR_ARRRAY / GL_INDEX_ARRAY / GL_NORMAL_ARRAY / GL_FOG_COORDINATE_ARRAY / GL_TEXTURE_COORD_ARRAY / GL_EDGE_FLAG_ARRAY. 例如,如果我們需要光照,就可以為每一個頂點定義一條發現向量。這種情況下使用頂點數組時,需要同時激活表面法向數組和頂點坐標數組。 glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); void display(void) { glClear(GL_COLOR_BUFFER_BIT); GLfloat vertices[]={0.25,0.25,0.75,0.25,0.75,0.75,0.25,0.75};GLfloat colors[]={1.0, 0.0, 0.0,1.0, 1.0, 0.0,0.0, 1.0, 0.0,0.0, 0.0, 1.0};glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_COLOR_ARRAY);glVertexPointer(2,GL_FLOAT,0,vertices);glColorPointer (3,GL_FLOAT,0,colors);glBegin(GL_POLYGON); glArrayElement(0);glArrayElement(1);glArrayElement(2);glArrayElement(3);glEnd(); glFlush(); } 輸出結果如下:2.把數據放入數組中
這些數據是通過指針進行訪問的。3.繪制幾何圖形
繪制圖形關鍵點在于“解引用”,而解引用關鍵在于glArrayElement()函數。該函數通常在glBegin()和glEnd()之間調用。否則,glArrayElement()函數就會設置所有啟用數組的當前狀態(頂點除外,因為它不存在當前狀態)。 下面例子展示的是,使用取自啟用的頂點數組的0,3,4號頂點繪制三角形。 glBegin(GL_POLYGON); glArrayElement(0);glArrayElement(2);glArrayElement(3);glEnd(); 輸出結果: 由于glArrayElemrnt()函數對于每個頂點只調用一次,因此它可能減少對函數的調用數量,從而提高程序的整體性能。3.重啟圖元
在OpenGL繪制圖形時,可能需要繪制多個并不相連的圖形。這樣的情況下這幾個圖形沒法被當做一個圖形來處理。也就需要多次調用 DrawArrays 或 DrawElements. 如果圖形很多,可能會需要用一個循環來調用:for (int i = 0; i < num_objects; i++) {glDrawArrays(GL_TRIANGLES,object[n]->first_vertex,object[n]->vertex_count); }每一次調用OpenGL 的繪制函數,都需要一定的資源開銷,如果每一幀調用太多次,會對程序的性能產生較大的影響。提高性能的辦法就是調用一次繪制函數,畫出分散的圖形。
一種方法是使用 glMultiDrawElements 函數來代替舊的繪制函數,可以減少調用次數,僅需調用此函數一次即可。但是這個函數在OpenGL ES 沒有得到支持。而且使用這個函數,仍然需要將每一個分散的圖形維護一組單獨的頂點坐標/紋理坐標,這個是免不了的,這些數據仍然需要分開上傳,還是會消耗一定的資源。針對這種情況使用圖元重啟會更加合適。
3.1 基本介紹
考慮通常的情況,當用戶繪制 GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINE_STRIP, GL_LINE_LOOP 這些圖元時,所有的繪制點按照特定的順序被連起來,以形成一個最終的復雜圖形,也就是說最終的復雜圖形由多個相連的三角形或線段組成。像上面提到的情況,想要繪制分散的圖形,應該怎么辦?圖元重啟(Primitive restart) 允許用戶繪制不連續的、分散的圖形。考慮使用 glDrawElements 函數,繪制時按照indices所指定的頂點的順序來繪制的。此時可以指定某一個值,該值表示一個重啟的標志。遇到這個值的時候,OpenGL不會繪制圖元,而是結束上一段繪制,然后重新啟動新的繪制,也就是說用后面的索引所指定的頂點來從頭繪制一個圖形。
舉個例子:比如指定8為重啟的標志,遇到8就重啟。
上面的是不啟用圖元重啟的情況,即通常的情況。 下面的是啟用圖元重啟的情況,我們可以看到,從9開始,又重新從頭開始繪制Triangle strip了。
3.2 執行過程
指定重啟位置的數值,在桌面版的OpenGL是可以自行設定的,glPrimitiveRestartIndex? 函數指定重啟的標志。在OpenGL ES 無法自行指定,只能用給定的值。首先設置啟用圖元重啟:
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);Fixed index就代表了使用固定的重啟的標志,具體數值和indices內數據類型有關。glDrawElements 的indices參數類型必須是以下的一種:GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT. 那么分別對應的重啟的標志就是 2^8 - 1;2^16 - 1;2^32 - 1;也就是說重啟的標志的數值就是indices數組所能允許的最大值。這個值一般來說是不會被用到的,拿來當標志正好。
所以我們只需要在 indices 里面的合適的位置插入一個標志,然后再調用 glDrawElements 函數即可實現圖元重啟。
下面代碼片段是一個具體的例子:
// Prepare index buffer data (not shown: vertex buffer data, loading vertex and index buffers) GLushort indexData[11] = {0, 1, 2, 3, 4, // triangle strip ABCDE0xFFFF, // primitive restart index (largest possible GLushort value) 5, 6, 7, 8, 9, // triangle strip FGHIJ }; // Draw triangle strips glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); glDrawElements(GL_TRIANGLE_STRIP, 11, GL_UNSIGNED_SHORT, 0);
4.參看資料
[1].Primitive Restart Makes GPGPU Tech Sparkle
[2].Combining Drawing Functions, Combining Geometry Using Primitive
[3].TechniquesforWorkingwithVertexData
總結
以上是生活随笔為你收集整理的OpenGL编程指南6:顶点数组的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 按摩椅控件?
- 下一篇: 目标跟踪:CamShift算法