紋理的加載
當我們設置好紋理對象后暴匠,就可以加載我們的紋理數(shù)據(jù)了孙咪。下面這個例子演示了如何加載一幅2*2像素的紋理:
這個函數(shù)非常重要沃饶,下面我們來看一下每個參數(shù)所表示的意義:
第一個參數(shù)很簡單先紫,表示綁定紋理對象的種類骗绕,這里我們依然以GL_TEXTURE_2D的紋理為例。
第二個參數(shù)表示該紋理對應的mipmaps的等級蹲嚣,0表示沒有進行縮小的原始圖片等級递瑰。
第三個參數(shù)表示了紋理所采用的內部格式,內部格式是我們的像素數(shù)據(jù)在顯卡中存儲的格式隙畜,這里的GL_RGB顯然就表示紋理中像素的顏色值是以RGB的格式存儲的抖部。
第四個和第五個參數(shù)表示了紋理的寬和高,這里我們采用的是2*2像素寬度的紋理议惰,因此這兩個參數(shù)都是2慎颗。
第六個參數(shù)通常為0.
第七和第八個參數(shù)描述了像素在內存中的存儲格式和數(shù)據(jù)類型。
第九個參數(shù)是存放紋理數(shù)據(jù)的指針。
不過問題又來了俯萎,我們如何生成一個含有紋理數(shù)據(jù)的數(shù)組呢傲宜?在實際工作中,我們通常需要使用一張JPG和PNG等格式的圖片文件作為模型的紋理夫啊,而OpenGL中并沒有提供相關API用于將這些圖片文件轉換成我們所需要的數(shù)組函卒。因此我們需要使用第三方庫來解決這一難題,目前使用得最廣泛的應該是SOIL庫撇眯,下面我們將以它為例來介紹如何將圖片文件轉換成紋理數(shù)據(jù)报嵌。
SOIL
SOIL(Simple OpenGL Image Library)是一個簡單易用的圖片加載庫,它提供的API可以將指定的任意格式圖片文件加載并生成紋理數(shù)據(jù):
這里熊榛,我們將一個名為“img.png”的圖片文件加載進內存锚国,最終將存儲紋理數(shù)據(jù)的指針image返回給我們,并且這個API還同時可以獲取圖片的寬度width和高度height玄坦,也可以指定內部格式為RGB血筑。
紋理數(shù)據(jù)使用完畢后釋放的工作也可以交給它完成:
正如上一篇中所提到的,OpenGL中紋理坐標系是以紋理左下角為坐標原點的煎楣,而圖片中像素的存儲順序是從左上到右下的豺总,因此我們需要對我們的坐標系進行一次Y軸的“翻轉”。我們以后的教程中的0,0坐標將會假設為是紋理的左上角而不再是左下角转质,這樣講解起來會更加直觀一些园欣。
使用紋理
我們知道紋理是采用紋理坐標進行采樣的,我們在使用紋理時休蟹,需要將頂點對應的紋理坐標輸入OpenGL沸枯。這里我們創(chuàng)建一個矩形區(qū)域的頂點數(shù)組,數(shù)組里每個頂點所包含的數(shù)據(jù)除位置赂弓、顏色外绑榴,還有紋理坐標的s和t值。
頂點著色器中將紋理坐標Texcoord接收并傳入片段著色器:
和其他頂點屬性一樣盈魁,將紋理坐標以AttribPointer的形式輸入著色器:
現(xiàn)在只剩下最后一件事情要處理翔怎,那就是在片段著色器中進行真正的紋理采樣。采樣方式很簡單杨耙,首先在著色器中聲明一個sapler2D類型的采樣器tex赤套,然后調用texture函數(shù)進行采樣。texture函數(shù)第一個參數(shù)是采樣器珊膜,第二個參數(shù)就是我們由頂點著色器傳入的紋理坐標容握。在這里我們對采集后的紋理與我們頂點的顏色進行一個混合,混合的方式就是對兩者做一個笛卡爾積车柠。
最終我們得到的效果如下:
紋理單元
紋理單元是能夠被著色器采樣的紋理對象的引用剔氏, 紋理通過調用glBindTexture函數(shù)綁定到指定的紋理單元塑猖。由于你沒有明確指定使用哪個紋理單元,所以紋理被默認綁定到了GL_TEXTURE0谈跛,這就是為什么我們在片段著色器中給我們的采樣器對象傳入一個0它依然能夠正常工作的原因羊苟。
那么我們怎么指定當前我們使用的紋理單元呢?OpenGL提供了一個叫做glActiveTexture的API來讓我們選擇用來綁定紋理的紋理單元ID:
OpenGL中最大支持的紋理單元數(shù)量根據(jù)顯卡不同而有所區(qū)別感憾,最少支持48個蜡励。不過基本上你同時用完所有紋理單元的幾率為0。下面讓我們通過一個例子來看看怎樣同時使用多個紋理單元來完成多張紋理的混合阻桅,首先我們需要修改一下我們的片段著色器巍虫,讓它同時對兩張紋理進行采樣:
colKitten和colPuppy分別對應兩幅紋理中的采樣結果,最終的片段顏色值由mix函數(shù)將兩者進行混合后得到鳍刷。
mix這個函數(shù)是GLSL中一個特殊的線性插值函數(shù),他將前兩個參數(shù)的值基于第三個參數(shù)按照以下公式進行插值:
genType mix (genType x, genType y, float a)
返回線性混合的x和y俯抖,如:x?(1?a)+y?a
現(xiàn)在我們的兩個采樣器對象texKitten和texPuppy已經準備好了输瓜,你需要在應用程序中將兩幅紋理綁定給兩個紋理單元,再將這兩個紋理單元的ID通過glUniform函數(shù)分別賦值給我們的采樣器芬萍,應用程序端代碼如下:
最終兩張紋理混合后得到的效果如下:
至此尤揣,如何使用簡單的二維紋理已經介紹完畢了,如果有什么疑問可以進入我們的QQ群:280689979中進行討論柬祠。