轉自:http://blog.csdn.net/i_dovelemon/article/details/27839279 算法
在3D空間中,紋理圖的大小每每並不老是和定義的三角形一樣的大小。也就是說,咱們須要對紋理進行放大和縮小,也就是進行縮放操做。那麼咱們如何對紋理進行操做,纔可以讓紋理可以放大和縮小以後,不會變的混亂不堪了?app
在這裏,使用的就是各類採樣方法,對紋理圖進行採樣,爲了更好的效果可能還須要再使用濾波器進行過濾。在DirectX中,支持三種不一樣種類的採樣方法。下面一一介紹他們。測試
首先給出這三種採樣方式的名稱,他們分別是:優化
咱們知道,在上面定義了幾個頂點的紋理座標,可是對於一個三角形來講,它是一個平面,它須要將紋理整個的映射到這個平面上來。也就是說,如何經過這三個頂點的紋理座標,來鋪滿整個平面? 讀者,可能注意到這個問題,和咱們之前討論的如何經過頂點的顏色,而後將整個三角形進行着色的問題很類似。對頭,這裏,咱們也是使用插值的方式來獲取每個像素點的紋理座標,而後經過這個紋理座標,採用不一樣的採樣方式來獲取紋理圖中的像素值,使用這個採集的值來填充這個像素。spa
咱們知道了如何進行紋理的插值(插值方法和前面介紹的顏色插值一致,這裏再也不贅述)以後,就要肯定到底使用哪一種採樣方法來進行採樣。下面將一一介紹不一樣的採樣方法。.net
點採樣,故名示意,就是使用咱們進行插值後的紋理座標來將它擴展到與紋理圖相應的尺寸大小(還記的前面說過的,紋理座標其實是歸一化的座標),而後將這個變換後的紋理座標進行取整,也就是截取小數部分,只保留整數部分,而後就使用這個整數的座標來獲取紋理圖中對應的紋素值。htm
好比下面的數據:blog
咱們紋理圖的尺寸是128*128 ;遊戲
咱們通過插值計算後的某個像素點的紋理座標爲(0,70,0.55)ip
那麼咱們將這個紋理座標進行變化,使得紋理座標的尺寸和紋理圖的尺寸一致,即:
0.70 * 128 = 89.6, 0.55 * 128 = 70.4
再進行取整操做獲得最後的紋理圖上的座標爲(89, 70)
而後,咱們就使用這樣的座標,來獲取紋理圖中第89列,第70行的那個像素的值,用這個值來填充咱們計算的那個像素點的顏色。
讀者能夠看出,因爲咱們截取了小數部分,因此失去的部分的信息,這樣的採樣方法效果確定是很不理想的。一種稍微改進點的方法就是保留小數部分,而將採起紋理圖中相鄰的兩個像素的值,使用小數部分做爲權值來進行採樣。
拿上面的例子來講吧,咱們計算後的保留小數的紋理圖座標爲(89.6, 70.4),而取整以後的數據爲(89,70)。
那麼咱們能夠發現,這個像素實際上佔用的空間是89列和90列這兩個像素的位置,也就是說它有0.6的(89,70)位置像素值,有0.4的(90,70)的像素值,因此最後的像素值應該爲:
0.6 * Texel(89,70) + 0.4 * Texel(90, 70)
經過這樣的方式,咱們能稍微的改進點採樣方法的效果。
點採樣方法效果不好,可是因爲操做簡單,因此效率會很高。
讀者可能發現,咱們上面討論改進版的點採樣方法時,故意沒有考慮v座標的跨度關係。也就是說,我只考慮了u座標,在相鄰兩個座標上的權值關係。因此,若是將v座標上的權值關係也考慮進去,效果是否更加的逼真了呢?
的確,這就是所謂的雙線性採樣理論。經過在u和v兩種維度上,都考慮權值關係,來獲取最後的像素值。
仍是拿上面的關係舉例,很明顯,這個紋理座標牽涉到了四個像素,他們的座標分別是(89,70), (90,70), (89,71)和(90,71)。
咱們知道了它是和這四個像素點相關的,那麼只要獲取每個像素點上的權值,咱們天然就可使用權值平均的方法來獲取最後的像素值了。爲了明確該紋理座標,在這四個像素上所佔有的權值,咱們使用圖示的方式來闡釋:
咱們就能夠經過下面的公式來計算各個像素的權值,這個公式能夠很容易的從上圖中推導來:
(89,70) : (89.6 - 89) * (70.4 - 70) = 0.6 * 0.4 = 0.24 ;
(90,70) : (90 - 86.6) * (70.4 - 70) = 0.4 * 0.4 = 0.16 ;
(89,71) : (89.6 - 89) * (71 - 70.4) = 0.6 * 0.6 = 0.36 ;
(90,71) : (90 - 89.6) * (71 - 70.4) = 0.4 * 0.6 = 0.24 ;
咱們將上面計算出來的權值相加,即0.24 + 0.16 + 0.36 + 0.24 = 1.0 ,也就是說完整的表述了這個像素值。
而後咱們用上面的權值分別乘以每個像素的值,來獲取最後的像素:
0.24 * Texel(89, 70) + 0.16 * Texel(90, 70) + 0.36 * Texel(89, 71) + 0.24 * Texel(90, 71)
好了,經過上面的方法,咱們就可以獲得最後的像素值了,並且這個方法可以基本上徹底保留紋理座標的信息,因此效果十分的不錯(之因此說基本上保留,是由於在進行插值計算的時候,使用浮點數,老是會存在一點偏差,因此會損失一點信息)。不少遊戲,都是採用這樣的方法來進行紋理的縮放的。
在講解三線性紋理濾波採樣以前,先來說解下什麼是Mipmap,以及使用Mipmap來作什麼用途。
咱們知道,在3D空間中,紋理圖老是要被縮放的,而咱們在本來紋理圖上進行採樣,並不老是那麼可靠。好比說,紋理圖的大小其實是128*128的尺寸。而咱們在3D程序中,咱們僅僅須要一個4*4的紋理圖就能夠了。若是,咱們在這個大圖上,獲取這個4*4的小圖的話,操做複雜,並且效果不理想。因此,若是,咱們可以預先使用這個大圖,來建立一些尺寸較小的圖,那麼在進行採樣的時候,咱們能夠選取,與須要的尺寸最接近的紋理圖來進行採樣。經過這樣的方式,不只可以提升效率,也能某種程度上改善效果。
Mipmap的做用就是這樣的。在DirectX中,你加載紋理的時候,它老是爲你建立了Mipmap鏈。若是你加載的是一個128*128的紋理圖,那麼它會爲你建立一個64*64, 32*32, 16*16, 8*8, 4*4 , 2*2, 1*1的紋理圖。
建立這些紋理圖的方法,就是須要進行採樣,一樣的,它是使用前面介紹的雙線性採樣方法進行採樣的。
當在3D空間中,某一個三角形須要一個紋理圖的時候,咱們先來判斷,它最接近的紋理圖是哪個。好比說,它須要的其實是50*50的紋理圖,那麼咱們就會發現,使用64*64的紋理圖,來進行採樣,效果會更好。實際上,選擇哪個Mip等級,有不少不一樣的實現方法,我並不知道DirectX是使用哪一種方式的,可是,它的原理無外乎就是選取最接近該紋理的紋理等級。
好了,在講述完了上面的Mipmap以後,就能夠來說解如何實現三次線性濾波採樣了。通常來講,三次線性濾波,已是紋理濾波的極限了,沒有辦法作的比它更好了。實際上,這個濾波方式,就是結合了前面介紹的Mipmap和雙線性採樣理論來共同實現。
咱們首先經過某種方法來獲取最終的Mipmap等級,多是經過面積計算,也多是經過其餘的方式來獲取,而最終獲取到的Mipmap等級值,會是像4.3這樣的帶有小數的值。這個小數的意思就是,咱們將要使用Mipmap等級爲4和5的這兩個紋理來進行紋理採樣,採樣的方法就是使用雙線性紋理濾波採樣來進行。經過這樣的方法,咱們可以獲得更加平滑的效果。
實現方式,將不會以代碼的形式來提供給你們,若是讀者感興趣的話,能夠本身寫個軟引擎,而後測試一下這個算法。可是不要指望,在軟件引擎中大量的使用此種算法,這樣的算法消耗將是很是巨大的。只可以少許的使用。
轉自:http://dev.gameres.com/Program/Visual/3D/Bilinear.htm
|
||||
|