09 - OpenGL學習之基本紋理

前言

前面文章中叹誉,我們通過為頂點添加顏色,來創(chuàng)建有趣的圖形宣吱,但是現(xiàn)實世界中的物體(例如磚墻,草坪等等)表面是有很多細節(jié)的瞳别,如果我們想要讓圖形看起來更加真實征候,必須要有足夠的頂點,從而能指定足夠多的顏色祟敛,描述圖形的細節(jié)疤坝。但是繪制一個立方體的時候,我們就需要繪制六個面垒棋,已經感覺很繁瑣卒煞,更不用說為每個面繪制不同的細節(jié)痪宰。
所以接下來我們介紹讓圖形看起來更加真實的技術------紋理叼架。
紋理類型包含以下幾種:2D紋理,立方圖紋理衣撬,3D紋理乖订,2D紋理數(shù)組,1D紋理具练,下面我們介紹最基本的2D紋理乍构,來幫助我們了解紋理這個概念。

下面我們在正方形上加載一個紋理扛点。


IMG_6718.PNG

片段著色器:

#version 300 es 

precision mediump float;

in vec2 oTextCoord;

uniform sampler2D  texture1;
 
out vec4 fragColor;

void main() {
    
    fragColor = texture(texture1,oTextCoord);
    
}

片段著色器中哥遮,我們用sampler2D 這個類表示紋理,texture函數(shù)加載紋理像素陵究,需要傳入兩個對象:紋理對象眠饮,紋理坐標。
這里我們說明下紋理坐標的概念:
這里我們使用的是2D紋理铜邮,紋理坐標在X軸和Y軸仪召,范圍在0~1之間,紋理坐標標明從紋理圖像的哪個部分采樣松蒜,通過使用紋理坐標把紋理圖像映射到屏幕的過程叫做紋理映射也叫紋理貼圖扔茅。


2D紋理坐標

代碼如下:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    [super glkView:view drawInRect:rect];

    _esContext.width = view.drawableWidth;
    _esContext.height = view.drawableHeight;
    
    GLfloat factor =  (view.frame.size.width / view.frame.size.height) * 0.5;
    
    
    //(x,y,z) (s,t)
    float position[] = {
        -0.5,  factor, 0.0,  0.0, 0.0,
        -0.5, -factor, 0.0,  0.0, 1.0,
         0.5, -factor, 0.0,  1.0, 1.0,
         0.5,  factor, 0.0,  1.0, 0.0,
    };
    
    
    //開啟深度測試,為了確定繪制的時候哪一個面繪制在上面
    glClear(GL_COLOR_BUFFER_BIT);
    
    GLuint vboIndex = 0;
    glGenBuffers(1, &vboIndex);
    glBindBuffer(GL_ARRAY_BUFFER, vboIndex);
    glBufferData(GL_ARRAY_BUFFER, sizeof(position), position, GL_STATIC_DRAW);
    
    GLuint positionIndex = glGetAttribLocation(_esContext.program, "vPosition");
    GLuint textCoordIndex = glGetAttribLocation(_esContext.program, "textCoord");
    
    GLuint textureLocation = glGetUniformLocation(_esContext.program, "texture1");
    
    glEnableVertexAttribArray(positionIndex);
    glEnableVertexAttribArray(textCoordIndex);
    
    GLuint offset = 3 * sizeof(float);
    glVertexAttribPointer(positionIndex, 3, GL_FLOAT, GL_FALSE, 5  * sizeof(float), NULL);
    glVertexAttribPointer(textCoordIndex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (const void *)offset);
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, self.baseTexture.name);
    glUniform1i(textureLocation, 0);
    _esContext.drawFunc(&_esContext);
    
    //關閉頂點屬性
    glDisableVertexAttribArray(positionIndex);
    glDisableVertexAttribArray(textCoordIndex);
    glDeleteBuffers(1, &vboIndex);
    
    
}

代碼中注意以下兩點:
1.這里我們設置頂點坐標的時候用上了屏幕寬高比秸苗,這是因為手機屏幕寬高不一樣召娜,如果按照0.5的比例來渲染的話,圖像會拉伸惊楼,所以需要乘以這個寬高比玖瘸。

 glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, self.baseTexture.name);
  glUniform1i(textureLocation, 0);

這里的baseTexture是通過GLkit庫提供的GLKTextLoader類加載的紋理對象吐句。得益于這個API,幫我們省去了很多工作店读,示例代碼中注釋的部分還含有自己生成紋理對象蠢古,并綁定使用的過程实幕。

紋理環(huán)繞

上面我們說的紋理坐標范圍是0~1如果我們超過了這個范圍,怎么辦呢,OpenGL ES默認的行為是重復這個紋理圖像(但OpenGL ES提供了更多的選擇:

#define GL_REPEAT                對紋理的默認行為前普。重復紋理圖像。
#define GL_CLAMP_TO_EDGE        紋理坐標會被約束在0到1之間假栓,超出的部分會重復紋理坐標的邊緣情臭,產生一種邊緣被拉伸的效果。
#define GL_MIRRORED_REPEAT       和GL_REPEAT一樣趴久,但每次重復圖片是鏡像放置的丸相。
紋理環(huán)繞方式圖解

紋理過濾:

紋理坐標不依賴于屏幕分辨率,它可以是任意浮點值彼棍,當你有一個很大的物體灭忠,但是紋理的分辨率很低的時候,ES需要知道怎樣將紋理映射到屏幕座硕,ES這里提供了對于紋理過濾的選項弛作。這里我們介紹最重要的兩項:
1.GL_NEARST(鄰近過濾),這個是默認的紋理過濾方式华匾,當設置為這個選項時映琳,ES會選擇中心點最接近紋理坐標的那個像素。如下圖所示

GL_NEARST

2.GL_LINEAR,當設置為這個選項時蜘拉,它會基于紋理坐標附近的紋理像素萨西,計算一個差值。一個紋理像素的中心距離紋理坐標越近旭旭,那么它在插值的計算中谎脯,占比越大。如下圖所示:


GL_LINEAR

看一下兩種方式對最終成像效果的影響:


效果圖

我們可以看到GL_NEARST方式的紋理具有顆粒感您机,可以看清像素穿肄,但是GL_LINEAR效果比較真實,過渡比較自然际看。

mipmap貼圖

想象一下咸产,假設我們繪制一段城墻,這個城墻表面是由一個個磚塊紋理拼接而成仲闽,近處的看起來效果很自然脑溢,但是距離很遠的時候,由于遠處的物體可能只產生很少的片段,OpenGL ES從高分辨率紋理中為這些片段獲取正確的顏色值就很困難屑彻,因為它需要對一個跨過紋理很大部分的片段只拾取一個紋理顏色验庙,在小物體上會產生不真實的感覺,而且對它們使用高分辨率的紋理也會浪費資源社牲,造成性能問題粪薛。
OPenGL ES使用一種叫做多級漸遠紋理(Mipmap)的概念來解決這個問題,它簡單來說就是一系列的紋理圖像搏恤,后一個紋理圖像是前一個的二分之一违寿。多級漸遠紋理背后的理念很簡單:距觀察者的距離超過一定的閾值,OpenGL ES 會使用不同的多級漸遠紋理熟空,即最適合物體的距離的那個藤巢。由于距離遠,解析度不高也不會被用戶注意到息罗。同時掂咒,多級漸遠紋理另一加分之處是它的性能非常好。

mipmap也有幾種過濾方式:

GL_NEAREST_MIPMAP_NEAREST   使用最鄰近的多級漸遠紋理來匹配像素大小迈喉,并使用鄰近插值進行紋理采樣
GL_LINEAR_MIPMAP_NEAREST    使用最鄰近的多級漸遠紋理級別绍刮,并使用線性插值進行采樣
GL_NEAREST_MIPMAP_LINEAR    在兩個最匹配像素大小的多級漸遠紋理之間進行線性插值,使用鄰近插值進行采樣
GL_LINEAR_MIPMAP_LINEAR 在兩個鄰近的多級漸遠紋理之間使用線性插值弊添,并使用線性插值進行采樣

1.生成和綁定紋理

   GLuint textId = 0;
   glGenTextures(1, &textId);
   glBindTexture(GL_TEXTURE_2D, textId)

2.加載紋理數(shù)據(jù)

 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 750, 750, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)_imageData.bytes);
  1. 設置紋理過濾方式
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 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);

