由于5G的发展,现在音视频越来越流行,我们的生活已经完全被抖音、视频号、B站等视频应用所包围。从这一点也能看到音视频的重要性。
而作为一名Android开发者,是时候来了解一下关于Android方面渲染方面的知识。音视频的应用都离不开OpenGL ES的处理。对于视频的高效渲染与融合操作是至关重要的。
上面的这种动画相信大家都很熟悉,类似的动画在各大直播间都会出现。那么这炫酷的原理实现内部都离不开OpenGL ES的高效渲染与更高级的融合处理。
多的就先不说了,现在我们就来认识一下OpenGL ES。
基本概念
Android可以通过OpenGL来支持高效的2D和3D图形,同时OpenGL是一种跨平台的图形API。其中OpenGL ES是OpenGL规范的一种形式,适用于嵌入式设备。
Android支持多种版本的OpenGL ES API:
- 1.0&1.1 Android1.0及以上
- 2.0 Android2.2及以上
- 3.0 Android4.3及以上
- 3.1 Android5.0及以上
我们的内容主要是基于OpenGL ES 2.0来进行,也就是进行二维的图形渲染。
坐标
在Android中通过Canvas进行绘制的坐标原点是在屏幕的左上角,同时它的坐标范围都是以屏幕的宽高来定义。
OpenGL ES则不同,它是以绘制区域的中心为原点,同时它的坐标范围是-1.0 ~ 1.0。也就是说它的坐标都是基于可绘制区域进行比例换算。并不是真正的值。

形状与方向
在OpenGL ES中,绘制的形状都是以三角形为基础,也就是说它必须由3个或者以上的点来进行绘制。所以它是由多个三角形进行组合成特定的形状,进过不同程度的交叉与重叠来达到不同的形状。
例如以二维空间来定义

同时还存在绘制顺序,所谓的绘制顺序也是以三角形为基础,通过三角形的三个顶点进行环绕绘制。默认是以逆时针进行绘制。
对于二维图像可能绘制顺序没那么重要,但是对于三维图像就很重要了。三维图像是由于视角的问题,会存在正反面的关系。
例如一款3D游戏,游戏中有一辆汽车,正对我们的为正面,我们看不到的一面为反面,虽然反面看不到,但OpenGL ES还是会进行绘制。为了对反面不做无用的绘制,可以使用OpenGL的面剔除操作,该操作允许渲染管道忽略形状的反面,这样就可以节约时间与内存并缩短处理周期。
那么这里的正面就是沿逆时针绘制的面。
GL程序
OpenGL ES渲染需要借助GL程序,通过创建GL程序、顶点与片段着色器、加载着色器代码、编译代码、应用、数据填充,最终进行渲染。
在创建GL程序之前,我们先来了解顶点着色器与片段着色器。
着色器源码
GL程序渲染的过程中需要确认顶点位置与对应的颜色,而这两个部分分别借助于顶点与片段着色器来实现。
|
|
上面分别是顶点着色器与片段着色器的源码。attribute是变量修饰符,用的比较多的是以下三种。
- attribute:表示只读的顶点数据,应用在顶点着色器中。可修饰声明顶点、颜色等数据
- uniform:顶点着色器与片段着色器的共享数据,在程序中值的不变的,初始值由程序外部传入
- varying:顶点着色器输入,片段着色器输出;由顶点着色器传输给片段着色器中的插值数据
vec4是变量类型,变量主要有以下几种
变量类别 | 变量类型 | 描述 |
---|---|---|
空 | void | 代表无返回值的函数或空参数列表 |
标量 | float,int,bool | 浮点型、整型、布尔型的标量 |
浮点型向量 | float,vec2,vec3,vec4 | 包含1,2,3,4个元素的浮点型向量 |
整型向量 | int,ivec2,ivec3,ivec4 | 包含1,2,3,4个元素的整型向量 |
布尔型向量 | bool,bvec2,bvec3,bvec4 | 包含1,2,3,4个元素的布尔型向量 |
矩阵 | mat2,mat3,mat4 | 尺寸为2x2,3x3,4x4的浮点型矩阵 |
纹理句柄 | sampler2D,samplerCube | 表示2D,立方体纹理的句柄 |
除此之外还有数组与结构体,用来实现复杂的数据类型。
我们将定义的a_Position赋值给gl_Position,这样GL程序就会使用定义的顶点数据进行渲染。
同理gl_FragColor也是一样,代表对应渲染顶点位置时的颜色,这里直接写死了一个蓝色。
创建GL程序
首先我们要创建GL程序
|
|
拿到programId,为之后的程序操作做准备
添加顶点与片段着色器
首先创建顶点与片段着色器
|
|
将之前定义的着色器源码加载到着色器中
|
|
通过GL程序进行编译
|
|
最后将编译完的顶点与片段着色器添加到指定的GL程序中,也就是我们第一步创建的GL程序
|
|
链接与应用
着色器装载完毕之后,剩下的就是将我们创建的GL程序进行链接与应用
|
|
这样我们的GL程序才算真正的完成了,下面就是数据的填充与渲染操作。
数据填充
在顶点着色器源码定义中,我们定义了a_Position变量,需要我们从外部将数据添加到a_Position,这样才能真正应用到gl_Position中。
下面我们来进行数据的填充
首先我们定义一个填充的顶点数据
|
|
顶点维度是二维,所以这里mVertexData中定义了6个顶点数据,也就是2个三角形的数据。第一个在左上角,第二个在中间。
我们将数据添加到Buffer中,并将索引位置定义到开始位置0
|
|
继续获取a_Position在GL程序中的参数位置
|
|
这一点与我们平常的编程不同,在GL程序中,如果要获取其中的变量,我们并不是直接拿到这个变量的本身,而是通过拿到它在GL中对应的位置索引,然后通过位置索引进行变量操作。
获取之后还要进行启动激活
|
|
最后就是填充
|
|
VERTEX_DIMENSION_SIZE代表的是填充一个二维的顶点数据,类型为GLES20.GL_FLOAT。
渲染
GL程序与顶点数据都已经准备完毕,接下来是最后一步渲染。
在渲染之前我们需要对屏幕进行清屏操作,默认屏幕是黑色,我们可以指定需要的清屏后的颜色
|
|
这里指定清屏颜色为白色
在渲染之前设置渲染的视图位置与大小,最后再进行渲染。
|
|
在渲染操作中使用了GLES20.GL_TRIANGLES,这是一种渲染方式,它代表会以每3个顶点为一组的方式进行三角形渲染,所以我们运行之后就能看到2个三角形。
参数0与mVertexData.size / VERTEX_DIMENSION_SIZE代表有6个顶点且从第0个位置开始,也就是第一个顶点位置。
最后我们再来看下运行后的效果

大功告成,与我们的预期完全一样。
后续会继续聊聊颜色的动态填充、渲染的三种方式与纹理的操作,敬请期待。
源码地址:OpenGL ES