Android调用OpenGL绘制曲线入门手册

 

 

Android  OpenGL ES2.0 JNI  Cmake

简介:该手册内容仅作为Android调用OpenGL实现绘制曲线图的入门手册,深入学习请参考手册推荐书籍。本手册针对采用jni接口实现java调用C++代码完成OpenGL在Android中的曲线绘制做了详细流程介绍,最终实现效果为在Android平台绘制正弦曲线。

 

撰写人:武斌(1595451722@qq.com)周星宇

时间:2017年10月11日

CopyRight :东南大学电子科学与工程学院601实验室

版本:1.0

 

 

OpenGL简介:

OpenGL为跨编程语言、跨平台的编程接口标准,被当做客户端-服务端系统实现,客户端为应用程序,服务端为硬件厂商提供的OpenGL实现,OpenGL ES为其嵌入式版本。OpenGL ES目前共有三个版本发布,版本一提供不灵活的固定功能管道;版本二引入可编程管道;版本三在原有基础上新增部分API,目前主流使用为版本二OpenGL ES2.0,手册如下内容均用OpenGL代指OpenGL ES2.0。其渲染流程为:OpenGL命令和数据会缓存在RAM中,在一定条件下,会将这些命令和数据通过CPU时钟发送到VRAM,在GPU的控制下,使用VRAM中的数据和命令,完成图形的渲染,并将结果存入帧缓冲区中,帧缓冲区中的帧最终会被发送到显示器上,显示出结果。在现代的图形硬件系统中,还支持不通过CPU时钟直接将数据由RAM发送至顶点缓存区,再由顶点缓存区将数据传递到VRAM或直接将数据由像素帧缓冲区发送至显存(例如OpenGL中的VBO,PBO)。

Android调用OpenGL ES方案

在android应用程序中使用OpenGL ES共有四种方案:

1.     使用GLSurfaceView作为绘图的窗口,利用GLSurfaceView.Renderer接口实现OpenGL渲染上下文,并通过调用android.OpenGL.GLES20中的API函数实现对图像的渲染。

2.     使用GLSurfaceView作为绘图的窗口,使用GLSurfaceView.Renderer实现OpenGL渲染上下文,和1不一样的是通过JNI接口调用#include 中的API函数来实现图形渲染。

3.     使用NativeActivity实现OpenGL渲染上下文,并通过JNI接口调用#include 中的API函数来实现图形渲染。使用这种方案就意味着整个APP全部用C++语言编写,不能实现android基本控件的绘制,如Button/TextView。

4.     最后一种方法,就是使用SurfaceView作为绘图的窗口,并使用native层的pthread作为OpenGL渲染上下文,并通过pthread调用#include 实现图形渲染。

综合以上方案内容,考虑实现效果以及入门难易度,采用方案2实现android 调用OpenGL.。

本手册以下内容将结合示例代码简述JNI接口实现OpenGL 曲线绘制的流程。示例代码采用Android Studio 2.2.2开发工具实现,详细内容参考示例代码文件(openGL_jni.rar)及参考资料。

绘制流程

工程文件目录:

   

./cpp/native-lib.cpp为C++调用OpenGL 库接口函数文件。

./java/com.example.dell.opengl_jni/canvasview文件为 自定义canvas view类,实现刻度标注绘制功能

./java/com.example.dell.opengl_jni/GL2JNILib  为JNI接口类定义

./java/com.example.dell.opengl_jni/MainActivity 为程序主界面activity类

./java/com.example.dell.opengl_jni/openGLView 为自定义view控件,绘制曲线。

  Mainactivity.java

Activity加载的布局文件中添加分别表示Y轴刻度的Y_ScaleView控件、表示X轴刻度的X_ScaleView控件、表示曲线图的openGLView控件。

 

  openGLView.java

自定义OpenGL绘图组件openGLView类继承GLSurfaceView,定义构造函数时需要指定使用OpenGL版本,并且设置绘图的渲染器:

其中new Renderer为自定义类,继承GLSurfaceView.Renderer接口。

OpenGL渲染上下文

选择方案1和方案2进行OpenGL绘图,渲染上下文都由GLSurfaceView类来维护。当用户调用GLSurfaceView.setRenderer函数绑定Renderer到GLSurfaceView时,GLSurfaceView会开启一个GLThread线程来初始化OpenGL渲染上下文,并循环运行来刷新渲染图像。

