www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]寫(xiě)在前面?在繼續(xù)討論模型變換等其他包含數(shù)學(xué)內(nèi)容的部分之前,本節(jié)介紹二維紋理映射,為后面學(xué)習(xí)做一個(gè)準(zhǔn)備。紋理映射本身也是比較大的主題,本節(jié)只限于討論二維紋理的基本使用,對(duì)于紋理映射的其他方法,后面會(huì)繼續(xù)

寫(xiě)在前面?
在繼續(xù)討論模型變換等其他包含數(shù)學(xué)內(nèi)容的部分之前,本節(jié)介紹二維紋理映射,為后面學(xué)習(xí)做一個(gè)準(zhǔn)備。紋理映射本身也是比較大的主題,本節(jié)只限于討論二維紋理的基本使用,對(duì)于紋理映射的其他方法,后面會(huì)繼續(xù)學(xué)習(xí)。可以從我的github下載本節(jié)代碼。

通過(guò)本節(jié)可以了解到

紋理映射的概念和原理二維紋理映射的處理方法使用紋理增加物體表面細(xì)節(jié)

要使渲染的物體更加逼真,一方面我們可以使用更多的三角形來(lái)建模,通過(guò)復(fù)雜的模型來(lái)逼近物體,但是這種方法會(huì)增加繪制流水線的負(fù)荷,而且很多情況下不是很方便的。使用紋理,將物體表面的細(xì)節(jié)映射到建模好的物體表面,這樣不僅能使渲染的模型表面細(xì)節(jié)更豐富,而且比較方便高效。紋理映射就是這樣一種方法,在程序中通過(guò)為物體指定紋理坐標(biāo),通過(guò)紋理坐標(biāo)獲取紋理對(duì)象中的紋理,最終顯示在屏幕區(qū)域上,已達(dá)到更加逼真的效果。

紋素(texel)和紋理坐標(biāo)

使用紋素這個(gè)術(shù)語(yǔ),而不是像素來(lái)表示紋理對(duì)象中的顯示元素,主要是為了強(qiáng)調(diào)紋理對(duì)象的應(yīng)用方式。紋理對(duì)象通常是通過(guò)紋理圖片讀取到的,這個(gè)數(shù)據(jù)保存到一個(gè)二維數(shù)組中,這個(gè)數(shù)組中的元素稱(chēng)為紋素(texel),紋素包含顏色值和alpha值。紋理對(duì)象的大小的寬度和高度應(yīng)該為2的整數(shù)冪,例如16, 32, 64, 128, 256。要想獲取紋理對(duì)象中的紋素,需要使用紋理坐標(biāo)(texture coordinate)指定。

紋理坐標(biāo)應(yīng)該與紋理對(duì)象大小無(wú)關(guān),這樣指定的紋理坐標(biāo)當(dāng)紋理對(duì)象大小變更時(shí),依然能夠工作,比如從256x256大小的紋理,換到512x256時(shí),紋理坐標(biāo)依然能夠工作。因此紋理坐標(biāo)使用規(guī)范化的值,大小范圍為[0,1],紋理坐標(biāo)使用uv表示,如下圖所示(來(lái)自:Basic Texture Mapping):?

u軸從左至右,v軸從底向上指向。右上角為(1,1),左下角為(0,0)。?
通過(guò)指定紋理坐標(biāo),可以映射到紋素。例如一個(gè)256x256大小的二維紋理,坐標(biāo)(0.5,1.0)對(duì)應(yīng)的紋素即是(128,256)。(256x0.5 = 128, 256x1.0 = 256)。

紋理映射時(shí)只需要為物體的頂點(diǎn)指定紋理坐標(biāo)即可,其余部分由片元著色器插值完成,如下圖所示(來(lái)自A textured cube):?

模型變換和紋理坐標(biāo)

所謂模型變換,就是對(duì)物體進(jìn)行縮放、旋轉(zhuǎn)、平移等操作,后面會(huì)著重介紹。當(dāng)對(duì)物體進(jìn)行這些操作時(shí),頂點(diǎn)對(duì)應(yīng)的紋理坐標(biāo)不會(huì)進(jìn)行改變,通過(guò)插值后,物體的紋理也像緊跟著物體發(fā)生了變化一樣。如下圖所示為變換前物體的紋理坐標(biāo)(來(lái)自:Basic Texture Mapping):?