4.綁定紋理到著色器

glUniform1i(textureLocation, 0);

使用紋理大致分為上面幾步录淡,示例程序中有兩種方式捌木,第一種簡易方式是借助GLKit.后面一種是實際的操作過程油坝。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刨裆,隨后出現(xiàn)的幾起案子澈圈,更是在濱河造成了極大的恐慌,老刑警劉巖帆啃,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞬女,死亡現(xiàn)場離奇詭異,居然都是意外死亡努潘,警方通過查閱死者的電腦和手機诽偷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疯坤,“玉大人报慕,你說我怎么就攤上這事⊙沟。” “怎么了眠冈?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長菌瘫。 經常有香客問我蜗顽,道長布卡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任雇盖,我火速辦了婚禮忿等,結果婚禮上,老公的妹妹穿的比我還像新娘崔挖。我一直安慰自己这弧,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布虚汛。 她就那樣靜靜地躺著匾浪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卷哩。 梳的紋絲不亂的頭發(fā)上蛋辈,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音将谊,去河邊找鬼冷溶。 笑死,一個胖子當著我的面吹牛尊浓,可吹牛的內容都是我干的逞频。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼栋齿,長吁一口氣:“原來是場噩夢啊……” “哼苗胀!你這毒婦竟也來了?” 一聲冷哼從身側響起瓦堵,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤基协,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后菇用,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澜驮,經...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年惋鸥,在試婚紗的時候發(fā)現(xiàn)自己被綠了杂穷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡卦绣,死狀恐怖耐量,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情迎卤,我是刑警寧澤拴鸵,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響劲藐,放射性物質發(fā)生泄漏八堡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一聘芜、第九天 我趴在偏房一處隱蔽的房頂上張望兄渺。 院中可真熱鬧,春花似錦汰现、人聲如沸挂谍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽口叙。三九已至,卻和暖如春嗅战,著一層夾襖步出監(jiān)牢的瞬間妄田,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工驮捍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疟呐,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓东且,卻偏偏與公主長得像启具,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子珊泳,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內容

  • 一旨椒、前言 圖片在屏幕上的顯示晓褪,最終都是解碼成位圖,然后進行顯示的综慎。 一個圖形在幀緩存區(qū)中的存儲空間,可以根據(jù)如下公...
    含笑州閱讀 733評論 0 0
  • 紋理(Texture) 紋理(Texture) 是一個2D圖像(也有1D和3D紋理存在)用于給一個對象添加細節(jié)信息...
    蓬篙人閱讀 1,174評論 0 5
  • 基本概念 ** 紋理 **概念:紋理是一個用來保存圖像顏色元素值的OpenGL ES緩存勤庐。應該盡量使用最小的圖像來...
    星空雪雨閱讀 1,520評論 0 6
  • 一愉镰、了解紋理 在OpenGL中米罚,紋理是一種圖形數(shù)據(jù),主要用于包裝不同的物體丈探。我們來舉個例子:裝修房子時录择,各個房間需...
    宇宙那么大丶閱讀 480評論 0 0
  • 紋理紋理是一個2D圖片,它可以用來添加物體的細節(jié),讓物體更加真實隘竭。為了能夠把紋理映射到三角形上塘秦,我們需要制定三角形...
    ccccr閱讀 768評論 0 0