Android apk 里面的畫圖分為2D和3D兩種:2D是由Skia 來實現(xiàn)的,也就是我們在框架圖上看到的SGL,SGL也會調(diào)用部分opengl 的內(nèi)容來實現(xiàn)簡單的3D效果;3D部分是由OpenGL|ES實現(xiàn)的,OpenGL|ES是Opengl的嵌入式版本,我們先了解一下Android apk的幾種畫圖方式,然后再來來看一看這一整套的圖形體系是怎么建立的。
首先畫圖都是針對提供給應(yīng)用 程序的一塊內(nèi)存填充數(shù)據(jù) ,沒去研究過一個Activity是否就對應(yīng)著底層的一個surface,但是應(yīng)該都是對這塊surface內(nèi)存進行操作。因此說穿了就是我們要么調(diào)用2D 的API畫圖,要么調(diào)用3D的API畫圖,然后將畫下來的圖保存在這個內(nèi)存中,最后這個內(nèi)存里面的內(nèi)容會被Opengl渲染以后變?yōu)榭梢栽谄聊簧系南袼匦畔ⅰ?/div>
二、了解了2D,我們再來看看3D的畫圖方式。3D畫圖SDK上講得很簡單,只是提了一個通用的方式,就是繼承一個View,然后在這個View里面獲得 Opengl的句柄進行畫圖,道理應(yīng)該來說是和2D一樣的,差別就是一個是使用2D的API畫圖,一個是使用3D的。不過因為3D openGl|ES具有一套本身的運行機制,比如渲染的過程控制等,因此Android為我們提供了一個專門的用在3D畫圖上的 GLSurfaceView。這個類被放在一個單獨的包android.opengl里面,其中實現(xiàn)了其他View所不具備的操作:
(1) 具有OpenGL|ES調(diào)用過程中的錯誤跟蹤,檢查工具,這樣就方便了Opengl編程過程的debug ;
(2) 所有的畫圖是在一個專門的Surface上進行,這個Surface可以最后被組合到android的View體系中 ;
(3) 它可以根據(jù)EGL的配置來選擇自己的buffer類型,比如RGB565,depth=16 (這里有點疑問,SurfaceHolder的類型是SURFACE_TYPE_GPU,內(nèi)存就是從EGL分配過來的?)
(4) 所有畫圖的操作都通過render來提供,而且render對Opengl的調(diào)用是在一個單獨的線程中
(5) Opengl的運行周期與Activity的生命周期可以協(xié)調(diào)
下面我們再看看利用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) 設(shè)置reander mode,可以為持續(xù)渲染或者根據(jù)命令 來渲染,默認(rèn)是continuous rendering [optional]: setRenderMode(int)
這里有一個要注意的地方就是必須將Opengl的運行和Activity的生命周期綁定在一起,也就是說Activity pause的時候,opengl的渲染也必須pause。另外GLSurfaceView還提供了一個非常實用的線程間交互的函數(shù) 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提供的一個非常值得學(xué)習(xí) 的類,它實際上是一個如何在View中添加畫圖線程的例子,如何在Java 中使用線程的例子,如何添加事件隊列的例子,一個使用SurfaceView畫圖的經(jīng)典Sequence,一個如何定義Debug信息的例子,覺得把它看懂了可以學(xué)到很多知識 ,具體的源碼在:/framworks/base/opengl/java/android/opengl/GLSurfaceView.java 。
3D的內(nèi)容基本到這里基本講完了,剩下的主要是如何使用Opengl API的問題了,可以看看API demo中簡單的立方體,復(fù)雜的可以看看它那個魔方的實現(xiàn)。下面我們總結(jié)一下3D畫圖需要用到的包:
Android.opengl //主要定義了GLSurfaceView
javax.microedition.khronos.egl //java層的egl接口
javax.microedition.khronos.opengles //opengl API
三、了解了2D和3D基本的畫圖方法,我們再回過頭來看看整個Android對Opengl和Skia的調(diào)用層次關(guān)系
3.1、首先來看2D,2D是主要使用的圖形引擎,畢竟3D受制于其過高的硬件要求在手機上使用還是比較少,而且Skia也能部分實現(xiàn)類似于3D的效果,因此可以說SKia實現(xiàn)了Android平臺上絕大多數(shù)的圖形工作。下面我們來看看從應(yīng)用層到底層對skia的調(diào)用關(guān)系:
Android對skia的調(diào)用是一個比較經(jīng)典 的調(diào)用過程,應(yīng)用程序的幾個包是在SDK中提供的;JNI放在框架的JNI目錄下面的Graphic目錄;skia是作為一個第三方組件放在external目錄下面。我們可以稍微了解一下skia的結(jié)構(gòu):
這里主要涉及到的3個庫:
libcorecg.so 包含/skia/src/core的部分內(nèi)容,比如其中的Region,Rect是在SurfaceFlinger里面計算可是區(qū)域的操作基本單位
libsgl.so 包含/skia/src/core|effects|images|ports|utils的部分和全部內(nèi)容,這個實現(xiàn)了skia大部分的圖形效果,以及圖形格式的編解碼
libskiagl.so 包含/skia/src/gl里面的內(nèi)容,主要用來調(diào)用opengl實現(xiàn)部分效果
另外我看到/skia/src中有兩個目錄animator和view沒有寫入makefile的編譯路徑中,我覺得這兩個目錄是很重要的,不知道是現(xiàn)在Android還沒使用到,還是用其他的方式加載進去的。
要想在底層使用skia的接口來畫圖需要全面了解skia的一整套機制,實際上skia開源到現(xiàn)在還沒多久,在網(wǎng)上能找到的資料是也是很粗淺的,如果將來真需要在這方面下功夫肯定是需要一定的工作量的。
3.2、Android對3D的調(diào)用曾經(jīng)讓我迷惑了一段時間,因為在framewoks/base/core/jni這個目錄一直沒找到跟opengl相關(guān)的內(nèi)容,后面去仔細看看opengl里面的內(nèi)容才知道Android把opengl的本地實現(xiàn),JNI,java接口都放在/frameworks /base/opengl下面了,而且它內(nèi)部還帶了一個工具可以生成JNI代碼。
我們來看看opengl的目錄結(jié)構(gòu):
/include 包含egl和gles所有的頭文件
/java/android/opengl 這個目錄包含的就是我們3D畫圖要使用到的GLSurfaceView
/java/com/google/android/gles_jni 這個目錄包含一些自動生成的文件
/java/javax/microedition/khronos/egl 這就是應(yīng)用層使用到的egl接口
/java/javax/microedition/khronos/opengl 這就是應(yīng)用層使用到的opengl接口
/libagl 這個就是opengl主要的實現(xiàn)了
/libs 這里面包含兩個庫的實現(xiàn),一個是libegl.so 還有一個是libGL|ES_CM.so
/tools 在我的理解這就是一個jni的生成工具
Opengl編程誰都知道是一個大工程,我覺得現(xiàn)在對3D的需求應(yīng)該是很低的,很多效果我們使用skia也可以實現(xiàn)。所以我覺得將來的重點應(yīng)該還是放在skia上面。