經(jīng)過(guò)旋轉(zhuǎn)等變換后,物體和對(duì)應(yīng)的紋理坐標(biāo)如下圖所示,可以看出上面圖中紋理部分的房子也跟著發(fā)生了旋轉(zhuǎn)。(來(lái)自:Basic Texture Mapping):?

注意?有一些技術(shù)可以使紋理坐標(biāo)有控制地發(fā)生改變,本節(jié)不深入討論,這里我們的紋理坐標(biāo)在模型變換下保持不變。

創(chuàng)建紋理對(duì)象

創(chuàng)建紋理對(duì)象的過(guò)程同前面講述的創(chuàng)建VBO,VAO類(lèi)似:

???GLuint?textureId;
???glGenTextures(1,?&textureId);
???glBindTexture(GL_TEXTURE_2D,?textureId);

這里我們綁定到GL_TEXTURE_2D目標(biāo),表示二維紋理。

WRAP參數(shù)

上面提到紋理坐標(biāo)(0.5, 1.0)到紋素的映射,恰好為(128,256)。如果紋理坐標(biāo)超出[0,0]到[1,1]的范圍該怎么處理呢? 這個(gè)就是wrap參數(shù)由來(lái),它使用以下方式來(lái)處理:

GL_REPEAT:坐標(biāo)的整數(shù)部分被忽略,重復(fù)紋理,這是OpenGL紋理默認(rèn)的處理方式.GL_MIRRORED_REPEAT: 紋理也會(huì)被重復(fù),但是當(dāng)紋理坐標(biāo)的整數(shù)部分是奇數(shù)時(shí)會(huì)使用鏡像重復(fù)。GL_CLAMP_TO_EDGE: 坐標(biāo)會(huì)被截?cái)嗟絒0,1]之間。結(jié)果是坐標(biāo)值大的被截?cái)嗟郊y理的邊緣部分,形成了一個(gè)拉伸的邊緣(stretched edge pattern)。GL_CLAMP_TO_BORDER: 不在[0,1]范圍內(nèi)的紋理坐標(biāo)會(huì)使用用戶(hù)指定的邊緣顏色。

當(dāng)紋理坐標(biāo)超出[0,1]范圍后,使用不同的選項(xiàng),輸出的效果如下圖所示(來(lái)自Textures objects and parameters):

在OpenGL中設(shè)置wrap參數(shù)方式如下:

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

上面的幾個(gè)選項(xiàng)對(duì)應(yīng)的都是整數(shù),因此使用glTexParameteri來(lái)設(shè)置。

Filter參數(shù)

當(dāng)使用紋理坐標(biāo)映射到紋素?cái)?shù)組時(shí),正好得到對(duì)應(yīng)紋素的中心位置的情況,很少出現(xiàn)。例如上面的(0.5,1.0)對(duì)應(yīng)紋素(128,256)的情況是比較少的。如果紋理坐標(biāo)映射到紋素位置(152.34,745.14)該怎么辦呢 ?

一種方式是對(duì)這個(gè)坐標(biāo)進(jìn)行取整,使用最佳逼近點(diǎn)來(lái)獲取紋素,這種方式即點(diǎn)采樣(point sampling),也就是最近鄰濾波( nearest neighbor filtering)。這種方式容易導(dǎo)致走樣誤差,明顯有像素塊的感覺(jué)。最近鄰濾波方法的示意圖如下所示(來(lái)自A Textured Cube):?
?
圖中目標(biāo)紋素位置,離紅色這個(gè)紋素最近,因此選擇紅色作為最終輸出紋素。

