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);
}