從0開(kāi)始的OpenGL學(xué)習(xí)(十三)-光照貼圖

本文主要解決一個(gè)問(wèn)題:

如何使用光照貼圖給材質(zhì)添加更多的靈活性?

引言

在上一篇文章中中敢茁,我們?yōu)檎麄€(gè)物體定義了一個(gè)整體的材質(zhì)宅荤,但是現(xiàn)實(shí)世界中的對(duì)象通常不只一種材質(zhì)嘴高,而是有多種材質(zhì)組成。 想象一輛汽車(chē):車(chē)框架是鋼制的娘摔,還噴了漆窄坦,看上去閃亮閃亮的,窗戶(hù)的部分能照出周?chē)木拔锏仕拢喬ナ窍鹉z不那么閃鸭津,里面的骨架是鋼就亮很多(前提是你洗了車(chē)) 。由此可見(jiàn)读第,物體有很大可能是由不同材質(zhì)組成的一個(gè)整體曙博。難道我們還對(duì)物體的每個(gè)部分都設(shè)置一個(gè)材質(zhì)嗎?

當(dāng)然不是怜瞒,我們有光照貼圖父泳!嚴(yán)格來(lái)說(shuō),有三種光照貼圖:環(huán)境光貼圖吴汪、漫反射光貼圖惠窄、鏡面高光貼圖。但是環(huán)境光和漫反射光的顏色相似漾橙,只是稍微暗淡點(diǎn)杆融,所以我們可以把漫反射光的貼圖用到環(huán)境光上。剩下的就只有兩種貼圖了:漫反射光貼圖和鏡面高光貼圖霜运。

漫反射光貼圖

還記得我們講紋理的章節(jié)嗎脾歇?在紋理章節(jié)里,我們直接把片元的顏色設(shè)置成從紋理種采樣的顏色值淘捡,而在這章中藕各,我們會(huì)對(duì)采樣后的顏色值再進(jìn)行一系列的計(jì)算,這就是光照貼圖(不管是漫反射還是鏡面高光)的原理焦除。

由于是對(duì)漫反射顏色產(chǎn)生影響激况,所以我們稱(chēng)之為漫反射光貼圖。但是膘魄,使用的方法還是類(lèi)似的乌逐。本次我們使用下面的圖來(lái)進(jìn)行操作:

使用圖片(來(lái)自:www.learningopengl.com)

這是一個(gè)帶金屬邊的木盒子,至于為什么要金屬邊创葡,你往下看就知道了浙踢。

要使用這張圖,我們需要把材質(zhì)結(jié)構(gòu)中的環(huán)境光和漫反射屬性去掉灿渴,替換成2D紋理圖洛波。

struct Material {
    sampler2D diffuse;
    vec3      specular;
    float     shininess;
}; 
...
in vec2 TexCoords;

記啄沤妗:sampler2D是OpenGL中的隱含類(lèi)型,我們不能去設(shè)置它奋岁,只能將它暴露出來(lái)讓OpenGL自己去設(shè)置思瘟。如果你強(qiáng)行設(shè)置,OpenGL會(huì)爆出一大堆亂七八糟的Error闻伶,煩都煩死了滨攻。

改了材質(zhì)結(jié)構(gòu)之后,引用的方式自然也得改蓝翰,從單純的一個(gè)變量引用光绕,現(xiàn)在需要對(duì)紋理進(jìn)行采樣了。

vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * (diff * vec3(texture(material.diffuse, TexCoords)));

環(huán)境光也用一樣的紋理(如果你非得要用別的紋理畜份,也沒(méi)什么問(wèn)題诞帐,用同樣的方法搞一張就行了。)爆雹,替換掉material.diffuse和material.ambient之后停蕉,就是這樣了。

當(dāng)然钙态,如果你現(xiàn)在就編譯運(yùn)行慧起,是絕對(duì)看不到什么效果滴,為啥册倒?因?yàn)槲覀冞€沒(méi)有把紋理坐標(biāo)傳遞給片元著色器膀炯贰!使用紋理當(dāng)然要為頂點(diǎn)指定紋理坐標(biāo)驻子,然后將紋理坐標(biāo)傳遞給頂點(diǎn)著色器灿意,讓頂點(diǎn)著色器將紋理坐標(biāo)傳遞給片元著色器。頂點(diǎn)屬性已經(jīng)準(zhǔn)備好了崇呵,就是這樣:

