因为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程序烘托的过程中需求确认极点方位与对应的色彩,而这两个部分别离凭借于极点与片段着色器来完成。
// 极点
private const val VERTEX_SHADER_SOURCE =
"attribute vec4 a_Position;\n" +
"void main() {\n" +
" gl_Position = a_Position;\n" +
"}"
// 片段
private const val FRAGMENT_SHADER_SOURCE =
"precision mediump float;\n" +
"void main() {\n" +
" gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n" +
"}"
上面别离是极点着色器与片段着色器的源码。attribute是变量修饰符,用的比较多的是以下三种。
- attribute:表示只读的极点数据,运用在极点着色器中。可修饰声明极点、色彩等数据
- uniform:极点着色器与片段着色器的同享数据,在程序中值的不变的,初始值由程序外部传入
- varying:极点着色器输入,片段着色器输出;由极点着色器传输给片段着色器中的插值数据
vec4是变量类型,变量主要有以下几种
除此之外还有数组与结构体,用来完成杂乱的数据类型。
咱们将界说的a_Position赋值给gl_Position,这样GL程序就会运用界说的极点数据进行烘托。
同理gl_FragColor也是相同,代表对应烘托极点方位时的色彩,这儿直接写死了一个蓝色。
创立GL程序
首先咱们要创立GL程序
// 创立GL程序
val programId = GLES20.glCreateProgram()
拿到programId,为之后的程序操作做准备
增加极点与片段着色器
首先创立极点与片段着色器
// 创立极点与片段着色器
val vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)
val fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)
将之前界说的着色器源码加载到着色器中
// 加载极点与片段着色器代码
GLES20.glShaderSource(vertexShader, VERTEX_SHADER_SOURCE)
GLES20.glShaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE)
经过GL程序进行编译
// 编译极点与片段着色器代码
GLES20.glCompileShader(vertexShader)
GLES20.glCompileShader(fragmentShader)
最终将编译完的极点与片段着色器增加到指定的GL程序中,也便是咱们第一步创立的GL程序
// 增加到GL程序中
GLES20.glAttachShader(programId, vertexShader)
GLES20.glAttachShader(programId, fragmentShader)
链接与运用
着色器装载完毕之后,剩下的便是将咱们创立的GL程序进行链接与运用
// 链接GL程序
GLES20.glLinkProgram(programId)
// 运用GL程序
GLES20.glUseProgram(programId)
这样咱们的GL程序才算真实的完成了,下面便是数据的填充与烘托操作。
数据填充
在极点着色器源码界说中,咱们界说了a_Position变量,需求咱们从外部将数据增加到a_Position,这样才能真实运用到gl_Position中。
下面咱们来进行数据的填充
首先咱们界说一个填充的极点数据
private val mVertexData = floatArrayOf(0.0f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 1.0f, -1.0f, 0.5f, 0f, 0.5f)
private const val VERTEX_DIMENSION_SIZE = 2
极点维度是二维,所以这儿mVertexData中界说了6个极点数据,也便是2个三角形的数据。第一个在左上角,第二个在中心。
咱们将数据增加到Buffer中,并将索引方位界说到开端方位0
// 加载极点数据
val vertexBuffer = ByteBuffer.allocateDirect(mVertexData.size * Float.SIZE_BYTES)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
vertexBuffer.put(mVertexData)
vertexBuffer.position(0)
持续获取a_Position在GL程序中的参数方位
// 获取对应参数方位
val positionLocation = GLES20.glGetAttribLocation(programId, "a_Position")
这一点与咱们平常的编程不同,在GL程序中,假如要获取其中的变量,咱们并不是直接拿到这个变量的本身,而是经过拿到它在GL中对应的方位索引,然后经过方位索引进行变量操作。
获取之后还要进行发动激活
// 发动对应参数方位
GLES20.glEnableVertexAttribArray(positionLocation)
最终便是填充
// 填充极点数据
GLES20.glVertexAttribPointer(positionLocation, VERTEX_DIMENSION_SIZE, GLES20.GL_FLOAT, false, 0, vertexBuffer)
VERTEX_DIMENSION_SIZE代表的是填充一个二维的极点数据,类型为GLES20.GL_FLOAT。
烘托
GL程序与极点数据都现已准备完毕,接下来是最终一步烘托。
在烘托之前咱们需求对屏幕进行清屏操作,默认屏幕是黑色,咱们可以指定需求的清屏后的色彩
// 设置清屏色彩
GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
// 清屏处理
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
这儿指定清屏色彩为白色
在烘托之前设置烘托的视图方位与巨细,最终再进行烘托。
// 设置视图巨细
GLES20.glViewport(0, 0, mSurfaceViewWidth, mSurfaceViewHeight)
// 烘托
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertexData.size / VERTEX_DIMENSION_SIZE)
在烘托操作中运用了GLES20.GL_TRIANGLES,这是一种烘托方法,它代表会以每3个极点为一组的方法进行三角形烘托,所以咱们运行之后就能看到2个三角形。
参数0与mVertexData.size / VERTEX_DIMENSION_SIZE代表有6个极点且从第0个方位开端,也便是第一个极点方位。
最终咱们再来看下运行后的作用
大功告成,与咱们的预期彻底相同。
后续会持续聊聊色彩的动态填充、烘托的三种方法与纹理的操作,敬请期待。
源码地址:OpenGL ES
引荐
android_startup: 供给一种在运用发动时可以更加简单、高效的方法来初始化组件,优化发动速度。不仅支撑Jetpack App Startup的全部功能,还供给额定的同步与异步等候、线程操控与多进程支撑等功能。
AwesomeGithub: 根据Github的客户端,纯练习项目,支撑组件化开发,支撑账户暗码与认证登陆。运用Kotlin言语进行开发,项目架构是根据JetPack&DataBinding的MVVM;项目中运用了Arouter、Retrofit、Coroutine、Glide、Dagger与Hilt等流行开源技能。
flutter_github: 根据Flutter的跨渠道版本Github客户端,与AwesomeGithub相对应。
android-api-analysis: 结合具体的Demo来全面解析Android相关的常识点, 帮助读者可以更快的把握与理解所阐述的要点。
daily_algorithm: 每日一算法,由浅入深,欢迎参加一同共勉。