GLThread线程的工作为初始化渲染上下文,并调用GLSurfaceView.Renderer接口中的回调函数。线程执行的流程图如下图所示:

 

对以下接口函数调用GL2JNILib类函数进行实例化。


OnSurfaceCreated(GL10  gl, EGLConfig config)函数在Surface创建时被GLsurfaceView调用,主要用于完成初始化工作。并且当用户在多个Activity中切换时,也会调用。

onSurfaceChanged(GL10gl, int width, int height)在 Surface创建后会自动调用,并且在检测平台横竖屏切换时调用,保证界面图像不发生形变做相应处理。

onDrawFrame(GL10gl)函数在程序执行后默认情况下会被系统Surface线程循环调用, 用于图像绘制。调用setRenderMode(int renderMode)函数可以设置渲染模式,可选模式有:

连续模式:传入参数RENDERMODE_CONTINUOUSLY,图像每隔16ms渲染一帧(60fps)。此模式适合于视频之类连续刷新的应用。

不连续模式:传入参数RENDERMODE_WHEN_DIRTY,当用户调用GLSurfaceView.requestRender()函数时才渲染一帧图像。此模式适合于图片浏览器之类不常更新画面的应用程序。

详见参考书籍《OpenGL ES 2 for Android A Quick - Start Guide (2013)》1.4节及官方API文档。

  GL2JNILib.java

JNI采用cmake方式实现在JAVA调用C++程序

JNI(java native interface)即java本地接口。Java的优点是跨平台,但是作为优点的同时,其在本地交互的时候就编程了缺点。Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供了jni专门用于和本地代码交互,这样就增强了Java语言的本地交互能力。

在 Android Studio 2.2 之后提供2种选择编译 c/c++ 代码。分别为:ndk-build + Android.mk + Application.mk 以及 CMake +CMakeLists.txt 组合。这2个组合与Android代码和c/c++代码无关,只是不同的构建脚本和构建命令,其中后者为主流应用。

实现步骤

Ø  编写Cmakelist.txt脚本

脚本内容可仿照OpenGL资料配套例程。这里需要注意在target_link_libraries中加入EGL和GLESv2两项,否则会导致找不到OpenGL函数的报错。此语句作用为将OpenGL应用程序与android系统的OpenGL与EGL框架进行链接。

target_link_libraries(native-lib
                     
android
                      log
                      EGL
                     
GLESv2)

 

Ø  导入依赖库native-lib,以及原生代码函数。

其中,System.LoadLibrary中库的名字应和CmakeList.txt中定义库的名字相同。将本地函数声明中加入publicstatic native关键字。

init(int width,int height)函数在onSurfaceChanged中调用,完成初始化工作。

step()函数在onDrawFrame中调用,实现绘制。

 

Ø  在native-lib.cpp代码文件添加如下内容

其中Java_com_example_dell_OpenGL_1jni_GL2JNILib_init()命名规则为java,java类完整包名称,函数名称。

可在声明为native的函数上使用android studio自动补全代码的功能生成对应的C++函数,并在其中加入需要的逻辑。

  native-lib.cpp

Ø  定义着色器源代码(GLSL语言):顶点着色器、片段着色器(OpenGL项目必须包含的着色器)

顶点着色器定义显示坐标位置变量;片段着色器定义像素属性。

顶点着色器和片段着色器在编译好后将运行在GPU中,所以如果着色器中包含错误将导致编译失败或者屏幕黑屏,但是log日志不打印任何报错信息。

对于着色器脚本若想深入理解,请阅读《OpenGL ES 2.0 programmer guide》

Ø  加载着色器对象

在该函数中调用glCreateShader()函数,创建着色器对象,返回着色器对象ID值shader。

glShaderSource(shader, 1,&pSource, NULL);//关联着色器对象与着色器源代码

      glCompileShader(shader);//编译着色器源代码

glGetShaderiv(shader,GL_COMPILE_STATUS, &compiled);//返回编译结果

glGetShaderInfoLog(shader,infoLen, NULL, buf);//返回着色器信息日志,常在编译失败调用。

Ø  加载着色器程序对象

调用函数加载着色器对象loadShader(GL_VERTEX_SHADER,pVertexSource)

GLuint program = glCreateProgram();//创建着色器程序对象

