opengl中坐标系对应关系
1:纹理坐标和顶点坐标对应关系
一般写一个opengl的render之后会写2个坐标系,一个是顶点坐标系,一个是纹理坐标系
具体坐标展示如下:
image-20230903232448645.png顶点坐标系,一般四个顶点,V0,V1,V2,V3,四个点对应成数组为
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
一般绘制整个屏幕的时候 就绘制2个三角形,2个三角形的2个顶点组成分别为 v0,v1,v2 和 v1,v2,v3
纹理坐标一般展示如下:
image-20230903233034036.png具体坐标长得如下:
public final static float[] TEXTURE_ROTATE_0 = {
0.0f, 0.0f,//T0
1.0f, 0.0f,//T1
0.0f, 1.0f,//T2
1.0f, 1.0f//T3
};
根据上面的对应关系,我们在写完render进行往上面绘制图像时,一般采取v0 对应T0,v1 对应T1,V2对应T2,V3对应T3 根据此种关系来进行绘制图形,即可将纹理根据刚才的对应关系贴上去
2:纹理坐标和展示窗口坐标
在A ndroid 设备中,一般左上角为原点(0,0)向右为x轴正方向,向下为 Y轴正方向,但是和上面的2个坐标系不一样,次坐标系并没有进行归一化,也就是向下和向右的正方向的做大值为屏幕实际像素大小值
image-20230903233646021.png那为什么单独提出来此坐标系来和纹理坐标系对应,因为如果按照第一节上面说的顶点坐标和纹理坐标对应,加载出来的纹理实际因为Android View坐标系的原因是上下颠倒的,因此需要我们在使用纹理坐标系时,对纹理先进性第一步处理,即上下颠倒一次。
上下颠倒如何理解?即T0点和T2点互换位置,T3和T1互换位置
上下颠倒完成一次之后的 顶点坐标和纹理坐标对应关系如下:
//上下颠倒过的顶点坐标和纹理坐标对应关系
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
public final static float[] TEXTURE_ROTATE_0 = {
0.0f, 1.0f,//新T0 原来的T2
1.0f, 1.0f,//新T1 原来的T3
0.0f, 0.0f,//新T2 原来的T0
1.0f, 0.0f //新T3 原来的T1
};
3:旋转角度
在经过第二步的处理之后,如果是一张静态图片,此时在Android View的窗口中已经能正常展示了,但是如果是从摄像头出来的数据本身带有一定的角度的话,我们还需要对纹理进行进一步的旋转。涉及到的主要几个角度是,相机出来的图片角度,屏幕的角度,以及纹理的方向。
3.1:相机出图片角度
在不考虑前置相机需要左右的镜像,不考虑纹理贴向Android View坐标系时的上下翻转,一般相机的出图如下:
实际相机图片展示,在一般Android上 后置相机一般时 orientation为90度,前置相机为 orientation为270度
image-20230910110417561.png3.2:相机出图的贴到纹理上
相机图片要贴到纹理上,需要我们知道纹理坐标和顶点坐标的对应关系,目前我们在opengl中创建了opengl的program 之后,相当于我们已经把画布布置好了,画布的大小不确定,有可能是 1080 *1920 大小的竖图,也有可能是 1280*720的横图,为此,opengl为了方便绘制,将最后展示的空间都归一化,也就是(-1,1)之间,所以我们在创建oepngl的program时,传入的顶点坐标就是
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
因为纹理绘制时,需要把纹理的每一个点和顶点的每一个点对应上即可,也就是如第二小节中的,T0<-->V0对应,T1<-->V1对应等,但是按照这种对应方式有可能使得图片出现旋转,镜像等,因此需要我们先将图像旋转正确,就像3.1小节中orition为0的时候的展示图像。因此我们基于T0<-->V0,T1<-->V1可以得到一种对应关系,此种对应关系如果出来的图像不是正确的,我们就可以以此作为标准 将纹理进行旋转和镜像进行得到正确的展示,就会得到一下几种对应关系:
我们规定,T0,T1,T2,T3坐标分别为(0,0),(1,0),(0,1),(1,1)
标准对应关系:
//标准对应关系,此时出现的纹理有可能是镜像的,顺时针或者逆时针旋转过的
//V0<-->T2
//V1<-->T3
//V2<-->T0
//V3<-->T1
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
public final static float[] TEXTURE_ROTATE_0 = {
0.0f, 1.0f,//T2
1.0f, 1.0f,//T3
0.0f, 0.0f,//T0
1.0f, 0.0f//T1
};
顺时针旋转90度
//顶点绘制顺序 v0 v1 v2 ,v1,v2,v3
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
//V0<-->T3
//V1<-->T1
//V2<-->T2
//V3<-->T0
public final static float[] TEXTURE_ROTATE_90 = {
1.0f, 1.0f,//T3
1.0f, 0.0f,//T1
0.0f, 1.0f,//T2
0.0f, 0.0f //T0
};
顺时针旋转180度
//顶点绘制顺序 v0 v1 v2 ,v1,v2,v3
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
//V0<-->T1
//V1<-->T0
//V2<-->T3
//V3<-->T2
public final static float[] TEXTURE_ROTATE_180 = {
1.0f, 0.0f,//T1
0.0f, 0.0f,//T0
1.0f, 1.0f,//T3
0.0f, 1.0f//T2
};
顺时针旋转270度
//顶点绘制顺序 v0 v1 v2 ,v1,v2,v3
public final static float[] VERTEX = {
-1.0f, -1.0f,//V0
1.0f, -1.0f,//V1
-1.0f, 1.0f,//V2
1.0f, 1.0f //V3
};
//V0<-->T0
//V1<-->T2
//V2<-->T1
//V3<-->T3
public final static float[] TEXTURE_ROTATE_270 = {
0.0f, 0.0f,//T0
0.0f, 1.0f,//T2
1.0f, 0.0f,//T1
1.0f, 1.0f//T3
};
PS:我们上面的坐标在绘制基准态的坐标对应时,并没有按照V0-->T0,V1--->T1,V2--->T2,V3-->T3的标准来对应,因为纹理在往内存区域贴的时候可以以任何一个点对应顶点的点,只要顶点的绘制关系和纹理的点坐标对齐即可。我们选择的标准是 //V0<-->T2 V1<-->T3 V2<-->T0 V3<-->T1来对应的,因此基于此我们可以得到实际纹理内容的方向,然后我们在基于VERTEX -->对应TEXTURE_ROTATE_0 得到的结果进一步调整纹理,使得纹理方向贴合到屏幕上 符合人类观察视觉。在Android上一般后置摄像头旋转90度,前置旋转270度,是一般经验,但是此经验可以根据实际调整
PS2:
1:在一般常见的使用流程中,可能会有多个opengl 的program在进行串行绘制,在串行绘制的过程中,每一个opengl 的program都存在一次顶点和纹理坐标的映射关系,也就是上面VERTEX和TEXTURE_ROTATE_0的对应关系在单帧绘制中,可能存在多次对应关系。
2:每一次新的一个program绘制,先存在一个 顶点和纹理坐标的对应关系,然后把上一次的绘制结果当成一个纹理在本次的program中进行操作。
3:如果采用都往fbo对应的纹理上绘制,也就是多个program操作同一个纹理,那么每一个program都可能的对单次绘制的顶点和纹理坐标系进行操作,而进一步影响最后绘制结果
3.3:纹理图片贴到View坐标系下
纹理显示的最后一步就是将上面纹理和顶点旋转完成之后在贴到屏幕上,在贴到屏幕上的时候是要完成一个 屏幕的View坐标系和纹理坐标系的一个转化,在上屏幕的过程只有一点注意即可,即将纹理做一次上下颠倒即可,具体可参考第二节的详细介绍