另外還存在其他濾波方法,例如線性濾波方法(linear filtering),它使用紋素位置(152.34,745.14)附近的一組紋素的加權(quán)平均值來(lái)確定最終的紋素值。例如使用 ( (152,745), (153,745), (152,744) and (153,744) )這四個(gè)紋素值的加權(quán)平均值。權(quán)系數(shù)通過(guò)與目標(biāo)點(diǎn)(152.34,745.14)的距離遠(yuǎn)近反映,距離(152.34,745.14)越近,權(quán)系數(shù)越大,即對(duì)最終的紋素值影響越大。線性濾波的示意圖如下圖所示(來(lái)自A Textured Cube):?
?
圖中目標(biāo)紋素位置周?chē)?個(gè)紋素通過(guò)加權(quán)平均計(jì)算出最終輸出紋素。

還存在其他的濾波方式,如三線性濾波(Trilinear filtering)等,感興趣的可以參考texture filtering wiki。最近鄰濾波和線性濾波的對(duì)比效果如下圖所示(來(lái)自Textures objects and parameters):

可以看出最近鄰方法獲取的紋素看起來(lái)有明顯的像素塊,而線性濾波方法獲取的紋素看起來(lái)比較平滑。兩種方法各自有不同的應(yīng)用場(chǎng)合,不能說(shuō)線性濾波一定比最近鄰濾波方法好,例如要制造8位圖形效果(8 bit graphics,每個(gè)像素使用8位字節(jié)表示)需要使用最近鄰濾波。作為一個(gè)興趣了解,8位圖形效果看起來(lái)也是很酷的(可以查看Welcome 8-bit, Pixel-Art Images Gallery!)獲得更多8位圖形),例如下面這張使用Excel制作的8位圖(來(lái)自Excel is a great for making 8 bit graphics!):?

另外一個(gè)問(wèn)題是,紋理應(yīng)用到物體上,最終要繪制在顯示設(shè)備上,這里存在一個(gè)紋素到像素的轉(zhuǎn)換問(wèn)題。有三種情形(參考自An Introduction to Texture Filtering):

一個(gè)紋素最終對(duì)應(yīng)屏幕上的多個(gè)像素 這稱(chēng)之為放大(magnification)一個(gè)紋素對(duì)應(yīng)屏幕上的一個(gè)像素 這種情況不需要濾波方法一個(gè)紋素對(duì)應(yīng)少于一個(gè)像素,或者說(shuō)多個(gè)紋素對(duì)應(yīng)屏幕上的一個(gè)像素 這個(gè)稱(chēng)之為縮小(minification)?
放大和縮小的示意圖如下:?

在OpenGL中通過(guò)使用下面的函數(shù),為紋理的放大和縮小濾波設(shè)置相關(guān)的控制選項(xiàng):

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

其中GL_LINEAR對(duì)應(yīng)線性濾波,GL_NEAREST對(duì)應(yīng)最近鄰濾波方式。

使用Mipmaps

考慮一個(gè)情景:當(dāng)物體在場(chǎng)景中離觀察者很遠(yuǎn),最終只用一個(gè)屏幕像素來(lái)顯示時(shí),這個(gè)像素該如何通過(guò)紋素確定呢?如果使用最近鄰濾波來(lái)獲取這個(gè)紋素,那么顯示效果并不理想。需要使用紋素的均值來(lái)反映物體在場(chǎng)景中離我們很遠(yuǎn)這個(gè)效果,對(duì)于一個(gè) 256×256的紋理,計(jì)算平均值是一個(gè)耗時(shí)工作,不能實(shí)時(shí)計(jì)算,因此可以通過(guò)提前計(jì)算一組這樣的紋理用來(lái)滿(mǎn)足這種需求。這組提前計(jì)算的按比例縮小的紋理就是Mipmaps。Mipmaps紋理大小每級(jí)是前一等級(jí)的一半,按大小遞減順序排列為:

原始紋理 256×256Mip 1 = 128×128Mip 2 = 64×64Mip 3 = 32×32Mip 4 = 16×16Mip 5 = 8×8Mip 6 = 4×4Mip 7 = 2×2Mip 8 = 1×1

