美文网首页
OpenGL ES 纹理翻转策略

OpenGL ES 纹理翻转策略

作者: 紫水依 | 来源:发表于2019-07-14 19:44 被阅读0次

    背景:使用GLSL渲染一张图片到屏幕上,发现图片是倒置的,这是因为屏幕的坐标原点在左上角,向右和向下为x和y正方向,而图片纹理坐标原点在左下角,向右和向上为正方向,导致图片渲染显示倒置。这就需要纹理翻转让图片显示正常。

    基本策略有:

    1. 改变顶点数据的纹理坐标,翻转y值(1-y)
    2. 顶点着色器翻转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,
        };
    

    相关文章

      网友评论

          本文标题:OpenGL ES 纹理翻转策略

          本文链接:https://www.haomeiwen.com/subject/gvpnhctx.html