背景:使用GLSL渲染一张图片到屏幕上,发现图片是倒置的,这是因为屏幕的坐标原点在左上角,向右和向下为x和y正方向,而图片纹理坐标原点在左下角,向右和向上为正方向,导致图片渲染显示倒置。这就需要纹理翻转让图片显示正常。
基本策略有:
- 改变顶点数据的纹理坐标,翻转y值(1-y)
- 顶点着色器翻转y坐标,替换texCoord的值为```texCoord = vec2(texCoord.x, 1.0-texCoord.y);
纹理翻转的几种方式
1、GLKit处理纹理翻转
//设置纹理
- (void)setUpTexture {
//获取纹理图片路径
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"hua" ofType:@"jpg"];
//设置纹理相关参数,纹理原点左下角,view原点左上角
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft, nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
//GLBaseEffect完成着色器工作
cEffect = [[GLKBaseEffect alloc] init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
}
2、修改顶点着色器,传递旋转矩阵让图形翻转,不翻转纹理
图形的顶点坐标乘以旋转矩阵旋转180°,纹理坐标不变
//传递旋转矩阵,旋转180度
- (void)rotateTextureImage {
//!!!注意:获得shader里面的变量需要在glLinkProgram后面
//获取顶点着色器的旋转矩阵rotateMatrix
GLuint rotate = glGetUniformLocation(self.myProgram, "rotateMatrix");
//旋转的弧度,度数转弧度
float radians = 180 * 3.14159 / 180.0;
//弧度对应的sin和cos值
float s = sin(radians);
float c = cos(radians);
//Z轴旋转矩阵
GLfloat zRotation[16] = {
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
/*
glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
location:shader的ID
count:旋转矩阵个数
transpose:是否转置,是否横向矩阵转为列项矩阵
value:传递数据的指针,首地址
*/
glUniformMatrix4fv(rotate, 1, GL_FALSE, zRotation);
}
顶点着色器顶点坐标乘以旋转矩阵
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix; //旋转矩阵
varying lowp vec2 varyTextCoord;
void main() {
varyTextCoord = textCoordinate;
vec4 vPos = position; //精度已经预定义,不需要指定精度
vPos = vPos * rotateMatrix; //顶点坐标乘以旋转矩阵,每一个顶点都应用旋转变化
/*不能rotateMatrix * vPos,因为vPos是一行四列,rotateMatrix是四行四列,
vPos * rotateMatrix会得到新的一行四列的顶点坐标,反过来矩阵相乘没有意义*/
gl_Position = vPos;
}
3、解压缩绘制图片时使用CoreGraphic旋转纹理
解压缩绘制图片时将图片翻转180°
/**
创建上下文 CoreGraphic
@param spriteData 指向要渲染的绘图的内存地址
@param width bitmap的宽,单位是像素
@param height bitmap的高,单位是像素
@param 8 bitPerComponent,内存中像素的每个组件的位数,比如32位GRBA,就设置为8
@param 4 bytesPerRow,bitmap的每一行的内存所占的比特数
@param spriteData colorSpace,bitmap使用的颜色空间
@param kCGImageAlphaPremultipliedLast颜色信息 RGBA
*/
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
//绘制图片
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(spriteContext, rect, spriteImage);
CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0, -1.0);
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage);
CGContextRelease(spriteContext);
4、修改片元着色器,翻转纹理坐标的y值
x坐标不变,y坐标翻转:1-y坐标;每一个像素点都会执行y坐标翻转,会执行很多次
varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main() {
//获取纹理坐标时,x坐标不变,y坐标翻转:1-y坐标
gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x, 1.0-varyTextCoord.y));
}
5、修改顶点着色器,翻转顶点坐标的y值
x坐标不变,y坐标翻转:1-y坐标;图形的每个顶点都会执行y坐标翻转,会执行6次
attribute vec4 position;
attribute vec2 textCoordinate;
uniform mat4 rotateMatrix;
varying lowp vec2 varyTextCoord;
void main() {
//x坐标不变,y坐标翻转:1-y坐标
varyTextCoord = vec2(textCoordinate.x, 1.0-textCoordinate.y);
gl_Position = position;
}
6、修改顶点坐标和纹理坐标的映射关系
//设置顶点/纹理坐标,正常的映射关系
// GLfloat attrArr[] = {
// 0.5, -0.5, -1.0, 1.0, 0.0,
// -0.5, 0.5, -1.0, 0.0, 1.0,
// -0.5, -0.5, -1.0, 0.0, 0.0,
//
// 0.5, 0.5, -1.0, 1.0, 1.0,
// 0.5, -0.5, -1.0, 1.0, 0.0,
// -0.5, 0.5, -1.0, 0.0, 1.0,
// };
//修改图形的顶点坐标和纹理坐标的映射关系,翻转之后的映射关系
GLfloat attrArr[] = {
0.5, -0.5, -1.0, 1.0, 1.0,
-0.5, 0.5, -1.0, 0.0, 0.0,
-0.5, -0.5, -1.0, 0.0, 1.0,
0.5, 0.5, -1.0, 1.0, 0.0,
0.5, -0.5, -1.0, 1.0, 1.0,
-0.5, 0.5, -1.0, 0.0, 0.0,
};
网友评论