OpenGL會(huì)根據(jù)物體離觀察者的距離選擇使用合適大小的Mipmap紋理。Mipmap紋理示意圖如下所示(來(lái)自wiki Mipmap):?
?
OpenGL中通過(guò)函數(shù)glGenerateMipmap(GL_TEXTURE_2D);來(lái)生成Mipmap,前提是已經(jīng)指定了原始紋理。原始紋理必須自己通過(guò)讀取紋理圖片來(lái)加載,這個(gè)后面會(huì)介紹。?
如果直接在不同等級(jí)的MipMap之間切換,會(huì)形成明顯的邊緣,因此對(duì)于Mipmap也可以同紋素一樣使用濾波方法在不同等級(jí)的Mipmap之間濾波。要在不同等級(jí)的MipMap之間濾波,需要將之前設(shè)置的GL_TEXTURE_MIN_FILTER選項(xiàng)更改為以下選項(xiàng)之一:

GL_NEAREST_MIPMAP_NEAREST: 使用最接近像素大小的Mipmap,紋理內(nèi)部使用最近鄰濾波。GL_LINEAR_MIPMAP_NEAREST: 使用最接近像素大小的Mipmap,紋理內(nèi)部使用線性濾波。GL_NEAREST_MIPMAP_LINEAR: 在兩個(gè)最接近像素大小的Mipmap中做線性插值,紋理內(nèi)部使用最近鄰濾波。GL_LINEAR_MIPMAP_LINEAR: 在兩個(gè)最接近像素大小的Mipmap中做線性插值,紋理內(nèi)部使用線性濾波。

Mipmap使用注意?使用使用glGenerateMipmap(GL_TEXTURE_2D)產(chǎn)生Mipmap的前提是你已經(jīng)加載了原始的紋理對(duì)象。使用MipMap時(shí)設(shè)置GL_TEXTURE_MIN_FILTER選項(xiàng)才能起作用,設(shè)置GL_TEXTURE_MAG_FILTER的Mipmap選項(xiàng)將會(huì)導(dǎo)致無(wú)效操作,OpenGL錯(cuò)誤碼為GL_INVALID_ENUM。

設(shè)置Mipmap選項(xiàng)如下代碼所示:

???glTexParameteri(GL_TEXTURE_2D,?
???????GL_TEXTURE_MIN_FILTER,?GL_LINEAR_MIPMAP_LINEAR);

加載原始紋理

從圖片加載紋理這部分工作不是OpenGL函數(shù)完成的,可以通過(guò)外部庫(kù)實(shí)現(xiàn)。這里我們使用SOIL(Simple OpenGL Image Library)庫(kù)完成。下載完這個(gè)庫(kù)后,你需要編譯到本地平臺(tái)對(duì)應(yīng)版本。你可以從我的github處下載已經(jīng)編譯好的32位庫(kù)。?
使用SOIL加載紋理的代碼如下:

GLubyte?*imageData?=?NULL;
int?picWidth,?picHeight;
imageData?=?SOIL_load_image("wood.png",?
????&picWidth,?&picHeight,?0,?SOIL_LOAD_RGB);?//?讀取圖片數(shù)據(jù)
glTexImage2D(GL_TEXTURE_2D,?0,?GL_RGB,?
????picWidth,picHeight,?0,?GL_RGB,?
????GL_UNSIGNED_BYTE,?imageData);?//?定義紋理圖像

其中g(shù)lTexImage2D函數(shù)定義紋理圖像的格式,寬度和高度等信息,具體參數(shù)如下:

API?void?glTexImage2D( GLenum target,?
GLint level,?
GLint internalFormat,?
GLsizei width,?
GLsizei height,?
GLint border,?
GLenum format,?
GLenum type,?
const GLvoid * data);

1.target參數(shù)指定設(shè)置的紋理目標(biāo),必須是GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D等參數(shù)。?
2.level指定紋理等級(jí),0代表原始紋理,其余等級(jí)對(duì)應(yīng)Mipmap紋理等級(jí)。?
3.internalFormat指定OpenGL存儲(chǔ)紋理的格式,我們讀取的圖片格式包含RGB顏色,因此這里也是用RGB顏色。?
4.width和height參數(shù)指定存儲(chǔ)的紋理大小,我們之前利用SOIL讀取圖片時(shí)已經(jīng)獲取了圖片大小,這里直接使用即可。?
5. border 參數(shù)為歷史遺留參數(shù),只能設(shè)置為0.?
6. 最后三個(gè)參數(shù)指定原始圖片數(shù)據(jù)的格式(format)和數(shù)據(jù)類(lèi)型(type,為GL_UNSIGNED_BYTE, GL_BYTE等值),以及數(shù)據(jù)的內(nèi)存地址(data指針)。

使用紋理的完整過(guò)程

Step1?首先要指定紋理坐標(biāo),這個(gè)坐標(biāo)和頂點(diǎn)位置、頂點(diǎn)顏色一樣處理,使用索引繪制,代碼如下所示:

???//?指定頂點(diǎn)屬性數(shù)據(jù)?頂點(diǎn)位置?顏色?紋理
????GLfloat?vertices[]?=?{
????????-0.5f,?-0.5f,?0.0f,?1.0f,?0.0f,?0.0f,0.0f,?0.0f,??//?0
????????0.5f,??-0.5f,?0.0f,?0.0f,?1.0f,?0.0f,1.0f,?0.0f,??//?1
????????0.5f,??0.5f,??0.0f,?0.0f,?0.0f,?1.0f,1.0f,?1.0f,??//?2
????????-0.5f,?0.5f,??0.0f,?1.0f,?1.0f,?0.0f,0.0f,?1.0f???//?3
????};
????GLushort?indices[]?=?{
????????0,?1,?2,??//?第一個(gè)三角形
????????0,?2,?3???//?第二個(gè)三角形
????};

同頂點(diǎn)位置和顏色一樣,需要指定紋理坐標(biāo)的解析方式。上面的數(shù)據(jù)格式如下圖所示(來(lái)自www.learnopengl.com):?

這個(gè)格式的說(shuō)明在OpenGL學(xué)習(xí)腳印: 繪制一個(gè)三角形?已經(jīng)講過(guò),如果不清楚,可以回過(guò)頭去查看。通過(guò)查看上圖,我們按照如下方式設(shè)置glVertexAttribPointer,讓OpenGL知道如何解析上述數(shù)據(jù):

????//?頂點(diǎn)位置屬性
????glVertexAttribPointer(0,?3,?GL_FLOAT,?GL_FALSE,?
????????8?*?sizeof(GL_FLOAT),?(GLvoid*)0);
????glEnableVertexAttribArray(0);
????//?頂點(diǎn)顏色屬性
????glVertexAttribPointer(1,?3,?GL_FLOAT,?GL_FALSE,
????????8?*?sizeof(GL_FLOAT),?(GLvoid*)(3?*?sizeof(GL_FLOAT)));
????glEnableVertexAttribArray(1);
????//?頂點(diǎn)紋理坐標(biāo)
????glVertexAttribPointer(2,?2,?GL_FLOAT,?GL_FALSE,
????????8?*?sizeof(GL_FLOAT),?(GLvoid*)(6?*?sizeof(GL_FLOAT)));
????glEnableVertexAttribArray(2);

對(duì)應(yīng)的頂點(diǎn)著色器如下:

#version?330

layout(location?=?0)?in?vec3?position;
layout(location?=?1)?in?vec3?color;
layout(location?=?2)?in?vec2?textCoord;?//?紋理坐標(biāo)

out?vec3?VertColor;
out?vec2?TextCoord;

void?main()
{
????gl_Position?=?vec4(position,?1.0);
????VertColor?=?color;
????TextCoord?=?textCoord;
}

Step2?:然后需要設(shè)置OpenGL紋理參數(shù);最后通過(guò)讀取紋理圖片,定義紋理圖像格式等信息。紋理數(shù)據(jù)最終傳遞到了顯卡中存儲(chǔ)。

