當(dāng)前位置:
首頁(yè) >
OpenGL编程指南6:顶点数组
發(fā)布時(shí)間:2025/3/15
44
豆豆
生活随笔
收集整理的這篇文章主要介紹了
OpenGL编程指南6:顶点数组
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1.前言
前面的例子中,我們可以看到,OpenGL需要進(jìn)行大量的函數(shù)調(diào)用才能完成對(duì)幾何圖元的渲染。繪制一個(gè)20條邊的多邊形至少需要22個(gè)函數(shù)調(diào)用。首先調(diào)用一個(gè)glBegin(),然后為每個(gè)頂點(diǎn)調(diào)用一次函數(shù),最后調(diào)用1次glEnd().如果我們還要添加其他的額外信息(如多邊形邊界標(biāo)志或表面法線),在每個(gè)頂點(diǎn)上還要增加函數(shù)調(diào)用。這可能會(huì)成倍地增加渲染幾何物體所需要的函數(shù)調(diào)用數(shù)量。在很多系統(tǒng)中,函數(shù)調(diào)用具有相當(dāng)大的開(kāi)銷(xiāo),可能會(huì)影響應(yīng)用程序的性能。另一個(gè)問(wèn)題是,相鄰多邊形的共享定點(diǎn)的冗余處理。如上圖所示的立方體具有六個(gè)面和8個(gè)共享頂點(diǎn)。遺憾的是,如果按照標(biāo)準(zhǔn)方法描述這個(gè)物體,每個(gè)頂點(diǎn)必須被指定3次,因?yàn)槊總€(gè)頂點(diǎn)都在三個(gè)面上。這樣就造成了大量的冗余。 幸運(yùn)的是,OpenGL提供了一些頂點(diǎn)數(shù)組函數(shù),允許只用少數(shù)幾個(gè)數(shù)組指定大量的與頂點(diǎn)相關(guān)的數(shù)據(jù),并用少量函數(shù)調(diào)用(與頂點(diǎn)數(shù)組的數(shù)量相仿)訪問(wèn)這些數(shù)據(jù)。使用頂點(diǎn)數(shù)組函數(shù),一個(gè)擁有20條邊的多邊形的頂點(diǎn)可以放在一個(gè)數(shù)組中,并且只通過(guò)1個(gè)函數(shù)進(jìn)行調(diào)用。其實(shí)有其他如文理、法向量等,也可以只通過(guò)1個(gè)函數(shù)進(jìn)行調(diào)用。 把數(shù)據(jù)放在頂點(diǎn)數(shù)組中可以提高應(yīng)用程序的性能。使用頂點(diǎn)數(shù)組可以減少函數(shù)的調(diào)用次數(shù),從而提高性能,也可以避免共享頂點(diǎn)的冗余處理。
2.頂點(diǎn)數(shù)組對(duì)幾何圖形渲染步驟
1.激活/啟用最多可達(dá)8個(gè)數(shù)組
每個(gè)數(shù)組用于存儲(chǔ)不同類型的數(shù)據(jù):頂點(diǎn)坐標(biāo)、表面法線、RGBA顏色、輔助顏色、顏色索引、霧坐標(biāo)、紋理坐標(biāo)以及多邊形的邊界標(biāo)志。 該步驟是調(diào)用void?glEnableClientState(GLenum array)函數(shù)實(shí)現(xiàn)。 array指定了需要啟用的數(shù)組。其參數(shù)可以是下面常量: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. 例如,如果我們需要光照,就可以為每一個(gè)頂點(diǎn)定義一條發(fā)現(xiàn)向量。這種情況下使用頂點(diǎn)數(shù)組時(shí),需要同時(shí)激活表面法向數(shù)組和頂點(diǎn)坐標(biāo)數(shù)組。 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(); } 輸出結(jié)果如下:2.把數(shù)據(jù)放入數(shù)組中
這些數(shù)據(jù)是通過(guò)指針進(jìn)行訪問(wèn)的。3.繪制幾何圖形
繪制圖形關(guān)鍵點(diǎn)在于“解引用”,而解引用關(guān)鍵在于glArrayElement()函數(shù)。該函數(shù)通常在glBegin()和glEnd()之間調(diào)用。否則,glArrayElement()函數(shù)就會(huì)設(shè)置所有啟用數(shù)組的當(dāng)前狀態(tài)(頂點(diǎn)除外,因?yàn)樗淮嬖诋?dāng)前狀態(tài))。 下面例子展示的是,使用取自啟用的頂點(diǎn)數(shù)組的0,3,4號(hào)頂點(diǎn)繪制三角形。 glBegin(GL_POLYGON); glArrayElement(0);glArrayElement(2);glArrayElement(3);glEnd(); 輸出結(jié)果: 由于glArrayElemrnt()函數(shù)對(duì)于每個(gè)頂點(diǎn)只調(diào)用一次,因此它可能減少對(duì)函數(shù)的調(diào)用數(shù)量,從而提高程序的整體性能。3.重啟圖元
在OpenGL繪制圖形時(shí),可能需要繪制多個(gè)并不相連的圖形。這樣的情況下這幾個(gè)圖形沒(méi)法被當(dāng)做一個(gè)圖形來(lái)處理。也就需要多次調(diào)用 DrawArrays 或 DrawElements. 如果圖形很多,可能會(huì)需要用一個(gè)循環(huán)來(lái)調(diào)用:for (int i = 0; i < num_objects; i++) {glDrawArrays(GL_TRIANGLES,object[n]->first_vertex,object[n]->vertex_count); }每一次調(diào)用OpenGL 的繪制函數(shù),都需要一定的資源開(kāi)銷(xiāo),如果每一幀調(diào)用太多次,會(huì)對(duì)程序的性能產(chǎn)生較大的影響。提高性能的辦法就是調(diào)用一次繪制函數(shù),畫(huà)出分散的圖形。
一種方法是使用 glMultiDrawElements 函數(shù)來(lái)代替舊的繪制函數(shù),可以減少調(diào)用次數(shù),僅需調(diào)用此函數(shù)一次即可。但是這個(gè)函數(shù)在OpenGL ES 沒(méi)有得到支持。而且使用這個(gè)函數(shù),仍然需要將每一個(gè)分散的圖形維護(hù)一組單獨(dú)的頂點(diǎn)坐標(biāo)/紋理坐標(biāo),這個(gè)是免不了的,這些數(shù)據(jù)仍然需要分開(kāi)上傳,還是會(huì)消耗一定的資源。針對(duì)這種情況使用圖元重啟會(huì)更加合適。
3.1 基本介紹
考慮通常的情況,當(dāng)用戶繪制 GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINE_STRIP, GL_LINE_LOOP 這些圖元時(shí),所有的繪制點(diǎn)按照特定的順序被連起來(lái),以形成一個(gè)最終的復(fù)雜圖形,也就是說(shuō)最終的復(fù)雜圖形由多個(gè)相連的三角形或線段組成。像上面提到的情況,想要繪制分散的圖形,應(yīng)該怎么辦?圖元重啟(Primitive restart) 允許用戶繪制不連續(xù)的、分散的圖形。考慮使用 glDrawElements 函數(shù),繪制時(shí)按照indices所指定的頂點(diǎn)的順序來(lái)繪制的。此時(shí)可以指定某一個(gè)值,該值表示一個(gè)重啟的標(biāo)志。遇到這個(gè)值的時(shí)候,OpenGL不會(huì)繪制圖元,而是結(jié)束上一段繪制,然后重新啟動(dòng)新的繪制,也就是說(shuō)用后面的索引所指定的頂點(diǎn)來(lái)從頭繪制一個(gè)圖形。
舉個(gè)例子:比如指定8為重啟的標(biāo)志,遇到8就重啟。
上面的是不啟用圖元重啟的情況,即通常的情況。 下面的是啟用圖元重啟的情況,我們可以看到,從9開(kāi)始,又重新從頭開(kāi)始繪制Triangle strip了。
3.2 執(zhí)行過(guò)程
指定重啟位置的數(shù)值,在桌面版的OpenGL是可以自行設(shè)定的,glPrimitiveRestartIndex? 函數(shù)指定重啟的標(biāo)志。在OpenGL ES 無(wú)法自行指定,只能用給定的值。首先設(shè)置啟用圖元重啟:
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);Fixed index就代表了使用固定的重啟的標(biāo)志,具體數(shù)值和indices內(nèi)數(shù)據(jù)類型有關(guān)。glDrawElements 的indices參數(shù)類型必須是以下的一種:GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT. 那么分別對(duì)應(yīng)的重啟的標(biāo)志就是 2^8 - 1;2^16 - 1;2^32 - 1;也就是說(shuō)重啟的標(biāo)志的數(shù)值就是indices數(shù)組所能允許的最大值。這個(gè)值一般來(lái)說(shuō)是不會(huì)被用到的,拿來(lái)當(dāng)標(biāo)志正好。
所以我們只需要在 indices 里面的合適的位置插入一個(gè)標(biāo)志,然后再調(diào)用 glDrawElements 函數(shù)即可實(shí)現(xiàn)圖元重啟。
下面代碼片段是一個(gè)具體的例子:
// 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
總結(jié)
以上是生活随笔為你收集整理的OpenGL编程指南6:顶点数组的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 按摩椅控件?
- 下一篇: 目标跟踪:CamShift算法