Android使用OpenGL ES需要搭配GLSurfaceView、Renderer,当然也可以使用TextureView,不过TextureView没有GLSurfaceView的OpenGL ES初始化操作,所以使用起来有些麻烦,需要自定义OpenGL初始化,本文使用GLSurfaceView初始化OpenGL ES。

首先讲一下Android中View,GLSurfaceView和TextureView等的区别吧

  • View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢。
  • SurfaceView:基于view视图进行拓展的视图类,更适合2D游戏的开发;**是view的子类,类似使用双缓机制,在新的线程中更新画面,所以刷新界面速度比view快。**其缺点是不能做变形和动画,也不能随屏幕的变化而变化,另外不能在其上面覆盖其它的SurfaceView。
  • GLSurfaceView:是surfaceview的子类,在其基础上封装了egl环境管理,以及render线程。专用于3D游戏开发的视图,OpenGL ES专用
  • TextureView:它也是继承自View,只能运行中硬件加速窗口。它的功能类似于SurfaceView + SurfaceTexture,它内部包含一个SurfaceTexture,它可以让Camera的数据和显示分离,比如需要做二次处理时,如Camera吧采集的数据发送给SurfaceTexture(比如做个美颜),SurfaceTexture处理后传给TextureView显示。TextureView可以做view的变形和动画。一般它是在主线程上做处理(在Android 5.0引入渲染线程后,它是在渲染线程中做的)。

##初始化OpenGL##

一般步骤如下:

  • 创建GLSurfaceView实例
  • 检查设备是否支持OpenGL ES 2.0
  • 配置OpenGL ES
  • 创建Renderer

前三步的代码可参考如下:

@Overrideprotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //实例化一个GLSurfaceView        mGLSurfaceView = new GLSurfaceView(this);        //检查设备是否支持OpenGL ES 2.0        final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();        final boolean supportES2 = configurationInfo.reqGlEsVersion >= 0x00020000;        //配置OpenGL ES,主要是版本设置和设置Renderer,Renderer用于执行OpenGL的绘制        if (supportES2) {            mGLSurfaceView.setEGLContextClientVersion(2);            mGLSurfaceView.setRenderer(new MyRenderer());            renderSet = true;        } else {            Toast.makeText(getApplicationContext(),"不支持OpenGL ES 2.0版本",Toast.LENGTH_SHORT).show();            return;        }//在屏幕上显示GLSurfaceViewsetContentView(mGLSurfaceView);    }

创建Renderer渲染器的代码如下:

public class MyRenderer implements GLSurfaceView.Renderer {        //当Surface创建后会调用此方法        @Override        public void onSurfaceCreated(GL10 gl, EGLConfig config) {            glClearColor(1.0f,0.0f,0.0f,0.0f);//清空屏幕的颜色,本例为红色        }        //当Surface创建成功或尺寸改变时都调用此方法        @Override        public void onSurfaceChanged(GL10 gl, int width, int height) {            glViewport(0,0,width,height);        }        //每绘制一帧都会调用此方法        @Override        public void onDrawFrame(GL10 gl) {            //清空颜色缓冲区,然后使用glClearColor()方法设置填充屏幕的颜色            glClear(GL_COLOR_BUFFER_BIT);        }    }

GL10 gl这个参数是OpenGL ES 1.0遗留下来的,如果使用OpenGL ES 2.0以上版本可以忽略它

现在运行起来屏幕会显示空白的红色窗口,初始化OpenGL就是这么简单

##Renderer子线程原理

之前讲了GLSurfaceView是在新的线程更新画面,也就是执行Renderer,现在通过源码来分析一下是如何做到的。

首先我们给GLSurfaceView设置Renderer渲染器是通过下面这个方法。

mGLSurfaceView.setRenderer(new MyRenderer());

我们进到此方法中,发现它会创建一个GLThread线程并启动

public void setRenderer(Renderer renderer) {        ......        //将renderer赋值给GLSurfaceView的实例变量mRenderer        mRenderer = renderer;        mGLThread = new GLThread(mThisWeakRef);        mGLThread.start();    }

mThisWeakRef是此GLSurfaceView的一个虚引用,防止内存泄露,它是GLSurfaceView的一个实例变量

private final WeakReference mThisWeakRef =            new WeakReference(this);

GLThread线程的run方法会执行guardedRun()方法

   @Override   public void run() {       ......       try {           guardedRun();       } catch (InterruptedException e) {           // fall thru and exit normally       } finally {           sGLThreadManager.threadExiting(this);       }   }

guardedRun方法里面首先会创建一个EglHelper实例,它是用来初始化EGL环境配置的,然后启动一个无限循环

private void guardedRun() throws InterruptedException {    mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);    while (true) {......}}

这个无限循环里面东西很多,核心为一下几块:

  • 初始化EGL环境配置,
mEglHelper = new EglHelper(mGLSurfaceViewWeakRef);......try {    mEglHelper.start();//} catch (RuntimeException t) {    sGLThreadManager.releaseEglContextLocked(this);    throw t;}mHaveEglContext = true;createEglContext = true;
  • 执行Renderer的onSurfaceCreated方法
//如果EGL环境配置好了,会执行onSurfaceCreated()方法,这个方法实际使用时可能会被多次调用,比如设备被唤醒或从别的Activity切换到此Activity时if (createEglContext) {//mGLSurfaceViewWeakRef就是前面的mThisWeakRef,它是GLThread构造函数里面设置的,通过mGLSurfaceViewWeakRef获取到所指的GLSurfaceView   GLSurfaceView view = mGLSurfaceViewWeakRef.get();   if (view != null) {   try {view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);   } finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);   }}    createEglContext = false;}
  • 执行Renderer的onSurfaceChanged方法

当Surface的尺寸改变时就会调用onSurfaceChanged()方法

if (sizeChanged) {    GLSurfaceView view = mGLSurfaceViewWeakRef.get();    if (view != null) {    try {view.mRenderer.onSurfaceChanged(gl, w, h);    } finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);    }    }    sizeChanged = false;}
  • 执行Renderer的onDrawFrame方法

它是在代码块中执行的,也就是说每绘制一帧时都会执行onDrawFrame()方法

{   GLSurfaceView view = mGLSurfaceViewWeakRef.get();   if (view != null) {       try {view.mRenderer.onDrawFrame(gl);       } finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);       }   }}

onDrawFrame()执行之后会交换前后缓冲区。

int swapError = mEglHelper.swap();public int swap() {    if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {        return mEgl.eglGetError();    }    return EGL10.EGL_SUCCESS;}

更多相关文章

  1. android 程序开发的插件化 模块化方法 之一
  2. Android中几种关闭Activity或app的方法
  3. Android主线程、子线程通信(Thread+handler)
  4. Windows下离线安装Android SDK的简单方法
  5. 超详细图文讲解android studio导入第三方类库的方法
  6. Android实现在ServiceManager中加入自定义服务的方法详解

随机推荐

  1. android 单元测试 附源码
  2. 书籍推荐下载
  3. 完美解决Android Studio在写XML布局的时
  4. [Android]Android(安卓)Sqlite3 常用命令
  5. 关于Android在非UI线程更新UI的问题。
  6. android用户界面之菜单(Menu)教程实例汇
  7. Android项目---listview的那些属性,常用却
  8. 【Android】进程间通信IPC——Binder
  9. android怎样实现关闭系统自动旋转屏幕时
  10. android adb和串口调试.