OpenGL 2D紋理單元&紋理翻轉(zhuǎn)解決策略

原文: CC老師
著作所屬權(quán)歸該作者所有,任何形式轉(zhuǎn)載請聯(lián)系作者并注明原文出處.

片元著色器

varying vec2 TexCoord;
uniform sampler2D ourTexture;

void main()
{
    gl_FragColor = texture(ourTexture, TexCoord);
}
  • TexCoord 紋理坐標(biāo),通過頂點(diǎn)著色器傳遞
  • ourTexture,紋理采樣器

片元著色器,是如何訪問紋理對象

首先,思考我們是如何將紋理對象傳遞給片元著色器? GLSL 中提供一個共紋理對象使用的內(nèi)建數(shù)據(jù)類型,叫做采樣器(sampler).

例如,sampler1D,sampler2D,sampler3D 表示不同維度的紋理類型.

那么我們在片元著色器是如何獲取一個紋理的? 我們簡單聲明一個紋理對象. uniform sampler2D,將一個紋理添加片元著色器中.

//聲明一個紋理對象
uniform sampler2D ourTexture;

如何獲取紋理對應(yīng)像素點(diǎn)的顏色值

我們可以使用GLSL內(nèi)建的texture函數(shù)來采樣紋理的顏色值.

gl_FragColor = texture(ourTexture, TexCoord);
//參數(shù)1: 紋理采樣器對象
//參數(shù)2: 紋理坐標(biāo)

紋理單元

你可能會奇怪為什么sampler2D變量是個uniform旭愧,我們卻不用glUniform給它賦值.

使用glUniform1i抵赢,我們可以給紋理采樣器分配一個位置值健芭,這樣的話我們能夠在一個片段著色器中設(shè)置多個紋理耘斩。

一個紋理的位置值通常稱為一個紋理單元(Texture Unit)。一個紋理的默認(rèn)紋理單元是0烛缔,它是默認(rèn)的激活紋理單元.

紋理單元的主要目的是讓我們在著色器中可以使用多于一個的紋理荧库。

通過把紋理單元賦值給采樣器汁果,我們可以一次綁定多個紋理拣帽,只要我們首先激活對應(yīng)的紋理單元疼电。就像glBindTexture一樣,我們可以使用glActiveTexture激活紋理單元减拭,傳入我們需要使用的紋理單元:

//在綁定紋理之前先激活紋理單元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

激活紋理單元之后澜沟,接下來的glBindTexture函數(shù)調(diào)用會綁定這個紋理到當(dāng)前激活的紋理單元,紋理單元GL_TEXTURE0默認(rèn)總是被激活.

OpenGL至少保證有16個紋理單元供你使用峡谊,也就是說你可以激活從GL_TEXTURE0GL_TEXTRUE15。它們都是按順序定義的,所以我們也可以通過GL_TEXTURE0 + 8的方式獲得GL_TEXTURE8既们,這在當(dāng)我們需要循環(huán)一些紋理單元的時候會很有用濒析。

varying vec2 TexCoord;
uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;

void main()
{
    gl_FragColor = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2);
}

最終輸出顏色是兩個紋理的結(jié)合。

GLSL內(nèi)建的mix函數(shù)需要接受兩個值作為參數(shù)啥纸,并對它們根據(jù)第三個參數(shù)進(jìn)行線性插值号杏。

如果第三個值是0.0,它會返回第一個輸入斯棒;如果是1.0盾致,會返回第二個輸入值。輸入0.2則會返回80%的第一個輸入顏色和20%的第二個輸入顏色荣暮,即返回兩個紋理的混合色庭惜。

為了使用第二個紋理(以及第一個),我們必須改變一點(diǎn)渲染流程穗酥,先綁定兩個紋理到對應(yīng)的紋理單元护赊,然后定義哪個uniform采樣器對應(yīng)哪個紋理單元:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1);

注意,我們使用glUniform1i設(shè)置uniform采樣器的位置值砾跃,或者說紋理單元骏啰。通過glUniform1i的設(shè)置,我們保證每個uniform采樣器對應(yīng)著正確的紋理單元

關(guān)于紋理翻轉(zhuǎn)

OpenGL要求y0.0坐標(biāo)是在圖片的底部的抽高,但是圖片的y0.0坐標(biāo)通常在頂部

  • 我們可以改變頂點(diǎn)數(shù)據(jù)的紋理坐標(biāo)判耕,翻轉(zhuǎn)y值(用1減去y坐標(biāo))。
  • 我們可以編輯頂點(diǎn)著色器來自動翻轉(zhuǎn)y坐標(biāo)翘骂,替換TexCoord的值為TexCoord = vec2(texCoord.x, 1.0f - texCoord.y);壁熄。

iOS紋理翻轉(zhuǎn)解決策略

第1種: 旋轉(zhuǎn)矩陣翻轉(zhuǎn)圖形,不翻轉(zhuǎn)紋理

  • 讓圖形頂點(diǎn)坐標(biāo)旋轉(zhuǎn)180°. 而紋理保持原狀.
    GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
    float radians = 180 * 3.14159f / 180.0f;
    float s = sin(radians);
    float c = cos(radians);
    
  
    GLfloat zRotation[16] = {
        c, -s, 0, 0,
        s, c, 0, 0,
        0, 0, 1.0, 0,
        0.0, 0, 0, 1.0
    };
    
   glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);

第2種: 解壓圖片時,將圖片源文件翻轉(zhuǎn)

CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));

CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
  
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), 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);
glBindTexture(GL_TEXTURE_2D, 0);

第3種: 修改片元著色器,紋理坐標(biāo)

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

第4種: 修改頂點(diǎn)著色器,紋理坐標(biāo)

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

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

第5種:直接從源紋理坐標(biāo)數(shù)據(jù)修改

     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, // 右下
     };
     */
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雏胃,隨后出現(xiàn)的幾起案子请毛,更是在濱河造成了極大的恐慌,老刑警劉巖瞭亮,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件方仿,死亡現(xiàn)場離奇詭異,居然都是意外死亡统翩,警方通過查閱死者的電腦和手機(jī)仙蚜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厂汗,“玉大人委粉,你說我怎么就攤上這事∪㈣耄” “怎么了贾节?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵汁汗,是天一觀的道長。 經(jīng)常有香客問我栗涂,道長知牌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任斤程,我火速辦了婚禮角寸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忿墅。我一直安慰自己扁藕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布疚脐。 她就那樣靜靜地躺著亿柑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亮曹。 梳的紋絲不亂的頭發(fā)上橄杨,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機(jī)與錄音照卦,去河邊找鬼式矫。 笑死,一個胖子當(dāng)著我的面吹牛役耕,可吹牛的內(nèi)容都是我干的采转。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼瞬痘,長吁一口氣:“原來是場噩夢啊……” “哼故慈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起框全,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤察绷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后津辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拆撼,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年喘沿,在試婚紗的時候發(fā)現(xiàn)自己被綠了闸度。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚜印,死狀恐怖莺禁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窄赋,我是刑警寧澤哟冬,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布楼熄,位于F島的核電站,受9級特大地震影響浩峡,放射性物質(zhì)發(fā)生泄漏孝赫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一红符、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伐债,春花似錦预侯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虹蒋,卻和暖如春糜芳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背魄衅。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工峭竣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晃虫。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓皆撩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哲银。 傳聞我的和親對象是個殘疾皇子扛吞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355