Android OpenGL ES 2.0 初次體驗(yàn)

本文目錄


一. OpenGL ES是什么?
二. OpenGL ES的版本
三. EGL是什么?
四. 需要知道的兩個(gè)方法
五. 在Android中使用OpenGL ES的步驟
六. 例子1:簡(jiǎn)單的程序+修改背景顏色

OpenGL ES是什么?

  • OpenGL(Open Graphics Library): 是用于渲染2D、3D矢量圖形的跨語(yǔ)言、跨平臺(tái)的應(yīng)用程序編程接口(API),使簡(jiǎn)單的圖形構(gòu)建出復(fù)雜的三維景象。
  • OpenGL ES(OpenGl for Embedded System):是 OpenGL三維圖形 API 的子集,針對(duì)手機(jī)、PDA和游戲主機(jī)等嵌入式設(shè)備而設(shè)計(jì),簡(jiǎn)單來(lái)說(shuō)就是OpenGL在移動(dòng)端的閹割版。
image.png

OpenGL ES 的版本

OpenGL ES版本 Android版本 描述
OpenGL ES1.0 Android 1.0+ OpenGL ES 1.x是針對(duì)固定硬件管線(Fixed Pipeline)的,通過(guò)它內(nèi)建的functions來(lái)設(shè)置諸如燈光、vertexes(圖形的頂點(diǎn)數(shù))、顏色和camera。
OpenGL ES2.0 Android 2.2(API 8)+ OpenGL ES 2.x是針對(duì)可編程硬件管線(Programmable Pipeline)的,不兼容OpenGL ES 1.x,需要自己動(dòng)手編寫任何功能。2.0相比于1.0更具靈活性,功能也更強(qiáng)大??梢宰远x頂點(diǎn)和像素計(jì)算,可以讓表現(xiàn)方式更加準(zhǔn)確。
OpenGL ES3.0 Android 4.3(API 18)+ 向下兼容OpenGL ES 2.x,是OpenGL ES2.0的擴(kuò)展,支持許多新的渲染技術(shù)、優(yōu)化和顯示質(zhì)量改進(jìn),包括引入了紋理相關(guān)的新功能,對(duì)著色語(yǔ)言進(jìn)行了重大更新和支持著色器新功能的API特性,引入了與幾何形狀規(guī)范和圖元渲染控制相關(guān)的新功能,引入了新的緩沖區(qū)對(duì)象,增添了許多與屏幕外渲染到幀緩沖區(qū)對(duì)象相關(guān)的新功能。
OpenGL ES3.x Android 5.0 (API 21)+ 向下兼容OpenGL ES3.0/2.0,Android 5.0(API 21)和更高的版本支持這個(gè)API規(guī)范。

EGL是什么?

  • EGL (Embedded Graphics Library):EGL 是連接 OpenGL ES 和本地窗口系統(tǒng)的接口,由于OpenGL ES是跨平臺(tái)的,引入EGL就是為了屏蔽不同平臺(tái)上的區(qū)別。

另外,EGL定義了控制 Displays、Contexts 以及 Surfaces 的統(tǒng)一的平臺(tái)接口,但一般情況在 Android 平臺(tái)上開(kāi)發(fā) OpenGL ES 應(yīng)用,無(wú)需直接使用javax.microedition.khronos.egl 包中的類按照EGL步驟來(lái)使用OpenGL ES繪制圖形,因?yàn)樵贏ndroid平臺(tái)中提供了一個(gè)android.opengl 包,GLSurfaceView類提供了對(duì)Display、Surface 和 Context 的管理,大大簡(jiǎn)化了 OpenGL ES 的程序框架,對(duì)應(yīng)大部分 OpenGL ES開(kāi)發(fā),只需調(diào)用一個(gè)方法來(lái)設(shè)置 OpenGLView 需要的GLSurfaceView.Renderer 即可。

EGL

EGL提供如下機(jī)制

  • 與設(shè)備的原生窗口系統(tǒng)通信
  • 查詢繪圖表面的可用類型和配置
  • 創(chuàng)建繪圖表面
  • 在OpenGL ES 和其他圖形渲染API之間同步渲染
  • 管理紋理貼圖等渲染資源
  • 為了讓OpenGL ES能夠繪制在當(dāng)前設(shè)備上,我們需要EGL作為OpenGL ES與設(shè)備的橋梁。

