1. 程式人生 > IOS開發 >OpenGL學習(十二)-- OpenGL ES 紋理翻轉的策略對比

OpenGL學習(十二)-- OpenGL ES 紋理翻轉的策略對比

我的 OpenGL 專題學習目錄,希望和大家一起學習交流進步!


一、前言

我在上一篇 OpenGL學習(十二)-- OpenGL ES 紋理翻轉的策略對比 講了如果用 GLSL 載入一張圖片,但是最後發現加載出來的圖片是 倒置 的,這是 為什麼 呢?

因為 OpenGL 要求 y0.0 座標是在圖片的底部的,但是圖片的 y0.0 座標通常在頂部。 這要怎麼解決呢?下面羅列了 5 種解決策略供我們選擇。

二、紋理翻轉策略

1、修改紋理座標和頂點座標的對映關係

圖片之所以倒置,就是紋理座標和頂點座標的對映關係發生了錯誤,所以我們把對映關係改對就行了。這種方法最直接最原始,也一勞永逸,但是容易在對應的時候犯糊塗出錯。

    //6.設定頂點、紋理座標
    //前3個是頂點座標,後2個是紋理座標
//    GLfloat attrArr[] =
//    {
//        0.5f,-0.5f,-1.0f,1.0f,0.0f,//        -0.5f,0.5f,//
//        0.5f,//        0.5f,//    };
    
    GLfloat attrArr[] =
    {
        0.5f,};
複製程式碼

2、旋轉矩陣翻轉圖形,不翻轉紋理

  • 在頂點著色器 shaderv.vsh 中,我們傳進一個旋轉矩陣 rotateMatrix,因為矩陣傳進來就不會再修改了,所以我們用 uniform 來修飾,4
    4 列的矩陣 mat4。然後用頂點座標 vPos 乘以這個 rotateMatrix 旋轉矩陣,讓每一個頂點都應用旋轉變化。

⚠️ 注意只能是 vPos * rotateMatrix,順序不能反過來,因為頂點是 14 列,旋轉矩陣是 44 列。 shaderv.vsh 中:

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;
}
複製程式碼

原始碼中:

- (void)rotateTextureImage {
    //注意,想要獲取shader裡面的變數,這裡記得要在glLinkProgram後面,後面,後面!
    //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,s,c,1,1
    };
    
    //5.設定旋轉矩陣
    /*
     glUniformMatrix4fv (GLint location,GLsizei count,GLboolean transpose,const GLfloat* value)
     location : 對於shader 中的ID
     count : 個數
     transpose : 是否需要轉置
     value : 指標
     */
    glUniformMatrix4fv(rotate,GL_FALSE,zRotation);
}
複製程式碼

3、在解壓圖片時,將圖片原始檔翻轉

使用下面三行程式碼,對圖片進行了平移縮放操作以後,再重新繪製。

    CGContextTranslateCTM(spriteContext,rect.size.height);
    CGContextScaleCTM(spriteContext,1.0,-1.0);
    CGContextDrawImage(spriteContext,rect,spriteImage);
複製程式碼

從圖片載入紋理的整體程式碼如下:

//從圖片中載入紋理
- (GLuint)setupTexture:(NSString *)fileName {
    
    //1、將 UIImage 轉換為 CGImageRef
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

    //2、讀取圖片的大小,寬和高
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    
    //3.獲取圖片位元組數 寬*高*4(RGBA)
    GLubyte * spriteData = (GLubyte *) calloc(width * height * 4,sizeof(GLubyte));
    
    //4.建立上下文
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData,width,height,8,width*4,CGImageGetColorSpace(spriteImage),kCGImageAlphaPremultipliedLast);
    

    //5、在CGContextRef上--> 將圖片繪製出來
    CGRect rect = CGRectMake(0,height);
   
    //6.使用預設方式繪製
    //CGContextDrawImage(spriteContext,spriteImage);
    // 圖片翻轉後繪製
    CGContextTranslateCTM(spriteContext,spriteImage);
    
    //7、畫圖完畢就釋放上下文
    CGContextRelease(spriteContext);
    
    //8、繫結紋理到預設的紋理ID
    glBindTexture(GL_TEXTURE_2D,0);
    
    //9.設定紋理屬性
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    
    float fw = width,fh = height;
    
    //10.載入紋理2D資料
    glTexImage2D(GL_TEXTURE_2D,GL_RGBA,fw,fh,GL_UNSIGNED_BYTE,spriteData);
    
    //11.釋放spriteData
    free(spriteData);   
    return 0;
}
複製程式碼

4、修改片元著色器中的紋理座標

這裡是修改了片元著色器的程式碼,x 座標不動,將 y 座標改為 1-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));
}
複製程式碼

5、修改頂點著色器中的紋理座標

在頂點著色器傳入的時候,就翻轉。相比上面的片元著色器,執行次數要少很多,有幾個頂點執行幾次。

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

void main() {
    varyTextCoord = vec2(textCoordinate.x,1.0-textCoordinate.y);
    gl_Position = position;
}
複製程式碼

上面五種方法都可以解決圖片倒置問題,第一種是最直接也是最原始的修改方式,但容易對映關係出錯。第二種和第三種相對麻煩。後兩種只用修改一行程式碼最輕鬆,喜歡選哪種看你的了。最後就得到了正著的圖片啦!

正常圖.png

轉載請備註原文出處,不得用於商業傳播——凡幾多