什么是OpenGL?
OpenGL:Open Graphics Library,图形领域的工业标准,是一套扩变成语言,跨平台的,专业的图形编程(软件)接口,它用于二维,三维图像,是一个功能强大,调用方法的底层图形库。
对视频进行编辑,美化需要使用OpenGL。
OpenGL ES?
是OpenGL的子集,专门为移动端优化的API规范,针对手机,PAD和游戏等嵌入式设备而设计的OpenGL API子集。
OpenGL ES的版本
Open ES 1.0和1.1 :Android1.0和更高的版本支持这个API规范。
Open ES 2.0 :Android2.2(API8)和更高的版本支持这个API规范。
Open ES 3.0 :Android4.3(API18)和更高的版本支持这个API规范。
Open ES 3.1 :Android5.0(API21)和更高的版本支持这个API规范。
OPenGL ES还需要由设备制造商提供实现支持,目前广泛支持的是2.0。
Android中如何使用OpenGL ES?
AndroidMainfest.xml需要加上:
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>意为加载app需要支持OpenGL ES2.0,如果是3.0就把2改为3。
我们可以用java或者c/c++(原生开发工具包NDK)来使用OpenGL,我们不需要纠结,因为OpenGL是跨平台的,接口都差不多。
比如我们使用GLES20这个API,点击进去查看,大部分都是通过native实现的。
不需要引入第三方库,使用SDK中自带的就行。
Android框架中有两个基本类,允许使用OpenGL ES API创建和操作图形:GLSurfaceView和GLSurfaceView.Renderer。
GLSurfaceView
- GLSurfaceView是SurfaceView的子类,它内嵌的surface专门负责OPenGL渲染,如果您想捕获触摸屏事件,应该扩展GLSurfaceView类来实现触摸监听器。
- 可以管理Surface和EGL,使用GLSurfaceView不需要操心EGL,它帮我们配置好了。如果要使用SurfaceView就需要我们自己配置EGL。
- 让渲染器在独立的线程里运作,和UI线程分离
- 支持按需渲染和连续渲染
什么是EGL?
OpenGL是一个扩平台操作CPU的API,如果在Android中使用OpenGL,就需要使用一个中间层将OpenGL和Android进行连接,这个中间层就是EGL,EGL就是连接OpenGL ES和本地窗口系统的接口,引入EGL就是为了屏蔽不同平台上的区别。
GLSurfaceView.Renderer
这个接口定义了在GLSurfaceView中绘制图形所需的方法。必须将此接口的实现作为一个单独的类提供,V并使用GLSurfaceiew. setRenderer()将其附加到您的GLSurfaceView实例中。
GLSurfaceView.Renderer接口需要实现以下方法
- onSurfaceCreated():系统在创建GLSurfaceView时调用此方法一次。使用此方法执行只需要执行一次的操作,例如设置OpenGL环境参数或初始化OpenGL图形对象。
- onDrawFrame():系统在每次重绘GLSurfaceView时调用这个方法。使用此方法作为绘制(和重新绘制)图形对象的主要执行点。
- onSurfaceChanged():当GLSurfaceView的几何形状发生变化,包括GLSurfaceView的大小或设备屏幕的方向发生变化时,系统调用该方法。例如,当设备从纵向转向横向时,系统调用这个方法。使用此方法响应GLSurfaceView容器中的更改。
一旦使用GLSurfaceView和GLSurfaceView.Renderer为OpenGL ES建立了一个容器视图和渲染器,就可以开始调用OpenGL api使用以下类:
android.opengl.GLES20
或者是使用其它的,如:
android.opengl.GLES30
android.opengl.GLES31
android.opengl.GLES31Ext
注:OpenGL ES 3.x API向后兼容2.0
OpenGL绘制流程
下面举个例子
1)比如绘制一头牛,opengl把物体分割成无数个三角形,而这些三角形又是由3个点构成,那么我们成这些点为顶点,这些顶点数据是需要我们传递给opengl的,opengl会把这些顶点数据交给顶点着色器来处理
2)图元装配:将这些顶点拼成三角形。
3)光栅化:拼成三角形后,接下来的步骤就是光栅化->把这些三角形分成一块块的区域,有无数个片段。
4)片元着色器:光栅化结束后,将纹理交给片元着色器来处理,片元着色器的作用:就是给区域上色的。
Android中我们需要完成顶点着色器和片元着色器的步骤的编写。
什么是着色器?
着色器是运行在GPU上的小程序。
顶点着色器:如何处理顶点,法线等数据的小程序
片元着色器:如何处理光,阴影,遮挡,环境等等对物体表面的影响,最终生成一幅图像的小程序。
要想学习着色器,并理解着色器的工作机制,就要对OpenGL固定的渲染管线有深入的了解。同样,先来统一一下术语。
- 几何图元:包括点、直线、三角形,均是通过顶点(vertex)来指定的。
- 模型:根据几何图元创建的物体。
- 渲染:计算机根据模型创建图像的过程。
最终渲染过程结束之后,人眼所看到的图像就是由屏幕上的所有像素点组成的,在内存中,这些像素点可以组织成一个大的一维数组,每4个Byte即表示一个像素点的RGBA数据,而在显中,这些像素点可以组织成帧缓冲区(FrameBuffer)的形式,帧缓冲区保存了图形硬件为了控制屏幕上所有像素的颜色和强度所需要的全部信息。理解了帧缓冲区的概念,接下来就来讨论一下OpenGL的渲染管线,这部分内容对于OpenGL来说是非常重要的。
那么OpenGL的渲染管线具体是做什么的呢?其实就是OpenGL引擎渲染图像的流程,也就是说OpenGL引擎是一步一步地将图片渲染到屏幕上去的过程。渲染管线分为以下几个阶段。
阶段一:指定几何对象所谓几何对象,就是上面说过的几何图元,这里将根据具体执行的指令绘制几何图元。比如,OpenGL提供给开发者的绘制方法glDrawArrays,这个方法里面的第一个参数是mode,就是制定绘制方式,可选值有以下几种。
- GL_POINTS:以点的形式进行绘制,通常用在绘制粒子效果的场景中。
- GL_LINES:以线的形式进行绘制,通常用在绘制直线的场景中。
- GL_TRIANGLE_STRIP:以三角形的形式进行绘制,所有二维图像的渲染都会使用这种方式。
具体选用哪一种绘制方式决定了OpenGL渲染管线的第一阶段应如何去绘制几何图元,所以这就是第一阶段指定的几何对象。
阶段二:顶点处理
不论以上的几何对象是如何指定的,所有的几何数据都将会经过这个阶段。这个阶段所做的操作就是,根据模型视图和投影矩阵进行变换来改变顶点的位置,根据纹理坐标与纹理矩阵来改变纹理坐标的位置,如果涉及三维的渲染,那么这里还要处理光照计算和法线变换(本书不会涉及三维的渲染)。这里的输出是以gl_Position来表示具体的顶点位置的,如果是以(GL_POINTS)来绘制几何图元,那么还应该输出gl_PointSize。
阶段三:图元组装
在经过阶段二的顶点处理操作之后,不论是模型的顶点,还是纹理坐标都是已经确定好了的。在这个阶段,顶点将会根据应用程序送往图元的规则(如GL_POINTS、GL_TRIANGLES等),将纹理组装成图元。
阶段四:栅格化操作
由阶段三传递过来的图元数据,在此将会被分解成更小的单元并对应于帧缓冲区的各个像素。这些单元称为片元,一个片元可能包含窗口颜色、纹理坐标等属性。片元的属性是根据顶点坐标利用插值来确定的,这其实就是栅格化操作,也就是确定好每一个片元是什么。
阶段五:片元处理
通过纹理坐标取得纹理(texture)中相对应的片元像素值(texel),根据自己的业务处理(比如提亮、饱和度调节、对比度调节、高斯模糊等)来变换这个片元的颜色。这里的输出是
gl_FragColor,用于表示修改之后的像素的最终结果。
阶段六:帧缓冲操作
该阶段主要执行帧缓冲的写入操作,这也是渲染管线的最后一步,负责将最终的像素值写到帧缓冲区中。前面也提到过,OpenGL ES 2.0版本与之前的版本相比,更出色的功能就是提供了可编程的着色器来代替OpenGL ES中渲染管线的某一阶段。那么具体是哪一个着色器,又可以替换渲染管线的哪一个阶段呢?具体如下所示。
- Vertex Shader(顶点着色器)用来替换顶点处理阶段。
- Fragment Shader(片元着色器,又称像素着色器)用来替换片元处理阶段。
glFinish和glFlush
提交给OpenGL的绘图指令并不会马上发送给图形硬件执行,而是放到一个缓冲区里面,等待缓冲区满了之后再将这些指令发送给图形硬件执行,所以指令较少或较简单时是无法填满缓冲区的,这些指令自然不能马上执行以达到所需要的效果。因此每次写完绘图代码,需要让其
立即完成效果时,开发者都需要在代码后面添加glFlush()或glFinish()函数。
- glFlush()的作用是将缓冲区中的指令(无论是否为满)立刻发
送给图形硬件执行,发送完立即返回。 - glFinish()的作用也是将缓冲区中的指令(无论是否为满)立刻发送给图形硬件执行,但是要等待图形硬件执行完成之后才返回这些指令。
接下来就是如何编写着色器小程序