1. 程式人生 > >安卓中繪製2D、3D圖形

安卓中繪製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);

到此大功告成,程式碼很簡單隻做一個簡單的演示;