float vertices[] = {
    // 位置                  // 法線(xiàn)                 // 紋理坐標(biāo)
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
     0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
     0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
     0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};

替換之后缤剧,在頂點(diǎn)著色器中添加屬性的輸入:

layout (location = 2) in vec2 aTexCoords;
...
out vec2 TexCoords;

void main()
{
    ...
    TexCoords = aTexCoords;
}  

別忘了添加頂點(diǎn)的紋理屬性,然后將一眾的屬性跨度改成8*sizeof(float)演熟。

// 紋理屬性
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);

因?yàn)槲覀兊捻?xiàng)目是開(kāi)始了光照之后的新鮮貨鞭执,之前紋理章節(jié)中加載圖片的代碼已經(jīng)沒(méi)了司顿,正好我們把這部分的功能封裝成一個(gè)函數(shù)芒粹,用起來(lái)就簡(jiǎn)單了。代碼已經(jīng)封裝好了大溜,請(qǐng)看:

//加載紋理
unsigned int loadTexture(char const * path){
    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char * data = stbi_load(path, &width, &height, &nrComponents, 0);
    if (data) {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        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_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    }
    else {
        std::cout << "紋理加載失敗化漆,路徑是:" << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}

最后,我們需要加載之前的圖片做紋理钦奋,設(shè)置漫反射紋理圖座云,啟用這張紋理圖:

unsigned int diffuseMap = loadTexture("container2.png");
...
lightingShader.setInt("material.diffuse", 0);
...
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);

編譯運(yùn)行疙赠,不出意外的話(huà),效果應(yīng)該像這樣:

運(yùn)行效果

如果效果有差朦拖,參考這里的完整代碼圃阳。

鏡面高光貼圖

乍一看效果倒是不錯(cuò),可是總感覺(jué)怪怪璧帝,為啥一個(gè)木頭箱子會(huì)有這么亮的反光呢捍岳?我們來(lái)修復(fù)這個(gè)問(wèn)題,將木頭的部分反光效果去除睬隶,邊框金屬部分的反光效果保留锣夹。這個(gè)過(guò)程看上去和漫反射貼圖一樣,巧合苏潜?我想不是。

用一張紋理圖來(lái)充當(dāng)鏡面高光的效果圖。我們需要生成一張黑白的紋理圖(當(dāng)然你想用彩色的也沒(méi)問(wèn)題)站绪,這張圖已經(jīng)準(zhǔn)備好了稚失,就是下面這張:

鏡面高光紋理圖

木頭的部分沒(méi)有鏡面高光效果,所以是黑色的飞袋,外面的金屬框有鏡面高光效果滤蝠,所以其顏色為灰色。

嚴(yán)格來(lái)說(shuō)授嘀,木頭也是有高光效果的物咳,只是非常微弱,大部分都被散射掉了蹄皱。我們出于學(xué)習(xí)的目的览闰,將高光效果設(shè)置成了0。

用神器PS或者其他的軟件就能做出一張合格的紋理圖巷折,所以压鉴,是不是考慮一下學(xué)個(gè)PS:)?

用法和之前幾乎沒(méi)有區(qū)別锻拘。先來(lái)把片元著色器中的代碼改一改:

struct Material{
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
};
vec3 specular = light.specular * (spec * vec3(texture(material.specular, TexCoords)));

將材質(zhì)中的鏡面高光改成紋理采樣油吭,計(jì)算鏡面高光的時(shí)候也改成紋理采樣。

緊接著署拟,在主函數(shù)中加載紋理圖婉宰,設(shè)置鏡面高光紋理圖,將紋理圖綁定到紋理單元1上推穷。

unsigned int specularMap = loadTexture("container2_specular.png");
lightingShader.setInt("material.specular", 1);
...
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, specularMap);  

