美文网首页Android应用Android知识程序员
Android OpenGl ES2.0编程_第一个OpenGL

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

作者: Donkor | 来源:发表于2017-05-13 16:24 被阅读552次

    前言
    最近找工作的朋友,可能在各大招聘网站上投递简历的时候,都会发现。招聘岗位的最下方,有一个加分项“熟悉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();
            }
        }
    }
    
    

    相关文章

      网友评论

      本文标题:Android OpenGl ES2.0编程_第一个OpenGL

      本文链接:https://www.haomeiwen.com/subject/uawxxxtx.html