Android OpenGl ES2.0編程_第一個OpenGL小程序

轉載請標明出處:http://blog.csdn.net/donkor_/article/details/71807627

前言
最近找工作的朋友,可能在各大招聘網站上投遞簡歷的時候,都會發現。招聘崗位的最下方,有一個加分項“熟悉OpenGL或者OpenCV優先”。而這個加分項其實就是目前互聯網上特別流行的人臉識別技術編程。百度百科告訴我們“人臉識別,是基於人的臉部特徵信息進行身份識別的一種生物識別技術。用攝像機或攝像頭採集含有人臉的圖像或視頻流,並自動在圖像中檢測和跟蹤人臉,進而對檢測到的人臉進行臉部的一系列相關技術,通常也叫做人像識別、面部識別。”

▲概念要點
在開始編碼之前,這裏先介紹一下概念術語

  • OpenGl 被嚴格定義爲“一種到圖形硬件的軟件接口”。不是一種編程語言,而是一種API(Application Programming Interface,應用程序編程接口)。作爲一種用於實時3D圖形的工業標準API,已經得到了廣泛的認可和接受。
  • 術語“三維”,即3D,指的是被描述或顯示的對象具有三個測量維度:寬度,高度和深度。
  • 渲染,渲染上獲得對三維對象的幾何描述並把它變成屏幕對象的一種行爲。
  • 3D圖形的常見用途:交互遊戲,仿真到科學,醫療或商業用途的數據虛擬

▲新建第一個應用程序FirstOpenGlDemo
在MainActivity中創建GLSurfaceView實例,使用rendererSet記住GLSurfaceView是否處於有效的狀態

private GLSurfaceView glSurfaceView;
private boolean rendererSet = false;

判斷是否支持OpenGl 2.0。獲取設備配置信息,取出reqGlEsVersion 變量檢查OpenGL ES版本號。如果版本號爲0x20000或後續版本,我們就可以使用OpenGl ES2.0的API

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
        boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000
                || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
                && (Build.FINGERPRINT.startsWith("generic")
                || Build.FINGERPRINT.startsWith("unknown")
                || Build.MODEL.contains("google_sdk")
                || Build.MODEL.contains("Emulator")
                || Build.MODEL.contains("Android SDK build for x86")));

爲OpenGL ES 2.0配置渲染表面

if (supportsEs2) {
            //Request an OpenGl ES 2.0 compatible context
            glSurfaceView.setEGLContextClientVersion(2);

            //Assign our renderer
            glSurfaceView.setRenderer(new FirstOpenGlProjectRenderer());
            rendererSet = true;
        } else {
            Toast.makeText(this, "This device does not support OpenGl Es 2.0", Toast.LENGTH_SHORT).show();
        }

使GLSurfaceView顯示在屏幕上

setContentView(glSurfaceView);

▲處理好Android Activity生命週期
他們確保surface視圖正確暫停並繼續後臺渲染線程,同時釋放和續用OpenGl上下文

    @Override
    protected void onPause() {
        super.onPause();
        if (rendererSet) {
            glSurfaceView.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (rendererSet) {
            glSurfaceView.onResume();
        }
    }

在後臺線程中渲染

GLSurfaceView會在一個單獨的線程中調用渲染器的方法。默認情況下,GLSurfaceView會以顯示設備的刷新頻率不斷地渲染,當然,它也可以配置爲按請求渲染,只需要用GlSurfaceView.RENDERMODE_WHEN_DIRTY作爲參數調用GLSurfaceView.setRenderMode()即可。
既然Android的GLSurfaceView在後臺線程中執行渲染,就必須要小心,只能在這個渲染線程中調用OpenGl,在Android主線程中使用UI(用戶界面你)相關的調用;兩個線程之間的通信可以用如下方法:在主線程中的GLSurfaceView實例可以調用queueEvent ()方法傳遞一個Runnable給後臺渲染線程,渲染線程可以調用Activity的runOnUIThread()來傳遞事件(event)給主線程

創建Renderer類
下面先看下渲染器接口定義的方法:

  • onSurfaceCreated(GL10 gl, EGLConfig config)當Surface被創建的時候,GLSurfaceView會調用這個方法;這發生在應用程序第一次運行的時候,並且,當設備被喚醒或者用戶從其他activity切換回來時,這個方法可可能被調用。在實踐中,這意味着,當應用程序運行時,本方法可能會被調用多次。

  • onSurfaceChanged(GL10 gl, int width, int height)在Surface被創建以後,每次Surface尺寸變化時,這個方法都會被GLSurfaceView調用到。在橫屏,豎屏來回切換的時候,Surface尺寸會發生變化

  • onDrawFrame(GL10 gl)當繪製一幀時,這個方法會被GLSurfaceView調用。在這個方法中,我們一定要繪製一些東西,即使只是清空屏幕;因爲,在這個方法返回後,渲染緩衝區會被交換並顯示在屏幕上,如果什麼都沒畫,可能會看到糟糕的閃爍效果。

爲了實現清空屏幕,並調用自定義顏色(紅色)顯示在屏幕上。首先需要新建渲染器FirstOpenGlProjectRenderer類並實現GLSurfaceView.Renderer接口
在onSurfaceCreated()中調用glClearColor(1.0f,0.0f,0.0f,0.0f)設置清屏時屏幕用的顏色。前三個參數爲紅,綠,藍,最後一個爲半透明度或透明度

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    }

在onSurfaceChanged()中調用glViewport(0, 0, width, height)設置視口(viewport)尺寸,告訴OpenGl可以用來渲染的surface的大小

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
    }

在onDrawFrame中調glClear(GL10.GL_COLOR_BUFFER_BIT)清空屏幕。這樣會擦出屏幕上的所有顏色,並用之前glClearColor()調用自定義的顏色填充整個屏幕。

    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    }

運行之後會得到以下頁面

▲這裏需要注意的是,如果使用模擬器運行程序,屏幕無任何渲染效果。eclipse的話需要查看模擬器的配置選項“Use Host GPU”是否已經勾選上。android studio的話需要看下在創建模擬器時,以下選項是否勾選上

▲ 完整代碼:

public class MainActivity extends AppCompatActivity {

    private GLSurfaceView glSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 判斷設備是否支持OpenGl ES 2.0
        if (IsSupported()) {

            // 先建GLSurfaceView實例
            glSurfaceView = new GLSurfaceView(this);

            // 創建渲染器實例
            MyRenderer mRenderer = new MyRenderer();

            // 設置渲染器
            glSurfaceView.setRenderer(mRenderer);

            // 顯示SurfaceView
            setContentView(glSurfaceView);
        }
    }

    private boolean IsSupported() {

        ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
        boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x2000;

        boolean isEmulator = Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
                && (Build.FINGERPRINT.startsWith("generic")
                || Build.FINGERPRINT.startsWith("unknown")
                || Build.MODEL.contains("google_sdk")
                || Build.MODEL.contains("Emulator")
                || Build.MODEL.contains("Android SDK built for x86"));

        supportsEs2 = supportsEs2 || isEmulator;
        return supportsEs2;
    }

    public class MyRenderer implements GLSurfaceView.Renderer {

        // Surface創建的時候調用
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // 設置清屏顏色爲紅色
            gl.glClearColor(1f, 0f, 0f, 0f);

        }

        // Surface改變的的時候調用
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // 設置窗口大小
            gl.glViewport(0, 0, width, height);

        }

        // 在Surface上繪製的時候調用
        @Override
        public void onDrawFrame(GL10 gl) {

            // 清除屏幕
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (glSurfaceView != null) {
            glSurfaceView.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (glSurfaceView != null) {
            glSurfaceView.onResume();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章