改完之后心包,編譯運(yùn)行,你會(huì)看到類(lèi)似下面的效果:

運(yùn)行效果

如果你看到的場(chǎng)景不正確馒铃,請(qǐng)查看這里的代碼比對(duì)蟹腾。

總結(jié)

在本文中痕惋,我們學(xué)習(xí)了如何用光照貼圖代替材質(zhì)的單一反射屬性,在同一個(gè)物體的不同部分應(yīng)用不同的材質(zhì)娃殖。使用的方式很簡(jiǎn)單值戳,對(duì)貼圖進(jìn)行采樣,然后和光照進(jìn)行計(jì)算炉爆。這種方式述寡,和之前紋理章節(jié)介紹的內(nèi)容十分相似,對(duì)比之前紋理章節(jié)的片元著色器代碼叶洞,你會(huì)有更深的理解鲫凶。

下一篇
目錄
上一篇

參考資料

www.learningopengl.com(非常好的網(wǎng)站,建議學(xué)習(xí))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衩辟,一起剝皮案震驚了整個(gè)濱河市螟炫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艺晴,老刑警劉巖昼钻,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異封寞,居然都是意外死亡然评,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)狈究,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碗淌,“玉大人,你說(shuō)我怎么就攤上這事抖锥∫诿撸” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵磅废,是天一觀的道長(zhǎng)纳像。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拯勉,這世上最難降的妖魔是什么竟趾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮宫峦,結(jié)果婚禮上岔帽,老公的妹妹穿的比我還像新娘。我一直安慰自己斗遏,他們只是感情好山卦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布鞋邑。 她就那樣靜靜地躺著诵次,像睡著了一般账蓉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逾一,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天铸本,我揣著相機(jī)與錄音,去河邊找鬼遵堵。 笑死箱玷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的陌宿。 我是一名探鬼主播锡足,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼壳坪!你這毒婦竟也來(lái)了舶得?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤爽蝴,失蹤者是張志新(化名)和其女友劉穎沐批,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蝎亚,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡九孩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了发框。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躺彬。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梅惯,靈堂內(nèi)的尸體忽然破棺而出顾患,到底是詐尸還是另有隱情,我是刑警寧澤个唧,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布江解,位于F島的核電站,受9級(jí)特大地震影響徙歼,放射性物質(zhì)發(fā)生泄漏犁河。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一魄梯、第九天 我趴在偏房一處隱蔽的房頂上張望桨螺。 院中可真熱鬧,春花似錦酿秸、人聲如沸灭翔。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肝箱。三九已至哄褒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間煌张,已是汗流浹背呐赡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骏融,地道東北人链嘀。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像档玻,于是被迫代替她去往敵國(guó)和親怀泊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • 這篇教程將涵蓋美術(shù)內(nèi)容創(chuàng)作的基礎(chǔ)知識(shí)碧囊,以及各種基于物理規(guī)則的渲染標(biāo)準(zhǔn)背后的一些理論推導(dǎo)(并沒(méi)有太過(guò)技術(shù)性的內(nèi)...
    DIGITALMAN閱讀 9,055評(píng)論 16 67
  • 我們都知道,一個(gè)三維場(chǎng)景的畫(huà)面的好壞纤怒,百分之四十取決于模型糯而,百分之六十取決于貼圖,可見(jiàn)貼圖在畫(huà)面中所占的重要性泊窘。在...
    自由的天空閱讀 12,384評(píng)論 0 12
  • 1 陳鳳終于要回她那不愿意回去的老家了熄驼。 陳鳳坐在弟弟車(chē)上的副駕駛位置,陳鳳她娘坐在汽車(chē)后座烘豹」霞郑縱然她刻意避開(kāi)了她娘...
    不想喝水的魚(yú)閱讀 646評(píng)論 5 11
  • 人的命祭芦,出生定 隨著年齡的增長(zhǎng),我越來(lái)越相信一個(gè)人的出身決定了他的命運(yùn)憔鬼。一個(gè)人出生在什么樣的家庭龟劲,耳濡目染,就會(huì)...
    幸運(yùn)水瓶閱讀 480評(píng)論 1 2