OpenGL ES 3.0: 圖元重啟(Primitive restart)


背景概述

在OpenGL繪制圖形時,可能需要繪制多個並不相連的圖形。這樣的情況下這幾個圖形沒法被當做一個圖形來處理。也就需要多次調用 DrawArraysDrawElements. 如果圖形很多,可能會需要用一個循環來調用:

for (int i = 0; i < num_objects; i++) {
    glDrawArrays(GL_TRIANGLES,
                object[n]->first_vertex,
                object[n]->vertex_count);
}

每一次調用OpenGL 的繪制函數,都需要一定的資源開銷,如果每一幀調用太多次,會對程序的性能產生較大的影響。提高性能的辦法就是調用一次繪制函數,畫出分散的圖形。

一種方法是使用 glMultiDrawElements 函數來代替舊的繪制函數,可以減少調用次數,僅需調用此函數一次即可。但是這個函數在OpenGL ES 沒有得到支持。而且使用這個函數,仍然需要將每一個分散的圖形維護一組單獨的頂點坐標/紋理坐標,這個是免不了的,這些數據仍然需要分開上傳,還是會消耗一定的資源。針對這種情況使用圖元重啟會更加合適。

圖元重啟介紹

考慮通常的情況,當用戶繪制 GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINE_STRIP, GL_LINE_LOOP 這些圖元時,所有的繪制點按照特定的順序被連起來,以形成一個最終的復雜圖形,也就是說最終的復雜圖形由多個相連的三角形或線段組成。像上面提到的情況,想要繪制分散的圖形,應該怎么辦?

圖元重啟(Primitive restart) 允許用戶繪制不連續的、分散的圖形。考慮使用 glDrawElements 函數,繪制時按照indices所指定的頂點的順序來繪制的。此時可以指定某一個值,該值表示一個重啟的標志。遇到這個值的時候,OpenGL不會繪制圖元,而是結束上一段繪制,然后重新啟動新的繪制,也就是說用后面的索引所指定的頂點來從頭繪制一個圖形。

舉個例子:比如指定8爲重啟的標志,遇到8就重啟。上面的是不啟用圖元重啟的情況,即通常的情況。下面的是啟用圖元重啟的情況,我們可以看到,從9開始,又重新從頭開始繪制Triangle strip了。

編程指南

指定重啟位置的數值,在桌面版的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 ABCDE

    0xFFFF,           // 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);

另外,如果 glDrawElements 的mode是points之類的,那么用不用圖元重啟其實是一樣的,對於性能沒有提高。

參考資料:

Primitive Restart Makes GPGPU Tech Sparkle

Combining Drawing Functions, Combining Geometry Using Primitive

TechniquesforWorkingwithVertexData


免責聲明!

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



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