androidopengl旋转,OpenGL纹理旋转及翻转问题详解

更新时间:2023-06-30 00:15:10 阅读: 评论:0

androidopengl旋转,OpenGL纹理旋转及翻转问题详解
⼤家好,我是程序员kenney,今天给⼤家讲解⼀下Android上OpenGL开发可能会遇到的⼀些纹理旋转及翻转的问题,其中有些原理在其它平台上如ios,osx上也是类似的。纹理旋转的问题⼀定要搞清楚,不能每当碰到⼀个⽅向不对的就⾃⼰旋转⼀下把它转正⽽不去研究背后的原因,这样虽然这⼀步旋转正确了,但之后的处理步骤可能都是建⽴在错误的认知上进⾏的,容易错上加错。
我们先来了解⼀下⼏个坐标系什么是电子邮箱
⾸先看下图⽚坐标系和纹理坐标系。图⽚坐标系的原点在图⽚左上⾓,x轴向右,y轴向下,x和y的取值范围都是0到对应的图⽚宽⾼。纹理坐标的原点在纹理左下⾓,x轴向右,y轴向上,x和y的取值范围都是0到1。把⼀张图⽚加载到纹理中,图⽚数据就会从图⽚坐标系到了纹理坐标系。石头男
再来看看NDC坐标系和屏幕坐标系。NDC坐标系就是设备标准化坐标系,是投影变换后将坐标归⼀化后就转换到了NDC坐标系,它的x轴向右,y轴向上,x和y的取值范围都是-1到1,这个范围就是显⽰的区域,超出这个范围的都不可见,NDC坐标系这个词可能稍显陌⽣,其实就是通常说的顶点坐标系,但从严格意义上说还是应该叫NDC坐标系,因为顶点严格来说是世界坐标系中的,世界坐标系是三维
的,NDC坐标系中的顶点其实是投影变换后将坐标归⼀化后得到的顶点。
屏幕坐标系x轴向右,y轴向下,x和y的取值范围都是0到对应的屏幕宽⾼。
在矩阵变换的最后⼀步变换中OpenGL会将NDC坐标系变换成屏幕坐标系然后上屏显⽰。
形容男性的成语
除此之后还有模型坐标系、视图坐标系等(可以参考:OpenGL ES ⾼级进阶:坐标系及矩阵变换),这⾥就不⼀⼀介绍了,因为不是讨论的重点。
另外,我们说"倒"的时候,实际上有两种倒,⼀种是上下倒置,⼀种是旋转了180度,是不⼀样的,要注意区别,看下图:
我们来看⼀些经常会遇到的问题:
荫蔽的意思1. 我的图⽚在图⽚查看器中看到是正的,程序中解码后查看是旋转过的
这时考虑是没处理exif中的旋转信息导致的,exif中有⼀个记录图⽚旋转值的信息,它会告诉你将图⽚旋转⼀个⾓度才是这张图的正确效果。exif信息可以有也可以没有,即使有exif信息,这个旋转值也不⼀定有,要看⽣成这个图⽚的逻辑有没有将它写进去。总之如果有exif 信息并且其的旋转⾓度不是0,
则要处理⼀下旋转让图⽚旋转到⼀个正确状态。在图⽚查看器中查看之所以是正常的,是因为图⽚查看器⼀般都处理了exif信息,会旋转后再展⽰出来。
2. 我的图⽚在程序中解码后查看是正的,OpenGL渲染出来是上下倒置的
在整个渲染管线中,有很多地⽅能影响翻转,⽐如将顶点坐标上下flip,或者将纹理坐标上下flip,或者将OpenGL摄像机y⽅向向量上下flip 等,我们本⽂中都先将这些因素先排除,来看最简单的情况,直接使⽤NDC坐标作为顶点坐标,不进⾏MVP矩阵变换。
假设我们渲染⽤的顶点坐标、纹理坐标配置分别是:
顶点坐标(-1, -1)对应纹理坐标(0, 0)、顶点坐标(-1, 1)对应纹理坐标(0, 1)、顶点坐标(1, 1)对应纹理坐标(1, 1)、顶点坐标(1, -1)对应纹理坐标(1, 0)。
那么渲染出来的结果是?
发现上下倒了过来,这是什么原因呢?是因为在程序中查看解码后的图⽚,实际上还是在图⽚坐标系下显⽰的,图⽚坐标系和纹理坐标系y 是相反的,当你把图⽚加载到纹理中的那⼀刻,图⽚在纹理坐标系下就已经倒了:中秋节英语作文
因此渲染⼀个倒的纹理,看到的⾃然是倒的。有细⼼的同学会发现,NDC坐标系和屏幕坐标系也是y轴相反的,为什么从NDC坐标系到最后的屏幕坐标系时它不会倒⼀下?因为NDC坐标系变换成屏幕坐标系的过程中OpenGL进⾏了相应的处理使得它不会倒过来,⽽把⼀张图⽚加载到纹理中是没有这样的变换过程的,是直接把数据扔进去,原点对齐,然后数据往对应轴的⽅向填充。
**这就是为什么常常发现在图⽚渲染场景下,在上屏的那⼀步渲染中要再上下翻转⼀下,⽽在相机和视频渲染中却不⽤的原因。**因为相机和视频渲染开发中,只要设置正确,相机和视频吐出来的纹理就是正的(后⾯会讲解),⽽图⽚场景下却没有办法让它加载到纹理后让它在纹理坐标系下的⽅向保持和图⽚坐标系下⼀致。
3. 我把纹理⽤glReadPixels读出来查看是正的,OpenGL渲染出来是上下倒置的
这个问题和问题2很类似,问题2的原因在于图⽚加载到纹理中产⽣了上下倒置,相反,从纹理将数据读出来显⽰也⼀样没有变换过程,也是直接把数据读出来,原点对齐,然后数据往对应轴的⽅向填充,因此如果glReadPixels出来的图⽚是正的,说明纹理在纹理坐标系中是上下倒置的,因此相当于渲染⼀个上下倒置的纹理。
4. 我的相机渲染画⾯是旋转过的
⾸先检测⼀下相机的display orientation设置是否正确,设置⽅法可参考android官⽅给出的⼀个标准写法:
public static void tCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera){
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.CameraInfo(cameraId, info);
int rotation = WindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
ca Surface.ROTATION_0: degrees = 0; break;
ca Surface.ROTATION_90: degrees = 90; break;
ca Surface.ROTATION_180: degrees = 180; break;
ca Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (ientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} el { // back-facing
result = (ientation - degrees + 360) % 360;
}
camera.tDisplayOrientation(result);
}
复制代码
此时从相机得到的图像还不⼀定是正的,如果将OES纹理glReadPixels出来查看,会发现它可能有各种旋转情况,不⽤担⼼,这是正常的,因为还需要做⼀步转换,SurfaceTexture有⼀个getTransformMatrix⽅法,它返回⼀个纹理坐标变换矩阵,我们在将OES纹理转换成普通纹理的时候可以顺带把纹理坐标⽤这个矩阵变换⼀下,这样转换后得到的纹理在纹理坐标系下就是正的,以下是shader:
val OES_VERTEX_SHADER =
"precision mediump float;\n" +
"attribute vec4 a_position;\n" +
"attribute vec4 a_textureCoordinate;\n" +
"varying vec2 v_textureCoordinate;\n" +
"uniform mat4 u_stMatrix;\n" +
"void main() {\n" +
" v_textureCoordinate = (u_stMatrix * a_textureCoordinate).xy;\n" +
" gl_Position = a_position;\n" +
我学会了包饺子作文
"}"
val OES_FRAGMENT_SHADER =
"#extension GL_OES_EGL_image_external : require\n" +
"precision mediump float;\n" +
"varying vec2 v_textureCoordinate;\n" +腾龙山
"uniform samplerExternalOES u_texture;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(u_texture, v_textureCoordinate);\n" +
"}"
复制代码
5. 我的视频渲染画⾯是旋转过的
这⾥讨论的是视频硬解码到SurfaceTexture上的场景,它和相机很类似,不过不像相机那样先要设置⼀下旋转。它解码到SurfaceTexture 上后也同样要做纹理坐标的变换才能变正,这⾥有⼀个兼容性问题要处理下,就是android 5.0 以下的系统SurfaceTexture返回的矩阵中是不包含视频旋转⾓度的,因此需要将旋转变换加到矩阵中:
private fun getStMatrix(surfaceTexture: SurfaceTexture, videoPath: String): FloatArray {
val stMatrix = FloatArray(16)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
val rotateStMatrix = FloatArray(16)
val rotateMatrix = FloatArray(16)
Matrix.tIdentityM(rotateMatrix,0)
Matrix.multiplyMM(rotateStMatrix, 0, rotateMatrix, 0, stMatrix, 0)
return rotateStMatrix
}
return stMatrix
九下历史书
}
复制代码
视频旋转⾓度的获取⽅法多种多样,最简单的就是⽤系统的MediaMetadataRetriever就可以。这⾥注意旋转时先要纹理的中⼼点移动到原点再旋转,旋转完后再移回原位置。否则效果就会是基于(0,0)点也就是纹理左下⾓的旋转,这样就不对了,看下图:
最后再乘上原矩阵,就是最终的变换矩阵,这样视频帧就会转成正的了。
好了,以上就是⼀些纹理旋转⽅向问题的分析,感谢阅读,我的github:/kenneycode

本文发布于:2023-06-30 00:15:10,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1060820.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:坐标系   纹理   旋转   坐标   渲染
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图