在以前的繪製中,咱們都是經過 glDrawArrays
方法來實現的,它會按照咱們傳入的頂點順序和指定的繪製方式進行繪製。java
回顧一下以前提到的繪製類型:git
繪製類型 | 繪製方式 |
---|---|
GL_POINTS | 將傳入的頂點座標做爲單獨的點繪製 |
GL_LINES | 將傳入的座標做爲單獨線條繪製,ABCDEFG六個頂點,繪製AB、CD、EF三條線 |
GL_LINE_STRIP | 將傳入的頂點做爲折線繪製,ABCD四個頂點,繪製AB、BC、CD三條線 |
GL_LINE_LOOP | 將傳入的頂點做爲閉合折線繪製,ABCD四個頂點,繪製AB、BC、CD、DA四條線。 |
GL_TRIANGLES | 將傳入的頂點做爲單獨的三角形繪製,ABCDEF繪製ABC,DEF兩個三角形 |
GL_TRIANGLE_STRIP | 將傳入的頂點做爲三角條帶繪製,ABCDEF繪製ABC,BCD,CDE,DEF四個三角形 |
GL_TRIANGLE_FAN | 將傳入的頂點做爲扇面繪製,ABCDEF繪製ABC、ACD、ADE、AEF四個三角形 |
<!--more-->github
假設要繪製一個立方體,以 GL_TRIANGLES
的類型進行繪製,那麼六個面,每一個面由兩個三角形組成,就得向渲染管線傳入 36 個頂點,36 個頂點按照順序進行繪製,而實際上,一個矩形也就才 8 個頂點而已。緩存
爲了優化繪製的效率,減小數據的傳遞,因而就有了 glDrawElements
繪製方法。微信
glDrawElements
方法仍是須要傳遞頂點數據,但只須要傳遞物體實際上的頂點數據,也就是最少的,不重複的頂點數據。函數
而後再向渲染管線傳遞要繪製的頂點數據的索引,根據索引從頂點數據中取出對應的頂點,而後再按照指定的方式進行繪製。優化
以下圖所示,圖片截自《OpenGL ES 3.x 遊戲開發上卷》:spa
由三個三角形組成的倒置的梯形,實際上只有五個頂點 $ \{v0,v1,v2,v3,v4\}$,所以也只傳遞了五個頂點,接下來就是肯定這個五個頂點的索引順序。code
索引順序和咱們要繪製的方式有很大的關係,不一樣繪製方式的索引順序不一樣。索引
採用 GL_TRIANGLE_STRIP
的類型繪製,那麼索引順序就是 $\{0,1,2,3,4\}$。
具體方法調用狀況代碼:
// 函數原型 public static native void glDrawElements( int mode, // 繪製方式 int count, // 繪製數量 int type, // 索引的數據類型 java.nio.Buffer indices // 索引緩衝 ); // 定義頂點的索引數據 private byte[] front = { // 前面索引 0, 1, 2, 3 }; // 索引數據傳遞到緩衝區 private ByteBuffer frontBuffer = ByteBuffer.allocateDirect(indices.length *Constants.BYTES_PRE_BYTE) .put(indices) frontBuffer.position(0) // glDrawElements 繪製 GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP,front.size,GLES20.GL_UNSIGNED_BYTE, frontBuffer) // glDrawArrays 繪製 // GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
在函數原型中定義了要傳入的參數,根據要繪製的方法和索引緩衝區,找到對應的點進行繪製。
對於繪製時有重複點,採用這種方式,就能夠減小向渲染管線中傳遞重複的點了。
並且,在定義一個頂點時,大都是 float
類型,它是四個字節,而對於繪製量比較小,頂點數量在 byte
所能表達整數範圍內,能夠採用 byte
類型定義索引順序,它只佔一個字節,減小了內存的使用。
glDrawElements
方法的 count
的參數定義了要取多少個索引出來繪製,並且這個繪製是連續的,必需要把 count
數量的頂點繪製完。
這裏就有一個頗有意思的地方了,有一些小遊戲是這樣的:要求一筆繪製完一個形狀,並且不容許交叉。
好比,要求一筆繞過立方體的六個面,並且不容許交叉,這就很難作到的了。
而使用 glDrawElements
方法一樣會這樣,採用索引不能一次不交叉的把圖形所有繪製完,得采起兩次繪製。
好比在實踐繪製一個立方體時,採用了以下的方式:
// 前面索引 private byte[] front = {0, 1, 2, 3}; // 後面索引 private byte[] back = { 4, 5, 6, 7}; // 上面索引 private byte[] top = {0, 1, 4, 5}; // 下面索引 private byte[] bottom = { 2, 3, 6, 7}; // 左面索引 private byte[] left = {0, 4, 2, 6}; // 右側索引 private byte[] right = {1, 5, 3, 7};
把立方體分解成了六個面的內容進行繪製,也就是採用了六個索引緩存。
而對於使用 glDrawArrays
的方式,能夠一次性把全部頂點傳到渲染管線,而且能夠選擇繪製的開始和結尾點,這樣就只要一個緩衝區就行了,不過代碼就是要多佔用內存空間了。
因此說,能用 glDrawElements 方式的仍是要採用的。
具體代碼詳情,能夠參考個人 Github 項目:
https://github.com/glumes/AndroidOpenGLTutorial
歡迎掃描關注微信公衆號:【紙上淺談】,得到最新文章推送~~~