Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android opengl es創建動畫詳解

Android opengl es創建動畫詳解

編輯:關於Android編程

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中的一個,默認值是4 type:指定了數組中每個頂點坐標的數據類型,可取常量:GL_BYTE, GL_SHORT,GL_FIXED,GL_FLOAT; stride:指定了連續頂點間的字節排列方式,如果為0,數組中的頂點就會被認為是按照緊湊方式排列的,默認值為0 pointer:制訂了數組中第一個頂點的首地址,默認值為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.html gl.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;     }   }  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved