iOS OpenGL ES菜鳥(niǎo)學(xué)習(xí)筆記(2)——繪制一張圖(紋理繪制)

第一篇筆記 iOS OpenGL ES菜鳥(niǎo)學(xué)習(xí)筆記(1)——畫(huà)一個(gè)簡(jiǎn)單的三角形 其實(shí)已經(jīng)寫(xiě)了很久了,其實(shí)研究OpenGL ES是為了在iOS原生App中使用AR高蜂。最近一直比較忙猪勇,也沒(méi)有那么時(shí)間去鼓搗這個(gè)筆記踱承,終于研究得差不多了排作,也就回來(lái)這里繼續(xù)行騙了乡革。(ps:菜鳥(niǎo)學(xué)習(xí)筆記寇僧,如有不對(duì),大神請(qǐng)指教)

一沸版、準(zhǔn)備

從我們第一篇筆記上進(jìn)行更改
準(zhǔn)備一張圖嘁傀,什么圖都可以(不要是白色,白色的東西在白色的背景下還能看見(jiàn)嗎)
我這里用的一個(gè)郁金香的圖片


tulip.png

什么是紋理這個(gè)我在文章末尾稍微介紹一下视粮,有興趣的可以看看细办。

二、修改vertices

因?yàn)橐L制紋理上去,所以我們必須在vertices上加上紋理坐標(biāo)

// 這個(gè)數(shù)據(jù)類(lèi)型用于存儲(chǔ)每一個(gè)頂點(diǎn)數(shù)據(jù)
typedef struct {
    GLKVector3 positionCoords;  // 頂點(diǎn)數(shù)據(jù)
    GLKVector2 textureCoords;   // 紋理坐標(biāo)
} SceneVertex;


// 創(chuàng)建本例中要用到的三角形頂點(diǎn)數(shù)據(jù)
// 這里的數(shù)據(jù)比上一個(gè)例子新增了紋理數(shù)據(jù)
static const SceneVertex vertices[] =
{
    {{-0.5, -0.5, 0.0}, {0.0, 0.0}},  // 左下
    {{ 0.5, -0.5, 0.0}, {1.0, 0.0}},  // 右下
    {{-0.5,  0.5, 0.0}, {0.0, 1.0}}  // 左上
};

三、- (void)viewDidLoad()

在這里我們要將圖片實(shí)現(xiàn)讀入到緩存中(如果在- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect中讀入舱痘,那么將會(huì)浪費(fèi)很多資源,畢竟繪制一次讀入一次)

在第一篇文章的- (void)viewDidLoad()的末尾追加

    // 讀入需要繪制的圖片的CGImageRef內(nèi)容
    // 畢竟OpenGL是基于C++的嘛茴肥,你直接給一個(gè)UIImage人怎么識(shí)別
    CGImageRef imageRefTulip = [UIImage imageNamed:@"tulip"].CGImage;
    
    // 使用GLKTextureLoader(紋理讀取)從上邊得到的imageRefTulip讀取紋理信息
    GLKTextureInfo *textureInfoTulip = [GLKTextureLoader textureWithCGImage:imageRefTulip
                                                               options:nil
                                                                 error:nil];
    
    // 將讀取到的紋理信息緩存到baseEffec的texture2d0中
    self.baseEffect.texture2d0.name = textureInfoTulip.name;
    self.baseEffect.texture2d0.target = textureInfoTulip.target;

從代碼備注中直接可以看書(shū)每句代碼干的事情荡灾。

GLKTextureInfo封裝了剛創(chuàng)建的紋理緩存相關(guān)的信息瓤狐,包括他的尺寸以及是否包含MIP貼圖。我們這里只需要OpenGL ES標(biāo)識(shí)符批幌、名字和用于紋理的OpenGL ES目標(biāo)础锐。

GLKTextureLoader會(huì)自動(dòng)調(diào)用glTexParameteri()方法來(lái)為創(chuàng)建的紋理緩存設(shè)置OpenGL ES取樣模式和循環(huán)模式。其實(shí)就是告訴OpenGL ES怎么處理可用紋素的數(shù)量與需要被著色的片源的數(shù)量不匹配的情況(基本不存在兩者相同的情況)逼裆。我們將在本文最后對(duì)此稍微介紹一下郁稍。

四、- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect

這里做的事情跟第一篇筆記其實(shí)沒(méi)什么差別胜宇,只是多了一個(gè)紋理的繪制耀怜。

在執(zhí)行繪制操作之前加入如下代碼

    // 繪制紋理數(shù)據(jù)準(zhǔn)備
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);     // 啟用紋理
    glVertexAttribPointer(GLKVertexAttribTexCoord0,
                          2,
                          GL_FLOAT,
                          GL_FALSE,
                          sizeof(SceneVertex),
                          NULL + offsetof(SceneVertex, textureCoords));

其實(shí)到這里代碼就沒(méi)了恢着,是不是很少。

五财破、運(yùn)行

沒(méi)有源碼的博客不是好的示例
https://github.com/JunesYin/LyOpenGLES/tree/master/LyOpenGLES_02

六掰派、一點(diǎn)紋理知識(shí)

說(shuō)了要介紹就要介紹,一個(gè)字都不能少左痢。

1靡羡、什么是紋理

紋理是一個(gè)用來(lái)保存圖像的顏色元素值的OpenGL ES緩存。簡(jiǎn)單來(lái)說(shuō)俊性,渲染場(chǎng)景其實(shí)渲染很多個(gè)像素點(diǎn)略步,這些像素點(diǎn)都有各自的顏色。如果我們?cè)阡秩緯r(shí)針對(duì)每一個(gè)像素點(diǎn)指定顏色定页,這將會(huì)是一個(gè)非常龐大的工程量趟薄,試想一個(gè)像素點(diǎn)有多大,而iPhone的屏幕又有多少像素點(diǎn)典徊,就算我們渲染10x10的一個(gè)正方形圖像杭煎,這都需要指定100個(gè)像素點(diǎn)了。所以需要紋理貼圖卒落,使用紋理貼圖使我們只需要關(guān)注渲染多大的場(chǎng)景羡铲,然后將需要呈現(xiàn)的圖像繪制進(jìn)這個(gè)場(chǎng)景就可以了(以上觀點(diǎn)僅個(gè)人理解,如有錯(cuò)誤儡毕,歡迎評(píng)論指正)也切。上邊的例子就是將郁金香作為紋理貼圖貼在我們繪制的三角形中。

2妥曲、紋理坐標(biāo)系

紋理坐標(biāo)系有一個(gè)命名為S和T的2D軸贾费。如下圖,一個(gè)紋理中無(wú)論有多少個(gè)紋素檐盟,紋理的尺寸永遠(yuǎn)在S軸上從0.0到1.0,T軸也是從0.0到1.0押桃。從一個(gè)寬為2像素寬為16像素的圖像初始化來(lái)的紋理葵萎,整個(gè)S軸有2像素,T軸有16像素唱凯。

3羡忘、如何對(duì)齊紋理

雖然我們給OpenGL ES提供了一個(gè)紋理貼圖,但是它還是不知道要怎么利用我們給定的紋理對(duì)幾何圖形進(jìn)行著色磕昼。咱們先來(lái)看幾個(gè)名詞:

  • 視口(viewport):幀緩存中的像素位置叫做視口卷雕。渲染時(shí),GPU會(huì)轉(zhuǎn)換純數(shù)學(xué)的OpenGL ES坐標(biāo)系中的X票从、Y漫雕、Z坐標(biāo)為幀緩存中所對(duì)應(yīng)真實(shí)的像素位置滨嘱。
  • 點(diǎn)陣化(rasterizing):轉(zhuǎn)換幾何形狀數(shù)據(jù)為幀緩存中的顏色像素的渲染步驟叫做點(diǎn)陣化。
  • 片元(fragment):每個(gè)顏色像素叫做片元浸间。
    映射(mapping):指定怎么對(duì)其紋理和頂點(diǎn)太雨,以便讓GPU知道每個(gè)片元的顏色由哪些紋素決定。這通過(guò)擴(kuò)展為每個(gè)頂點(diǎn)保存的數(shù)據(jù)來(lái)實(shí)現(xiàn):除了X魁蒜、Y囊扳、Z坐標(biāo),每個(gè)頂點(diǎn)還給出了U和V坐標(biāo)值兜看。U坐標(biāo)映射到S軸的位置锥咸,V坐標(biāo)映射到T軸。不同的是{U细移,V}坐標(biāo)可能會(huì)超出0.0到1.0的這個(gè)范圍她君。

在每個(gè)頂點(diǎn)的X、Y葫哗、Z坐標(biāo)被轉(zhuǎn)換為視口坐標(biāo)后缔刹,GPU會(huì)設(shè)置轉(zhuǎn)換生成的三角形內(nèi)的每個(gè)像素的顏色。當(dāng)OpenGL ES沒(méi)有使用紋理時(shí)劣针,GPU會(huì)根據(jù)包含該片元的對(duì)象的頂點(diǎn)的顏色來(lái)計(jì)算每個(gè)片元的顏色校镐。使用紋理時(shí),GPU會(huì)根據(jù)當(dāng)前綁定的紋理緩存中的紋素來(lái)計(jì)算每個(gè)片元的顏色捺典。

Note:我們?cè)谏鲜隼又惺褂脅-0.5, -0.5, 0.0}鸟廓、{ 0.5, -0.5, 0.0}、{-0.5, 0.5, 0.0}這三個(gè)坐標(biāo)點(diǎn)指定了一個(gè)三角形的三個(gè)頂點(diǎn)襟己,這個(gè)三角形的寬度和高度在純數(shù)學(xué)的OpenGL ES坐標(biāo)系中是相等的引谜。但是我們?cè)诶L制三角形時(shí),幀緩存是按照像素來(lái)匹配屏幕坐標(biāo)的擎浴。將坐標(biāo)點(diǎn)轉(zhuǎn)換為視口坐標(biāo)员咽,這使得所有繪制的幾何圖形都被拉伸以適合屏幕大小,iPhone屏幕的比例均為高大于寬贮预,所以我們的例子中看起來(lái)高都大于寬贝室。如果要控制這個(gè)轉(zhuǎn)換,需要做一點(diǎn)操作仿吞,這個(gè)我們?cè)诤罄m(xù)文章會(huì)慢慢了解的滑频。

4、取樣模式

每個(gè)頂點(diǎn)的U和V坐標(biāo)會(huì)附加到每個(gè)頂點(diǎn)在視口坐標(biāo)中的最終位置唤冈。GPU會(huì)根據(jù)計(jì)算出來(lái)的每個(gè)片元的U峡迷、V位置從綁定的紋理中選擇紋素,這個(gè)過(guò)程叫做取樣你虹。取樣會(huì)把紋理的S和T坐標(biāo)系與每個(gè)渲染的三角形的頂點(diǎn)的U绘搞、V坐標(biāo)匹配起來(lái)彤避。

如上圖所示,在S和T坐標(biāo)系中與{0.0看杭,0.0}位置最近的紋素會(huì)被映射到擁有{0.0忠藤, 0.0}的頂點(diǎn)U、V坐標(biāo)的頂點(diǎn)所對(duì)應(yīng)的片元上楼雹。每個(gè)隨后的片元位置對(duì)應(yīng)于一個(gè)沿著S和T軸的與該片元在U模孩、V坐標(biāo)中的位置等比例的位置。例如贮缅,一個(gè)U榨咐、V坐標(biāo)為{0.5, 0.5}的片元會(huì)被當(dāng)前綁定的紋理中最接近中間位置的紋素所著色谴供。

OpenGL ES支持多個(gè)不同的取樣模式块茁。當(dāng)一個(gè)三角形生成的片元少于綁定的紋理的可用紋素時(shí)會(huì)發(fā)生什么。一個(gè)含有大量紋素的紋理被映射到幀緩存內(nèi)一個(gè)只覆蓋幾個(gè)像素的三角形中桂肌,這種情況是很常見(jiàn)的数焊,相反的情況也很常見(jiàn)。到底是怎么才能比較好的將片元與紋素對(duì)應(yīng)起來(lái)呢崎场?

先看看如下幾個(gè)函數(shù)調(diào)用

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

4.1 GL_TEXTURE_MIN_FILTER

GL_TEXTURE_MIN_FILTER 參數(shù)適用于紋素過(guò)多的情況

  • 使用GL_LINEAR 指定這種情況時(shí)佩耳,出現(xiàn)多個(gè)紋素對(duì)應(yīng)一個(gè)片元時(shí),從相配的多個(gè)紋素中取樣顏色谭跨,使用線(xiàn)性?xún)?nèi)插法來(lái)混著這些顏色從而得到這個(gè)片元的顏色干厚,簡(jiǎn)
    單來(lái)說(shuō)就是混合與當(dāng)前片元相配的所有紋素的顏色。這很可能出現(xiàn)一個(gè)紋理中不存在的顏色螃宙。
  • 使用GL_NEAREST指定時(shí)蛮瞄,與該片元的U、V坐標(biāo)最接近的紋素的顏色將被作為片元的顏色谆扎。例如挂捅,一個(gè)紋理是由交替的黑色紋素和白色紋素組成,GL_NEAREST會(huì)拾取與相近的一個(gè)紋素或另一個(gè)紋素燕酷,此時(shí)最終片元的顏色要么是黑色籍凝,要么是白色。

4.2 GL_TEXTURE_MAG_FILTER

GL_TEXTURE_MAG_FILTER 參數(shù)適用于紋素不足的情況苗缩,此時(shí)將唯一地映射一個(gè)或多個(gè)紋素到每個(gè)片元上時(shí)配置取樣。

  • 使用GL_LINEAR指定這種情況時(shí)声诸,OpenGL ES將混合附近紋素的顏色來(lái)計(jì)算片元的顏色酱讶。GL_LINEAR有一個(gè)放大紋理的效果并將其模糊地出現(xiàn)在渲染的三角形片元上。
  • 使用GL_NEAREST指定時(shí)彼乌,OpenGL ES僅僅拾取與片元的U泻肯、V位置接近的紋素的顏色渊迁,并放大紋理,這讓紋素像素化地出現(xiàn)在渲染的三角形片元上灶挟。

Note:GLKTextureLoader會(huì)自動(dòng)設(shè)置GL_TEXTURE_MIN_FILTER為GL_LINEAR琉朽。

5、循環(huán)模式

除了減小和放大過(guò)濾選項(xiàng)稚铣,當(dāng)U箱叁、V坐標(biāo)的值小于0或者大于1時(shí),程序會(huì)指定發(fā)生什么惕医。這里有兩個(gè)選擇:

· 盡可能多地重復(fù)紋理以填滿(mǎn)映射到整個(gè)結(jié)合圖形的U耕漱、V坐標(biāo)區(qū)域;
· 每當(dāng)片元的U抬伺、V坐標(biāo)值超出紋理的S螟够、T坐標(biāo)系范圍時(shí),從紋理邊緣取樣紋素峡钓。

紋理的循環(huán)模式需要為S軸與T軸分開(kāi)設(shè)置妓笙,來(lái)看看這幾句代碼

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

第一句代碼:S軸,若片元的U坐標(biāo)超出紋理的S坐標(biāo)系范圍能岩,取樣紋理邊緣的紋素寞宫;
第二句代碼:S軸,若片元的U坐標(biāo)超出紋理的S坐標(biāo)系范圍捧灰,重復(fù)紋理淆九;
第三局代碼:T軸,若片元的V坐標(biāo)超出紋理的T坐標(biāo)系范圍毛俏,取樣紋理邊緣的紋素炭庙;
第四局代碼:T軸,若片元的V坐標(biāo)超出紋理的T坐標(biāo)系范圍煌寇,重復(fù)紋理焕蹄。

Note:GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T都會(huì)自動(dòng)被設(shè)置為GL_CLAMP_TO_EDGE。

系列源碼傳送門(mén):https://github.com/JunesYin/LyOpenGLES

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阀溶,一起剝皮案震驚了整個(gè)濱河市腻脏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌银锻,老刑警劉巖永品,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異击纬,居然都是意外死亡鼎姐,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炕桨,“玉大人饭尝,你說(shuō)我怎么就攤上這事∠坠” “怎么了钥平?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)姊途。 經(jīng)常有香客問(wèn)我涉瘾,道長(zhǎng),這世上最難降的妖魔是什么吭净? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任睡汹,我火速辦了婚禮,結(jié)果婚禮上寂殉,老公的妹妹穿的比我還像新娘囚巴。我一直安慰自己,他們只是感情好友扰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布彤叉。 她就那樣靜靜地躺著,像睡著了一般村怪。 火紅的嫁衣襯著肌膚如雪秽浇。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天甚负,我揣著相機(jī)與錄音柬焕,去河邊找鬼。 笑死梭域,一個(gè)胖子當(dāng)著我的面吹牛斑举,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播病涨,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼富玷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了既穆?” 一聲冷哼從身側(cè)響起赎懦,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幻工,沒(méi)想到半個(gè)月后励两,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡囊颅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年伐蒋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了工三。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迁酸。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡先鱼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出奸鬓,到底是詐尸還是另有隱情焙畔,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布串远,位于F島的核電站宏多,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏澡罚。R本人自食惡果不足惜伸但,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望留搔。 院中可真熱鬧更胖,春花似錦、人聲如沸隔显。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)括眠。三九已至彪标,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間掷豺,已是汗流浹背捞烟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留当船,地道東北人题画。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像生年,于是被迫代替她去往敵國(guó)和親婴程。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容