glAttachShader(program, pixelShader);//关联着色器对象到着色器程序对象
glLinkProgram(program);//链接着色器程序对象成为可被GPU调度的二进制程序

Ø  init函数

setupGraphics(int w, int h)函数在init函数中调用,函数体内容如下。

1)         调用createProgram(gVertexShader,gFragmentShader),实现着色器程序对象的初始化。

2)         gvPositionHandle= glGetAttribLocation(gProgram, "vPosition");

gvValueHandle=glGetAttribLocation(gProgram,"vValue");

guFragColorHandle=glGetUniformLocation(gProgram,"uFragColor");

获得着色器中vPosition,vValue,uFragColor在程序执行时的位置。

3)         glViewport(0,0, w, h);//初始化屏幕信息

getXop();//生成X轴刻度数据

getYop();//生成Y轴刻度数据

Ø  step函数

定义renderFrame()函数,在step函数中调用,函数体内容如下。

生成曲线数据

updata();

设置背景颜色

glClearColor(grey, grey, grey,1.0f);//r,g,b,a其中a指透明度

清空绘制区域缓存,在OpenGL中有三种缓存数据,分别是颜色缓存,深度缓存和模板缓存,依据需要清除相应缓存数据。

glClear( GL_DEPTH_BUFFER_BIT |GL_COLOR_BUFFER_BIT);

通知GPU执行相应的着色器程序

glUseProgram(gProgram);

填充当前绑定顶点数组对象,启用与gvPositionHandle索引相关联的顶点数组,保证GPU可以拿到数据。

glVertexAttribPointer(gvPositionHandle, 1,GL_FLOAT, GL_FALSE, 0,xpos); glEnableVertexAttribArray(gvPositionHandle);

指定片段颜色

glUniform4f(guFragColorHandle, 0.75f,0.75f,0.75f, 1.0f);

绘制相应曲线

glDrawArrays(GL_LINE_STRIP, 0, frequency);

实现的绘制效果及性能如下:

由于OpenGL绘制汉字、数字等实现难度大,因此采用canvas类绘制曲线标度。

曲线绘制(10000点数据)CPU占用率11%~15%之间。

OpenGL学习参考链接:

http://www.twinklingstar.cn/2015/1532/introduce-to-OpenGL/

http://www.cnblogs.com/android-blogs/p/5454698.html

http://blog.csdn.net/qq_16564215/article/details/51764145

http://wondertwo.me/2017/04/14/OpenGL-%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2/

http://www.qingpingshan.com/rjbc/az/119625.html

http://blog.csdn.net/kkae8643150/article/details/52805738、

http://blog.csdn.net/aa841538513/article/details/52291759(渲染过程)

http://www.android-doc.com/reference/android/opengl/GLSurfaceView.html

书籍推荐

《OpenGL ES 2 for Android A Quick - Start Guide(2013)》1~7章

中文版《OpenGL ES应用开发实践指南》

《OpenGL ES.2.0 Programming Guide(2008-7)》(按需阅读)

《OpenGL编程指南(第八版)》

《OpenGL超级宝典》

JNI学习参考链接:

http://www.jianshu.com/p/6332418b12b1

http://blog.csdn.net/carson_ho/article/details/73250163

http://www.cnblogs.com/tt2015-sz/p/6027662.html

示例代码:

https://download.csdn.net/download/u011361385/10356706




更多相关文章

  1. Android(安卓)自动化测试―robotium(一)环境
  2. android emulator中调用部署在我自己电脑上的webservice
  3. Android(安卓)4.1.2系统添加重启功能
  4. Android(安卓)Sensor传感器系统架构初探
  5. Android中Service的使用详解和注意点(LocalService)
  6. ANdroid之蓝牙
  7. Android应用程序请求SurfaceFlinger服务渲染Surface的过程分析
  8. 详解Android应用开发中Intent的作用及使用方法
  9. 箭头函数的基础使用

随机推荐

  1. 关于android中进行http通信的几个问题
  2. json连接中央气象台api异常
  3. Android下如何计算要显示的字符串所占的
  4. 【Androidd Release】AndroidStudio 发布
  5. Android 图文数据JSON解析,金山词霸每日一
  6. Android之USB Camera摄像头节点后移
  7. Android中的style和theme
  8. Android user defined service handling
  9. Android 中文API (94) ―― MediaControlle
  10. Android之路之十七(重要组件之Service)