???//?Section3?準(zhǔn)備紋理對(duì)象
????//?Step1?創(chuàng)建并綁定紋理對(duì)象
????GLuint?textureId;
????glGenTextures(1,?&textureId);
????glBindTexture(GL_TEXTURE_2D,?textureId);
????//?Step2?設(shè)定wrap參數(shù)
????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_WRAP_S,?GL_REPEAT);
????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_WRAP_T,?GL_REPEAT);
????//?Step3?設(shè)定filter參數(shù)
????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_MAG_FILTER,?GL_LINEAR);
????glTexParameteri(GL_TEXTURE_2D,?GL_TEXTURE_MIN_FILTER,?
????????GL_LINEAR_MIPMAP_LINEAR);?//?為MipMap設(shè)定filter方法
????//?Step4?加載紋理
????GLubyte?*imageData?=?NULL;
????int?picWidth,?picHeight;
????imageData?=?SOIL_load_image("wood.png",?
????????&picWidth,?&picHeight,?0,?SOIL_LOAD_RGB);
????glTexImage2D(GL_TEXTURE_2D,?0,?GL_RGB,?picWidth,?picHeight,?
????????0,?GL_RGB,?GL_UNSIGNED_BYTE,?imageData);
????glGenerateMipmap(GL_TEXTURE_2D);
????//?Step5?釋放紋理圖片資源
????SOIL_free_image_data(imageData);
????glBindTexture(GL_TEXTURE_2D,?0);

注意?圖片資源在創(chuàng)建完紋理后就可以釋放了,使用SOIL_free_image_data完成。

Step3?著色器中使用紋理對(duì)象?
在頂點(diǎn)著色器中我們傳遞了紋理坐標(biāo),有了紋理坐標(biāo),獲取最終的紋素使用過(guò)在片元著色器中完成的。由于紋理對(duì)象通過(guò)使用uniform變量來(lái)像片元著色器傳遞,實(shí)際上這里傳遞的是對(duì)應(yīng)紋理單元(texture unit)的索引號(hào)。紋理單元、紋理對(duì)象對(duì)應(yīng)關(guān)系如下圖所示:?

著色器通過(guò)紋理單元的索引號(hào)索引紋理單元,每個(gè)紋理單元可以綁定多個(gè)紋理到不同的目標(biāo)(1D,2D)。OpenGL可以支持的紋理單元數(shù)目,一般至少有16個(gè),依次為GL_TEXTURE0 到GL_TEXTURE15,紋理單元最大支持?jǐn)?shù)目可以通過(guò)查詢(xún)GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS常量獲取。這些常量值是按照順序定義的,因此可以采用 GL_TEXTURE0 + i 的形式書(shū)寫(xiě)常量,其中整數(shù)i在[0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)范圍內(nèi)。

作為一個(gè)了解,紋理對(duì)象不僅包含紋理數(shù)據(jù),還包含采樣參數(shù),這些采樣參數(shù)稱(chēng)之為采樣狀態(tài)(sampling state)。而采樣對(duì)象(sampler object)就是只包含采樣參數(shù)的對(duì)象,將它綁定到紋理單元時(shí),它會(huì)覆蓋紋理對(duì)象中的采樣狀態(tài),從而重新配置采樣方式。這里不再繼續(xù)討論采樣對(duì)象的使用了。

要使用紋理必須在使用之前激活對(duì)應(yīng)的紋理單元,默認(rèn)狀態(tài)下0號(hào)紋理單元是激活的,因此即使沒(méi)有顯式地激活也能工作。激活并使用紋理的代碼如下:

??//?使用0號(hào)紋理單元
??glActiveTexture(GL_TEXTURE0);
??glBindTexture(GL_TEXTURE_2D,?textureId);
??glUniform1i(glGetUniformLocation(shader.programId,?"tex"),?0);

上述glUniform1i將0號(hào)紋理單元作為整數(shù)傳遞給片元著色器,片元著色器中使用uniform變量對(duì)應(yīng)這個(gè)紋理采樣器,使用變量類(lèi)型為:

uniform?sampler2D?tex;

uniform變量與attribute變量?uniform變量與頂點(diǎn)著色器中使用的屬性變量(attribute variables)不同,?
屬性變量首先進(jìn)入頂點(diǎn)著色器,如果要傳遞給片元著色器,需要在頂點(diǎn)著色器中定義輸出變量輸出到片元著色器。而uniform變量則類(lèi)似于全局變量,在整個(gè)著色器程序中都可見(jiàn)。

完整的片元著色器代碼為:

#version?330

