當前位置: 妍妍網 > 碼農

OpenGL 面試中被問到的 Mipmap 紋理,了解下

2024-04-18碼農

一 、先了解紋理過濾

想要了解為什麽要使用Mipmap,首先要知道 紋理過濾 是什麽。

當你在玩吃雞的時候可能會發現一個現象,一個人在距離你5公尺的地方,可以觀察到敵人的一舉一動,包括身上的裝備等等,但當你拿到98k時,你會蹲在遠處狙擊別人,這時不開鏡的你看500公尺遠處的敵人只能看到一個黑點,這其中遠近看到的區別就有套用到 紋理過濾

遊戲中A物體的遊戲設計紋理貼圖是400*400Texel(紋理像素)

1. 當你(攝影機)跟A物體的距離為0時,在你螢幕上顯示的像素就是400*400,跟貼圖的紋理像素大小相同,此時不需要做特殊處理

2. 假設你離A物體10公尺遠時,螢幕顯示的pix為200*200,當200*200的像素要顯示400*400紋理像素的物體時,此時的一顆像素需要對映2*2的紋理像素,這個時候就有個問題了,這顆像素要顯示什麽顏色?

只能用合適的演算法在這2*2裏的紋理像素中計算得出,在這裏參照OpenGL中的鄰近過濾和線性過濾:

GL_NEAREST(也叫鄰近過濾,Nearest Neighbor Filtering)是OpenGL預設的紋理過濾方式。當設定為GL_NEAREST的時候,OpenGL會選擇中心點最接近紋理座標的那個像素。

下圖中你可以看到四個像素,加號代表紋理座標。左上角那個紋理像素的中心距離紋理座標最近,所以它會被選擇為樣本顏色:

GL_LINEAR(也叫線性過濾,(Bi)linear Filtering)它會基於紋理座標附近的紋理像素,計算出一個插值,近似出這些紋理像素之間的顏色。

一個紋理像素的中心距離紋理座標越近,那麽這個紋理像素的顏色對最終的樣本顏色的貢獻越大。下圖中你可以看到返回的顏色是鄰近像素的混合色:

那麽這兩種紋理過濾方式有怎樣的視覺效果呢?讓我們看看在一個很大的物體上套用一張低分辨率的紋理會發生什麽吧(紋理被放大了,每個紋理像素都能看到):

二、當距離很遠的時候怎麽算?

此時的你來到遠離市區500公尺的山上,想要狙擊別人,你只能看到一個個很小的人影,在不開鏡的情況下只能看到人的跑動。

此時敵人在螢幕顯示為20*20,400*400的紋理像素對映在20*20的像素內,一顆像素需要對映20*20的紋理像素。

如果直接進行紋理過濾,那麽在使用線性過濾的情況下,只會使用紋理座標對映點的周圍4顆紋理像素進行計算,那麽其他的396顆紋理像素就沒了參考價值。

考慮極端情況下,如果紋理座標對映點在人的頭發,那麽不就只是顯示黑色了?

那麽在最終的顯示效果上可能會產生 鋸齒 或者 莫耳紋 ,莫耳紋長這樣:

這視覺效果必須得改善,那我不能參考所有需要對映的紋理像素進行平均取色嗎?

可以,但是你的GPU允許你這麽做嗎,有興趣可以做個實驗,自己采樣所有紋理像素進行紋理過濾,此時你如果遠處的模型較多的情況下,

使用原生的線性過濾:60FPS,渲染一個物體每顆像素的顏色需要計算4個紋理像素的插值。

采樣所有紋理像素進行紋理過濾:1FPS,渲染一個物體每顆像素的顏色需要采樣計算400個紋理像素的插值。

可以想象效能換品質的消耗實在太大,在如今的GPU算力下是施行不了的.

那有辦法不損耗算力,又可以提升顯示品質嗎?可以,使用Mipmap.

三、Mipmap概念

想象一下,假設我們有一個包含著上千物體的大房間,每個物體上都有紋理。有些物體會很遠,但其紋理會擁有與近處物體同樣高的分辨率。

由於遠處的物體可能只產生很少的片段,OpenGL從高分辨率紋理中為這些片段獲取正確的顏色值就很困難,因為它需要對一個跨過紋理很大部份的片段只拾取一個紋理顏色。

在小物體上這會產生不真實的感覺,更不用說對它們使用高分辨率紋理浪費記憶體的問題了。

OpenGL使用一種叫做多級漸遠紋理(Mipmap)的概念來解決這個問題,它簡單來說就是一系列的紋理影像,後一個紋理影像是前一個的二分之一。