需要知道的兩個(gè)方法

  • GLSurfaceView:渲染表面類(android.opengl.GLSurfaceView),自動(dòng)負(fù)責(zé)管理EGL執(zhí)行步驟,但用戶需要確定針對(duì)渲染表面 OpenGL ES 的版本,即調(diào)用 setEGLContextClientVersion(int version) 方法。隨后調(diào)用 setRenderer() 方法來(lái)為OpenGLES配置渲染表面。此外還有其他的 setEGL* 方法去配置上下文環(huán)境,例如渲染表面的 RGB 顏色分量的位深。

  • GLSurfaceView.Renderer:渲染器類(android.opengl.GLSurfaceView.Renderer),GLSurfaceView 需要通過(guò)渲染器對(duì)象完成實(shí)際的渲染操作,自定義渲染器對(duì)象需要繼承 Renderer 接口類,并實(shí)現(xiàn)三個(gè)方法:onSurfaceCreated()、onSurfaceChanged()和onDrawFrame()。


在Android中使用OpenGL ES的步驟:

  1. 創(chuàng)建GLSurfaceView組件,使用 Activity 來(lái)顯示 GLSurfaceView 組件。
  2. 為 GLSurfaceView 配置渲染類GLSurfaceView.Renderer,實(shí)現(xiàn)GLSurfaceView.Renderer接口并重寫3個(gè)方法。
    • onSurfaceCreated():當(dāng)Surface被第一次創(chuàng)建或從其他Activity切換回來(lái)都會(huì)調(diào)用此方法,方法中還可以初始化OpenGLES圖形(背景色)。
    • onSurfaceChanged():在Surface被創(chuàng)建后,每次Surface尺寸變化,還有屏幕橫豎切換都會(huì)調(diào)用此方法。
    • onDrawFrame():每繪制一幀都會(huì)調(diào)用此方法,在這個(gè)方法中必須繪制點(diǎn)什么,即使只是清空屏幕。因?yàn)槿绻裁炊紱](méi)畫,會(huì)導(dǎo)致屏幕不斷閃爍。重點(diǎn):此方法是繪制圖形的主要執(zhí)行點(diǎn)。
  3. 調(diào)用GLSurfaceView組件的setRenderer()方法指定Renderer對(duì)象,該Renderer對(duì)象會(huì)完成GLSurfaceView里的3D圖形的繪制。

例子1:簡(jiǎn)單的程序+修改背景顏色 OpenGLESVersion

  1. 創(chuàng)建GLSurfaceView實(shí)例,檢查設(shè)備版本,Activity生命周期,配置上下文。
  2. 創(chuàng)建Renderer類,實(shí)現(xiàn)渲染方法。
  3. 效果展示。

1.創(chuàng)建GLSurfaceView實(shí)例

我們通過(guò) GLSurfaceView 來(lái)初始化 OpenGLES,如配置顯示設(shè)備 Display 以及在后臺(tái)線程中渲染。在此之前,我們需要對(duì)設(shè)備的進(jìn)行版本檢查,以及在 Android Activity 生命周期的維護(hù)、渲染請(qǐng)求方式進(jìn)行配置。最后才會(huì)配置這個(gè) Surface 視圖和傳入自定義 Renderer 類。

public class VersionActivity extends AppCompatActivity {

    private GLSurfaceView surfaceView;
    private boolean rendererSet = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //檢查OpenGl ES版本
        final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();

        //獲取版本號(hào)
        int VersionNum = configurationInfo.reqGlEsVersion;

        //輸出196608 16進(jìn)制=0x30000 3.0版本
        if (VersionNum >= 196608) {
            Toast.makeText(this, "OpenGLES version is 3.0 or more", Toast.LENGTH_SHORT).show();
            rendererSet = true;
            //執(zhí)行3.0版本的方法
        }
        //輸出131072 16進(jìn)制=0x20000 2.0版本
        else if (VersionNum >= 131072 && VersionNum < 196608) {
            Toast.makeText(this, "OpenGLES version is 2.0", Toast.LENGTH_SHORT).show();
            rendererSet = true;
            //執(zhí)行2.0版本的方法, 配置ES 2.0的上下文
            surfaceView = new GLSurfaceView(this);
            //確定針對(duì)渲染表面 OpenGL ES 的版本
            surfaceView.setEGLContextClientVersion(2);
            //1.連續(xù)刷新頻率不停渲染,0.按請(qǐng)求來(lái)渲染
            surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
            surfaceView.setRenderer(new GLES20Renderer());

            setContentView(surfaceView);
        } else {
            Toast.makeText(this, "Current devices do not support OpenGLES", Toast.LENGTH_SHORT).show();
            return;
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        if (rendererSet) {
            surfaceView.onPause();
        }
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (rendererSet) {
            surfaceView.onResume();
        }
    }
}

