OpenGLES學習之路-紋理(一)

學習之路系列

OpenGLES學習之路

本篇主要內容

多重紋理渲染

效果展示

  • 這個效果看起來有點詭異

實現過程

  • 我這里先把上期的效果Copy過來, 我直接在這上面添加紋理

1.頂點著色器

首相我們在頂點著色器(TextureVertex.glsl)里面添加一段聲明
attribute vec2 TexCoordIn;
varying   vec2 TexCoordOut;
把下面這段代碼添加到main函數的末尾
TexCoordOut = TexCoordIn;
修改完成后如下圖:

接著我們在片段著色器(TextureFragment.glsl)里面添加代碼
uniform sampler2D ourTexture1;
varying lowp vec2 TexCoordOut;
把下面這段代碼
 gl_FragColor = OutColor;

改為

gl_FragColor = OutColor * texture2D(ourTexture1, TexCoordOut);

2.設置紋理數據

/*
 *  通過UIImage的方式獲取紋理對象
 */
+ (GLuint)getTextureImageName:(NSString *)imageName {
    
    // 獲取UIImage并轉換成CGImage
    CGImageRef spriteImage = [UIImage imageNamed:imageName].CGImage;
    
    if(!spriteImage) {
        return 0;
    }
    
    // 獲取圖片的大小
    GLsizei width  = (GLsizei)CGImageGetWidth(spriteImage);
    GLsizei height = (GLsizei)CGImageGetHeight(spriteImage);
    
    
    // 分配內存,并初始化該內存空間為零, 因為一個像素有4個通道(RGBA)所以乘4
    GLubyte * spriteData = (GLubyte *)calloc(width * height * 4, sizeof(GLubyte));
    
    /*
     *  創建位圖上下文
     */
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,
                                                       CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    
    // 在上下文中繪制
    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
    // 釋放上下文
    CGContextRelease(spriteContext);
    
    
    // 創建紋理對象并且綁定, 紋理對象用無符號整數表示, 這個紋理對象相當于我們在C語言文件操作里面的句柄
    GLuint texName;
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    
    // 加載圖像數據, 并上傳紋理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    // 解綁紋理對象(在本文這里解不解綁都一樣,因為后面還是要綁定)
    glBindTexture(GL_TEXTURE_2D, 0);
    // 釋放分配的內存空間
    free(spriteData);
    
    return texName;
}
上面的這些函數講解可以看這篇文章 LearnOpenGL??, 里面還有例子, 講解的很詳細

2.獲取著色器里的變量

我們在compileShaders方法下新增一段代碼

_textureSlot      = glGetAttribLocation(_program, "TexCoordIn");
glEnableVertexAttribArray(_textureSlot);

_textureUniform  = glGetUniformLocation(_program, "ourTexture1");

//獲取紋理對象
_texture1 = [TextureManager getTextureImageName:@"Texture1.jpg"];

3. 開始渲染

render方法中新增一段代碼

static const float Texture[] = {
    0, 0,
    1, 0,
    0, 1,
    1, 1,
};
glVertexAttribPointer(_textureSlot,      2, GL_FLOAT, GL_FALSE, 0, Texture);

上面這段代碼可以參照上一篇文章

//使用紋理單元
glActiveTexture(GL_TEXTURE0);
//綁定紋理對象
glBindTexture(GL_TEXTURE_2D, _texture1);
//這里的參數要對應紋理單元(如果紋理單元為0,這里也要給0)
glUniform1i(_textureUniform, 0);
這里講到了兩個東西紋理單元紋理對象
  • 紋理對象:

也就是上面我們提到的類似于C語言中文件操作的句柄

  • 紋理單元:

紋理單元就是將程序中的紋理貼圖反應到像素位置的運算單元,顯卡會劃分N個紋理存儲區域,多重紋理可以開啟多個紋理單元。上面的glUniform1i(_textureUniform, 0);這段代碼對應的就是紋理單元的位置。
紋理單元的數量跟硬件有關,蘋果給用的紋理單元數量如下:

