OpenGL作為強大的圖形接口,可以畫出豐富且動感十足的動畫,但因涉及到很多理論東西和數學知識,是以往往看書能看死一片人,來直接看看源代碼吧,裡面包含了詳細的注解:當然,我們還是先看看效果圖:

首先我們需要實作GLSurfaceView.Renderer這樣一個内部接口來為我們繪制圖形,看源碼AbstractRenderer檔案:
public abstract class AbstractRenderer implements GLSurfaceView.Renderer {
// GL10接口包含了java(TM)程式語言為OpenGL綁定的核心功能
public void onDrawFrame(GL10 gl) {
// glDisable()方法是關閉某些功能,下面這句是關閉抗抖動
gl.glDisable(GL10.GL_DITHER);
// glClear()方法時擦除繪圖表面
// GL_COLOR_BUFFER_BIT --- 顔色緩沖區
// GL_DEPTH_BUFFER_BIT --- 深度緩沖區
// GL_STENCIL_BUFFER_BIT --- 模型緩沖區
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// glMatrixMode指明那個矩陣是目前矩陣
// GL_MODELVIEW --- 應用視圖矩陣堆的後續矩陣操作
// GL_PROJECTION --- 應用投射矩陣堆的後續矩陣操作
// GL_TEXTURE --- 應用文理矩陣堆的後續矩陣操作
// GL_MATRIX_PALETTE_OES --- 啟用矩陣調色闆堆棧擴充,并應用矩陣調色闆堆棧後續操作
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 使用特征矩陣代替目前矩陣
gl.glLoadIdentity();
// 輔助函數,提供一個更直覺的方法來設定modelview變換矩陣,也就是控制照相機的方向
// 前三個浮點參數: 指定觀測點的空間坐标
// 中間三個浮點參數:指定被觀測者物體的參考點的坐标
// 後面三個浮點參數: 指定觀測點方向為“上”的向量
// 注:這些坐标都是采用世界坐标
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// 啟動用戶端的某項功能
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 開始繪畫,叫給子類完成
draw (gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 控制螢幕大小或者相機“膠片”的尺寸
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
//控制視體或縮放級别
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER);
// 當擁有解釋的空間時,GL某些方面的行為可以由hints控制
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glClearColor(.5f, .5f, .5f, 1);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
}
protected abstract void draw (GL10 gl);
}
這樣我們在自定義一個實作類,來繪制我們自己的圖形,SimpleTriangleRender檔案:
public class SimpleTriangleRender extends AbstractRenderer {
// 三角形的三個點
private final static int VERTS = 3;
private FloatBuffer mFVertexBuffer;
private ShortBuffer mIndexBuffer;
public SimpleTriangleRender(Context context) {
// 建立一個位元組緩沖區,每個點有3個浮點值,因為它有三個坐标,每個浮點值占用4位元組,是以需要3 * 4,而一個三角
// 行有3個頂點,故需要3 * 3 * 4個位元組空間來存放
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
// 使用本機位元組順序對緩沖位元組進行排序
vbb.order(ByteOrder.nativeOrder());
// 收集緩沖位元組到本地緩沖區中
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
// 一次放入資料,下同
float[] coords = { -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.0f, 0.5f, 0 };
for (int i = 0; i < VERTS; i++) {
for (int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i * 3 + j]);
}
}
short[] myIndecesArray = { 0, 1, 2 };
for (int i = 0; i < 3; i++) {
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
protected void draw(GL10 gl) {
// 設定目前顔色, R,G,B,alpha
gl.glColor4f(1.0f, 0, 0, 0.5f);
// 定義一個頂點坐标矩陣
// 第一個參數是維數,二維則為2,三維則為3
// 第二個參數表示坐标需要解釋為浮點數
// 第三個參數表示每個點分開的位元組數
// 第四個參數是指向緩沖區的指針
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
// 按照OpenGL ES所支援的一種原始形狀來繪制這些點
// 第一個參數:繪制的幾何圖形
// 第二個參數:指明被渲染的元素個數
// 第三個參數:指向索引指的類型
// 第四個參數:指向索引緩沖區
gl.glDrawElements(GL10.GL_TRIANGLES, VERTS, GL10.GL_UNSIGNED_SHORT,
mIndexBuffer);
}
}
最後我們在Activity中呈現我們所畫出的東西出來,OpenGLTestHarnessActivity檔案:
public class OpenGLTestHarnessActivity extends Activity {
//***************************************
// GLSurfaceView類提供如下功能:
// * 在OpenGL ES和view系統之間建立聯系
// * 使得OpenGL ES可以工作在Activity生命周期中
// * 可以選擇合适的frame buffer像素格式
// * 建立并管理一個單獨的渲染線程,可以實作平滑的動畫
// * 提供debugging工具和API
//***************************************
private GLSurfaceView mTestHarness = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
mTestHarness = new GLSurfaceView(this);
//If no setEGLConfigChooser method is called, then by default the view will choose an RGB_565
//surface with a depth buffer depth of at least 16 bits.
// 無需特殊的EGL配置選擇程式,采用預設的配置即可
mTestHarness.setEGLConfigChooser(false);
// GLSurfaceView.Renderer接口支援使用派生類進行繪制。它允許GLSurfaceView在表面發生改變時調用它來進行繪制,
// 這是程式員通常使用的主要接口
mTestHarness.setRenderer(new SimpleTriangleRender (this));
// 渲染模式 1、GLSurfaceView.RENDERMODE_WHEN_DIRTY --- 通知渲染;一般是等待使用者互動時進行渲染
// 2、GLSurfaceView.RENDERMODE_CONTINUOUSLY --- 持續渲染;大多數3D遊戲都是進行持續渲染的
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
}
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
}
到此基本上就結束了,你可以将OpenGLTestHarnessActivity設定為主Activity,也可以在主Activity中通過Intent來啟動這個Activity,最後看到了結果。
我們總結一下使用OpenGL ES畫圖的基本步驟吧:
* 1、實作Renderer接口
* 2、在呈現器的實作中提供繪圖所必需的Camera設定
* 3、在實作的onDrawFrame方法中提供繪圖代碼
* 4、構造GLSurfaceView
* 5、設定在GLSurfaceView中實作的呈現器
* 6、指定是否需要将GLSurfaceView制作成動畫
* 7、在Activity中将GLSurfaceView設定為内容視圖(也可以在使用正常視圖的地方使用此視圖)