Android OpenGl ES2.0编程_第一个OpenGL小程序

前言
最近找工作的朋友,可能在各大招聘网站上投递简历的时候,都会发现。招聘岗位的最下方,有一个加分项“熟悉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) {
        //设置视口(viewport)尺寸,告诉OpenGl可以用来渲染的surface的大小
        //Set the OpenGl viewport to fill the entire surface
        gl.glViewport(0, 0, width, height);
    }

在onDrawFrame中调glClear(GL10.GL_COLOR_BUFFER_BIT)清空屏幕。这样会擦出屏幕上的所有颜色,并用之前glClearColor()调用自定义的颜色填充整个屏幕。

    @Override
    public void onDrawFrame(GL10 gl) {
        //清空屏幕,并调用之前glClearColor的颜色填充整个surface
        //clear the rendering surface
        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();
        }
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容