OpenGL ES圖元形式及繪製方式
OpenGL ES的繪製主要涉及到兩個方面,一個是圖元繪製,還有一個是繪製方式。下面我們先以圖元繪製開始,下面再講解繪製順序。
圖元繪製(此處默認使用GLES30.glDrawArrays()函數繪製)
在OpenGL ES中支持的繪製圖元有以下三種:點、線、三角形,每一種圖元都有多種繪製方式,我們都會講解說明。以下是示例代碼,感興趣的可以下載下來看一下。
先上一下我們實例代碼中四個點的座標位置:
//頂點座標數組(每三個一組,共四組,對應四個頂點座標)
val vertexIndexArray = floatArrayOf(
//x,y,z
//左上
-1.0f, 1.0f, 1f,
//右上
1.0f, 1.0f, 1f,
//右下
1.0f, -1.0f, 1f,
//左下
-1.0f, -1.0f, 1f
)
對應的空間座標圖如下:
可能畫的不是很好,見諒啊。
點
點的繪製只有一種即GLES30.GL_POINTS,它會按我們上面定義的順序依次繪製,效果圖如下:
在繪製點的時候有一點需要注意:
在OpenGL ES1.0裏面,在java層是有API可以直接設置點大小的:gl.glPointSize(),這裏的gl爲實現GLSurfaceView.Renderer重寫方法中的GL10,但是從OpenGL ES2.0/3.0開始是沒有這個API的,如果要設置點大小,只能在頂點着色器裏面設置,它提供了內置變量gl_PointSize。具體可以下載上面的Demo,裏面都有詳細的註釋。
線
線的繪製形式有三種:
- GLES30.GL_LINES。以給定的頂點爲依據,每兩個繪製一條直線,頂點數超過會被丟棄,比如五個頂點,那麼第五個不會繪製出來
- GLES30.GL_LINE_STRIP。以給定的頂點爲依據,按照頂點順序連接頂點
- GLES30.GL_LINE_LOOP。以給定的頂點爲依據,按照頂點順序連接頂點,最後會將首尾兩點連接
還是以上面四個點爲例,效果分別如下:
三角形
三角形的繪製形式同樣有三種:
- GL_TRIANGLES。三個點一組,如果不夠三個點就會被丟棄
- GL_TRIANGLE_STRIP。頂點按照順序依次組成三角形繪製,最後實際形成的是一個三角型帶。
- GL_TRIANGLE_FAN。將第一個點作爲中心點,其他點作爲邊緣點,繪製一系列的組成扇形的三角形
以上面的4個頂點爲例,效果如下:
第四個點由於沒有可以拼成的三角形,被丟棄。
繪製方式
繪製同樣的圖元,在OpenGL ES中其實是有多種方式的,下面我們就介紹一下常用的,一些不常用的也會列出,可以自己去查詢:
- glDrawArrays
- glDrawElements
- glDrawRangeElements
- glDrawArraysInstanced(渲染大量類似對象時使用)
- glDrawElementsInstanced(渲染大量類似對象時使用)
我們以1、2爲例,我們上面的效果圖用的都是glDrawArrays,現在我們詳細說明每一個參數的含義:
public static native void glDrawArrays(
//繪製圖元的形式,就是我們上面一節講的GLES30.GL_GL_TRIANGLES、GLES30.GL_POINTS等
int mode,
//第一個頂點索引從多少開始,一般都是從0開始
int first,
//要繪製的頂點個數
int count
)
我們以繪製GL_TRIANGLE_FAN爲例,first設置1,看看效果圖:
我們發現當我們索引從1開始時,三角形少了一個,因爲雖然我們繪製的是四個頂點,可是第一個點並沒有繪製,而是從第二個點開始。
現在說明glDrawElements的參數含義:
public static native void glDrawElements(
//繪製圖元的形式
int mode,
//繪製的頂點個數
int count,
//頂點參數類型,GL_FLOAT、GL_INT、GL_UNSIGNED_SHORT等
int type,
//保存頂點索引數組的緩存數據
java.nio.Buffer indices
)
我們以如下順序作爲索引數組
//頂點繪製索引數組
val vertexIndexArray = shortArrayOf(
//x,y,z
//右上
1,
//右下
2,
//左下
3,
//左上
0
)
此時的效果是:
補充知識點(爲了看代碼不會懵逼)
編寫OpenGL ES程序的大致流程,這個是在所有OpenGL ES項目中都有涉及到的,基本上都是相同的。
創建GLSurface子類
這裏主要是做一些初始化操作,比如初始化版本、初始化渲染器、設置渲染器、設置渲染模式
渲染器的初始化
渲染器爲GLSurfaceView.Renderer的子實現類,主要是重寫三個方法:onSurfaceCreated、onSurfaceChanged、onDrawFrame,在這三個函數中做一些不同的邏輯處理。onSurfaceCreated主要是做一些初始化配置,比如初始化算法實例(算法類裏面會定義頂點相關數據,繪製操作等,相當於把所有的邏輯都放在這裏,當然你也可以不這麼做,按自己的想法來搞)、初始化着色器程序、初始化着色器變量句柄(可以理解爲着色器變量的唯一標識);onSurfaceChanged主要是做視口設置、相機位置設置、投影矩陣設置等;onDrawFrame則是爲着色器傳遞數據,並繪製
算法類實例化時做一些初始化操作–初始化頂點數據、初始化着色器和句柄
初始化頂點數據:這一步其實就是第二步中onSurfaceCreated執行的邏輯,我們在這裏會初始化頂點座標、頂點顏色、頂點紋理、頂點索引、頂點法向量等等
初始化着色器和句柄:這一步也是在第二步中onSurfaceCreated執行的邏輯,我們需要讀取着色器源碼,然後傳遞給相應的API來創建着色器程序,一旦創建成功,我們需要從着色器程序中獲取着色器變量的句柄(可以理解爲着色器變量的唯一標識),後面繪製時我們可以根據這個句柄爲着色器變量傳值
算法類的onCreate方法,對應onSurfaceCreated
這裏我們主要是做設置背景、根據需要開啓一些被禁用的功能(比如深度測試、混合等等)、初始化線程等
算法類的onChange方法,對應onSurfaceChanged
主要是設置視口、設置相機、設置投影等
算法類的onDraw方法,對應onDrawFrame
主要是配置着色器程序、爲着色器變量(句柄)賦值、矩陣變換(平移、旋轉、縮放…)、繪製相應的圖元等
有了上面一個大致順序的說明,在看demo的時候纔不會暈。到這裏也已經差不多了,如有什麼不足之處還請指出,互相學習。