/* TextureUnit */
#define GL_TEXTURE0                                      0x84C0
#define GL_TEXTURE1                                      0x84C1
#define GL_TEXTURE2                                      0x84C2
#define GL_TEXTURE3                                      0x84C3
#define GL_TEXTURE4                                      0x84C4
#define GL_TEXTURE5                                      0x84C5
#define GL_TEXTURE6                                      0x84C6
#define GL_TEXTURE7                                      0x84C7
#define GL_TEXTURE8                                      0x84C8
#define GL_TEXTURE9                                      0x84C9
#define GL_TEXTURE10                                     0x84CA
#define GL_TEXTURE11                                     0x84CB
#define GL_TEXTURE12                                     0x84CC
#define GL_TEXTURE13                                     0x84CD
#define GL_TEXTURE14                                     0x84CE
#define GL_TEXTURE15                                     0x84CF
#define GL_TEXTURE16                                     0x84D0
#define GL_TEXTURE17                                     0x84D1
#define GL_TEXTURE18                                     0x84D2
#define GL_TEXTURE19                                     0x84D3
#define GL_TEXTURE20                                     0x84D4
#define GL_TEXTURE21                                     0x84D5
#define GL_TEXTURE22                                     0x84D6
#define GL_TEXTURE23                                     0x84D7
#define GL_TEXTURE24                                     0x84D8
#define GL_TEXTURE25                                     0x84D9
#define GL_TEXTURE26                                     0x84DA
#define GL_TEXTURE27                                     0x84DB
#define GL_TEXTURE28                                     0x84DC
#define GL_TEXTURE29                                     0x84DD
#define GL_TEXTURE30                                     0x84DE
#define GL_TEXTURE31                                     0x84DF
#define GL_ACTIVE_TEXTURE                                0x84E0

運行效果

發現圖像是反的,解決辦法有兩個

  • 1、修改頂點數據
  • 2、修改著色器中的紋理數據
    這里使用第二種辦法, 將頂點著色器(TextureVertex.glsl)中的
TexCoordOut = TexCoordIn; 

改為

TexCoordOut = vec2(TexCoordIn.x, 1. - TexCoordIn.y);

把Y軸顛倒一下以后在運行看看效果

新增紋理

在片段著色器(TextureFragment.glsl)中新增一個變量

uniform sampler2D ourTexture2;

gl_FragColor = OutColor * texture2D(ourTexture1, TexCoordOut);

改為

gl_FragColor = OutColor * mix(texture2D(ourTexture1, TexCoordOut), texture2D(ourTexture2, TexCoordOut), 0.7);

mix 函數是一個混合線性函數,聲明及算法如下

genType mix (genType x, genType y, genType a)

x ? ( 1 ? a ) + y ? a


在中compileShaders方法的底部新增下面兩端代碼

_textureUniform2 = glGetUniformLocation(_program, "ourTexture2");
_texture2 = [TextureManager getTextureImageName:@"Texture2.jpg"];

在渲染方法render新增

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _texture2);
glUniform1i(_textureUniform2, 1);

運行效果

- (void)dealloc {
    
    //刪除綁定的渲染緩沖區
    if(_renderBuffer) {
        glDeleteRenderbuffers(GL_RENDERBUFFER, &_renderBuffer);
    }
    
    //刪除綁定的幀緩沖區
    if(_frameBuffer) {
        glDeleteFramebuffers(GL_FRAMEBUFFER, &_frameBuffer);
    }
    
    //釋放著色器
    if(_vertexShader) {
        
        //刪除頂點著色器連接
        glDetachShader(_program, _vertexShader);
        
        //刪除頂點著色器
        glDeleteShader(_vertexShader);
    }
    
    if(_fragmentShader) {
        
        //刪除片段著色器連接
        glDetachShader(_program, _fragmentShader);
        
        //刪除片段著色器
        glDeleteShader(_fragmentShader);
    }
    
    if(_program) {
        glDeleteProgram(_program);
    }

    glDisableVertexAttribArray(_positionSlot);
    glDisableVertexAttribArray(_colorSlot);
    glDisableVertexAttribArray(_textureSlot);
    
    glDeleteTextures(1, &_texture1);
    glDeleteTextures(1, &_texture2);
    
    glBindTexture(GL_TEXTURE_2D, 0);
}

最后記得將資源釋放

Demo鏈接:LearnOpenGLES

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容