OpenGL ES: 紋理採樣 texture sample

嚴正聲明:
作者:psklf
出處: https://www.cnblogs.com/psklf/p/5762308.html
歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接;否則必究法律責任!
Sampler (GLSL)
Sampler通常是在Fragment shader(片元着色器)內定義的,這是一個uniform類型的變量,即處理不同的片元時這個變量是一致不變的。一個sampler和一個texture對應,類型也是對應的,比如sampler2D 的sampler對應的就是GL_TEXTURE_2D類型的紋理對象。Sampler是個變量,但是它是沒有值的,或者說是特殊的一種類型,討論其數值沒有意義,只要明確其同一個texture對應即可。sampler變量在shader內使用的地方就是texture函數。這是一個lookup 函數(我不知道該如何翻譯,我的理解是這是一個查找/查詢的函數,以給定的紋理座標去紋理的數據中查到相應的顏色的信息),得到顏色信息渲在每一個片元上。例如,一個三角形,我們只要傳遞三個紋理座標給頂點着色器就行了,接着片元着色器會爲每個像素生成紋理座標的插值,根據紋理座標就得到了每一個像素的顏色值。

紋理採樣的機制
Texture Wrapping
紋理座標通常的範圍是從(0, 0)到(1, 1),如果我們把紋理座標設置爲範圍以外會發生什麼?OpenGL默認的行爲是重複這個紋理圖像(我們簡單地忽略浮點紋理座標的整數部分),但OpenGL提供了更多的選擇:

GL_REPEAT:紋理的默認行爲。重複紋理圖像。
GL_MIRRORED_REPEAT:和GL_REPEAT一樣,除了重複的圖片是鏡像放置的。
GL_CLAMP_TO_EDGE:紋理座標會在0到1之間。超出的部分會重複紋理座標的邊緣,就是邊緣被拉伸。
GL_CLAMP_TO_BORDER:超出的部分是用戶指定的邊緣的顏色。
在生成紋理對象的時候,需要用 glTexParameter() 設置一系列參數,設置的就是這個參數以及下面的 Texture Filtering 的參數。

Texture Filtering
magnification/minification
組成紋理的圖片數據和其要貼上去的形狀的大小往往是不一樣的。兩種情況:

magnification:紋理圖片小,貼圖區域大,需要放大紋理
minification:反過來,紋理圖片大,貼圖區域小,縮小紋理顯示出來
在做放大和縮小的操作的時候的具體的策略如下:

GL_NEAREST:直接選擇最臨近的像素的顏色,magnification(放大)時:由於多個片元會在同一個紋理像素上面取值,故最終得到的圖片顆粒度很大,會有鋸齒。
GL_LINEAR:根據臨近四個的像素點的顏色值,做線性的插值計算,得到最終的顏色。magnification(放大)時:不會產生鋸齒,顯示更加平滑。
在minification(縮小)時,上面的兩種方法其實都不理想,無論如何都會丟失很多圖片的細節,OpenGL 用Mipmap來解決這個問題。

Mipmap
它就是一系列紋理,每個後面的一個紋理是前一個的二分之一,這一系列的紋理是OpenGL生成的,生成時進行了圖像質量的優化,使其擁有更多的細節。這一系列的紋理是提前生成的,程序運行時只需要從中挑出合適大小的紋理應用即可,而不是運行時進行圖像大小的處理,效率上會有提高。

OpenGL渲染的時候,兩個不同級別的mipmap之間會產生不真實感的生硬的邊界。就像普通的紋理過濾一樣,也可以在兩個不同mipmap級別之間使用NEAREST和LINEAR過濾。指定不同mipmap級別之間的過濾方式可以使用下面四種選項代替原來的過濾方式:

GL_NEAREST_MIPMAP_NEAREST:接收最近的mipmap來匹配像素大小,並使用最臨近插值進行紋理採樣。
GL_LINEAR_MIPMAP_NEAREST:接收最近的mipmap級別,並使用線性插值採樣。
GL_NEAREST_MIPMAP_LINEAR:在兩個mipmap之間進行線性插值,通過最鄰近插值採樣。
GL_LINEAR_MIPMAP_LINEAR:在兩個相鄰的mipmap進行線性插值,並通過線性插值進行採樣。
總結一下:magnification和minification的時候都可以設置NEAREST和LINEAR兩種方式;minification的時候還可以設置mipmap的方式,該方法效果更好。關於具體的算法的實現,可以參考《OpenGL ES specification》的8.13-8.14內容。

Sampler object
一個texture對象包括了兩部分的屬性,一部分是具體的圖片信息,另一部分是紋理採樣的設置,即上文提到的不同的方式。通常生成紋理的時候是將這兩部分一起設置好的,但是後面這部分的內容可以單獨拿出來,封裝成爲一個對象,就是 sampler object .

使用 GenSamplers() 函數創建一個新的sampler對象,然後用 BindSampler() 做綁定操作,將sampler和texture對象綁定起來,然後調用 glSamplerParameterf() 這一類的函數來設置sampler的具體的參數。

texture object, sampler object, program object 的關係如圖:

參考資料:

OpenGL 教程–紋理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章