Android opengl es建立動畫詳解

來源:互聯網
上載者:User

OpenGL(全寫Open Graphics Library)是一個跨語言、跨平台的三維圖象編程介面,同樣他也可以用來建立二維映像。OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL三維圖形 API 的子集,針對手機、PDA和遊戲主機等嵌入式裝置而設計。android 平台上同樣整合了opengl es的開發包,opengl es在android平台上的運用,既有利於充分利用android平台不斷進步的硬體設定,也能為使用者提供更加多姿多彩的視覺體驗。android平台建立三維動畫有二種方式,一種是使用matrix三維變形實現偽3D,一種就是使用opengl建立真3D。使用matrix三維變形,方法簡單,速度快,效率高,但因為其是偽3D,所以拋開視覺感受不談,其缺陷也非常明顯,他沒有真正的3D建模,只是對二維的VIEW做3D移動,大小變換和旋轉等操作,當你需要建立一個旋轉的六面體時,你需要建立六個VIEW,並讓他們實現繞一個虛擬軸做同步旋轉,當這個3D模型有足夠多的面時,其複雜度大大增加了,因為在初始化時需要提前計算每個面的初始位置資訊,旋轉,大小,位移的同步資訊,這對於非矩形的view來說,這種計算相當繁瑣而且易於出錯並且不容易精確,而且目前來看,使用偽3D技術構建規則曲面似乎是難以實現。這時opengl es的優勢相當明顯。你可以建立任意形狀的多面體,只要把VIEW轉為BITMAP為多面體貼圖就行了。android使用opengl ES建立立方體,需要用到下面一些函數。gl.glFrontFace(GL10.GL_CW);  gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);  gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);  gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);   void glFrontFace(GLenum mode);作用是控制多面形的正面是如何決定的。在預設情況下,mode是GL_CCW。一個多邊形有兩個面,每個面使用不同的介質貼圖,旋轉時是可以看到mode的值為:GL_CCW   表示視窗座標上投影多邊形的頂點順序為逆時針方向的表面為正面。GL_CW     表示頂點順序為順時針方向的表面為正面。void glVertexPointer(GLint size,GLenum type,GLsizei stride,const GLvoid * pointer) 作用是指定多面體每個頂點的座標, size:指定了每個頂點對應的座標個數,只能是2,3,4中的一個,預設值是4type:指定了數組中每個頂點座標的資料類型,可取常量:GL_BYTE, GL_SHORT,GL_FIXED,GL_FLOAT;stride:指定了連續頂點間的位元組相片順序,如果為0,數組中的頂點就會被認為是按照緊湊方式排列的,預設值為0pointer:制訂了數組中第一個頂點的首地址,預設值為0,對於我們的android,大家可以不用去管什麼地址的,一般給一個IntBuffer就可以了。需要說明的是第二個參數,一般在android中,會使用 GL10.GL_FIXED和GL10. FLOAT, 整型和浮點型相互對應, 0x10000=1.0f,整型的低八位表示浮點的小數,高八位表示浮點小數部分。而且第四個參數必須是 nativeOrder,如果是直接賦值的數組,需要使用下面代碼轉化        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);          vbb.order(ByteOrder.nativeOrder());          mVertexBuffer = vbb.asIntBuffer();          mVertexBuffer.put(vertices);          mVertexBuffer.position(0);  gl.glColorPointer這個是顏色了,和上一個函數一樣,是指定每個頂點的顏色值,參數結構也類似 gl.glDrawElements這個是用來顯示的,六面體六個面,有12個三角形,每個三角形三個頂點,共36個 這樣就可以得到下面的四面體的類:package com.example.openglactivity; import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.nio.IntBuffer; import javax.microedition.khronos.opengles.GL10; import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.opengl.GLUtils; public class Cube {    private IntBuffer   mVertexBuffer;      private IntBuffer   mColorBuffer;      private ByteBuffer  mIndexBuffer;     // 定義本程式所使用的紋理      private int texture;      public Cube()      {          int one = 0x10000;  //int 10000=1.0f        int vertices[] = {                                  -one, -one, -2000,//-one,  //第三象限                one, -one, -2000,//-one,  //第四象限                one,  one, -2000,//-one,  //第一象限                -one,  one, -2000,//-one,  //第二象限                                -one, -one,  0, //one,  //第三象限                one, -one,  0, //one,  //第四象限                one,  one,  0, //one,  //第一象限                -one,  one,  0, //one,  //第二象限                                      };            int colors[] = {                  0,    0,    0,  one,                  one,  0,    0,  one,                  one,  one,    0,  one,                  0,  one,    0,  one,                                  0,    0,  one,  one,                  one,    0,  one,  one,                  one,  one,  one,  one,                  0,  one,  one,  one,          };            byte indices[] = {                  0, 4, 5,    0, 5, 1,                  1, 5, 6,    1, 6, 2,                  2, 6, 7,    2, 7, 3,                  3, 7, 4,    3, 4, 0,                  4, 7, 6,    4, 6, 5,                  3, 0, 1,    3, 1, 2          };            ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);          vbb.order(ByteOrder.nativeOrder());          mVertexBuffer = vbb.asIntBuffer();          mVertexBuffer.put(vertices);          mVertexBuffer.position(0);            ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);          cbb.order(ByteOrder.nativeOrder());          mColorBuffer = cbb.asIntBuffer();          mColorBuffer.put(colors);          mColorBuffer.position(0);            mIndexBuffer = ByteBuffer.allocateDirect(indices.length);          mIndexBuffer.put(indices);          mIndexBuffer.position(0);      }          public void draw(GL10 gl)      {          gl.glFrontFace(GL10.GL_CW);          gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);          gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);          gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE,             mIndexBuffer);      }     } 這是使用opengl建立的體面體,要匯入android中使用,還需要經過一些步驟,一個是GLSurfaceView,一個是Renderer,Renderer是GLSurfaceView提供的介面,我們需要通過重載Renderer載入我們的四面體,然後通過setRenderer把包含我們六面體Renderer傳給GLSurfaceView,最後通過activity的setContentView把GLSurfaceView設定為activity的內容,代碼如下: myGLRenderer 派生自Renderer,需要實現 Renderer的 onSurfaceCreated, onSurfaceChanged, onDrawFrame三個方法。這是比較重要的,定義了顯示3D模型的環境,顯示方式顯示特效等一系列東西。 onSurfaceCreated和 onSurfaceChanged熟悉surfaceview的人肯定不陌生,他原本就是surfaceview的方法,我們對於3D螢幕初始化,opengl環境設定都會在這兩個函數裡實現,然後就是onDrawFrame,用來顯示,大致來說,應該和view的onDraw差不多的功能,能夠自動適時重新整理。用到的函數是這幾個:gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 設定背景顏色gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 啟動頂點數組支援,類似的函數還有gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);一個啟動法向量支援,一個啟動紋理渲染支援  gl.glViewport(0, 0, width, height);設定顯示地區,一般就是整個螢幕吧 gl.glMatrixMode(GL10.GL_PROJECTION);   gl.glLoadIdentity();                這兩句是設定當前矩陣模式和重載矩陣,不可省略,有三種模式,GL_MODELVIEW,對模型視景矩陣堆棧應用隨後的矩陣操作.GL_PROJECTION,對投影矩陣應用隨後的矩陣操作.GL_TEXTURE,對紋理矩陣堆棧應用隨後的矩陣操作.設定矩陣後必須使用 glLoadIdentity才會生效,該函數的功能是重設當前指定的矩陣為設定矩陣。還有一個函數gluPerspective也很重要,他是建立一個投影矩陣並且與當前矩陣相乘,得到的矩陣設定為當前變換,但要先通過glMatrixMode設定成GL_PROJECTION 投影矩陣才會得到想要的投影矩陣變換。 gl.glFrustumf(-ratio, ratio, -1, 1, 3, 100);  ratio=(float) width / height,所以 glFrustumf是設定長寬比例,因為opengl是按預設的正方形螢幕投影的,這樣當在一個高比寬大的長方形的屏上時,投影的正方形會變成高比寬大的長方形,要真實的投影,需要通過這個函數來校正投投影。GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);  建立觀察者座標系,這裡可以參考下面的文章:http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.htmlgl.glRotatef(ang, 0f, 0.2f, 0f);    這個是對函數進行旋轉,第一個參數是角度,後面三個參數是XYZ三個方向,類似的函數還有gl.glTranslatef(0, 0, -3.5f);移動操作package com.example.openglactivity;import java.nio.Buffer;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;import java.nio.IntBuffer; import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer;import android.opengl.GLU; public class myGLRenderer implements Renderer {    private Cube m_cube;    private float ang = 0.0f;     public myGLRenderer()     {          m_cube = new Cube();           }    @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config) {        // TODO Auto-generated method stub                       gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //設定清除色                   }        @Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        // TODO Auto-generated method stub                     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, 100);  // 根據長寬比設定投影矩陣              }     @Override    public void onDrawFrame(GL10 gl) {        // TODO Auto-generated method stub                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);//清空緩衝          // 設定當前矩陣為模型視圖模式 //        gl.glMatrixMode(GL10.GL_MODELVIEW);          gl.glLoadIdentity();   // reset the matrix to its default state gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);            // 設定視點          GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);          gl.glRotatef(ang, 0f, 0.2f, 0f);              m_cube.draw(gl); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);            gl.glDisableClientState(GL10.GL_COLOR_ARRAY);          ang+=1.0f;              }} myGLSurfaceView類派生自 GLSurfaceView,GLSurfaceView 派生自SurfaceView,這下一切就熟悉了,SurfaceView是為了動畫,特效而設計的高效UI類。 GLSurfaceView是專門為opengl服務的類。這裡也十分簡單。 setRenderer就行了,可以查看setRenderer在 GLSurfaceView裡的實現: public void setRenderer(Renderer renderer) {        checkRenderThreadState();        if (mEGLConfigChooser == null) {            mEGLConfigChooser = new SimpleEGLConfigChooser(true);        }        if (mEGLContextFactory == null) {            mEGLContextFactory = new DefaultContextFactory();        }        if (mEGLWindowSurfaceFactory == null) {            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();        }        mRenderer = renderer;        mGLThread = new GLThread(renderer);        mGLThread.start();    }開了個新線程去操作 renderer。下面是 myGLSurfaceView代碼 package com.example.openglactivity; import android.content.Context;import android.graphics.PixelFormat;import android.opengl.GLSurfaceView;import android.view.KeyEvent; public class myGLSurfaceView extends GLSurfaceView {    private myGLRenderer mrender;     public myGLSurfaceView(Context context) {         super(context);         // TODO Auto-generated constructor stub         //getHolder().setFormat(PixelFormat.TRANSLUCENT);        mrender = new myGLRenderer();         setRenderer(mrender);     }         @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        // TODO Auto-generated method stub        return super.onKeyDown(keyCode, event);    }} 最後看一下 Activity的調用,一切都瞭解了,和調用普通的view沒有區別。package com.example.openglactivity; import android.os.Bundle;import android.app.Activity;import android.view.Menu; public class MainActivity extends Activity {    private myGLSurfaceView mGLSurfaceView;     public static Activity instance = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //setContentView(R.layout.activity_main);        instance = this;        mGLSurfaceView = new myGLSurfaceView(this);         setContentView(mGLSurfaceView);//這裡我們用mGLSurfaceView來替換以前常用的R.layout.main          }        @Override    protected void onDestroy() {        // TODO Auto-generated method stub        instance = null;        super.onDestroy();    }     @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    } } 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.