Android中的NDK OpenGL

有过android开发经验应该或多或少地听说过OpengGL,甚至也行使用过framework提供的opengl包做过一些2d,3d相关的绘制,但事实上Android还提供了NDK方面的opengl能力,这个能力更接近真实的opengl,网上这部分的文章并不多,因此打算写一篇NDK相关的OpenGL。

什么是OpenGL

按照官方文档的说法:

OpenGL(Open Graphics Library开发图形接口)是一个跨平台的图形API,用于指定3D图形处理硬件中的标准软件接口。

但在移动平台端我们说的OpenGL更确切地说是OpenGL ES。因为OpenGL一般用于在图形工作站,PC端使用,由于性能各方面原因,在移动端使用OpenGL基本带不动。为此,Khronos公司就为OpenGL提供了一个子集,OpenGL ES(OpenGl for Embedded System)。

环境准备

提供Surface

要想在android上使用NDK的OpenGL,我们需要提供一个画布给NDK,这个画布其实就是一个SurfaceView,在framework层构造一个SurfaceView并获取其中的Surface传给NDK

<?xml version="1.0" encoding="utf-8"?>
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/sv_main"
    >
</SurfaceView>
mSurfaceView = findViewById(R.id.sv_main);
mSurfaceView = findViewById(R.id.sv_main);
        if(null != mSurfaceView) {
            mSurfaceView.setZOrderMediaOverlay(true);
            mSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);
            mSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback2() {
                @Override
                public void surfaceRedrawNeeded(@NonNull SurfaceHolder surfaceHolder) {
                    
                }

                @Override
                public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
// native方法传递给NDK                    OpenGLClass.getInstance().onSurfaceCreateNative(surfaceHolder.getSurface());
                }

                @Override
                public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {

                }

                @Override
                public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {

                }
            });
        }

获取当前平台窗口

接下来开始都是NDK部分的处理

ANativeWindow* m_CurrentNativeWindow = ANativeWindow_fromSurface(env, surface);

上面获取到的ANativeWindow就是android平台用于与openGL渲染的本地窗口,不同平台有不同的本地窗口,比如Window系统对应的就是Window,获取窗口之后接下去要做的将本地窗口与OpenGL渲染做环境准备和绑定,这里我们通常会引入EGL。

EGL简单理解就是OpenGL渲染和本地窗口系统之间的中间层,通过它我们可以屏蔽不同平台不同窗口的处理差异。

获取 EGLDisplay 对象,建立与本地窗口系统的连接

EGLDisplay eglDisplay; /**< 系统显示 ID 或句柄。 */
eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    

获取 EGLConfig 对象,确定渲染表面的配置信息

EGLint eglConfigNum = 0;
    EGLint configSpec[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE
    };
    int initConfig = eglChooseConfig(eglDisplay, configSpec, &eglConfig, 1, &eglConfigNum);
    if (EGL_TRUE != initConfig)
    {
        LOGD("eglChooseConfig failed!");
        return;
    }

创建渲染表面 EGLSurface

EGLSurface eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, m_CurrentNativeWindow, NULL);

创建渲染上下文EGLContext

const EGLint ctxAttr[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE
    };
    EGLContext eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, ctxAttr);

绑定EGLDisplay,EGLSurface,EGLContext

if (EGL_TRUE != eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext))
    {
        LOGD("eglMakeCurrent failed!");
        return;
    }

当我们完成EGLDisplay,EGLSurface,EGLContext三者的绑定之后,OpenGL ES的环境就安装好了。接下去可以直接使用OpenGL ES的接口进行渲染绘制了。

简单画个背景

// 绘制功能,这里指简单绘制背景
    glClearColor(1.0, 1.0, 0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glFlush();
    // 交换缓冲
    eglSwapBuffers(eglDisplay, eglSurface);

因为这篇文章重点介绍怎么使用NDK的opengl,因此绘制部分我们就简单绘制一个黄色背景。

依赖配置

前面我们用到的NDK相关的方法需要配置对应的依赖才能保证编译通过,比如ANativeWindow_fromSurface以及egl相关接口,因此在NDK的CMakeList里具体新增了如下的依赖
target_link_libraries( # Specifies the target library.
            # 制定目标库.
            OpenGLUI
            android # 保证能编译过ANativeWindow_fromSurface
            EGL #编译过相关egl接口
            GLESv2 #编译过相关opengl es接口
            # Links the target library to the log library
            # included in the NDK.
            ${log-lib} )

源码

上面说了这么多,demo我也写了一个,传送门

关于chenzujie

非著名码农一枚,认真工作,快乐生活
此条目发表在Android分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注