最近用GLSL实现渲染图片,原始图片是正常显示的,但是渲染出来的是倒置的,通过查找许多资料才明白是因为手机的(0,0)点在左上角,纹理的(0,0)点在左下角,所以才会产生这样的问题,所以总结了下面5种纹理翻转方法供大家参考也方便后期查阅。
一、旋转顶点坐标
在顶点着色器中,将顶点坐标叉乘一个180度旋转矩阵。代码如下:
-
顶点着色器
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; }
-
旋转矩阵输入
//1. rotate等于shaderv.vsh中的uniform属性,rotateMatrix GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix"); //2.获取渲旋转的弧度 float radians = 180 * 3.14159f / 180.0f; //3.求得弧度对于的sin\cos值 float s = sin(radians); float c = cos(radians); //4.因为在3D课程中用的是横向量,在OpenGL ES用的是列向量 /* 参考Z轴旋转矩阵 */ GLfloat zRotation[16] = { c,-s,0,0, s,c,0,0, 0,0,1,0, 0,0,0,1 }; //5.设置旋转矩阵 /* glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) location : 对于shader 中的ID count : 个数 transpose : 转置 value : 指针 */ glUniformMatrix4fv(rotate, 1, GL_FALSE, zRotation);
二、解压图片时改变图片坐标
加载纹理时,需要解压图片,此时通过平移缩放改变图片坐标,即可达成目的。相关代码如下:
-
图片解压、平移、缩放
//1、将 UIImage 转换为 CGImageRef CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage; //判断图片是否获取成功 if (!spriteImage) { NSLog(@"Failed to load image %@", fileName); exit(1); } //2、读取图片的大小,宽和高 size_t width = CGImageGetWidth(spriteImage); size_t height = CGImageGetHeight(spriteImage); //3.获取图片字节数 宽*高*4(RGBA) GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); //4.创建上下文 /* 参数1:data,指向要渲染的绘制图像的内存地址 参数2:width,bitmap的宽度,单位为像素 参数3:height,bitmap的高度,单位为像素 参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8 参数5:bytesPerRow,bitmap的没一行的内存所占的比特数 参数6:colorSpace,bitmap上使用的颜色空间 kCGImageAlphaPremultipliedLast:RGBA */ CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); //5、在CGContextRef上--> 将图片绘制出来 /* CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit 不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角。 CGContextDrawImage 参数1:绘图上下文 参数2:rect坐标 参数3:绘制的图片 */ CGRect rect = CGRectMake(0, 0, width, height); //6.使用默认方式绘制 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); //7、画图完毕就释放上下文 CGContextRelease(spriteContext);
三、改变纹素获取坐标
在片元着色器中,改变纹素获取的y值,即可达成目的。
-
片元着色器代码
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)); }
四、改变纹理坐标
在顶点着色器中,改变纹理坐标的y值,即可达成目的。
-
顶点着色器代码
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; }
五、直接改动纹理坐标数组
最复杂的方法,但是最容易想到的,就是在顶点、纹理坐标数组里改变纹理坐标值。
-
数组改变代码
//前3个是顶点坐标,后2个是纹理坐标 // 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, // }; 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, };