前言
OpenGL是Android音视频开发绕不过去的东西,书接上文,OpenGL ES加载一张小猫咪图片加载出来的小猫咪图片是倒着的,而且还把猫脸拉长了。像下图这样:
本文就分析一下为啥会这样,然后将它摆正。有爱好能够拷一份代码一同看看:github.com/MReP1/OpenG…。
分析原因
猫咪翻转
倒过来也分两种状况,一种是旋转180度,别的一种是笔直翻转,而从结果来看,咱们展现的小猫咪是笔直翻转了。
因为在默认状况下,OpenGL ES 中的纹路坐标系的原点在左下角,而图画数据通常是从左上角开始存储的。因而,当加载图画数据到纹路中时,图画会在笔直方向上翻转。
图片拉伸
而图片被拉伸的原因是因为纹路坐标和极点坐标的映射不正确。咱们看一下代码中的极点着色器的shader代码。
private val VERTEX_SHADER_STRING = """
#version 300 es
precision mediump float;
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 inputTextureCoordinate;
uniform mat4 textureTransform;
out vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = (textureTransform * inputTextureCoordinate).xy;
}
""".trimIndent()
private const val glPositionId = 0
代码中的position入参能够用于调整极点的方位,它是一个四维变量,在前文中,我图方便,直接传入了填满整个NDC坐标系的四个极点,由所以展现图片,没有涉及到3D,所以只传入了x轴和y轴的值。
val FULL_RECTANGLE_BUF = floatArrayOf(
-1.0f, -1.0f, // Bottom left.
1.0f, -1.0f, // Bottom right.
-1.0f, 1.0f, // Top left.
1.0f, 1.0f // Top right.
).toFloatBuffer()
GLES30.glVertexAttribPointer(
glPositionId, 2, GLES30.GL_FLOAT, false, 0, FULL_RECTANGLE_BUF
)
此刻上屏展现之后的效果便是将纹路中的内容拉伸填满至四角。
OpenGL以三个极点为单位制作内容,但是为什么这儿能够传入四个极点能正常显现。这个和制作API传入的参数GLES30.GL_TRIANGLE_STRIP
有关。此处与拉伸的问题无关先不展开。
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)
问题处理
处理图片翻转
还记得咱们在极点着色器传入了一个矩阵吗?
// 将矩阵传入着色器uniform变量
val glTexTransformId = GLES30.glGetUniformLocation(programId, "textureTransform")
GLES30.glUniformMatrix4fv(glTexTransformId, 1, false, identityMtx, 0)
而在极点着色器中将纹路坐标与矩阵相乘,取得实践烘托的方位,由于烘托图片是2D的,因而只取xy轴。
textureCoordinate = (textureTransform * inputTextureCoordinate).xy;
此刻咱们就能够对这个矩阵做手脚了,一开始运用的矩阵是一个单位矩阵,咱们在小学二年级的线性代数中背过矩阵相乘公式,证明这个矩阵与另一个矩阵相乘的结果是不变的。
val identityMtx = floatArrayOf(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
)
看到这儿,其实处理方法很简略了,咱们能够将这个矩阵换成一个翻转的矩阵。所以我运用Matrix
东西类的函数来做缩放操作,将y轴缩到-1。
Matrix.scaleM(identityMtx, 0, 1f, -1f, 1f)
所以咱们就把图片翻到下面去了,咱们需要将这个图片挪回原位,像这样:
咱们仍是运用Matrix
东西类来将矩阵调整一下:
Matrix.translateM(identityMtx, 0, 0f, -1f, 0f)
翻转问题搞好了,接下来处理拉伸问题。
处理图片拉伸
处理拉伸的方式有很多种,这儿就简略评论两种,注意:下面处理方式只针对本案例,而在实践运用需要考虑更多状况。
修正极点
依据肉眼调查,是在竖直方向拉长了,此刻咱们就将极点坐标往里缩缩就好啦。
val ratio = (bitmap.width).toFloat() / (bitmap.height).toFloat()
val rectangleBuf = floatArrayOf(
-1F, -1F * ratio,
1F, -1F * ratio,
-1F, 1F * ratio,
1.0F, 1F * ratio
).toFloatBuffer()
GLES30.glVertexAttribPointer(
glPositionId, 2, GLES30.GL_FLOAT, false, 0, rectangleBuf
)
将极点的y轴往里缩缩就好啦
修正制作ViewPort
那假如我不想改极点,也能够在制作的时候修正制作的ViewPort。
val viewPortWidth: Int
val viewPortHeight: Int
if (width > height) {
viewPortWidth = height * bitmap.width / bitmap.height
viewPortHeight = height
} else {
viewPortWidth = width
viewPortHeight = width * bitmap.height / bitmap.width
}
val y = (height - viewPortHeight) / 2
val x = (width - viewPortWidth) / 2
// 设置ViewPort
GLES30.glViewport(x, y, viewPortWidth, viewPortHeight)
// 制作纹路
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)
第一步首先获取制作ViewPort的巨细。由于图片的份额和咱们屏幕份额不相同嘛,所以咱们就将制作的份额调整成和图片的份额相同,再算出屏幕最大能够制作的宽高像素。
第二部就需要调整制作ViewPort的方位,也便是x,y轴,将制作区域居中。
如下图所示蓝色框框便是ViewPort方位:
总结
到这儿,猫咪照片就被摆正了,我们也能够拉一下文章开头的代码跑一下看看,挺好玩的。这个OpenGL ES小案例就告一段落了,之后便是真正关于Android音视频的内容了。水平有限,因而写的比较少,引荐我们看看下列参阅文章。
参阅
矩阵改换:
- /post/684490…
- /post/684490…
纹路翻转问题:
- /post/685457…
着色器
- xcsf.github.io/blog/2020/0…