Android為OpenGL ES支援提供了GLSurfaceView元件,這個元件用于顯示3D圖形。GLSurfaceView本身并不提供繪制3D圖形的功能,而是由GLSurfaceView.Renderer來完成了SurfaceView中3D圖形的繪制。
歸納起來,在Android中使用OpenGL ES需要三個步驟:
1、建立GLSurfaceView元件,使用Activity來顯示GLSurfaceView元件。
2、為GLSurfaceView元件建立GLSurfaceView.Renderer執行個體,實作GLSurfaceView.Renderer類時需要實作該接口裡的三個方法:
abstract void onDrawFrame(GL10 gl):Renderer對象調用該方法繪制GLSurfaceView的目前幀。
abstract void onSurfaceChanged(GL10 gl , int width ,int height):當GLSurfaceView的大小改變時回調該方法。
abstract void onSurfaceCreated(GL10 gl , EGLConfig config):當GLSurfaceView被建立時回調該方法。
3、調用GLSurfaceView元件的setRenderer()方法指定Renderer對象,該Renderer對象将會完成GLSurfaceView裡3D圖像的繪制。
從上面的介紹不難看出,實際上繪制3D圖形的難點不是如何使用GLSurfaceView元件,而是如何實作Renderer類。實作Renderer類時需要實作三個方法,這三個方法都有一個GL10形參,它就代表了GLOpen ES的“繪制畫筆”,我們可以把它想象成Swing 2D繪圖中的Graphics,也可以想象成Android 2D繪圖中的Canvas元件-----當我們希望Renderer繪制3D圖形時,實際上是調用GL10的方法來進行繪制的。
當SurfaceView被建立時,系統會回調Renderer對象的onSurfaceCreated()方法,該方法将可以對OpenGL ES執行一些無須任何改變的初始化,例如:
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 關閉抗抖動
gl.glDisable(GL10.GL_DITHER);
//設定系統對透視進行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glClearColor(0, 0, 0, 0);
//設定陰影平滑模式
gl.glShadeModel(GL10.GL_SMOOTH);
//啟用深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
//設定深度測試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
}
GL10就是OpenGL ES的繪圖接口,但實際上他也是GL11的執行個體,可通過(gl Instansof GL11)判斷它是否為GL11接口的執行個體。
glDisable(int cap):該方法用于禁用OpenGL ES某個方面的特性,上例中代碼用于關閉抗抖性,這樣可以提高性能。
glHint(int target , int mode):該方法用于對OpenGL ES某方法進行修正。
clearColor(float red , float green , float blue , float alpha):該方法設定OpenGL ES“清屏”所用的顔色,四個參數分别設定紅、綠、藍、透明度值;0為最小值,1為最大值。例如設定gl.glClearColor(0 , 0 , 0 , 0):就是用黑色“清屏”。
glShadeMode(int mode):該方法用于設定OpenGL ES的陰影模式,此處設為陰影平滑模式。
glEnable(int cap):該方法與glDisable(int cap)方法相對,用于啟用OpenGL ES某方面的特性,此處用于啟動OpenGL ES的深度測試,所謂“深度測試”,就是讓OpenGL ES負責跟蹤每個物體在Z軸上的深度,這樣就可避免後面的物體遮擋前面的物體。
當SurfaceView元件的大小發生改變時,系統會回調Renderer對象的onSurfaceChanged()方法,是以該方法通常用于初始化3D場景。例如如下初始化代碼:
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 設定3D視窗的大小及位置
gl.glViewport(0, 0, width, height);
//将目前矩陣模式設為投影矩陣
gl.glMatrixMode(GL10.GL_PROJECTION);
//初始化機關矩陣
gl.glLoadIdentity();
//計算透視視窗的寬度、高度比
float ratio = (float)width/height;
//調用此方法設定透視視窗的空間大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
上面的方法中用到了GL10的一些初始化方法,此處做簡要說明:
glViewport(int x , int y , int width , int height):設定3D視窗的位置與大小。其中前兩個參數指定該視窗的位置,後兩個參數指定該視窗的寬、高。
glMatrixMode(int mode):設定視圖的矩陣模型。通常可接受GL10.GL_PROJECTION、GL10.GL_MODEVIEW兩個常量值。
當調用glMatrixMode(GL10.GL_PROJECTION):代碼後,指定将螢幕視為透視圖(要想看到逼真的三維物體,這是必要的),這意味着越遠的東西看起來越小;當調用glMatrixMode(GL10.GL_MODEVIEW):代碼後,即将目前矩陣模式設為模型視圖矩陣,這意味着任何新的變換都會影響該矩陣中的所有物體。
glLoadIdentity():相當于reset()方法,用于初始化機關矩陣。
glFrustumf(float left , float right , float bottom , float top , float zNear , float zFar):用于設定透視投影的空間大小。前路兩個參數用于設定X軸上的最小坐标值、最大坐标值;中間兩個參數用于設定Y軸上的最小坐标值、最大坐标值;後面兩個參數用于設定Z軸上所能繪制的場景的深度的最小值、最大值。
注:三維坐标系統與二維坐标系統并不相同,而二維坐标系統上的坐标值通常就直接使用系統的像素數量;但三維坐标系統的坐标值則取決于glFrustumf()方法的設定。
GLSurfaceView上的所有3D圖形都是有Renderer的onDrawFrame(GL10 gl)方法繪制出來的,重寫該方法時就要把所有3D圖形都繪制出來,該方法通常以如下形式開始:
@Override
public void onDrawFrame(GL10 gl) {
// 清除螢幕緩存和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
}