在在上篇OpenGL ES 使用GLSL加載圖片案例中,我們發(fā)現(xiàn)加載的圖片是倒置的,如下圖所示

倒置的原因:主要是由于紋理坐標(biāo)的原點(diǎn)(0,0)是在左下角,而屏幕的坐標(biāo)原點(diǎn)(0,0)是在左上角。
幾種紋理倒置的解決方案
方案一:圖形頂點(diǎn)翻轉(zhuǎn)180°,紋理保持原狀
- 在自定義的頂點(diǎn)著色器中實(shí)現(xiàn)頂點(diǎn)數(shù)據(jù)的翻轉(zhuǎn)
180°,需要將頂點(diǎn) * 旋轉(zhuǎn)矩陣,得到新的頂點(diǎn)坐標(biāo),在賦值給內(nèi)建變量gl_Position
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
vec4 vPos = position;
vPos = vPos * rotateMatrix;
gl_Position = vPos;
}
- 自定義方法:使用矩陣翻轉(zhuǎn)圖形頂點(diǎn)
- (void)rotateTextureImage{
//注意,想要獲取shader里面的變量,這里記得要在glLinkProgram后面,后面,后面!
//1. rotate等于shaderv.vsh中的uniform屬性,rotateMatrix
GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
//2.獲取渲旋轉(zhuǎn)的弧度
float radius = 180 * 3.14159f / 180.0f;
//3.求得弧度對(duì)于的sin\cos值
float s = sin(radius);
float c = cos(radius);
//4.設(shè)置旋轉(zhuǎn)矩陣 OpenGL ES用的是列向量
/*
參考Z軸旋轉(zhuǎn)矩陣
*/
GLfloat zRotation[16] = {
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
//5.設(shè)置旋轉(zhuǎn)矩陣
/*
glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
location : 對(duì)于shader 中的ID
count : 個(gè)數(shù)
transpose : 轉(zhuǎn)置
value : 指針
*/
glUniformMatrix4fv(rotate, 1, GL_FALSE, zRotation);
}
- 在
renderLayer函數(shù)中的設(shè)置紋理采樣器之后調(diào)用[self rotateTextureImage];
問題
其實(shí)在上述步驟之后翻轉(zhuǎn)的圖片雖然翻轉(zhuǎn)了,但是并不是我們期望的結(jié)果,所以,還需要再次進(jìn)行翻轉(zhuǎn),即圍繞x軸進(jìn)行翻轉(zhuǎn),在上面代碼的基礎(chǔ)上增加以下代碼
-
shaderv.vsh中增加一個(gè)翻轉(zhuǎn)矩陣uniform mat4 scaleMatrix; - 修改
main中矩陣相乘為vPos = vPos * rotateMatrix * scaleMatrix;
shaderv.vsh完整源碼如下
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
uniform mat4 scaleMatrix;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
vec4 vPos = position;
vPos = vPos * rotateMatrix * scaleMatrix;
gl_Position = vPos;
}
-
view中的rotateTextureImage函數(shù)中- 拿到著色器中
scaleMatrix的入口 - 在
zRotation矩陣數(shù)組后新增一個(gè)翻轉(zhuǎn)矩陣 - 再設(shè)置一個(gè)翻轉(zhuǎn)矩陣
- 拿到著色器中
rotateTextureImage完整代碼如下
- (void)rotateTextureImage{
//注意,想要獲取shader里面的變量,這里記得要在glLinkProgram后面,后面,后面!
//1. rotate等于shaderv.vsh中的uniform屬性,rotateMatrix
GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
GLuint scale = glGetUniformLocation(self.myPrograme, "scaleMatrix");
//2.獲取渲旋轉(zhuǎn)的弧度
float radius = 180 * 3.14159f / 180.0f;
//3.求得弧度對(duì)于的sin\cos值
float s = sin(radius);
float c = cos(radius);
//4.因?yàn)樵?D課程中用的是橫向量,在OpenGL ES用的是列向量
/*
參考Z軸旋轉(zhuǎn)矩陣
*/
GLfloat zRotation[16] = {
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
GLfloat scaleMartix[16] = {
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
//5.設(shè)置旋轉(zhuǎn)矩陣
/*
glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
location : 對(duì)于shader 中的ID
count : 個(gè)數(shù)
transpose : 轉(zhuǎn)置
value : 指針
*/
glUniformMatrix4fv(rotate, 1, GL_FALSE, zRotation);
glUniformMatrix4fv(scale, 1, GL_FALSE, scaleMartix);
}
方案二:解壓圖片時(shí),將圖片源文件翻轉(zhuǎn)
在加載紋理setupTexture函數(shù)的第六步 使用默認(rèn)方法繪制后,及context繪制的圖片進(jìn)行翻轉(zhuǎn),主要代碼如下
//圍繞x、y平移
CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
//圍繞y平移
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
//x?向不變 y?向沿著畫布?己的 坐標(biāo)系對(duì)應(yīng)的y軸渲染
CGContextScaleCTM(spriteContext, 1.0, -1.0);//翻轉(zhuǎn)
//相對(duì)于畫布,在自己的坐標(biāo)系上畫圖
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage);
也可以簡(jiǎn)化為:
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
//x?向不變 y?向沿著畫布?己的 坐標(biāo)系對(duì)應(yīng)的y軸渲染
CGContextScaleCTM(spriteContext, 1.0, -1.0);//翻轉(zhuǎn)
CGContextDrawImage(spriteContext, rect, spriteImage);
方案三:修改片元著色器,紋理坐標(biāo)圍繞y軸翻轉(zhuǎn)
將shaderf.fsh中的gl_FragColor = texture2D(colorMap, varyTextCoord);改為gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x,1.0-varyTextCoord.y));,將紋理坐標(biāo)圍繞y軸翻轉(zhuǎn)
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main()
{
//gl_FragColor = texture2D(colorMap, varyTextCoord);
gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x,1.0-varyTextCoord.y));
}
方案四:修改頂點(diǎn)著色器,紋理坐標(biāo)圍繞y軸翻轉(zhuǎn)
將shaderv.vsh中的varyTextCoord = textCoordinate;改為varyTextCoord = vec2(textCoordinate.x,1.0-textCoordinate.y);,將紋理坐標(biāo)圍繞y軸翻轉(zhuǎn),其實(shí)方案四與方案三是一個(gè)原理,只是在不同的著色器中修改紋理坐標(biāo)
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main()
{
//varyTextCoord = textCoordinate;
varyTextCoord = vec2(textCoordinate.x,1.0-textCoordinate.y);
gl_Position = position;
}
方案五:直接修改頂點(diǎn)數(shù)組中的紋理坐標(biāo)
原理同3、4一致,只是直接在頂點(diǎn)數(shù)組中修改源數(shù)據(jù)
- 原頂點(diǎn)數(shù)據(jù)數(shù)組
GLfloat attrArr[] =
{
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
0.5f, 0.5f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
};
- 修改后的頂點(diǎn)數(shù)組
GLfloat attrArr[] =
{
0.5f, -0.5f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -1.0f, 0.0f, 1.0f,
0.5f, 0.5f, -1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -1.0f, 1.0f, 1.0f,
};
方案六:直接翻轉(zhuǎn)頂點(diǎn)著色器中的頂點(diǎn)
在翻轉(zhuǎn)頂點(diǎn)時(shí),就不是直接對(duì)Y值用1去減,因?yàn)轫旤c(diǎn)的取值范圍是[-1 1] ,所以我們直接加上負(fù)號(hào)做翻轉(zhuǎn)即可
attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;
void main(){
varyTextCoord = textCoordinate;
gl_Position = vec4(position.x, -position.y, position.z, 1);
}
總結(jié)
根據(jù)本文提及的6個(gè)方案,可以簡(jiǎn)單歸納為以下三種倒置翻轉(zhuǎn)的思路
翻轉(zhuǎn)紋理坐標(biāo)(可以在頂點(diǎn)著色器、片元著色器,甚至頂點(diǎn)數(shù)組中修改):方案三、方案四、方案五
翻轉(zhuǎn)頂點(diǎn)坐標(biāo)(通過矩陣旋轉(zhuǎn),或者定點(diǎn)著色器中修改頂點(diǎn)坐標(biāo)):方案一、方案六
圖片源文件翻轉(zhuǎn)(其實(shí)也是通過將context通過矩陣變換進(jìn)行翻轉(zhuǎn)):方案二