Android基礎系列-----------OpenGL ES(一)

一、OpenGL ES

        OpenGL(全寫Open Graphics Library)是個定義了一個跨編程語言、跨平臺的編程接口的規範,它用於生成二維、三維圖像。這個接口由近三百五十個不同的函數調用組成,用來從簡單的圖元繪製複雜的三維景象。它本身只是協議規範,而不是軟件源碼庫。主要用於pc和工作站。
        OpenGL ES (OpenGL for Embedded Systems) 是一個針對嵌入式應用的,免費的,支持全功能2D、3D的跨平臺API(OpenGL® ES is a royalty-free, cross-platform API for full-function 2D and 3D graphics on embedded systems - including consoles, phones, appliances and vehicles)。
        android中2D向量圖形函數庫使用了Google在05年收購的一家公司提供的引擎叫skia。

二、Android的圖形系統

        Android apk 裏面的畫圖分爲2D和3D兩種:2D是由Skia 來實現的,Skia 也會調用部分opengl 的內容來實現簡單的3D效果;3D部分是由OpenGL|ES實現的,OpenGL|ES是OpenGL的嵌入式版本。先了解一下Android apk的幾種畫圖方式,然後再來來看一看這一整套的圖形體系是怎麼建立的。
      首先畫圖都是針對提供給應用程序的一塊內存填充數據 , 因此說穿了就是要麼調用2D 的API畫圖,要麼調用3D的API畫圖,然後將畫下來的圖保存在這個內存中,最後這個內存裏面的內容會被Opengl渲染以後變爲可以在屏幕上的像素信 息。
      Apk應用主要關心的還是這些API的使用,在Android apk裏面2D畫圖有2種方式 :

      1、Simple Graphics in View

       就是直接使用Android已經實現的一些畫圖操作,比如說images,shapes,colors,pre-defined animation等等,這些簡單的畫圖操作實際上是由skia來提供的2D圖形操作。使用這些預定義好的操作,可以實現諸如貼一張背景圖,畫出簡單形狀,實現一些簡單的動畫之類的操作。這裏的簡單可以這麼理解,就是我們在這裏沒有一筆一畫地構造出一個圖形出來,我們只是把我們的Graphic 資源放入View體系中,由系統 來將這些Graphic畫出來。舉個例子:我們現在在Activity裏面綁定一個ImageView,我們可以設置這 個ImageView的內容是我們的picture,然後我們可以讓這個picture整體顏色上來點藍色調,然後我們還可以爲這個ImageView加 入一個預定義動畫,這樣當系統要顯示這個View的時候就會顯示我們的picture,並且會有動畫,並帶有一個藍色調,我們並沒有自己去定義畫圖操作, 而是將這些內容放入View中,由系統來將這些內容畫出來。這種方式只能畫靜態或者極爲簡單的2D圖畫,對於實時性很強的動畫,高品質的遊戲都是沒法實現的。

      2、Canvas

       Canvas是一個2D的概念,是在Skia中定義的。可以把這個Canvas理解成系統提供給我們的一塊內存區域(但實際上它只是一套畫圖的API,真正的內存是下面的Bitmap),而且它還提供了一整套對這個內存區域進行操作的方法, 所有的這些操作都是畫圖API。也就是說在這種方式下我們已經能一筆一劃或者使用Graphic來畫我們所需要的東西了,要畫什麼要顯示什麼都由我們自己控制。這種方式根據環境還分爲兩種:一種就是使用普通View的canvas畫圖,還有一種就是使用專門的SurfaceView的canvas來畫圖。 兩種的主要是區別就是可以在SurfaceView中定義一個專門的線程來完成畫圖工作,應用程序不需要等待View的刷圖,提高性能。前面一種適合處理量比較小,幀率比較小的動畫,比如說象棋遊戲之類的;而後一種主要用在遊戲,高品質動畫方面的畫圖。下面是這兩種方式的典型sequence :

       2.1、View canvas

      (1)  定義一個自己的View :class your_view extends View{}  ;
      (2)  重載View的onDraw方法:protected void onDraw(Canvas canvas){} ;
      (3)  在onDraw方法中定義你自己的畫圖操作 ;

      2.2、Surface View Canvas

      (1)  定義一個自己的SurfaceView : class your_surfaceview extends SurfaceView  implements SurfaceHolder.Callback() {}  ;
      (2)  實現SurfaceHolder.Callback的3個方法surfaceCreated()   surfaceChanged()   surfaceDestroyed() ;
      (3)  定義自己的專注於畫圖的線程  : class your_thread extends Thread() {} ;
      (4)  重載線程的run()函數  [一般在run中定義畫圖操作,在surfaceCreated中啓動這個線程]
      (5)  畫圖的過程一般是這樣的:
            SurfaceHolder surfaceHolder = getHolder() ;          //取得holder,這個holder主要是對surface操作的適配,用戶不具備對surface操作的權限
            surfaceHolder.addCallback(this) ;                          //註冊實現好的callback
            Canvas canvas = surfaceHolder.lockCanvas() ;      //取得畫圖的Canvas
            /*---------------------------------畫圖
            **-------------------------------- 畫圖結束*/
            surfaceHolder.unlockCanvasAndPost() ;                //提交併顯示      
      以下是2D畫圖用到的包 :
          android.view                   //畫圖是在View中進行的
          android.view.animation         //定義了一些簡單的動畫效果Tween Animation 和 Frame. Animation
          android.graphics                  //定義了畫圖比較通用的API,比如canvas,paint,bitmap等
          android.graphics.drawable       //定義了相應的Drawable(可畫的東西),比如說BitmapDrawable,PictureDrawable等
          android.graphics.drawable.shapes          //定義了一些shape
      3D畫圖SDK上講得很簡單,只是提了一個通用的方式,就是繼承一個View,然後在這個View裏面獲得 Opengl的句柄進行畫圖,道理應該來說是和2D一樣的,差別就是一個是使用2D的API畫圖,一個是使用3D的。不過因爲3D openGl|ES具有一套本身的運行機制,比如渲染的過程控制等,因此Android提供了一個專門的用在3D畫圖上的GLSurfaceView。這個類被放在一個單獨的包android.opengl裏面,其中實現了其他View所不具備的操作:
      (1) 具有OpenGL|ES調用過程中的錯誤跟蹤,檢查工具,這樣就方便了Opengl編程過程的debug ;
      (2) 所有的畫圖是在一個專門的Surface上進行,這個Surface可以最後被組合到android的View體系中 ;
      (3) 它可以根據EGL的配置來選擇自己的buffer類型,比如RGB565,depth=16 (這裏有點疑問,SurfaceHolder的類型是SURFACE_TYPE_GPU,內存就是從EGL分配過來的?)
      (4) 所有畫圖的操作都通過render來提供,而且render對Opengl的調用是在一個單獨的線程中
      (5) Opengl的運行週期與Activity的生命週期可以協調
      下面是利用GLSurface畫3D圖形的一個典型的Sequence
      (1)  選擇EGL配置(就是你畫圖需要的buffer類型) [optional] :
            setEGLConfigChooser(boolean)
            setEGLConfigChooser(EGLConfigChooser) 
            setEGLConfigChooser(int, int, int, int, int, int)
      (2) 選擇是否需要Debug信息 [optional] :
           setDebugFlags(int)
           setGLWrapper(GLSurfaceView.GLWrapper).
      (3) 爲GLSurfaceView註冊一個畫圖的renderer : setRenderer(GLSurfaceView.Renderer)
      (4) 設置reander mode,可以爲持續渲染或者根據命令 來渲染,默認是continuous rendering [optional]: setRenderMode(int)
      這裏有一個要注意的地方就是必須將Opengl的運行和Activity的生命週期綁定在一起,也就是說Activity pause的時候,opengl的渲染也必須pause。另外GLSurfaceView還提供了一個非常實用的線程間交互的函數 queueEvent(Runnable),可以用在主線程和render線程之間的交互,下面就是SDK提供的範例:
     class MyGLSurfaceView extends GLSurfaceView {
     private MyRenderer mMyRenderer;
     public void start() {
         mMyRenderer = ...;
         setRenderer(mMyRenderer);
     }
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             queueEvent(new Runnable() {
                 // This method will be called on the rendering
                 // thread:
                 public void run() {
                     mMyRenderer.handleDpadCenter();
                 }});
             return true;
         }
         return super.onKeyDown(keyCode, event);
      }
   }
     GLSurfaceView是Android提供的一個非常值得學習 的類,它實際上是一個如何在View中添加畫圖線程的例子,如何在Java 中使用線程的例子,如何添加事件隊列的例子,一個使用SurfaceView畫圖的經典Sequence,一個如何定義Debug信息的例子,覺得把它看懂了可以學到很多知識 ,具體的源碼在:/framworks/base/opengl/java/android/opengl/GLSurfaceView.java 。
     如何使用Opengl API的問題了,可以看看API demo中簡單的立方體,複雜的可以看看它那個魔方的實現。下面總結一下3D畫圖需要用到的包:
     Android.opengl     //主要定義了GLSurfaceView
     javax.microedition.khronos.egl   //java層的egl接口
  javax.microedition.khronos.opengles  //opengl API

三、圖形渲染API——EGL

      EGL 是 OpenGL ES 和底層 Native 平臺視窗系統之間的接口。主要提供如下功能:
      1、創建rendering surfaces
       Surface通俗地講就是能夠承載圖形的介質,如一張“畫紙”。只有成功申請到Surface,應用程序才能真正“作圖”到屏幕上。
       2、創造圖形環境(graphics context)        
      EGL 是爲 OpenGL ES 提供平臺獨立性而設計。OpenGL ES 本質上是一個圖形渲染管線的狀態機,而 EGL 則是用於監控這些狀態以及維護 Frame buffer 和其他渲染 Surface 的外部層。EGL 視窗設計是基於人們熟悉的用於 Microsoft Windows ( WGL )和 UNIX ( GLX )上的 OpenGL 的 Native 接口,與後者比較接近。OpenGL ES 圖形管線的狀態被存儲於 EGL 管理的一個 Context 中。 Frame Buffers 和其他繪製 Surfaces 通過 EGL API 創建、管理和銷燬。EGL 同時也控制和提供了對設備顯示和可能的設備渲染配置的訪問。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章