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();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值