in?vec3?VertColor;
in?vec2?TextCoord;

uniform?sampler2D?tex;

out?vec4?color;


void?main()
{
????color?=?texture(tex,?TextCoord);
}

其中texture函數(shù)根據(jù)紋理坐標(biāo),獲取紋理對(duì)象中的紋素。?
運(yùn)行程序,效果如下圖所示:

這里為繪制的矩形添加了紋理,可以從我的github下載程序完整代碼。

重構(gòu)代碼

將上面處理紋理部分的代碼整理成一個(gè)函數(shù),放在textureHelper類(lèi)里,可以從我的github查看這個(gè)類(lèi)的代碼。使用textureHelper類(lèi)加載紋理的代碼為:

GLint?textureId?=?TextureHelper::load2DTexture("wood.png");

在上面的頂點(diǎn)著色器中,我們也傳遞了頂點(diǎn)顏色屬性,將頂點(diǎn)顏色和紋理混合,修改片元著色器中代碼為:

color?=?texture(tex,?TextCoord)?*?vec4(VertColor,?1.0f);

使用多個(gè)紋理單元

上面介紹了一個(gè)紋理單元支持多個(gè)紋理綁定到不同的目標(biāo),一個(gè)程序中也可以使用多個(gè)紋理單元加載多個(gè)2D紋理。使用多個(gè)紋理單元的代碼如下:

shader.use();
//?使用0號(hào)紋理單元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,?textureId1);
glUniform1i(glGetUniformLocation(shader.programId,?"tex1"),?0);?
//?使用1號(hào)紋理單元
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,?textureId2);
glUniform1i(glGetUniformLocation(shader.programId,?"tex2"),?1);

在著色器中,對(duì)兩個(gè)紋理的顏色進(jìn)行混合:

???#version?330

in?vec3?VertColor;
in?vec2?TextCoord;

uniform?sampler2D?tex1;
uniform?sampler2D?tex2;
uniform?float?mixValue;

out?vec4?color;


void?main()
{
????vec4?color1?=?texture(tex1,?TextCoord);
????vec4?color2?=?texture(tex2,?TextCoord);
????color?=?mix(color1,?color2,?mixValue);
}

其中mix函數(shù)完成顏色插值,函數(shù)原型為:

API?genType mix( genType x,?
genType y,?
genType a);

最終值得計(jì)算方法為:x×(1?a)+y×ax×(1?a)+y×a。?
mixValue通過(guò)程序傳遞,可以通過(guò)鍵盤(pán)上的A和S鍵,調(diào)整紋理混合值,改變混合效果。

運(yùn)行效果如下:

畫(huà)面中這只貓是倒立的,主要原因是加載圖片時(shí),圖片的(0,0)位置一般在左上角,而OpenGL紋理坐標(biāo)的(0,0)在左下角,這樣y軸順序相反。有的圖片加載庫(kù)提供了相應(yīng)的選項(xiàng)用來(lái)翻轉(zhuǎn)y軸,SOIL沒(méi)有這個(gè)選項(xiàng)。我們可以修改頂點(diǎn)數(shù)據(jù)中的紋理坐標(biāo)來(lái)達(dá)到目的,或者對(duì)于我們這里的簡(jiǎn)單情況使用如下代碼實(shí)現(xiàn)y軸的翻轉(zhuǎn):

vec4?color2?=?texture(tex2,?
????vec2(TextCoord.s,?1.0?-?TextCoord.t));

修改后的運(yùn)行效果如下所示:

上述程序完整的代碼可以從我的github下載。

說(shuō)明?限于時(shí)間關(guān)系,文中的示例圖片部分來(lái)源于網(wǎng)絡(luò),均注明了出處,向原作者表示感謝。

參考資料Android Lesson Six: An Introduction to Texture Filteringwww.learnopengl.com?TexturesBasic Texture MappingTextures objects and parametersTutorial 5 : A Textured Cube推薦閱讀關(guān)于Texture filtering?Shawn Hargreaves Blog-Texture filtering關(guān)于Mipmap的Shawn Hargreaves Blog-Texture filtering: mipmaps

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱(chēng),數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