OpenGL/OpenGL ES入门:iOS纹理翻转策略解析

2,252 阅读3分钟

系列推荐文章:
OpenGL/OpenGL ES入门:图形API以及专业名词解析
OpenGL/OpenGL ES入门:渲染流程以及固定存储着色器
OpenGL/OpenGL ES入门:图像渲染实现以及渲染问题
OpenGL/OpenGL ES入门:基础变换 - 初识向量/矩阵
OpenGL/OpenGL ES入门:纹理初探 - 常用API解析
OpenGL/OpenGL ES入门: 纹理应用 - 纹理坐标及案例解析(金字塔)
OpenGL/OpenGL ES入门: 顶点着色器与片元着色器(OpenGL过渡OpenGL ES)
OpenGL/OpenGL ES入门: GLKit以及API简介
OpenGL/OpenGL ES入门: GLKit使用以及案例
OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片
OpenGL/OpenGL ES入门:iOS纹理翻转策略解析
OpenGL ES入门: 渲染金字塔 - 颜色、纹理、纹理与颜色混合填充以及GLKit实现

在上一篇文章OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片的案例二中渲染图片时,CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角,导致了图片翻转的问题,同时也提出了一种解决方案,这篇文章,我们总结一下关于解决图片翻转的策略。

纹理翻转策略

第一种:解压图片时,将图片源文件翻转

    CGRect rect = CGRectMake(0, 0, width, height);
    CGContextTranslateCTM(spriteContext, 0, rect.size.height);
    CGContextScaleCTM(spriteContext, 1.0, -1.0);
    CGContextDrawImage(spriteContext, rect, spriteImage);

第一种也是在上篇文章OpenGL/OpenGL ES入门: 使用OpenGL ES 渲染图片中使用的方案,具体的翻转实现都有详细的说明,需要了解的小伙伴可以前去查看。

第二种:旋转矩阵翻转图形,不翻转纹理

思路:让图形的所有顶点都旋转180度,纹理坐标不用改变
在顶点着色器中声明一个uniform,传入一个旋转矩阵,使每个顶点都进行旋转

attribute vec4 position;
uniform mat4 rotationMatrix;

void main() {
    vec4 vPos;
    vPos = position * rotationMatrix;
    gl_Position = vPos;
}

然后获取这个旋转矩阵的入口通道,进行赋值:

// rotate等于shaderv.vsh中的uniform属性,rotateMatrix
GLuint rotate = glGetUniformLocation(self.myProgram, "rotationMatrix");
// 获取渲旋转的弧度
float radians = 180 * 3.14159f / 180.0f;
// 求得弧度对于的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, 0, 0, 1.0
};
// 设置旋转矩阵
    /*
     glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
     location : 对于shader 中的ID
     count : 个数
     transpose : 转置
     value : 指针
     */
glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);

苹果文档关于单元矩阵,平移,缩放,围绕x,y,z轴旋转的矩阵

第三种:修改片元着色器,纹理坐标

思路:改变顶点数据的纹理坐标,翻转y值(用1减去y坐标)

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;

void main()
{ 
    gl_FragColor = texture2D(colorMap, vec2(varyTextCoord.x, 1.0 - varyTextCoord.y));
}

第四种:修改顶点着色器,纹理坐标

思路,同第三种一样,只不过纹理坐标的修改,放在了顶点着色器中

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main()
{
    varyTextCoord = vec2(textCoordinate.x, 1.0 - textCoordinate.y);
    gl_Position = position;
}

第五种:直接从源纹理坐标数据修改

思路:最后一种方法是在生成顶点数组的时候,直接改变纹理坐标的映射方式

GLfloat attrArr[] =
     {
     0.5f, -0.5f, 0.0f,        1.0f, 1.0f, //右下
     -0.5f, 0.5f, 0.0f,        0.0f, 0.0f, // 左上
     -0.5f, -0.5f, 0.0f,       0.0f, 1.0f, // 左下
     0.5f, 0.5f, 0.0f,         1.0f, 0.0f, // 右上
     -0.5f, 0.5f, 0.0f,        0.0f, 0.0f, // 左上
     0.5f, -0.5f, 0.0f,        1.0f, 1.0f, // 右下
     };

个人感觉这种方式是最实在的方式,在一开始就杜绝了图片翻转的问题。

总结: 以上5种方法,都可以解决我们遇到的图片翻转的问题,在实际开发当中,具体使用哪一种方式,看大家的心情。

OpenGL/OpenGL ES入门: GLKit使用以及案例文章中,在使用GLKit渲染图片的过程里,其实我们也遇到了图片翻转的问题,只不过因为GLKit封装的原因,我们使用一段代码设置纹理属性的过程中就能解决图片翻转问题,感兴趣的小伙伴也可以区查看一下。

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:@(1),GLKTextureLoaderOriginBottomLeft, nil];    
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];