Android OpenGL初探

作者: Tifkingsly | 来源:发表于2018-10-28 22:47 被阅读13次

    最近在做一些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的绘制。

    相关文章

      网友评论

        本文标题:Android OpenGL初探

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