天天看點

在Android應用中使用OpenGL

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

}