注意:渲染線程方式setRenderMode:
1.RENDERMODE_CONTINUOUSLY按設(shè)備刷新頻率不斷地渲染。
0.RENDERMODE_WHEN_DIRTY按請(qǐng)求方式來(lái)渲染。

2.創(chuàng)建Renderer類

在GLSurfaceView中傳入了一個(gè)自定義Renderer類,那么Renderer是一個(gè)渲染器,他需要重寫3個(gè)方法來(lái)實(shí)現(xiàn)渲染的整個(gè)過(guò)程。

public class GLES20Renderer implements GLSurfaceView.Renderer {
    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //第一次創(chuàng)建或切換回來(lái)都會(huì)調(diào)用此方法
        GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1);
    }
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //每次Surface尺寸變化,比如屏幕橫豎切換都會(huì)調(diào)用此方法
        GLES20.glViewport(0, 0, width, height);
    }
    @Override
    public void onDrawFrame(GL10 gl) {
        //每繪制一幀都會(huì)調(diào)用此方法
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }
}
  • onSurfaceCreated:其中的glClearColor是設(shè)置清空屏幕用的顏色,四個(gè)參數(shù):紅綠藍(lán)透明,都是float類型,最大值為1,最小值為0。
  • onSurfaceChanged:其中的glViewport是設(shè)置視口的尺寸,告訴OpenGLES用來(lái)顯示Surface的大小。
  • onDrawFrame:其中的glClear(GL_COLOR_BUFFER_BIT)表示清空屏幕,并會(huì)用glClearColor再次填充整個(gè)屏幕。

問(wèn):參數(shù)中的GL10是什么?
GL10是OpenGLES 1.0的API遺留下來(lái)的。但是要編寫使用OpenGLES1.0的渲染器,就用這個(gè)參數(shù)。但是對(duì)于OpenGLES2.0就直接通過(guò)靜態(tài)方法GLES20來(lái)直接獲取。OpenGLES3.0也是直接使用GLES30。

3.結(jié)果

當(dāng)運(yùn)行這個(gè)Activity的時(shí)候,會(huì)看到屏幕渲染上了一層藍(lán)色背景色,這也就是我們?cè)趏nSurfaceCreated中設(shè)置的glClearColor方法。

運(yùn)行效果圖

總結(jié)

這雖然是學(xué)習(xí)OpenGLES20的第一課,只學(xué)習(xí)了GLSurfaceView和Renderer渲染器,但有了整個(gè)程序的大體框架,是最接下來(lái)的學(xué)習(xí)有著大大的幫助。

參考文獻(xiàn)


為什么要使用OpenGL ES

通常來(lái)說(shuō),計(jì)算機(jī)系統(tǒng)中 CPU、GPU 是協(xié)同工作的。CPU 計(jì)算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會(huì)按照 VSync 信號(hào)逐行讀取幀緩沖區(qū)的數(shù)據(jù),經(jīng)過(guò)可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。所以,盡可能讓 CPU 和 GPU 各司其職發(fā)揮作用是提高渲染效率的關(guān)鍵。

正如我們之前提到過(guò),OpenGL 正是給我們提供了訪問(wèn) GPU 的能力,不僅如此,它還引入了緩存(Buffer)這個(gè)概念,大大提高了處理效率。

從一個(gè)內(nèi)存區(qū)域復(fù)制到另一個(gè)內(nèi)存區(qū)域的速度是相對(duì)較慢的,并且在內(nèi)存復(fù)制的過(guò)程中,CPU 和 GPU 都不能處理這區(qū)域內(nèi)存,避免引起錯(cuò)誤。此外,CPU / GPU 執(zhí)行計(jì)算的速度是很快的,而內(nèi)存的訪問(wèn)是相對(duì)較慢的,這也導(dǎo)致處理器的性能處于次優(yōu)狀態(tài),這種狀態(tài)叫做 數(shù)據(jù)饑餓,簡(jiǎn)單來(lái)說(shuō)就是空有一身本事卻無(wú)用武之地。

針對(duì)此,OpenGL 為了提升渲染的性能,為兩個(gè)內(nèi)存區(qū)域間的數(shù)據(jù)交換定義了緩存。緩存是指 GPU 能夠控制和管理的連續(xù) RAM。程序從 CPU 的內(nèi)存復(fù)制數(shù)據(jù)到 OpenGL ES 的緩存。通過(guò)獨(dú)占緩存,GPU 能夠盡可能以有效的方式讀寫內(nèi)存。 這也意味著 GPU 使用緩存中的數(shù)據(jù)工作的同時(shí),運(yùn)行在 CPU 中的程序可以繼續(xù)執(zhí)行。

來(lái)源:http://linbinghe.com/2018/b8f62c8f.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容