安卓中繪製2D、3D圖形
一、概述
偶然看到一個遊戲的人物動畫,聯想到在安卓中繪製3D圖形,因為基本在平時的開發中基本都是用canvas繪製自定義View,很少使用這些圖形的繪製,因此藉此機會練練基本操作,國際慣例看下執行效果
這個gif有BUG,開始我以為沒錄上,所以期動後愣了一會才反應過來,所以有一些卡頓,湊活看吧。。。。
二、OpenGL與OpenGL ES
OpenGl的全稱 Open Graphics Library即開放的圖形介面,它定義了一個跨程式語言、跨平臺的程式設計介面規範,它主要用於三維圖形的繪製,但在手機等手持終端上執行OpenGl有些不太合適,因此安卓系統內建的是OpenGL ES。
三、2D圖形的繪製
先來點簡單的部分,萬一直接來複雜的部分,嚇跑同學怎麼辦。。。
在Activity中使用:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView glSurfaceView = new GLSurfaceView(this);
MyRenderer renderer = new MyRenderer();
glSurfaceView.setRenderer(renderer);
setContentView(glSurfaceView);
}
程式碼很簡單,仔細看程式碼,就可以看出來裡面除了建立GLSurfaceView的物件外,只有MyRenderer,一看便知道基本程式碼中以My開頭的類,都是自己實現的子類,所以2D圖形繪製也一樣,最主要的就是提供一個Renderer;
public class MyRenderer implements GLSurfaceView.Renderer {
public MyRenderer() {
triangleDataBuffer = floatBufferUtil(triangleData);
rectDataBuffer = floatBufferUtil(rectData);
rectDataBuffer2 = floatBufferUtil(rectData2);
pentacleBuffer = floatBufferUtil(pentacle);
triangleColorBuffer = intBufferUtil(triangleColor);
rectColorBuffer = intBufferUtil(rectColor);
}
@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);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
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);
}
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glMatrixMode(GL10.GL_MODELVIEW);
//-------------------------繪製圖形-------------------------
//重置當前的模型試圖矩陣
gl.glLoadIdentity();
//控制圖形中心位置
gl.glTranslatef(-0.32f,0.35f,-1.2f);
//設定定點資料
gl.glVertexPointer(3, GL10.GL_FLOAT,0,triangleDataBuffer);
//設定顏色資料
gl.glColorPointer(4, GL10.GL_FIXED,0,triangleColorBuffer);
//繪製圖形
gl.glDrawArrays(GL10.GL_TRIANGLES,0,3);
gl.glLoadIdentity();
gl.glTranslatef(0.6f,0.8f,-1.5f);
gl.glRotatef(rotate,0f,0f,0.1f);
gl.glVertexPointer(3, GL10.GL_FLOAT,0,rectDataBuffer);
gl.glColorPointer(4, GL10.GL_FIXED,0,rectColorBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
gl.glLoadIdentity();
gl.glTranslatef(-0.4f,-0.5f,-1.5f);
gl.glRotatef(rotate,0f,0.2f,0f);
gl.glVertexPointer(3, GL10.GL_FLOAT,0,rectDataBuffer2);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4);
gl.glLoadIdentity();
gl.glTranslatef(0.4f,-0.5f,-1.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT,0,pentacleBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,5);
gl.glFinish();
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
rotate +=1;
}
建立MyRenderer實現Renderer,重寫
- onDrawFrame(GL10 gl) ;Renderer物件呼叫該方法繪製GLSurfaceView當前幀
- onSurfaceChanged();當GLSurfaceView的大小改變時回撥該方法
onSurfaceCreated();當GLSurfaceView建立時呼叫
具體每個方法詳情請參考上面程式碼中的註釋,這裡偷個懶不想一一解釋了,另外裡面定義兩個方法intBufferUtil()和floatBufferUtil()將矩陣轉換為Buffer:
private IntBuffer intBufferUtil(int[] ints){
IntBuffer mBuffer;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4);
byteBuffer.order(ByteOrder.nativeOrder());
mBuffer = byteBuffer.asIntBuffer();
mBuffer.put(ints);
mBuffer.position(0);
return mBuffer;
}
private FloatBuffer floatBufferUtil(float[] floats){
FloatBuffer mBuffer;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(floats.length*4);
byteBuffer.order(ByteOrder.nativeOrder());
mBuffer = byteBuffer.asFloatBuffer();
mBuffer.put(floats);
mBuffer.position(0);
return mBuffer;
}
到此為止2D圖形繪製完成,離最終目標只差一步,就是讓圖形旋轉起來,其實很簡單就是一個旋轉屬性
gl.glRotatef(rotate,0f,0.2f,0f);
四、3D圖形繪製
只需修改Renderer,其餘像2D圖形繪製一樣,如果我們按前面的過程繪製出3D效果,那麼如何按順序組織三維空間的每個頂點,為了解決此方法,安卓提供了glDrawElements(int mode, int count ,int type, Buffer indices),引數:
- mode; 繪製圖形的型別,GL10.GL_TRIANGLE_STRIP或GL10.GL_TRIANGLE
- count ;頂點數量
- indices;頂點座標資料來源,注意的是一維陣列,每三個數字代表一個頂點
其餘都參照2D,這裡只貼出不一樣的部分:
//重置當前的模型試圖矩陣
gl.glLoadIdentity();
//控制圖形中心位置
gl.glTranslatef(-0.6f,0.0f,-1.5f);
gl.glRotatef(rotate,0f,0.2f,0f);
//設定定點資料
gl.glVertexPointer(3, GL10.GL_FLOAT,0,taperVerticesBuffer);
//設定顏色資料
gl.glColorPointer(4, GL10.GL_FIXED,0,taperColorBuffer);
//繪製圖形
gl.glDrawElements(GL10.GL_TRIANGLE_STRIP,taperFacetsBuffer.remaining(), GL10.GL_UNSIGNED_BYTE,taperFacetsBuffer);
到此大功告成,程式碼很簡單隻做一個簡單的演示;