多級漸遠紋理背後的理念很簡單: 距觀察者的距離超過一定的閾值,OpenGL會使用不同的多級漸遠紋理,即最適合物體的距離的那個

由於距離遠,解析度不高也不會被使用者註意到。同時,多級漸遠紋理另一加分之處是它的效能非常好。

四、Mipmap效果

上圖是Mipmap的紋理, 在儲存上最大的為mipmap0,mipmap1的分辨率為mipmap0的一半,以此一直建立下去,直到紋理為一個像素時停止 ,在某些引擎中可以設定Mipmap的強弱,也就是Mipmap的建立次數。但一般直接拉到最強,因為越到後面建立的大小越小,占用的記憶體也就越小.

不使用Mipmap:

在先前講的1顆像素需要對映20*20的紋理像素時,顯示效果失真,鋸齒以及可能會產生莫耳紋,發生的原因是在紋理過濾時 ,一顆像素只采樣了原本20*20紋理像素裏2*2紋理像素的顏色進行線性插值,得到最終的顏色,其他的396顆紋理像素無用,浪費視訊記憶體且取色不精確。

使用Mipmap:

Mipmap建立: 預先建立原紋理大小2分之一的多級漸遠紋理,在多級漸遠紋理取色采樣時,也會進行線性過濾,可以理解成預先建立每隔一定閾值(也就是每次對映像素為上一級別多級漸遠紋理的2分之一的時候)並經過了線性過濾的紋理。

使用Mipmap的渲染過程:20*20的像素需要對映400*400的紋理像素時,檢測到一顆像素需要對映到紋理像素為20*20,在Mipmap紋理中裏尋找最接近20*20紋理像素的多級漸遠紋理,並使用此多級漸遠紋理進行采樣。

此時采樣用的多級漸遠紋理的顏色也是從上一級的多級漸遠紋理叠代采樣插值計算而來,也就是一顆像素對映此多級漸遠紋理間接插值計算了20*20的紋理像素的顏色,取色的效果當然比一顆像素直接對映原圖20*20只采樣了2*2的紋理像素顏色進行線性插值要好得多,使用Mipmap就避免了采樣的紋理像素過少而失真,

理論上點對點的對映最為精確,而如果最鄰近的子紋理跟20*20無法點對點采樣對映,還可以設定多級漸遠紋理的過濾方式

過濾方式 描述
GL_NEAREST_MIPMAP_NEAREST 使用最鄰近的多級漸遠紋理來匹配像素大小,並使用鄰近插值進行紋理采樣
GL_LINEAR_MIPMAP_NEAREST 使用最鄰近的多級漸遠紋理級別,並使用線性插值進行采樣
GL_NEAREST_MIPMAP_LINEAR 在兩個最匹配像素大小的多級漸遠紋理之間進行線性插值,使用鄰近插值進行采樣
GL_LINEAR_MIPMAP_LINEAR 在兩個鄰近的多級漸遠紋理之間使用線性插值,並使用線性插值進行采樣

五、Mipmap的優點與缺點

優點:

1.品質高: 避免了在遠距離情況下的采樣頻率低和數據頻率高造成的失真和莫耳紋,效果比無Mipmap好得多。

2.效能好: 避免了不使用Mipmap下距離遠時采樣頻率低和數據頻率高而照成texture cache命中率不高(相鄰Pixel采樣Texel時uv相差比較大)使效能下降。

缺點:

1. 占用視訊記憶體,可使用ue的紋理流緩存最佳化(IO換視訊記憶體)

六:UE4的紋理流緩存(多級漸變紋理的記憶體最佳化)

UE4的紋理流緩存是動態的,在攝影機位置離物體遠時,紋理流緩存會動態重新整理目前位置的多級漸變紋理,所以在遠的時候緩存區小,近的時候緩存區大,緩存的紋理大小隨距離遠近需求的紋理細節而改變.只有紋理細節大且多,占用視訊記憶體過高的3A級別的遊戲,才會使用紋理流緩存最佳化視訊記憶體空間(IO換視訊記憶體)。

原文連結: https://blog.csdn.net/qq_42428486/article/details/118856697

-- END --

進技術交流群, 掃碼添加我的微信:Byte-Flow

獲取相關資料和源碼

學習音視訊、OpenGL ES、Vulkan 、Metal、影像濾鏡、視訊特效及相關渲染技術的付費社群,面試指導,1v1 簡歷服務,職業規劃。

我的付費社群

推薦: