Android OpenGL初探

最近在做一些Android OpenGL相关的工作,作为一名初学者,第一次接触OpenGL难免有点畏惧心理,踩了很多坑。写这篇文章介绍关于OpenGL的一些基础知识,帮助大家能够快速理解。

OpenGL概念:

OpenGL(open Graphics Library):开放图形库,主要用于2D、3D矢量图形的绘制。封装了一些列API用于图像绘制,OpenGL具有非常好的跨平台性,可在windows、linux、MacOS上使用,它依赖于硬件的支持,能够通过GPU高效绘制各种图形和动画。

Android OpenGL ES:

Android的OpenGL ES库中封装了大量API,对OpenGL绘制操作提供了非常好的支持。App开发者可以通过这些接口实现OpenGL的绘制,其实这些接口底层都是通过native方法调用OpenGL库的API。应用开发者只需要理解上层接口的含义、参数的意义,就可以完成简单的绘制,对于开发者来说相当友好。

EGL相关概念:

EGL是Android为OpenGL ES提供平台独立性而设计的,上面我们提到过,OpenGL其实是通过GPU进行渲染。但是我们的程序是运行在CPU上,要与GPU关联,就需要通过EGL,它相当于Android上层应用与GPU通讯的中间层。 要在Android平台实现OpenGL渲染,需要完成一系列的EGL操作,主要为下面几步:

1、获取显示设备(EGLDisplay)

获取将要用于显示的设备,有些系统具有多个显示器,会存在多个Display。在Android上通过调用EGL10的eglGetDisplay(Object native_display)方法获得EGLDisplay对象,通常传入的参数为EGL10.EGL_DEFAULT_DISPLAY。

2、初始化EGL

调用EGL10的eglInitialize(EGLDisplay display, int[] major_minor)方法完成初始化操作。display参数即为上一步获取的对象,major_minor传入的是一个int数组,通常传入的是一个大小为2的数组。

3、选择Config配置

调用EGL10的eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config)方法,参数1、2其意明显,参数3用于存放输出的configs,参数4指定最多输出多少个config,参数5由EGL系统写入,表明满足attributes的config一共有多少个。

4、创建EGL环境(EGLContext)

eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);参数1即为上面获取的Display,参数2为上一步chooseConfig传入的configs,share_context,是否有context共享,共享的contxt之间亦共享所有数据,通常设置为EGL_NO_CONTEXT代表不共享。attrib_list为int数组 {EGL_CONTEXT_CLIENT_VERSION, 2,EGL10.EGL_NONE };中间的2代表的是OpenGL ES的版本。

4、创建EGLSurface

eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);参数1、2均为上述步骤得到的结果,参数3为上层创建的用于绘制内容的surface对象,参数4常设置为null。

5、设置OpenGL的渲染环境

eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);该方法的参数意义很明确,该方法在异步线程中被调用,该线程也会被成为GL线程,一旦设定后,所有OpenGL渲染相关的操作都必须放在该线程中执行。下面介绍GLSurfaceView的流程会描述该线程。

通过上述5步操作,就完成了EGL的初始化设置,便可以进行OpenGL的渲染操作。

GLSurfaceView绘制流程:

Android的UI绘制必须要在主线程,而OpenGL的某些操作比较耗时,放在主线程显然是不合适的。因此,Android提供了GLSurfaceView用于OpenGL的绘制,下面我们将简单介绍一下GLSurfaceView的绘制流程。

Renderer
 public interface Renderer {
        /**
         * Called when the surface is created or recreated.
         * <p>
         * Called when the rendering thread
         * starts and whenever the EGL context is lost. The EGL context will typically
         * be lost when the Android device awakes after going to sleep.
         * <p>
         * Since this method is called at the beginning of rendering, as well as
         * every time the EGL context is lost, this method is a convenient place to put
         * code to create resources that need to be created when the rendering
         * starts, and that need to be recreated when the EGL context is lost.
         * Textures are an example of a resource that you might want to create
         * here.
         * <p>
         * Note that when the EGL context is lost, all OpenGL resources associated
         * with that context will be automatically deleted. You do not need to call
         * the corresponding "glDelete" methods such as glDeleteTextures to
         * manually delete these lost resources.
         * <p>
         * @param gl the GL interface. Use <code>instanceof</code> to
         * test if the interface supports GL11 or higher interfaces.
         * @param config the EGLConfig of the created surface. Can be used
         * to create matching pbuffers.
         */
        void onSurfaceCreated(GL10 gl, EGLConfig config);

        /**
         * Called when the surface changed size.
         * <p>
         * Called after the surface is created and whenever
         * the OpenGL ES surface size changes.
         * <p>
         * Typically you will set your viewport here. If your camera
         * is fixed then you could also set your projection matrix here:
         * <pre class="prettyprint">
         * void onSurfaceChanged(GL10 gl, int width, int height) {
         *     gl.glViewport(0, 0, width, height);
         *     // for a fixed camera, set the projection too
         *     float ratio = (float) width / height;
         *     gl.glMatrixMode(GL10.GL_PROJECTION);
         *     gl.glLoadIdentity();
         *     gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
         * }
         * </pre>
         * @param gl the GL interface. Use <code>instanceof</code> to
         * test if the interface supports GL11 or higher interfaces.
         * @param width
         * @param height
         */
        void onSurfaceChanged(GL10 gl, int width, int height);

        /**
         * Called to draw the current frame.
         * <p>
         * This method is responsible for drawing the current frame.
         * <p>
         * The implementation of this method typically looks like this:
         * <pre class="prettyprint">
         * void onDrawFrame(GL10 gl) {
         *     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
         *     //... other gl calls to render the scene ...
         * }
         * </pre>
         * @param gl the GL interface. Use <code>instanceof</code> to
         * test if the interface supports GL11 or higher interfaces.
         */
        void onDrawFrame(GL10 gl);
    }

使用GLSurfaceView时需要自定义一个渲染器,实现Render接口,并将渲染器对象设置给GLSurfaceView。Render接口中定义的方法意义非常明确。将GLSurfaceView放入布局中,自定义实现Render接口就能完成OpenGL的绘制了,使用上非常简单。

GLThread

GLThread就是上面在介绍EGL时提到的GL线程,所有的EGL相关操作都在该线程中被调用,OpenGL绘制相关操作都由该线程完成,包括Render中的方法。而该线程最主要的方法就是guardedRun(),所有的操作都在该方法中执行。该方法的代码较长,在此处不贴出。不过逻辑还是比较好理解:
1、检测渲染环境是否准备好(EGL的初始化操作);
2、循环调用Render的onDrawFrame方法;
3、 调用EGL10的eglSwapBuffers(EGLDisplay display, EGLSurface surface)方法,该方法才是真正的将surface中的内容渲染到屏幕的操作。

结束语

本篇文章主要是为了介绍Android中使用OpenGL绘图的一些基础知识,没有具体的实践代码。关于GLSurfaceView建议大家阅读一下源码,源码比较容易理解。只要理解了上述的过程,其实还是比较容易看懂的。后面的文章会通过实例介绍OpenGL的绘制。

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

推荐阅读更多精彩内容