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

個人 OpenGL 專題學習目錄,但願和你們一塊兒學習交流進步!bash


1、前言

我在上一篇 OpenGL學習(十二)-- OpenGL ES 紋理翻轉的策略對比 講了若是用 GLSL 加載一張圖片,可是最後發現加載出來的圖片是 倒置 的,這是 爲何 呢? post

由於 OpenGL 要求 y0.0 座標是在圖片的底部的,可是圖片的 y0.0 座標一般在頂部。 這要怎麼解決呢?下面羅列了 5 種解決策略供咱們選擇。學習

2、紋理翻轉策略

一、修改紋理座標和頂點座標的映射關係

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

//6.設置頂點、紋理座標
    //前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,
    };
複製代碼

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

  • 在頂點着色器 shaderv.vsh 中,咱們傳進一個旋轉矩陣 rotateMatrix,由於矩陣傳進來就不會再修改了,因此咱們用 uniform 來修飾,44 列的矩陣 mat4。而後用頂點座標 vPos 乘以這個 rotateMatrix 旋轉矩陣,讓每個頂點都應用旋轉變化。

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

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

源碼中:spa

- (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,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);
}
複製代碼

三、在解壓圖片時,將圖片源文件翻轉

使用下面三行代碼,對圖片進行了平移縮放操做之後,再從新繪製。指針

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

從圖片加載紋理的總體代碼以下:code

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

    //二、讀取圖片的大小,寬和高
    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);
    

    //五、在CGContextRef上--> 將圖片繪製出來
    CGRect rect = CGRectMake(0, 0, width, height);
   
    //6.使用默認方式繪製
    //CGContextDrawImage(spriteContext, rect, spriteImage);
    // 圖片翻轉後繪製
    CGContextTranslateCTM(spriteContext, 0, rect.size.height);
    CGContextScaleCTM(spriteContext, 1.0, -1.0);
    CGContextDrawImage(spriteContext, rect, spriteImage);
    
    //七、畫圖完畢就釋放上下文
    CGContextRelease(spriteContext);
    
    //八、綁定紋理到默認的紋理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_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, 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, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    
    //11.釋放spriteData
    free(spriteData);   
    return 0;
}
複製代碼

四、修改片元着色器中的紋理座標

這裏是修改了片元着色器的代碼,x 座標不動,將 y 座標改成 1-y,這樣就達到了翻轉的效果。其餘地方代碼不用動。orm

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));
}
複製代碼

五、修改頂點着色器中的紋理座標

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

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

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

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

正常圖.png

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

相關文章
相關標籤/搜索