概述
这是一个系列的Android平台下OpenGl ES介绍,从最基本的使用最终到VR图的展示的实现,属于基础篇。(后面针对VR视频会再有几篇文章,属于进阶篇)
OpenGL ES之一——概念扫盲
OpenGL ES之二——Android中的OpenGL ES概述
OpenGL ES之三——绘制纯色背景
OpenGL ES之四——绘制点,线,三角形
OpenGL ES之五——相机和投影,绘制等腰三角形
OpenGL ES之六——绘制矩形和圆形
OpenGL ES之七——着色器语言GLSL
OpenGL ES之八——GLES20类和Matrix类
OpenGL ES之九——相机和投影
OpenGL ES之十——纹理贴图(展示一张图片)
OpenGL ES之十一——绘制3D图形
OpenGL ES之十二——地球仪和VR图
本篇概述
上一篇主要想要脱离Android平台介绍一下OpenGL和OpenGL ES到底是什么,从本篇起开始从零开始搭建自己的Android平台下OpenGL ES知识体系。本篇的内容是Android平台中的OpenGL ES
。
一.Android基本架构中OpenGL ES
1.1 OpenGL ES在Android的基本架构中位置
如下图,我们从Android的基本架构中找到OpenGL ES的位置。
OpenGL ES就在Libraries里面,从中我们可知Android中自身是支持OpenGL ES的。下面看一下OpenGL ES各个版本在Android各个版本中的支持情况。
1.2 OpenGL ES各个版本在Android各个版本中的支持情况
-
OpenGL ES1.0是基于OpenGL 1.3的,OpenGL ES1.1是基于OpenGL 1.5的。Android1.0和更高的版本支持这个API规范。OpenGL ES 1.x是针对固定硬件管线的。
-
OpenGL ES2.0是基于OpenGL 2.0的,不兼容OpenGL ES 1.x。Android 2.2(API 8)和更高的版本支持这个API规范。OpenGL ES 2.x是针对可编程硬件管线的。
-
OpenGL ES3.0的技术特性几乎完全来自OpenGL 3.x的,向下兼容OpenGL ES 2.x。Android 4.3(API 18)及更高的版本支持这个API规范。
-
OpenGL ES3.1基本上可以属于OpenGL 4.x的子集,向下兼容OpenGL ES3.0/2.0。Android 5.0(API 21)和更高的版本支持这个API规范。
Android通过其框架API和Native Development Kit(NDK)支持OpenGL。
二.OpenGL ES在Android中涉及的关键类
Android框架中有两个基础类,可让您使用OpenGL ES API创建和操作图形:GLSurfaceView和 GLSurfaceView.Renderer。下面我们就来了解一下这俩类的用法。
2.1 GLSurfaceView
我们想在Android中使用OpenGL ES 的最简单的方法就是将我们要显示的图像渲染到GLSurfaceView上。但是它只是一个展示类,至于怎么渲染到上面我们就要自己实现GLSurfaceView.Renderer来生成我们自己的渲染器从而完成渲染操作。
2.2 GLSurfaceView.Renderer
它是一个接口,里面定义了我们需要实现的方法,如下面代码,里面各个要实现的方法已经注释的很清楚了。
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2 {
//-----------省略代码------------
public interface Renderer {
//创建时,系统调用此方法一次,且仅一次,我们将初始化工作在这里完成。例如设置OpenGL环境参数或初始化OpenGL图形对象。
void onSurfaceCreated(GL10 gl, EGLConfig config);
//系统在GLSurfaceView中几何图形更改时调用此方法,例如视频第一帧图像创建或者横竖屏切换。
void onSurfaceChanged(GL10 gl, int width, int height);
//完成绘制工作,每一帧图像的渲染都要在此处完成。
void onDrawFrame(GL10 gl);
}
//-----------省略代码------------
}
三.OpenGL ES使用环境配置
3.1 声明OpenGL要求
第一:AndroidManifest.xml 清单文件中我们添加如下的代码,告诉系统我要使用OpenGL ES 2.0版本。
<!-- Tell the system this app requires OpenGL ES 2.0. -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
注意:如果我们想要使用更高版本的OpenGL ES以带来更好更高效的运行,那么我们可以将上面的版本号提高如下:
<!-- Tell the system this app requires OpenGL ES 3.0. -->
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
或者更高如下:
<!-- Tell the system this app requires OpenGL ES 3.1. -->
<uses-feature android:glEsVersion="0x00030001" android:required="true" />
直到最高版本。
第二:如果你的应用程序需要使用纹理压缩,你还需要声明你的应用程序需要支持哪种压缩格式,以便他们安装在兼容的设备上。实例代码如下:
<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
更多关于纹理压缩的知识请参看官网关于纹理压缩的介绍,这里不展开说明。
3.2 版本声明之后的结果:
- 我们可以使用OpenGL ES的api了;
- 添加了上面的声明之后,我们的应用可以安装到不支持OpenGL ES 2.0更低系统版本的手机上,这样一来在运行的时候就有可能崩溃掉。这就是兼容性问题,那么如何解决这个兼容性问题呢?如下:
我们知道OpenGL ES 3.0 API向后兼容2.0 API,那么我们在清单文件中设置OpenGL ES 2.0 API作为默认版本,在运行时检查3.0 API的可用性,然后在设备支持时使用OpenGL ES 3.0功能
。
同时这里我们也要同时考虑到我们的应用支持的最小系统版本(也就是minSdkVersion),如果我们的最小安装版本都大于等于18(也就是OpenGL ES 3.0对应的最小Android系统版本)了,那么我们也就可以放心的将OpenGL ES 版本设置为3.0了(例如我司的App就因必须引入网信办的统计SDK只能将最小版本提升到19)。
3.3 OpenGL ES版本和Android系统版本兼容性处理
例如我们想检测手机系统版本是否支持OpenGL ES 3.0,我们可以采用下面的两种方式。
1.确定目标版本,尝试创建更高级别的OpenGL ES上下文(EGLContext),创建成功了则表示支持,负责不支持;
2.直接创建OpenGL ES上下文(EGLContext),然后获取支持的最低版本。
使用第一种方法的代码如下
//设定目标版本
private static double glVersion = 3.0;
private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public EGLContext createContext(
EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
EGL10.EGL_NONE };
//尝试创建OpenGL ES 3.0的上下文(EGLContext)
EGLContext context = egl.eglCreateContext(
display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
//创建成功了则支持3.0版本,没成功则不支持
return context;
}
}
使用第二种方法
//简单粗暴,直接得出最小支持版本
String version = gl.glGetString(GL10.GL_VERSION);
四 OpenGL ES 数据存储
目的:之所以要在这里介绍OpenGL ES 数据存储,是为了后面做准备。后面每次操作着色器的时候都要自己手动调用ByteBuffer
相关操作来为数组分配本地内存。(好这里看不懂没关系后面遇到,想起来这里提过就好了)
android中的程序运行在虚拟机中的,OpenGL ES作为本地系统库是运行在硬件上的
,虚拟机与OpenGL ES数据传输的方式有两种,如下:
1.使用Java调用本地接口JNI的方式,当我们使用GLES20包里的方法时,内部实现其实就是调用本地方法(这不用我们管)。
2…改变内存的分配方式,Java当中有个特殊的类(如ByteBuffer)集合,可以直接分配本地内存块,并把Java的数据复制到本地内存,本地内存可以被本地环境存取,而不受垃圾回收器管控(后面我们会遇到,到时候可以回来看一下)。